summaryrefslogtreecommitdiffstats
path: root/kicker/taskmanager
diff options
context:
space:
mode:
Diffstat (limited to 'kicker/taskmanager')
-rw-r--r--kicker/taskmanager/Makefile.am11
-rw-r--r--kicker/taskmanager/configure.in.in25
-rw-r--r--kicker/taskmanager/tasklmbmenu.cpp281
-rw-r--r--kicker/taskmanager/tasklmbmenu.h85
-rw-r--r--kicker/taskmanager/taskmanager.cpp1521
-rw-r--r--kicker/taskmanager/taskmanager.h713
-rw-r--r--kicker/taskmanager/taskrmbmenu.cpp328
-rw-r--r--kicker/taskmanager/taskrmbmenu.h59
8 files changed, 3023 insertions, 0 deletions
diff --git a/kicker/taskmanager/Makefile.am b/kicker/taskmanager/Makefile.am
new file mode 100644
index 000000000..ffe7912e7
--- /dev/null
+++ b/kicker/taskmanager/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = $(all_includes) -I$(srcdir)/../libkicker
+
+lib_LTLIBRARIES = libtaskmanager.la
+libtaskmanager_la_SOURCES = tasklmbmenu.cpp taskrmbmenu.cpp taskmanager.cpp
+libtaskmanager_la_METASOURCES = AUTO
+
+libtaskmanager_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined
+libtaskmanager_la_LIBADD = $(LIB_KDECORE) $(LIB_XFIXES) $(LIB_XRENDER) $(LIB_XCOMPOSITE) ../libkicker/libkickermain.la
+
+messages:
+ $(XGETTEXT) *.cpp *.h -o $(podir)/libtaskmanager.pot
diff --git a/kicker/taskmanager/configure.in.in b/kicker/taskmanager/configure.in.in
new file mode 100644
index 000000000..0ee479dde
--- /dev/null
+++ b/kicker/taskmanager/configure.in.in
@@ -0,0 +1,25 @@
+if test "x$with_composite" != "xno"; then
+ dnl XComposite check
+ KDE_CHECK_HEADER(X11/extensions/Xcomposite.h, [xcomposite_h=yes], [xcomposite_h=no], [#include <X11/Xlib.h>])
+ if test "$xcomposite_h" = yes; then
+ KDE_CHECK_LIB(Xcomposite, XCompositeQueryExtension, [
+ LIB_XCOMPOSITE=-lXcomposite
+ AC_DEFINE_UNQUOTED(HAVE_XCOMPOSITE, 1, [Define if you have the XComposite extension])
+ ], [], -lXext -lX11 $X_EXTRA_LIBS)
+ else
+ LIB_XCOMPOSITE=
+ fi
+ AC_SUBST(LIB_XCOMPOSITE)
+fi
+
+dnl XFixes check
+KDE_CHECK_HEADER(X11/extensions/Xfixes.h, [xfixes_h=yes], [xfixes_h=no], [#include <X11/Xlib.h>])
+if test "$xfixes_h" = yes; then
+ KDE_CHECK_LIB(Xfixes, XFixesQueryExtension, [
+ LIB_XFIXES=-lXfixes
+ AC_DEFINE_UNQUOTED(HAVE_XFIXES, 1, [Define if you have the XFixes extension])
+ ], [], -lXext -lX11 $X_EXTRA_LIBS)
+else
+ LIB_XFIXES=
+fi
+AC_SUBST(LIB_XFIXES)
diff --git a/kicker/taskmanager/tasklmbmenu.cpp b/kicker/taskmanager/tasklmbmenu.cpp
new file mode 100644
index 000000000..03278c0fe
--- /dev/null
+++ b/kicker/taskmanager/tasklmbmenu.cpp
@@ -0,0 +1,281 @@
+/*****************************************************************
+
+Copyright (c) 2001 Matthias Elter <[email protected]>
+Copyright (c) 2002 John Firebaugh <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include "tasklmbmenu.h"
+#include "tasklmbmenu.moc"
+
+#include <qpainter.h>
+#include <qstyle.h>
+
+#include <kdebug.h>
+#include <kglobalsettings.h>
+
+#include "global.h"
+
+TaskMenuItem::TaskMenuItem(const QString &text,
+ bool active, bool minimized, bool attention)
+ : QCustomMenuItem(),
+ m_text(text),
+ m_isActive(active),
+ m_isMinimized(minimized),
+ m_demandsAttention(attention),
+ m_attentionState(true)
+{
+}
+
+TaskMenuItem::~TaskMenuItem()
+{
+}
+
+void TaskMenuItem::paint(QPainter *p, const QColorGroup &cg,
+ bool highlighted, bool /*enabled*/,
+ int x, int y, int w, int h )
+{
+ if (m_isActive)
+ {
+ QFont font = p->font();
+ font.setBold(true);
+ p->setFont(font);
+ }
+
+ if (highlighted)
+ {
+ p->setPen(cg.highlightedText());
+ }
+ else if (m_isMinimized)
+ {
+ p->setPen(QPen(KickerLib::blendColors(cg.background(), cg.text())));
+ }
+ else if (m_demandsAttention && !m_attentionState)
+ {
+ p->setPen(cg.mid());
+ }
+
+ p->drawText(x, y, w, h, AlignAuto|AlignVCenter|DontClip|ShowPrefix, m_text);
+}
+
+QSize TaskMenuItem::sizeHint()
+{
+ QFont font = QFont();
+ if (m_isActive)
+ {
+ font.setBold(true);
+ }
+ return QFontMetrics(font).size(AlignAuto|AlignVCenter|DontClip|ShowPrefix,
+ m_text);
+}
+
+/*****************************************************************************/
+
+TaskLMBMenu::TaskLMBMenu(const Task::List& tasks, QWidget *parent, const char *name)
+ : QPopupMenu(parent, name),
+ m_tasks(tasks),
+ m_lastDragId(-1),
+ m_attentionState(false)
+{
+ fillMenu();
+
+ setAcceptDrops(true); // Always enabled to activate task during drag&drop.
+
+ m_dragSwitchTimer = new QTimer(this, "DragSwitchTimer");
+ connect(m_dragSwitchTimer, SIGNAL(timeout()), SLOT(dragSwitch()));
+}
+
+void TaskLMBMenu::fillMenu()
+{
+ setCheckable(true);
+
+ Task::List::iterator itEnd = m_tasks.end();
+ for (Task::List::iterator it = m_tasks.begin(); it != itEnd; ++it)
+ {
+ Task::Ptr t = (*it);
+
+ QString text = t->visibleName().replace("&", "&&");
+
+ TaskMenuItem *menuItem = new TaskMenuItem(text,
+ t->isActive(),
+ t->isIconified(),
+ t->demandsAttention());
+ int id = insertItem(QIconSet(t->pixmap()), menuItem);
+ connectItem(id, t, SLOT(activateRaiseOrIconify()));
+ setItemChecked(id, t->isActive());
+
+ if (t->demandsAttention())
+ {
+ m_attentionState = true;
+ m_attentionMap.append(menuItem);
+ }
+ }
+
+ if (m_attentionState)
+ {
+ m_attentionTimer = new QTimer(this, "AttentionTimer");
+ connect(m_attentionTimer, SIGNAL(timeout()), SLOT(attentionTimeout()));
+ m_attentionTimer->start(500, true);
+ }
+}
+
+void TaskLMBMenu::attentionTimeout()
+{
+ m_attentionState = !m_attentionState;
+
+ for (QValueList<TaskMenuItem*>::const_iterator it = m_attentionMap.constBegin();
+ it != m_attentionMap.constEnd();
+ ++it)
+ {
+ (*it)->setAttentionState(m_attentionState);
+ }
+
+ update();
+
+ m_attentionTimer->start(500, true);
+}
+
+void TaskLMBMenu::dragEnterEvent( QDragEnterEvent* e )
+{
+ // ignore task drags
+ if (TaskDrag::canDecode(e))
+ {
+ return;
+ }
+
+ int id = idAt(e->pos());
+
+ if (id == -1)
+ {
+ m_dragSwitchTimer->stop();
+ m_lastDragId = -1;
+ }
+ else if (id != m_lastDragId)
+ {
+ m_lastDragId = id;
+ m_dragSwitchTimer->start(1000, true);
+ }
+
+ QPopupMenu::dragEnterEvent( e );
+}
+
+void TaskLMBMenu::dragLeaveEvent( QDragLeaveEvent* e )
+{
+ m_dragSwitchTimer->stop();
+ m_lastDragId = -1;
+
+ QPopupMenu::dragLeaveEvent(e);
+
+ hide();
+}
+
+void TaskLMBMenu::dragMoveEvent( QDragMoveEvent* e )
+{
+ // ignore task drags
+ if (TaskDrag::canDecode(e))
+ {
+ return;
+ }
+
+ int id = idAt(e->pos());
+
+ if (id == -1)
+ {
+ m_dragSwitchTimer->stop();
+ m_lastDragId = -1;
+ }
+ else if (id != m_lastDragId)
+ {
+ m_lastDragId = id;
+ m_dragSwitchTimer->start(1000, true);
+ }
+
+ QPopupMenu::dragMoveEvent(e);
+}
+
+void TaskLMBMenu::dragSwitch()
+{
+ bool ok = false;
+ Task::Ptr t = m_tasks.at(indexOf(m_lastDragId), &ok);
+ if (ok)
+ {
+ t->activate();
+
+ for (unsigned int i = 0; i < count(); ++i)
+ {
+ setItemChecked(idAt(i), false );
+ }
+
+ setItemChecked( m_lastDragId, true );
+ }
+}
+
+void TaskLMBMenu::mousePressEvent( QMouseEvent* e )
+{
+ if (e->button() == LeftButton)
+ {
+ m_dragStartPos = e->pos();
+ }
+ else
+ {
+ m_dragStartPos = QPoint();
+ }
+
+ QPopupMenu::mousePressEvent(e);
+}
+
+void TaskLMBMenu::mouseReleaseEvent(QMouseEvent* e)
+{
+ m_dragStartPos = QPoint();
+ QPopupMenu::mouseReleaseEvent(e);
+}
+
+void TaskLMBMenu::mouseMoveEvent(QMouseEvent* e)
+{
+ if (m_dragStartPos.isNull())
+ {
+ QPopupMenu::mouseMoveEvent(e);
+ return;
+ }
+
+ int delay = KGlobalSettings::dndEventDelay();
+ QPoint newPos(e->pos());
+
+ if ((m_dragStartPos - newPos).manhattanLength() > delay)
+ {
+ int index = indexOf(idAt(m_dragStartPos));
+ if (index != -1)
+ {
+ bool ok = false;
+ Task::Ptr task = m_tasks.at(index, &ok);
+ if (ok)
+ {
+ Task::List tasks;
+ tasks.append(task);
+ TaskDrag* drag = new TaskDrag(tasks, this);
+ drag->setPixmap(task->pixmap());
+ drag->dragMove();
+ }
+ }
+ }
+
+ QPopupMenu::mouseMoveEvent(e);
+}
+
diff --git a/kicker/taskmanager/tasklmbmenu.h b/kicker/taskmanager/tasklmbmenu.h
new file mode 100644
index 000000000..945c3e649
--- /dev/null
+++ b/kicker/taskmanager/tasklmbmenu.h
@@ -0,0 +1,85 @@
+/*****************************************************************
+
+Copyright (c) 2001 Matthias Elter <[email protected]>
+Copyright (c) 2002 John Firebaugh <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#ifndef __tasklmbmenu_h__
+#define __tasklmbmenu_h__
+
+#include <qpopupmenu.h>
+#include <qtimer.h>
+
+#include "taskmanager.h"
+
+class TaskMenuItem : public QCustomMenuItem
+{
+public:
+ TaskMenuItem(const QString &text,
+ bool active, bool minimized, bool attention);
+ ~TaskMenuItem();
+
+ void paint(QPainter*, const QColorGroup&, bool, bool, int, int, int, int);
+ QSize sizeHint();
+ void setAttentionState(bool state) { m_attentionState = state; }
+
+private:
+ QString m_text;
+ bool m_isActive;
+ bool m_isMinimized;
+ bool m_demandsAttention;
+ bool m_attentionState;
+};
+
+/*****************************************************************************/
+
+class KDE_EXPORT TaskLMBMenu : public QPopupMenu
+{
+ Q_OBJECT
+
+public:
+ TaskLMBMenu(const Task::List& list, QWidget *parent = 0, const char *name = 0);
+
+protected slots:
+ void dragSwitch();
+ void attentionTimeout();
+
+protected:
+ void dragEnterEvent(QDragEnterEvent*);
+ void dragLeaveEvent(QDragLeaveEvent*);
+ void dragMoveEvent(QDragMoveEvent*);
+ void mousePressEvent(QMouseEvent*);
+ void mouseMoveEvent(QMouseEvent*);
+ void mouseReleaseEvent(QMouseEvent*);
+
+private:
+ void fillMenu();
+
+ Task::List m_tasks;
+ int m_lastDragId;
+ bool m_attentionState;
+ QTimer* m_attentionTimer;
+ QTimer* m_dragSwitchTimer;
+ QPoint m_dragStartPos;
+ QValueList<TaskMenuItem*> m_attentionMap;
+};
+
+#endif
diff --git a/kicker/taskmanager/taskmanager.cpp b/kicker/taskmanager/taskmanager.cpp
new file mode 100644
index 000000000..dd9364c0e
--- /dev/null
+++ b/kicker/taskmanager/taskmanager.cpp
@@ -0,0 +1,1521 @@
+/*****************************************************************
+
+Copyright (c) 2000 Matthias Elter <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qimage.h>
+#include <qtimer.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <klocale.h>
+// #include <kpixmapio.h>
+#include <kstaticdeleter.h>
+#include <kwinmodule.h>
+#include <kxerrorhandler.h>
+#include <netwm.h>
+
+#include "taskmanager.h"
+#include "taskmanager.moc"
+
+TaskManager* TaskManager::m_self = 0;
+static KStaticDeleter<TaskManager> staticTaskManagerDeleter;
+uint TaskManager::m_xCompositeEnabled = 0;
+
+TaskManager* TaskManager::the()
+{
+ if (!m_self)
+ {
+ staticTaskManagerDeleter.setObject(m_self, new TaskManager());
+ }
+ return m_self;
+}
+
+TaskManager::TaskManager()
+ : QObject(),
+ _active(0),
+ _startup_info(0),
+ m_winModule(new KWinModule()),
+ m_trackGeometry(false)
+{
+ KGlobal::locale()->insertCatalogue("libtaskmanager");
+ connect(m_winModule, SIGNAL(windowAdded(WId)),
+ this, SLOT(windowAdded(WId)));
+ connect(m_winModule, SIGNAL(windowRemoved(WId)),
+ this, SLOT(windowRemoved(WId)));
+ connect(m_winModule, SIGNAL(activeWindowChanged(WId)),
+ this, SLOT(activeWindowChanged(WId)));
+ connect(m_winModule, SIGNAL(currentDesktopChanged(int)),
+ this, SLOT(currentDesktopChanged(int)));
+ connect(m_winModule, SIGNAL(windowChanged(WId,unsigned int)),
+ this, SLOT(windowChanged(WId,unsigned int)));
+
+ // register existing windows
+ const QValueList<WId> windows = m_winModule->windows();
+ QValueList<WId>::ConstIterator end(windows.end());
+ for (QValueList<WId>::ConstIterator it = windows.begin(); it != end; ++it)
+ {
+ windowAdded(*it);
+ }
+
+ // set active window
+ WId win = m_winModule->activeWindow();
+ activeWindowChanged(win);
+ configure_startup();
+}
+
+TaskManager::~TaskManager()
+{
+ KGlobal::locale()->removeCatalogue("libtaskmanager");
+}
+
+void TaskManager::configure_startup()
+{
+ KConfig c("klaunchrc", true);
+ c.setGroup("FeedbackStyle");
+ if (!c.readBoolEntry("TaskbarButton", true))
+ return;
+ _startup_info = new KStartupInfo( KStartupInfo::CleanOnCantDetect, this );
+ connect( _startup_info,
+ SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )),
+ SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )));
+ connect( _startup_info,
+ SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )),
+ SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )));
+ connect( _startup_info,
+ SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )),
+ SLOT( killStartup( const KStartupInfoId& )));
+ c.setGroup( "TaskbarButtonSettings" );
+ _startup_info->setTimeout( c.readUnsignedNumEntry( "Timeout", 30 ));
+}
+
+#ifdef THUMBNAILING_POSSIBLE
+void TaskManager::setXCompositeEnabled(bool state)
+{
+ Display *dpy = QPaintDevice::x11AppDisplay();
+
+ if (!state)
+ {
+ if (!--m_xCompositeEnabled)
+ {
+ // unredirecting windows
+ for (int i = 0; i < ScreenCount(dpy); i++)
+ {
+ XCompositeUnredirectSubwindows(dpy, RootWindow(dpy, i),
+ CompositeRedirectAutomatic);
+ }
+ }
+ return;
+ }
+
+ if (m_xCompositeEnabled)
+ {
+ // we don't unlearn riding bike ;)
+ m_xCompositeEnabled++;
+ return;
+ }
+
+ // XComposite extension check
+ int event_base, error_base;
+ if (!XCompositeQueryExtension(dpy, &event_base, &error_base))
+ {
+ return;
+ }
+
+ int major = 0, minor = 99; // The highest version we support
+ XCompositeQueryVersion(dpy, &major, &minor);
+
+ // We use XCompositeNameWindowPixmap(), i.e. we need at least
+ // version 0.2.
+ if (major == 0 && minor < 2)
+ {
+ return;
+ }
+
+ // XRender extension check
+ if (!XRenderQueryExtension(dpy, &event_base, &error_base))
+ {
+ return;
+ }
+
+ major = 0, minor = 99; // The highest version we support
+ XRenderQueryVersion(dpy, &major, &minor);
+
+ // We use SetPictureTransform() and SetPictureFilter(), i.e. we
+ // need at least version 0.6.
+ if (major == 0 && minor < 6)
+ {
+ return;
+ }
+
+ // XFixes extension check
+ if (!XFixesQueryExtension(dpy, &event_base, &error_base))
+ {
+ return;
+ }
+
+ major = 3, minor = 99; // The highest version we support
+ XFixesQueryVersion(dpy, &major, &minor);
+
+ // We use Region objects, i.e. we need at least version 2.0.
+ if (major < 2)
+ {
+ return;
+ }
+
+ // if we get here, we've got usable extensions
+ m_xCompositeEnabled++;
+
+ // redirecting windows to backing pixmaps
+ for (int i = 0; i < ScreenCount(dpy); i++)
+ {
+ XCompositeRedirectSubwindows(dpy, RootWindow(dpy, i),
+ CompositeRedirectAutomatic);
+ }
+
+ Task::Dict::iterator itEnd = m_tasksByWId.end();
+ for (Task::Dict::iterator it = m_tasksByWId.begin(); it != itEnd; ++it)
+ {
+ it.data()->updateWindowPixmap();
+ }
+}
+#else // THUMBNAILING_POSSIBLE
+void TaskManager::setXCompositeEnabled(bool)
+{
+}
+#endif // !THUMBNAILING_POSSIBLE
+
+Task::Ptr TaskManager::findTask(WId w)
+{
+ // TODO: might be able to be made more efficient if
+ // we check to see if w is a transient first?
+ // profiling would say whether this is worth the effort
+
+ Task::Dict::iterator it = m_tasksByWId.begin();
+ Task::Dict::iterator itEnd = m_tasksByWId.end();
+
+ for (; it != itEnd; ++it)
+ {
+ if (it.key() == w || it.data()->hasTransient(w))
+ {
+ return it.data();
+ }
+ }
+
+ return 0;
+}
+
+Task::Ptr TaskManager::findTask(int desktop, const QPoint& p)
+{
+ QValueList<WId> list = winModule()->stackingOrder();
+
+ Task::Ptr task = 0;
+ int currentIndex = -1;
+ Task::Dict::iterator itEnd = m_tasksByWId.end();
+ for (Task::Dict::iterator it = m_tasksByWId.begin(); it != itEnd; ++it)
+ {
+ Task::Ptr t = it.data();
+ if (!t->isOnAllDesktops() && t->desktop() != desktop)
+ {
+ continue;
+ }
+
+ if (t->isIconified() || t->isShaded())
+ {
+ continue;
+ }
+
+ if (t->geometry().contains(p))
+ {
+ int index = list.findIndex(t->window());
+ if (index > currentIndex)
+ {
+ currentIndex = index;
+ task = t;
+ }
+ }
+ }
+
+ return task;
+}
+
+void TaskManager::windowAdded(WId w )
+{
+ NETWinInfo info(qt_xdisplay(), w, qt_xrootwin(),
+ NET::WMWindowType | NET::WMPid | NET::WMState);
+
+ // ignore NET::Tool and other special window types
+ NET::WindowType wType =
+ info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask |
+ NET::ToolbarMask | NET::MenuMask | NET::DialogMask |
+ NET::OverrideMask | NET::TopMenuMask |
+ NET::UtilityMask | NET::SplashMask );
+
+ if (wType != NET::Normal &&
+ wType != NET::Override &&
+ wType != NET::Unknown &&
+ wType != NET::Dialog &&
+ wType != NET::Utility)
+ {
+ return;
+ }
+
+ // ignore windows that want to be ignored by the taskbar
+ if ((info.state() & NET::SkipTaskbar) != 0)
+ {
+ _skiptaskbar_windows.push_front( w ); // remember them though
+ return;
+ }
+
+ Window transient_for_tmp;
+ if (XGetTransientForHint( qt_xdisplay(), (Window) w, &transient_for_tmp ))
+ {
+ WId transient_for = (WId) transient_for_tmp;
+
+ // check if it's transient for a skiptaskbar window
+ if( _skiptaskbar_windows.contains( transient_for ))
+ return;
+
+ // lets see if this is a transient for an existing task
+ if( transient_for != qt_xrootwin()
+ && transient_for != 0
+ && wType != NET::Utility )
+ {
+ Task::Ptr t = findTask(transient_for);
+ if (t)
+ {
+ if (t->window() != w)
+ {
+ t->addTransient(w, info);
+ // kdDebug() << "TM: Transient " << w << " added for Task: " << t->window() << endl;
+ }
+ return;
+ }
+ }
+ }
+
+ Task::Ptr t = new Task(w, this);
+ m_tasksByWId[w] = t;
+
+ // kdDebug() << "TM: Task added for WId: " << w << endl;
+
+ emit taskAdded(t);
+}
+
+void TaskManager::windowRemoved(WId w)
+{
+ _skiptaskbar_windows.remove(w);
+
+ // find task
+ Task::Ptr t = findTask(w);
+ if (!t)
+ {
+ return;
+ }
+
+ if (t->window() == w)
+ {
+ m_tasksByWId.remove(w);
+ emit taskRemoved(t);
+
+ if (t == _active)
+ {
+ _active = 0;
+ }
+
+ //kdDebug() << "TM: Task for WId " << w << " removed." << endl;
+ }
+ else
+ {
+ t->removeTransient(w);
+ //kdDebug() << "TM: Transient " << w << " for Task " << t->window() << " removed." << endl;
+ }
+}
+
+void TaskManager::windowChanged(WId w, unsigned int dirty)
+{
+ if (dirty & NET::WMState)
+ {
+ NETWinInfo info (qt_xdisplay(), w, qt_xrootwin(),
+ NET::WMState | NET::XAWMState);
+ if (info.state() & NET::SkipTaskbar)
+ {
+ windowRemoved(w);
+ _skiptaskbar_windows.push_front(w);
+ return;
+ }
+ else
+ {
+ _skiptaskbar_windows.remove(w);
+ if (info.mappingState() != NET::Withdrawn && !findTask(w))
+ {
+ // skipTaskBar state was removed and the window is still
+ // mapped, so add this window
+ windowAdded( w );
+ }
+ }
+ }
+
+ // check if any state we are interested in is marked dirty
+ if (!(dirty & (NET::WMVisibleName | NET::WMName | NET::WMIcon |
+ NET::WMState | NET::XAWMState | NET::WMDesktop) ||
+ (m_trackGeometry && dirty & NET::WMGeometry)))
+ {
+ return;
+ }
+
+ // find task
+ Task::Ptr t = findTask(w);
+ if (!t)
+ {
+ return;
+ }
+
+ //kdDebug() << "TaskManager::windowChanged " << w << " " << dirty << endl;
+
+ if (dirty & NET::WMState)
+ {
+ t->updateDemandsAttentionState(w);
+ }
+
+ // refresh icon pixmap if necessary
+ if (dirty & NET::WMIcon)
+ {
+ t->refreshIcon();
+
+ // we're done with the icon processing, don't pass this on anymore
+ dirty ^= NET::WMIcon;
+ }
+
+ if (dirty)
+ {
+ // only refresh this stuff if we have other changes besides icons
+ t->refresh(dirty);
+ }
+
+ if (dirty & (NET::WMDesktop | NET::WMState | NET::XAWMState))
+ {
+ // moved to different desktop or is on all or change in iconification/withdrawnnes
+ emit windowChanged(t);
+
+ if (m_xCompositeEnabled && dirty & NET::WMState)
+ {
+ // update on restoring a minimized window
+ updateWindowPixmap(w);
+ }
+
+ }
+ else if (dirty & NET::WMGeometry)
+ {
+ emit windowChangedGeometry(t);
+
+ if (m_xCompositeEnabled)
+ {
+ // update on size changes, not on task drags
+ updateWindowPixmap(w);
+ }
+
+ }
+}
+
+void TaskManager::updateWindowPixmap(WId w)
+{
+ if (!m_xCompositeEnabled)
+ {
+ return;
+ }
+
+ Task::Ptr task = findTask(w);
+ if (task)
+ {
+ task->updateWindowPixmap();
+ }
+}
+
+void TaskManager::activeWindowChanged(WId w )
+{
+ //kdDebug() << "TaskManager::activeWindowChanged" << endl;
+
+ Task::Ptr t = findTask( w );
+ if (!t) {
+ if (_active) {
+ _active->setActive(false);
+ _active = 0;
+ }
+ }
+ else {
+ if (_active)
+ _active->setActive(false);
+
+ _active = t;
+ _active->setActive(true);
+ }
+}
+
+void TaskManager::currentDesktopChanged(int desktop)
+{
+ emit desktopChanged(desktop);
+}
+
+void TaskManager::gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data )
+{
+ Startup::Ptr s = new Startup( id, data, this );
+ _startups.append(s);
+
+ emit startupAdded(s);
+}
+
+void TaskManager::gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data )
+{
+ Startup::List::iterator itEnd = _startups.end();
+ for (Startup::List::iterator sIt = _startups.begin(); sIt != itEnd; ++sIt)
+ {
+ if ((*sIt)->id() == id)
+ {
+ (*sIt)->update(data);
+ return;
+ }
+ }
+}
+
+void TaskManager::killStartup( const KStartupInfoId& id )
+{
+ Startup::List::iterator sIt = _startups.begin();
+ Startup::List::iterator itEnd = _startups.end();
+ Startup::Ptr s = 0;
+ for (; sIt != itEnd; ++sIt)
+ {
+ if ((*sIt)->id() == id)
+ {
+ s = *sIt;
+ break;
+ }
+ }
+
+ if (!s)
+ {
+ return;
+ }
+
+ _startups.erase(sIt);
+ emit startupRemoved(s);
+}
+
+void TaskManager::killStartup(Startup::Ptr s)
+{
+ if (!s)
+ {
+ return;
+ }
+
+ Startup::List::iterator sIt = _startups.begin();
+ Startup::List::iterator itEnd = _startups.end();
+ for (; sIt != itEnd; ++sIt)
+ {
+ if ((*sIt) == s)
+ {
+ _startups.erase(sIt);
+ break;
+ }
+ }
+
+ emit startupRemoved(s);
+}
+
+QString TaskManager::desktopName(int desk) const
+{
+ return m_winModule->desktopName(desk);
+}
+
+int TaskManager::numberOfDesktops() const
+{
+ return m_winModule->numberOfDesktops();
+}
+
+bool TaskManager::isOnTop(const Task* task)
+{
+ if (!task)
+ {
+ return false;
+ }
+
+ QValueList<WId>::ConstIterator begin(m_winModule->stackingOrder().constBegin());
+ QValueList<WId>::ConstIterator it = m_winModule->stackingOrder().fromLast();
+ do
+ {
+ Task::Dict::iterator taskItEnd = m_tasksByWId.end();
+ for (Task::Dict::iterator taskIt = m_tasksByWId.begin();
+ taskIt != taskItEnd; ++taskIt)
+ {
+ Task::Ptr t = taskIt.data();
+ if ((*it) == t->window())
+ {
+ if (t == task)
+ {
+ return true;
+ }
+
+ if (!t->isIconified() &&
+ (t->isAlwaysOnTop() == task->isAlwaysOnTop()))
+ {
+ return false;
+ }
+
+ break;
+ }
+ }
+ } while (it-- != begin);
+
+ return false;
+}
+
+bool TaskManager::isOnScreen(int screen, const WId wid)
+{
+ if (screen == -1)
+ {
+ return true;
+ }
+
+ KWin::WindowInfo wi = KWin::windowInfo(wid, NET::WMKDEFrameStrut);
+
+ // for window decos that fudge a bit and claim to extend beyond the
+ // edge of the screen, we just contract a bit.
+ QRect window = wi.frameGeometry();
+ QRect desktop = QApplication::desktop()->screenGeometry(screen);
+ desktop.addCoords(5, 5, -5, -5);
+ return window.intersects(desktop);
+}
+
+Task::Task(WId win, QObject *parent, const char *name)
+ : QObject(parent, name),
+ _active(false),
+ _win(win),
+ m_frameId(win),
+ _info(KWin::windowInfo(_win, 0, NET::WM2AllowedActions)),
+ _lastWidth(0),
+ _lastHeight(0),
+ _lastResize(false),
+ _lastIcon(),
+ _thumbSize(0.2),
+ _thumb(),
+ _grab()
+{
+ // try to load icon via net_wm
+ _pixmap = KWin::icon(_win, 16, 16, true);
+
+ // try to guess the icon from the classhint
+ if(_pixmap.isNull())
+ {
+ KGlobal::iconLoader()->loadIcon(className().lower(),
+ KIcon::Small,
+ KIcon::Small,
+ KIcon::DefaultState,
+ 0, true);
+ }
+
+ // load xapp icon
+ if (_pixmap.isNull())
+ {
+ _pixmap = SmallIcon("kcmx");
+ }
+
+#ifdef THUMBNAILING_POSSIBLE
+ m_windowPixmap = 0;
+ findWindowFrameId();
+
+ if (TaskManager::xCompositeEnabled())
+ {
+ updateWindowPixmap();
+ }
+#endif // THUMBNAILING_POSSIBLE
+}
+
+Task::~Task()
+{
+#ifdef THUMBNAILING_POSSIBLE
+ if (m_windowPixmap)
+ {
+ XFreePixmap(QPaintDevice::x11AppDisplay(), m_windowPixmap);
+ }
+#endif // THUMBNAILING_POSSIBLE
+}
+
+// Task::findWindowFrameId()
+// Code was copied from Kompose.
+// Copyright (C) 2004 Hans Oischinger
+// Permission granted on 2005-04-27.
+void Task::findWindowFrameId()
+{
+#ifdef THUMBNAILING_POSSIBLE
+ Window target_win, parent, root;
+ Window *children;
+ uint nchildren;
+
+ target_win = _win;
+ for (;;)
+ {
+ if (!XQueryTree(QPaintDevice::x11AppDisplay(), target_win, &root,
+ &parent, &children, &nchildren))
+ {
+ break;
+ }
+
+ if (children)
+ {
+ XFree(children); // it's a list, that's deallocated!
+ }
+
+ if (!parent || parent == root)
+ {
+ break;
+ }
+ else
+ {
+ target_win = parent;
+ }
+ }
+
+ m_frameId = target_win;
+#endif // THUMBNAILING_POSSIBLE
+}
+
+void Task::refreshIcon()
+{
+ // try to load icon via net_wm
+ _pixmap = KWin::icon(_win, 16, 16, true);
+
+ // try to guess the icon from the classhint
+ if(_pixmap.isNull())
+ {
+ KGlobal::iconLoader()->loadIcon(className().lower(),
+ KIcon::Small,
+ KIcon::Small,
+ KIcon::DefaultState,
+ 0, true);
+ }
+
+ // load xapp icon
+ if (_pixmap.isNull())
+ {
+ _pixmap = SmallIcon("kcmx");
+ }
+
+ _lastIcon.resize(0,0);
+ emit iconChanged();
+}
+
+void Task::refresh(unsigned int dirty)
+{
+ QString name = visibleName();
+ _info = KWin::windowInfo(_win, 0, NET::WM2AllowedActions);
+
+ if (dirty != NET::WMName || name != visibleName())
+ {
+ emit changed(dirty == NET::WMGeometry);
+ }
+}
+
+void Task::setActive(bool a)
+{
+ _active = a;
+ emit changed(false);
+ if ( a )
+ emit activated();
+ else
+ emit deactivated();
+}
+
+bool Task::isMaximized() const
+{
+ return _info.valid() && (_info.state() & NET::Max);
+}
+
+bool Task::isMinimized() const
+{
+ return _info.valid() && _info.isMinimized();
+}
+
+bool Task::isIconified() const
+{
+ return _info.valid() && _info.isMinimized();
+}
+
+bool Task::isAlwaysOnTop() const
+{
+ return _info.valid() && (_info.state() & NET::StaysOnTop);
+}
+
+bool Task::isKeptBelowOthers() const
+{
+ return _info.valid() && (_info.state() & NET::KeepBelow);
+}
+
+bool Task::isFullScreen() const
+{
+ return _info.valid() && (_info.state() & NET::FullScreen);
+}
+
+bool Task::isShaded() const
+{
+ return _info.valid() && (_info.state() & NET::Shaded);
+}
+
+bool Task::isOnCurrentDesktop() const
+{
+ return _info.valid() && _info.isOnCurrentDesktop();
+}
+
+bool Task::isOnAllDesktops() const
+{
+ return _info.valid() && _info.onAllDesktops();
+}
+
+bool Task::isActive() const
+{
+ return _active;
+}
+
+bool Task::isOnTop() const
+{
+ return TaskManager::the()->isOnTop(this);
+}
+
+bool Task::isModified() const
+{
+ static QString modStr = QString::fromUtf8("[") +
+ i18n("modified") +
+ QString::fromUtf8("]");
+ int modStrPos = _info.visibleName().find(modStr);
+
+ return ( modStrPos != -1 );
+}
+
+bool Task::demandsAttention() const
+{
+ return (_info.valid() && (_info.state() & NET::DemandsAttention)) ||
+ _transients_demanding_attention.count() > 0;
+}
+
+bool Task::isOnScreen( int screen ) const
+{
+ return TaskManager::isOnScreen( screen, _win );
+}
+
+void Task::updateDemandsAttentionState( WId w )
+{
+ if (window() != w)
+ {
+ // 'w' is a transient for this task
+ NETWinInfo i( qt_xdisplay(), w, qt_xrootwin(), NET::WMState );
+ if(i.state() & NET::DemandsAttention)
+ {
+ if (!_transients_demanding_attention.contains(w))
+ {
+ _transients_demanding_attention.append(w);
+ }
+ }
+ else
+ {
+ _transients_demanding_attention.remove( w );
+ }
+ }
+}
+
+void Task::addTransient( WId w, const NETWinInfo& info )
+{
+ _transients.append(w);
+ if (info.state() & NET::DemandsAttention)
+ {
+ _transients_demanding_attention.append(w);
+ emit changed(false);
+ }
+}
+
+void Task::removeTransient(WId w)
+{
+ _transients.remove(w);
+ _transients_demanding_attention.remove(w);
+}
+
+QString Task::className()
+{
+ XClassHint hint;
+ if(XGetClassHint(qt_xdisplay(), _win, &hint)) {
+ QString nh( hint.res_name );
+ XFree( hint.res_name );
+ XFree( hint.res_class );
+ return nh;
+ }
+ return QString::null;
+}
+
+QString Task::classClass()
+{
+ XClassHint hint;
+ if(XGetClassHint(qt_xdisplay(), _win, &hint)) {
+ QString ch( hint.res_class );
+ XFree( hint.res_name );
+ XFree( hint.res_class );
+ return ch;
+ }
+ return QString::null;
+}
+
+QPixmap Task::icon( int width, int height, bool allowResize )
+{
+ if ( (width == _lastWidth)
+ && (height == _lastHeight)
+ && (allowResize == _lastResize )
+ && (!_lastIcon.isNull()) )
+ return _lastIcon;
+
+ QPixmap newIcon = KWin::icon( _win, width, height, allowResize );
+ if ( !newIcon.isNull() ) {
+ _lastIcon = newIcon;
+ _lastWidth = width;
+ _lastHeight = height;
+ _lastResize = allowResize;
+ }
+
+ return newIcon;
+}
+
+QPixmap Task::bestIcon( int size, bool &isStaticIcon )
+{
+ QPixmap pixmap;
+ isStaticIcon = false;
+
+ switch( size ) {
+ case KIcon::SizeSmall:
+ {
+ pixmap = icon( 16, 16, true );
+
+ // Icon of last resort
+ if( pixmap.isNull() ) {
+ pixmap = KGlobal::iconLoader()->loadIcon( "go",
+ KIcon::NoGroup,
+ KIcon::SizeSmall );
+ isStaticIcon = true;
+ }
+ }
+ break;
+ case KIcon::SizeMedium:
+ {
+ //
+ // Try 34x34 first for KDE 2.1 icons with shadows, if we don't
+ // get one then try 32x32.
+ //
+ pixmap = icon( 34, 34, false );
+
+ if ( (( pixmap.width() != 34 ) || ( pixmap.height() != 34 )) &&
+ (( pixmap.width() != 32 ) || ( pixmap.height() != 32 )) )
+ {
+ pixmap = icon( 32, 32, true );
+ }
+
+ // Icon of last resort
+ if( pixmap.isNull() ) {
+ pixmap = KGlobal::iconLoader()->loadIcon( "go",
+ KIcon::NoGroup,
+ KIcon::SizeMedium );
+ isStaticIcon = true;
+ }
+ }
+ break;
+ case KIcon::SizeLarge:
+ {
+ // If there's a 48x48 icon in the hints then use it
+ pixmap = icon( size, size, false );
+
+ // If not, try to get one from the classname
+ if ( pixmap.isNull() || pixmap.width() != size || pixmap.height() != size ) {
+ pixmap = KGlobal::iconLoader()->loadIcon( className(),
+ KIcon::NoGroup,
+ size,
+ KIcon::DefaultState,
+ 0L,
+ true );
+ isStaticIcon = true;
+ }
+
+ // If we still don't have an icon then scale the one in the hints
+ if ( pixmap.isNull() || ( pixmap.width() != size ) || ( pixmap.height() != size ) ) {
+ pixmap = icon( size, size, true );
+ isStaticIcon = false;
+ }
+
+ // Icon of last resort
+ if( pixmap.isNull() ) {
+ pixmap = KGlobal::iconLoader()->loadIcon( "go",
+ KIcon::NoGroup,
+ size );
+ isStaticIcon = true;
+ }
+ }
+ }
+
+ return pixmap;
+}
+
+bool Task::idMatch( const QString& id1, const QString& id2 )
+{
+ if ( id1.isEmpty() || id2.isEmpty() )
+ return false;
+
+ if ( id1.contains( id2 ) > 0 )
+ return true;
+
+ if ( id2.contains( id1 ) > 0 )
+ return true;
+
+ return false;
+}
+
+
+void Task::move()
+{
+ bool on_current = _info.isOnCurrentDesktop();
+
+ if (!on_current)
+ {
+ KWin::setCurrentDesktop(_info.desktop());
+ KWin::forceActiveWindow(_win);
+ }
+
+ if (_info.isMinimized())
+ {
+ KWin::deIconifyWindow(_win);
+ }
+
+ QRect geom = _info.geometry();
+ QCursor::setPos(geom.center());
+
+ NETRootInfo ri(qt_xdisplay(), NET::WMMoveResize);
+ ri.moveResizeRequest(_win, geom.center().x(),
+ geom.center().y(), NET::Move);
+}
+
+void Task::resize()
+{
+ bool on_current = _info.isOnCurrentDesktop();
+
+ if (!on_current)
+ {
+ KWin::setCurrentDesktop(_info.desktop());
+ KWin::forceActiveWindow(_win);
+ }
+
+ if (_info.isMinimized())
+ {
+ KWin::deIconifyWindow(_win);
+ }
+
+ QRect geom = _info.geometry();
+ QCursor::setPos(geom.bottomRight());
+
+ NETRootInfo ri(qt_xdisplay(), NET::WMMoveResize);
+ ri.moveResizeRequest(_win, geom.bottomRight().x(),
+ geom.bottomRight().y(), NET::BottomRight);
+}
+
+void Task::setMaximized(bool maximize)
+{
+ KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop);
+ bool on_current = info.isOnCurrentDesktop();
+
+ if (!on_current)
+ {
+ KWin::setCurrentDesktop(info.desktop());
+ }
+
+ if (info.isMinimized())
+ {
+ KWin::deIconifyWindow(_win);
+ }
+
+ NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
+
+ if (maximize)
+ {
+ ni.setState(NET::Max, NET::Max);
+ }
+ else
+ {
+ ni.setState(0, NET::Max);
+ }
+
+ if (!on_current)
+ {
+ KWin::forceActiveWindow(_win);
+ }
+}
+
+void Task::toggleMaximized()
+{
+ setMaximized(!isMaximized());
+}
+
+void Task::restore()
+{
+ KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop);
+ bool on_current = info.isOnCurrentDesktop();
+
+ if (!on_current)
+ {
+ KWin::setCurrentDesktop(info.desktop());
+ }
+
+ if( info.isMinimized())
+ {
+ KWin::deIconifyWindow(_win);
+ }
+
+ NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
+ ni.setState(0, NET::Max);
+
+ if (!on_current)
+ {
+ KWin::forceActiveWindow( _win );
+ }
+}
+
+void Task::setIconified(bool iconify)
+{
+ if (iconify)
+ {
+ KWin::iconifyWindow(_win);
+ }
+ else
+ {
+ KWin::WindowInfo info = KWin::windowInfo(_win, NET::WMState | NET::XAWMState | NET::WMDesktop);
+ bool on_current = info.isOnCurrentDesktop();
+
+ if (!on_current)
+ {
+ KWin::setCurrentDesktop(info.desktop());
+ }
+
+ KWin::deIconifyWindow(_win);
+
+ if (!on_current)
+ {
+ KWin::forceActiveWindow(_win);
+ }
+ }
+}
+
+void Task::toggleIconified()
+{
+ setIconified(!isIconified());
+}
+
+void Task::close()
+{
+ NETRootInfo ri( qt_xdisplay(), NET::CloseWindow );
+ ri.closeWindowRequest( _win );
+}
+
+void Task::raise()
+{
+// kdDebug(1210) << "Task::raise(): " << name() << endl;
+ KWin::raiseWindow( _win );
+}
+
+void Task::lower()
+{
+// kdDebug(1210) << "Task::lower(): " << name() << endl;
+ KWin::lowerWindow( _win );
+}
+
+void Task::activate()
+{
+// kdDebug(1210) << "Task::activate():" << name() << endl;
+ WId w = _win;
+ if (_transients_demanding_attention.count() > 0)
+ {
+ w = _transients_demanding_attention.last();
+ }
+ KWin::forceActiveWindow( w );
+}
+
+void Task::activateRaiseOrIconify()
+{
+ if (!isActive() || isIconified())
+ {
+ activate();
+ }
+ else if (!isOnTop())
+ {
+ raise();
+ }
+ else
+ {
+ setIconified(true);
+ }
+}
+
+void Task::toDesktop(int desk)
+{
+ NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMDesktop);
+ if (desk == 0)
+ {
+ if (_info.valid() && _info.onAllDesktops())
+ {
+ ni.setDesktop(TaskManager::the()->winModule()->currentDesktop());
+ KWin::forceActiveWindow(_win);
+ }
+ else
+ {
+ ni.setDesktop(NETWinInfo::OnAllDesktops);
+ }
+
+ return;
+ }
+ ni.setDesktop(desk);
+ if(desk == TaskManager::the()->winModule()->currentDesktop())
+ KWin::forceActiveWindow(_win);
+}
+
+void Task::toCurrentDesktop()
+{
+ toDesktop(TaskManager::the()->winModule()->currentDesktop());
+}
+
+void Task::setAlwaysOnTop(bool stay)
+{
+ NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
+ if(stay)
+ ni.setState( NET::StaysOnTop, NET::StaysOnTop );
+ else
+ ni.setState( 0, NET::StaysOnTop );
+}
+
+void Task::toggleAlwaysOnTop()
+{
+ setAlwaysOnTop( !isAlwaysOnTop() );
+}
+
+void Task::setKeptBelowOthers(bool below)
+{
+ NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
+
+ if (below)
+ {
+ ni.setState(NET::KeepBelow, NET::KeepBelow);
+ }
+ else
+ {
+ ni.setState(0, NET::KeepBelow);
+ }
+}
+
+void Task::toggleKeptBelowOthers()
+{
+ setKeptBelowOthers(!isKeptBelowOthers());
+}
+
+void Task::setFullScreen(bool fullscreen)
+{
+ NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
+
+ if (fullscreen)
+ {
+ ni.setState(NET::FullScreen, NET::FullScreen);
+ }
+ else
+ {
+ ni.setState(0, NET::FullScreen);
+ }
+}
+
+void Task::toggleFullScreen()
+{
+ setFullScreen(!isFullScreen());
+}
+
+void Task::setShaded(bool shade)
+{
+ NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
+ if(shade)
+ ni.setState( NET::Shaded, NET::Shaded );
+ else
+ ni.setState( 0, NET::Shaded );
+}
+
+void Task::toggleShaded()
+{
+ setShaded( !isShaded() );
+}
+
+void Task::publishIconGeometry(QRect rect)
+{
+ if (rect == m_iconGeometry)
+ {
+ return;
+ }
+
+ m_iconGeometry = rect;
+ NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), 0);
+ NETRect r;
+
+ if (rect.isValid())
+ {
+ r.pos.x = rect.x();
+ r.pos.y = rect.y();
+ r.size.width = rect.width();
+ r.size.height = rect.height();
+ }
+ ni.setIconGeometry(r);
+}
+
+void Task::updateThumbnail()
+{
+ if ( !_info.valid() ||
+ !isOnCurrentDesktop() ||
+ !isActive() ||
+ !_grab.isNull() ) // We're already processing one...
+ {
+ return;
+ }
+
+ //
+ // We do this as a two stage process to remove the delay caused
+ // by the thumbnail generation. This makes things much smoother
+ // on slower machines.
+ //
+ QWidget *rootWin = qApp->desktop();
+ QRect geom = _info.geometry();
+ _grab = QPixmap::grabWindow(rootWin->winId(),
+ geom.x(), geom.y(),
+ geom.width(), geom.height());
+
+ if (!_grab.isNull())
+ {
+ QTimer::singleShot(200, this, SLOT(generateThumbnail()));
+ }
+}
+
+void Task::generateThumbnail()
+{
+ if ( _grab.isNull() )
+ return;
+
+ QImage img = _grab.convertToImage();
+
+ double width = img.width();
+ double height = img.height();
+ width = width * _thumbSize;
+ height = height * _thumbSize;
+
+ img = img.smoothScale( qRound(width), qRound(height) );
+ _thumb = img;
+ _grab.resize( 0, 0 ); // Makes grab a null image.
+
+ emit thumbnailChanged();
+}
+
+#ifdef THUMBNAILING_POSSIBLE
+QPixmap Task::thumbnail(int maxDimension)
+{
+ if (!TaskManager::xCompositeEnabled() || !m_windowPixmap)
+ {
+ return QPixmap();
+ }
+
+ Display *dpy = QPaintDevice::x11AppDisplay();
+
+ XWindowAttributes winAttr;
+ XGetWindowAttributes(dpy, m_frameId, &winAttr);
+ XRenderPictFormat *format = XRenderFindVisualFormat(dpy, winAttr.visual);
+
+ XRenderPictureAttributes picAttr;
+ picAttr.subwindow_mode = IncludeInferiors; // Don't clip child widgets
+
+ Picture picture = XRenderCreatePicture(dpy, m_windowPixmap, format,
+ CPSubwindowMode, &picAttr);
+
+ // Get shaped windows handled correctly.
+ XserverRegion region = XFixesCreateRegionFromWindow(dpy, m_frameId,
+ WindowRegionBounding);
+ XFixesSetPictureClipRegion(dpy, picture, 0, 0, region);
+ XFixesDestroyRegion(dpy, region);
+
+ double factor;
+ if (winAttr.width > winAttr.height)
+ {
+ factor = (double)maxDimension / (double)winAttr.width;
+ }
+ else
+ {
+ factor = (double)maxDimension / (double)winAttr.height;
+ }
+ int thumbnailWidth = (int)(winAttr.width * factor);
+ int thumbnailHeight = (int)(winAttr.height * factor);
+
+ QPixmap thumbnail(thumbnailWidth, thumbnailHeight);
+ thumbnail.fill(QApplication::palette().active().background());
+
+#if 0 // QImage::smoothScale() scaling
+ QPixmap full(winAttr.width, winAttr.height);
+ full.fill(QApplication::palette().active().background());
+
+ bool hasAlpha = format->type == PictTypeDirect && format->direct.alphaMask;
+
+ XRenderComposite(dpy,
+ hasAlpha ? PictOpOver : PictOpSrc,
+ picture, // src
+ None, // mask
+ full.x11RenderHandle(), // dst
+ 0, 0, // src offset
+ 0, 0, // mask offset
+ 0, 0, // dst offset
+ winAttr.width, winAttr.height);
+
+ KPixmapIO io;
+ QImage image = io.convertToImage(full);
+ thumbnail = io.convertToPixmap(image.smoothScale(thumbnailWidth,
+ thumbnailHeight));
+#else // XRENDER scaling
+ // Scaling matrix
+ XTransform transformation = {{
+ { XDoubleToFixed(1), XDoubleToFixed(0), XDoubleToFixed( 0) },
+ { XDoubleToFixed(0), XDoubleToFixed(1), XDoubleToFixed( 0) },
+ { XDoubleToFixed(0), XDoubleToFixed(0), XDoubleToFixed(factor) }
+ }};
+
+ XRenderSetPictureTransform(dpy, picture, &transformation);
+ XRenderSetPictureFilter(dpy, picture, FilterBest, 0, 0);
+
+ XRenderComposite(QPaintDevice::x11AppDisplay(),
+ PictOpOver, // we're filtering, alpha values are probable
+ picture, // src
+ None, // mask
+ thumbnail.x11RenderHandle(), // dst
+ 0, 0, // src offset
+ 0, 0, // mask offset
+ 0, 0, // dst offset
+ thumbnailWidth, thumbnailHeight);
+#endif
+ XRenderFreePicture(dpy, picture);
+
+ return thumbnail;
+}
+#else // THUMBNAILING_POSSIBLE
+QPixmap Task::thumbnail(int /* maxDimension */)
+{
+ return QPixmap();
+}
+#endif // THUMBNAILING_POSSIBLE
+
+void Task::updateWindowPixmap()
+{
+#ifdef THUMBNAILING_POSSIBLE
+ if (!TaskManager::xCompositeEnabled() || !isOnCurrentDesktop() ||
+ isMinimized())
+ {
+ return;
+ }
+
+ Display *dpy = QPaintDevice::x11AppDisplay();
+
+ if (m_windowPixmap)
+ {
+ XFreePixmap(dpy, m_windowPixmap);
+ }
+
+ KXErrorHandler err;
+ m_windowPixmap = XCompositeNameWindowPixmap(dpy, m_frameId);
+ if( err.error( true ))
+ m_windowPixmap = None;
+#endif // THUMBNAILING_POSSIBLE
+}
+
+Startup::Startup(const KStartupInfoId& id, const KStartupInfoData& data,
+ QObject * parent, const char *name)
+ : QObject(parent, name), _id(id), _data(data)
+{
+}
+
+Startup::~Startup()
+{
+}
+
+void Startup::update(const KStartupInfoData& data)
+{
+ _data.update(data);
+ emit changed();
+}
+
+int TaskManager::currentDesktop() const
+{
+ return m_winModule->currentDesktop();
+}
+
+TaskDrag::TaskDrag(const Task::List& tasks, QWidget* source, const char* name)
+ : QStoredDrag("taskbar/task", source, name)
+{
+ QByteArray data;
+ QDataStream stream(data, IO_WriteOnly);
+
+ Task::List::const_iterator itEnd = tasks.constEnd();
+ for (Task::List::const_iterator it = tasks.constBegin(); it != itEnd; ++it)
+ {
+ stream << (*it)->window();
+ }
+
+ setEncodedData(data);
+}
+
+TaskDrag::~TaskDrag()
+{
+}
+
+bool TaskDrag::canDecode(const QMimeSource* e)
+{
+ return e->provides("taskbar/task");
+}
+
+Task::List TaskDrag::decode( const QMimeSource* e )
+{
+ QByteArray data(e->encodedData("taskbar/task"));
+ Task::List tasks;
+
+ if (data.size())
+ {
+ QDataStream stream(data, IO_ReadOnly);
+ while (!stream.atEnd())
+ {
+ WId id;
+ stream >> id;
+ if (Task::Ptr task = TaskManager::the()->findTask(id))
+ {
+ tasks.append(task);
+ }
+ }
+ }
+
+ return tasks;
+}
+
diff --git a/kicker/taskmanager/taskmanager.h b/kicker/taskmanager/taskmanager.h
new file mode 100644
index 000000000..5885569d9
--- /dev/null
+++ b/kicker/taskmanager/taskmanager.h
@@ -0,0 +1,713 @@
+/*****************************************************************
+
+Copyright (c) 2000-2001 Matthias Elter <[email protected]>
+Copyright (c) 2001 Richard Moore <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#ifndef __taskmanager_h__
+#define __taskmanager_h__
+
+#include <sys/types.h>
+
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qdragobject.h>
+#include <qrect.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+
+#include <ksharedptr.h>
+#include <kstartupinfo.h>
+#include <kwin.h>
+
+#include <config.h>
+
+#if defined(HAVE_XCOMPOSITE) && \
+ defined(HAVE_XRENDER) && \
+ defined(HAVE_XFIXES)
+#include <X11/Xlib.h>
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/Xrender.h>
+#if XCOMPOSITE_VERSION >= 00200 && \
+ XFIXES_VERSION >= 20000 && \
+ (RENDER_MAJOR > 0 || RENDER_MINOR >= 6)
+#define THUMBNAILING_POSSIBLE
+#endif
+#endif
+
+class KWinModule;
+class TaskManager;
+
+typedef QValueList<WId> WindowList;
+
+/**
+ * A dynamic interface to a task (main window).
+ *
+ * @see TaskManager
+ * @see KWinModule
+ */
+class KDE_EXPORT Task: public QObject, public KShared
+{
+ Q_OBJECT
+ Q_PROPERTY( QString visibleIconicName READ visibleIconicName )
+ Q_PROPERTY( QString iconicName READ iconicName )
+ Q_PROPERTY( QString visibleIconicNameWithState READ visibleIconicNameWithState )
+ Q_PROPERTY( QString visibleName READ visibleName )
+ Q_PROPERTY( QString name READ name )
+ Q_PROPERTY( QString visibleNameWithState READ visibleNameWithState )
+ Q_PROPERTY( QPixmap pixmap READ pixmap )
+ Q_PROPERTY( bool maximized READ isMaximized )
+ Q_PROPERTY( bool minimized READ isMinimized )
+ // KDE4 deprecated
+ Q_PROPERTY( bool iconified READ isIconified )
+ Q_PROPERTY( bool shaded READ isShaded WRITE setShaded )
+ Q_PROPERTY( bool active READ isActive )
+ Q_PROPERTY( bool onCurrentDesktop READ isOnCurrentDesktop )
+ Q_PROPERTY( bool onAllDesktops READ isOnAllDesktops )
+ Q_PROPERTY( bool alwaysOnTop READ isAlwaysOnTop WRITE setAlwaysOnTop )
+ Q_PROPERTY( bool modified READ isModified )
+ Q_PROPERTY( bool demandsAttention READ demandsAttention )
+ Q_PROPERTY( int desktop READ desktop )
+ Q_PROPERTY( double thumbnailSize READ thumbnailSize WRITE setThumbnailSize )
+ Q_PROPERTY( bool hasThumbnail READ hasThumbnail )
+ Q_PROPERTY( QPixmap thumbnail READ thumbnail )
+
+public:
+ typedef KSharedPtr<Task> Ptr;
+ typedef QValueVector<Task::Ptr> List;
+ typedef QMap<WId, Task::Ptr> Dict;
+
+ Task(WId win, QObject *parent, const char *name = 0);
+ virtual ~Task();
+
+ WId window() const { return _win; }
+ KWin::WindowInfo info() const { return _info; }
+
+#if 0 // this would use (_NET_)WM_ICON_NAME, which is shorter, but can be different from window name
+ QString visibleIconicName() const { return _info.visibleIconName(); }
+ QString visibleIconicNameWithState() const { return _info.visibleIconNameWithState(); }
+ QString iconicName() const { return _info.iconName(); }
+#else
+ QString visibleIconicName() const { return _info.visibleName(); }
+ QString visibleIconicNameWithState() const { return _info.visibleNameWithState(); }
+ QString iconicName() const { return _info.name(); }
+#endif
+ QString visibleName() const { return _info.visibleName(); }
+ QString visibleNameWithState() const { return _info.visibleNameWithState(); }
+ QString name() const { return _info.name(); }
+ QString className();
+ QString classClass();
+
+ /**
+ * A list of the window ids of all transient windows (dialogs) associated
+ * with this task.
+ */
+ WindowList transients() const { return _transients; }
+
+ /**
+ * Returns a 16x16 (KIcon::Small) icon for the task. This method will
+ * only fall back to a static icon if there is no icon of any size in
+ * the WM hints.
+ */
+ QPixmap pixmap() const { return _pixmap; }
+
+ /**
+ * Returns the best icon for any of the KIcon::StdSizes. If there is no
+ * icon of the specified size specified in the WM hints, it will try to
+ * get one using KIconLoader.
+ *
+ * <pre>
+ * bool gotStaticIcon;
+ * QPixmap icon = myTask->icon( KIcon::SizeMedium, gotStaticIcon );
+ * </pre>
+ *
+ * @param size Any of the constants in KIcon::StdSizes.
+ * @param isStaticIcon Set to true if KIconLoader was used, false otherwise.
+ * @see KIcon
+ */
+ QPixmap bestIcon( int size, bool &isStaticIcon );
+
+ /**
+ * Tries to find an icon for the task with the specified size. If there
+ * is no icon that matches then it will either resize the closest available
+ * icon or return a null pixmap depending on the value of allowResize.
+ *
+ * Note that the last icon is cached, so a sequence of calls with the same
+ * parameters will only query the NET properties if the icon has changed or
+ * none was found.
+ */
+ QPixmap icon( int width, int height, bool allowResize = false );
+
+ /**
+ * Returns true iff the windows with the specified ids should be grouped
+ * together in the task list.
+ */
+ static bool idMatch(const QString &, const QString &);
+
+ // state
+
+ /**
+ * Returns true if the task's window is maximized.
+ */
+ bool isMaximized() const;
+
+ /**
+ * Returns true if the task's window is minimized.
+ */
+ bool isMinimized() const;
+
+ /**
+ * @deprecated
+ * Returns true if the task's window is minimized(iconified).
+ */
+ bool isIconified() const;
+
+ /**
+ * Returns true if the task's window is shaded.
+ */
+ bool isShaded() const;
+
+ /**
+ * Returns true if the task's window is the active window.
+ */
+ bool isActive() const;
+
+ /**
+ * Returns true if the task's window is the topmost non-iconified,
+ * non-always-on-top window.
+ */
+ bool isOnTop() const;
+
+ /**
+ * Returns true if the task's window is on the current virtual desktop.
+ */
+ bool isOnCurrentDesktop() const;
+
+ /**
+ * Returns true if the task's window is on all virtual desktops.
+ */
+ bool isOnAllDesktops() const;
+
+ /**
+ * Returns true if the task's window will remain at the top of the
+ * stacking order.
+ */
+ bool isAlwaysOnTop() const;
+
+ /**
+ * Returns true if the task's window will remain at the bottom of the
+ * stacking order.
+ */
+ bool isKeptBelowOthers() const;
+
+ /**
+ * Returns true if the task's window is in full screen mode
+ */
+ bool isFullScreen() const;
+
+ /**
+ * Returns true if the document the task is editing has been modified.
+ * This is currently handled heuristically by looking for the string
+ * '[i18n_modified]' in the window title where i18n_modified is the
+ * word 'modified' in the current language.
+ */
+ bool isModified() const ;
+
+ /**
+ * Returns the desktop on which this task's window resides.
+ */
+ int desktop() const { return _info.desktop(); }
+
+ /**
+ * Returns true if the task is not active but demands user's attention.
+ */
+ bool demandsAttention() const;
+
+
+ /**
+ * Returns true if the window is on the specified screen of a multihead configuration
+ */
+ bool isOnScreen( int screen ) const;
+
+ /**
+ * Returns true if the task should be shown in taskbar-like apps
+ */
+ bool showInTaskbar() const { return _info.state() ^ NET::SkipTaskbar; }
+
+ /**
+ * Returns true if the task should be shown in pager-like apps
+ */
+ bool showInPager() const { return _info.state() ^ NET::SkipPager; }
+
+ /**
+ * Returns the geometry for this window
+ */
+ QRect geometry() const { return _info.geometry(); }
+
+ /**
+ * Returns the geometry for the from of this window
+ */
+ QRect frameGeometry() const { return _info.frameGeometry(); }
+
+ // internal
+
+ //* @internal
+ void refresh(unsigned int dirty);
+ //* @internal
+ void refreshIcon();
+ //* @internal
+ void addTransient( WId w, const NETWinInfo& info );
+ //* @internal
+ void removeTransient( WId w );
+ //* @internal
+ bool hasTransient(WId w) const { return _transients.find(w) != _transients.end(); }
+ //* @internal
+ void updateDemandsAttentionState( WId w );
+ //* @internal
+ void setActive(bool a);
+
+ // For thumbnails
+
+ /**
+ * Returns the current thumbnail size.
+ */
+ double thumbnailSize() const { return _thumbSize; }
+
+ /**
+ * Sets the size for the window thumbnail. For example a size of
+ * 0.2 indicates the thumbnail will be 20% of the original window
+ * size.
+ */
+ void setThumbnailSize( double size ) { _thumbSize = size; }
+
+ /**
+ * Returns true if this task has a thumbnail. Note that this method
+ * can only ever return true after a call to updateThumbnail().
+ */
+ bool hasThumbnail() const { return !_thumb.isNull(); }
+
+ /**
+ * Returns the thumbnail for this task (or a null image if there is
+ * none).
+ */
+ const QPixmap &thumbnail() const { return _thumb; }
+
+ QPixmap thumbnail(int maxDimension);
+
+ void updateWindowPixmap();
+
+public slots:
+ // actions
+
+ /**
+ * Maximise the main window of this task.
+ */
+ void setMaximized(bool);
+ void toggleMaximized();
+
+ /**
+ * Restore the main window of the task (if it was iconified).
+ */
+ void restore();
+
+ /**
+ * Move the window of this task.
+ */
+ void move();
+
+ /**
+ * Resize the window of this task.
+ */
+ void resize();
+
+ /**
+ * Iconify the task.
+ */
+ void setIconified(bool);
+ void toggleIconified();
+
+ /**
+ * Close the task's window.
+ */
+ void close();
+
+ /**
+ * Raise the task's window.
+ */
+ void raise();
+
+ /**
+ * Lower the task's window.
+ */
+ void lower();
+
+ /**
+ * Activate the task's window.
+ */
+ void activate();
+
+ /**
+ * Perform the action that is most appropriate for this task. If it
+ * is not active, activate it. Else if it is not the top window, raise
+ * it. Otherwise, iconify it.
+ */
+ void activateRaiseOrIconify();
+
+ /**
+ * If true, the task's window will remain at the top of the stacking order.
+ */
+ void setAlwaysOnTop(bool);
+ void toggleAlwaysOnTop();
+
+ /**
+ * If true, the task's window will remain at the bottom of the stacking order.
+ */
+ void setKeptBelowOthers(bool);
+ void toggleKeptBelowOthers();
+
+ /**
+ * If true, the task's window will enter full screen mode.
+ */
+ void setFullScreen(bool);
+ void toggleFullScreen();
+
+ /**
+ * If true then the task's window will be shaded. Most window managers
+ * represent this state by displaying on the window's title bar.
+ */
+ void setShaded(bool);
+ void toggleShaded();
+
+ /**
+ * Moves the task's window to the specified virtual desktop.
+ */
+ void toDesktop(int);
+
+ /**
+ * Moves the task's window to the current virtual desktop.
+ */
+ void toCurrentDesktop();
+
+ /**
+ * This method informs the window manager of the location at which this
+ * task will be displayed when iconised. It is used, for example by the
+ * KWin inconify animation.
+ */
+ void publishIconGeometry(QRect);
+
+ /**
+ * Tells the task to generate a new thumbnail. When the thumbnail is
+ * ready the thumbnailChanged() signal will be emitted.
+ */
+ void updateThumbnail();
+
+signals:
+ /**
+ * Indicates that this task has changed in some way.
+ */
+ void changed(bool geometryChangeOnly);
+
+ /**
+ * Indicates that the icon for this task has changed.
+ */
+ void iconChanged();
+
+ /**
+ * Indicates that this task is now the active task.
+ */
+ void activated();
+
+ /**
+ * Indicates that this task is no longer the active task.
+ */
+ void deactivated();
+
+ /**
+ * Indicates that the thumbnail for this task has changed.
+ */
+ void thumbnailChanged();
+
+protected slots:
+ //* @internal
+ void generateThumbnail();
+
+protected:
+ void findWindowFrameId();
+
+private:
+ bool _active;
+ WId _win;
+ WId m_frameId;
+ QPixmap _pixmap;
+ KWin::WindowInfo _info;
+ WindowList _transients;
+ WindowList _transients_demanding_attention;
+
+ int _lastWidth;
+ int _lastHeight;
+ bool _lastResize;
+ QPixmap _lastIcon;
+
+ double _thumbSize;
+ QPixmap _thumb;
+ QPixmap _grab;
+ QRect m_iconGeometry;
+#ifdef THUMBNAILING_POSSIBLE
+ Pixmap m_windowPixmap;
+#endif // THUMBNAILING_POSSIBLE
+};
+
+
+/**
+ * Provids a drag object for tasks across desktops.
+ */
+class KDE_EXPORT TaskDrag : public QStoredDrag
+{
+public:
+ /**
+ * Constructs a task drag object for a task list.
+ */
+ TaskDrag(const Task::List& tasks, QWidget* source = 0,
+ const char* name = 0);
+ ~TaskDrag();
+
+ /**
+ * Returns true if the mime source can be decoded to a TaskDrag.
+ */
+ static bool canDecode( const QMimeSource* e );
+
+ /**
+ * Decodes the tasks from the mime source and returns them if successful.
+ * Otherwise an empty task list is returned.
+ */
+ static Task::List decode( const QMimeSource* e );
+};
+
+
+/**
+ * Represents a task which is in the process of starting.
+ *
+ * @see TaskManager
+ */
+class KDE_EXPORT Startup: public QObject, public KShared
+{
+ Q_OBJECT
+ Q_PROPERTY( QString text READ text )
+ Q_PROPERTY( QString bin READ bin )
+ Q_PROPERTY( QString icon READ icon )
+
+public:
+ typedef KSharedPtr<Startup> Ptr;
+ typedef QValueVector<Startup::Ptr> List;
+
+ Startup( const KStartupInfoId& id, const KStartupInfoData& data, QObject * parent,
+ const char *name = 0);
+ virtual ~Startup();
+
+ /**
+ * The name of the starting task (if known).
+ */
+ QString text() const { return _data.findName(); }
+
+ /**
+ * The name of the executable of the starting task.
+ */
+ QString bin() const { return _data.bin(); }
+
+ /**
+ * The name of the icon to be used for the starting task.
+ */
+ QString icon() const { return _data.findIcon(); }
+ void update( const KStartupInfoData& data );
+ const KStartupInfoId& id() const { return _id; }
+
+signals:
+ /**
+ * Indicates that this startup has changed in some way.
+ */
+ void changed();
+
+private:
+ KStartupInfoId _id;
+ KStartupInfoData _data;
+ class StartupPrivate *d;
+};
+
+
+/**
+ * A generic API for task managers. This class provides an easy way to
+ * build NET compliant task managers. It provides support for startup
+ * notification, virtual desktops and the full range of WM properties.
+ *
+ * @see Task
+ * @see Startup
+ * @see KWinModule
+ */
+class KDE_EXPORT TaskManager : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY( int currentDesktop READ currentDesktop )
+ Q_PROPERTY( int numberOfDesktops READ numberOfDesktops )
+
+public:
+ static TaskManager* the();
+ ~TaskManager();
+
+ /**
+ * Returns the task for a given WId, or 0 if there is no such task.
+ */
+ Task::Ptr findTask(WId w);
+
+ /**
+ * Returns the task for a given location, or 0 if there is no such task.
+ */
+ Task::Ptr findTask(int desktop, const QPoint& p);
+
+ /**
+ * Returns a list of all current tasks.
+ */
+ Task::Dict tasks() const { return m_tasksByWId; }
+
+ /**
+ * Returns a list of all current startups.
+ */
+ Startup::List startups() const { return _startups; }
+
+ /**
+ * Returns the name of the nth desktop.
+ */
+ QString desktopName(int n) const;
+
+ /**
+ * Returns the number of virtual desktops.
+ */
+ int numberOfDesktops() const;
+
+ /**
+ * Returns the number of the current desktop.
+ */
+ int currentDesktop() const;
+
+ /**
+ * Returns true if the specified task is on top.
+ */
+ bool isOnTop(const Task*);
+
+ /**
+ * Tells the task manager whether or not we care about geometry
+ * updates. This generates a lot of activity so should only be used
+ * when necessary.
+ */
+ void trackGeometry() { m_trackGeometry = true; }
+ void trackGeometry(bool track) { m_trackGeometry = track; }
+
+ /**
+ * Returns whether the Window with WId wid is on the screen screen
+ */
+ static bool isOnScreen( int screen, const WId wid );
+
+ KWinModule* winModule() const { return m_winModule; }
+
+ void setXCompositeEnabled(bool state);
+ static bool xCompositeEnabled() { return m_xCompositeEnabled != 0; }
+
+signals:
+ /**
+ * Emitted when a new task has started.
+ */
+ void taskAdded(Task::Ptr);
+
+ /**
+ * Emitted when a task has terminated.
+ */
+ void taskRemoved(Task::Ptr);
+
+ /**
+ * Emitted when a new task is expected.
+ */
+ void startupAdded(Startup::Ptr);
+
+ /**
+ * Emitted when a startup item should be removed. This could be because
+ * the task has started, because it is known to have died, or simply
+ * as a result of a timeout.
+ */
+ void startupRemoved(Startup::Ptr);
+
+ /**
+ * Emitted when the current desktop changes.
+ */
+ void desktopChanged(int desktop);
+
+ /**
+ * Emitted when a window changes desktop.
+ */
+ void windowChanged(Task::Ptr);
+ void windowChangedGeometry(Task::Ptr);
+
+protected slots:
+ //* @internal
+ void windowAdded(WId);
+ //* @internal
+ void windowRemoved(WId);
+ //* @internal
+ void windowChanged(WId, unsigned int);
+
+ //* @internal
+ void activeWindowChanged(WId);
+ //* @internal
+ void currentDesktopChanged(int);
+ //* @internal
+ void killStartup( const KStartupInfoId& );
+ //* @internal
+ void killStartup(Startup::Ptr);
+
+ //* @internal
+ void gotNewStartup( const KStartupInfoId&, const KStartupInfoData& );
+ //* @internal
+ void gotStartupChange( const KStartupInfoId&, const KStartupInfoData& );
+
+protected:
+ void configure_startup();
+ void updateWindowPixmap(WId);
+
+private:
+ TaskManager();
+
+ Task::Ptr _active;
+ Task::Dict m_tasksByWId;
+ WindowList _skiptaskbar_windows;
+ Startup::List _startups;
+ KStartupInfo* _startup_info;
+ KWinModule* m_winModule;
+ bool m_trackGeometry;
+
+ static TaskManager* m_self;
+ static uint m_xCompositeEnabled;
+
+ class TaskManagerPrivate *d;
+};
+
+#endif
diff --git a/kicker/taskmanager/taskrmbmenu.cpp b/kicker/taskmanager/taskrmbmenu.cpp
new file mode 100644
index 000000000..47260687f
--- /dev/null
+++ b/kicker/taskmanager/taskrmbmenu.cpp
@@ -0,0 +1,328 @@
+/*****************************************************************
+
+Copyright (c) 2001 Matthias Elter <[email protected]>
+Copyright (c) 2001 John Firebaugh <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <assert.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include "taskmanager.h"
+
+#if defined(HAVE_XCOMPOSITE) && \
+ defined(HAVE_XRENDER) && \
+ defined(HAVE_XFIXES)
+#include <fixx11h.h>
+#endif
+
+#include "taskrmbmenu.h"
+#include "taskrmbmenu.moc"
+
+TaskRMBMenu::TaskRMBMenu(const Task::List& theTasks, bool show, QWidget *parent, const char *name)
+ : QPopupMenu( parent, name )
+ , tasks( theTasks )
+ , showAll( show )
+{
+ assert(tasks.count() > 0);
+ if (tasks.count() == 1)
+ {
+ fillMenu(tasks.first());
+ }
+ else
+ {
+ fillMenu();
+ }
+}
+
+TaskRMBMenu::TaskRMBMenu(Task::Ptr task, bool show, QWidget *parent, const char *name)
+ : QPopupMenu( parent, name )
+ , showAll( show )
+{
+ fillMenu(task);
+}
+
+void TaskRMBMenu::fillMenu(Task::Ptr t)
+{
+ int id;
+ setCheckable(true);
+
+ insertItem(i18n("Ad&vanced"), makeAdvancedMenu(t));
+ bool checkActions = KWin::allowedActionsSupported();
+
+ if (TaskManager::the()->numberOfDesktops() > 1)
+ {
+ id = insertItem(i18n("To &Desktop"), makeDesktopsMenu(t));
+
+ if (showAll)
+ {
+ id = insertItem(i18n("&To Current Desktop"),
+ t, SLOT(toCurrentDesktop()));
+ setItemEnabled( id, !t->isOnCurrentDesktop() );
+ }
+
+ if (checkActions)
+ {
+ setItemEnabled(id, t->info().actionSupported(NET::ActionChangeDesktop));
+ }
+ }
+
+ id = insertItem(SmallIconSet("move"), i18n("&Move"), t, SLOT(move()));
+ setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMove));
+
+ id = insertItem(i18n("Re&size"), t, SLOT(resize()));
+ setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionResize));
+
+ id = insertItem(i18n("Mi&nimize"), t, SLOT(toggleIconified()));
+ setItemChecked(id, t->isIconified());
+ setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMinimize));
+
+ id = insertItem(i18n("Ma&ximize"), t, SLOT(toggleMaximized()));
+ setItemChecked(id, t->isMaximized());
+ setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionMax));
+
+ id = insertItem(i18n("&Shade"), t, SLOT(toggleShaded()));
+ setItemChecked(id, t->isShaded());
+ setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionShade));
+
+ insertSeparator();
+
+ id = insertItem(SmallIcon("fileclose"), i18n("&Close"), t, SLOT(close()));
+ setItemEnabled(id, !checkActions || t->info().actionSupported(NET::ActionClose));
+}
+
+void TaskRMBMenu::fillMenu()
+{
+ int id;
+ setCheckable( true );
+
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ Task::Ptr t = (*it);
+
+ id = insertItem( QIconSet( t->pixmap() ),
+ t->visibleNameWithState(),
+ new TaskRMBMenu(t, this) );
+ setItemChecked( id, t->isActive() );
+ connectItem( id, t, SLOT( activateRaiseOrIconify() ) );
+ }
+
+ insertSeparator();
+
+ bool enable = false;
+
+ if (TaskManager::the()->numberOfDesktops() > 1)
+ {
+ id = insertItem(i18n("All to &Desktop"), makeDesktopsMenu());
+
+ id = insertItem(i18n("All &to Current Desktop"), this, SLOT(slotAllToCurrentDesktop()));
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ if (!(*it)->isOnCurrentDesktop())
+ {
+ enable = true;
+ break;
+ }
+ }
+ setItemEnabled(id, enable);
+ }
+
+ enable = false;
+
+ id = insertItem( i18n( "Mi&nimize All" ), this, SLOT( slotMinimizeAll() ) );
+ itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ if( !(*it)->isIconified() ) {
+ enable = true;
+ break;
+ }
+ }
+ setItemEnabled( id, enable );
+
+ enable = false;
+
+ id = insertItem( i18n( "Ma&ximize All" ), this, SLOT( slotMaximizeAll() ) );
+ itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ if( !(*it)->isMaximized() ) {
+ enable = true;
+ break;
+ }
+ }
+ setItemEnabled( id, enable );
+
+ enable = false;
+
+ id = insertItem( i18n( "&Restore All" ), this, SLOT( slotRestoreAll() ) );
+ itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ if( (*it)->isIconified() || (*it)->isMaximized() ) {
+ enable = true;
+ break;
+ }
+ }
+ setItemEnabled( id, enable );
+
+ insertSeparator();
+
+ enable = false;
+
+ insertItem( SmallIcon( "remove" ), i18n( "&Close All" ), this, SLOT( slotCloseAll() ) );
+}
+
+QPopupMenu* TaskRMBMenu::makeAdvancedMenu(Task::Ptr t)
+{
+ int id;
+ QPopupMenu* menu = new QPopupMenu(this);
+
+ menu->setCheckable(true);
+
+ id = menu->insertItem(SmallIconSet("up"),
+ i18n("Keep &Above Others"),
+ t, SLOT(toggleAlwaysOnTop()));
+ menu->setItemChecked(id, t->isAlwaysOnTop());
+
+ id = menu->insertItem(SmallIconSet("down"),
+ i18n("Keep &Below Others"),
+ t, SLOT(toggleKeptBelowOthers()));
+ menu->setItemChecked(id, t->isKeptBelowOthers());
+
+ id = menu->insertItem(SmallIconSet("window_fullscreen"),
+ i18n("&Fullscreen"),
+ t, SLOT(toggleFullScreen()));
+ menu->setItemChecked(id, t->isFullScreen());
+
+ if (KWin::allowedActionsSupported())
+ {
+ menu->setItemEnabled(id, t->info().actionSupported(NET::ActionFullScreen));
+ }
+
+ return menu;
+}
+
+QPopupMenu* TaskRMBMenu::makeDesktopsMenu(Task::Ptr t)
+{
+ QPopupMenu* m = new QPopupMenu( this );
+ m->setCheckable( true );
+
+ int id = m->insertItem( i18n("&All Desktops"), t, SLOT( toDesktop(int) ) );
+ m->setItemParameter( id, 0 ); // 0 means all desktops
+ m->setItemChecked( id, t->isOnAllDesktops() );
+
+ m->insertSeparator();
+
+ for (int i = 1; i <= TaskManager::the()->numberOfDesktops(); i++) {
+ QString name = QString("&%1 %2").arg(i).arg(TaskManager::the()->desktopName(i).replace('&', "&&"));
+ id = m->insertItem( name, t, SLOT( toDesktop(int) ) );
+ m->setItemParameter( id, i );
+ m->setItemChecked( id, !t->isOnAllDesktops() && t->desktop() == i );
+ }
+
+ return m;
+}
+
+QPopupMenu* TaskRMBMenu::makeDesktopsMenu()
+{
+ QPopupMenu* m = new QPopupMenu( this );
+ m->setCheckable( true );
+
+ int id = m->insertItem( i18n("&All Desktops"), this, SLOT( slotAllToDesktop(int) ) );
+ m->setItemParameter( id, 0 ); // 0 means all desktops
+
+ m->insertSeparator();
+
+ for (int i = 1; i <= TaskManager::the()->numberOfDesktops(); i++) {
+ QString name = QString("&%1 %2").arg(i).arg(TaskManager::the()->desktopName(i).replace('&', "&&"));
+ id = m->insertItem( name, this, SLOT( slotAllToDesktop(int) ) );
+ m->setItemParameter( id, i );
+ }
+
+ return m;
+}
+
+void TaskRMBMenu::slotMinimizeAll()
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->setIconified(true);
+ }
+}
+
+void TaskRMBMenu::slotMaximizeAll()
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->setMaximized(true);
+ }
+}
+
+void TaskRMBMenu::slotRestoreAll()
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->restore();
+ }
+}
+
+void TaskRMBMenu::slotShadeAll()
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->setShaded( !(*it)->isShaded() );
+ }
+}
+
+void TaskRMBMenu::slotCloseAll()
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->close();
+ }
+}
+
+void TaskRMBMenu::slotAllToDesktop( int desktop )
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->toDesktop( desktop );
+ }
+}
+
+void TaskRMBMenu::slotAllToCurrentDesktop()
+{
+ Task::List::iterator itEnd = tasks.end();
+ for (Task::List::iterator it = tasks.begin(); it != itEnd; ++it)
+ {
+ (*it)->toCurrentDesktop();
+ }
+}
diff --git a/kicker/taskmanager/taskrmbmenu.h b/kicker/taskmanager/taskrmbmenu.h
new file mode 100644
index 000000000..a167d6665
--- /dev/null
+++ b/kicker/taskmanager/taskrmbmenu.h
@@ -0,0 +1,59 @@
+/*****************************************************************
+
+Copyright (c) 2001 Matthias Elter <[email protected]>
+Copyright (c) 2001 John Firebaugh <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#ifndef __taskrmbmenu_h__
+#define __taskrmbmenu_h__
+
+#include <qpopupmenu.h>
+
+class KDE_EXPORT TaskRMBMenu : public QPopupMenu
+{
+ Q_OBJECT
+
+public:
+ TaskRMBMenu(const Task::List&, bool showAll = true, QWidget *parent = 0, const char *name = 0);
+ TaskRMBMenu(Task::Ptr, bool showAll = true, QWidget *parent = 0, const char *name = 0);
+
+private:
+ void fillMenu(Task::Ptr);
+ void fillMenu();
+ QPopupMenu* makeAdvancedMenu(Task::Ptr);
+ QPopupMenu* makeDesktopsMenu(Task::Ptr);
+ QPopupMenu* makeDesktopsMenu();
+
+private slots:
+ void slotMinimizeAll();
+ void slotMaximizeAll();
+ void slotRestoreAll();
+ void slotShadeAll();
+ void slotCloseAll();
+ void slotAllToDesktop( int desktop );
+ void slotAllToCurrentDesktop();
+
+private:
+ Task::List tasks;
+ bool showAll;
+};
+
+#endif