• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libtaskmanager

taskmanager.cpp

Go to the documentation of this file.
00001 /*****************************************************************
00002 
00003 Copyright (c) 2000 Matthias Elter <elter@kde.org>
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00018 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00019 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021 
00022 ******************************************************************/
00023 
00024 // Own
00025 #include "taskmanager.h"
00026 
00027 // Qt
00028 #include <QApplication>
00029 #include <QDesktopWidget>
00030 #include <QUuid>
00031 
00032 // KDE
00033 #include <KConfig>
00034 #include <KConfigGroup>
00035 #include <KDebug>
00036 #include <KGlobal>
00037 #include <KLocale>
00038 
00039 #ifdef Q_WS_X11
00040 #include <QX11Info>
00041 #endif
00042 
00043 namespace TaskManager
00044 {
00045 
00046 class TaskManagerSingleton
00047 {
00048 public:
00049    TaskManager self;
00050 };
00051 
00052 K_GLOBAL_STATIC( TaskManagerSingleton, privateTaskManagerSelf )
00053 
00054 TaskManager* TaskManager::self()
00055 {
00056     return &privateTaskManagerSelf->self;
00057 }
00058 
00059 class TaskManager::Private
00060 {
00061 public:
00062     Private()
00063         : active(0),
00064           startupInfo(0)
00065     {
00066     }
00067 
00068     TaskPtr active;
00069     KStartupInfo* startupInfo;
00070     TaskDict tasksByWId;
00071     StartupList startups;
00072     WindowList skiptaskbarWindows;
00073     QSet<QUuid> trackGeometryTokens;
00074 };
00075 
00076 TaskManager::TaskManager()
00077     : QObject(),
00078       d(new Private)
00079 {
00080     KGlobal::locale()->insertCatalog("libtaskmanager");
00081     connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)),
00082             this,       SLOT(windowAdded(WId)));
00083     connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)),
00084             this,       SLOT(windowRemoved(WId)));
00085     connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)),
00086             this,       SLOT(activeWindowChanged(WId)));
00087     connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)),
00088             this,       SLOT(currentDesktopChanged(int)));
00089     connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,unsigned int)),
00090             this,       SLOT(windowChanged(WId,unsigned int)));
00091 
00092     // register existing windows
00093     const QList<WId> windows = KWindowSystem::windows();
00094     QList<WId>::ConstIterator end(windows.end());
00095     for (QList<WId>::ConstIterator it = windows.begin(); it != end; ++it)
00096     {
00097         windowAdded(*it);
00098     }
00099 
00100     // set active window
00101     WId win = KWindowSystem::activeWindow();
00102     activeWindowChanged(win);
00103     configureStartup();
00104 }
00105 
00106 TaskManager::~TaskManager()
00107 {
00108     KGlobal::locale()->removeCatalog("libtaskmanager");
00109     delete d;
00110 }
00111 
00112 void TaskManager::configureStartup()
00113 {
00114     KConfig _c("klaunchrc");
00115     KConfigGroup c(&_c, "FeedbackStyle");
00116     if (!c.readEntry("TaskbarButton", true)) {
00117         return;
00118     }
00119 
00120     d->startupInfo = new KStartupInfo( KStartupInfo::CleanOnCantDetect, this );
00121     connect( d->startupInfo,
00122         SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )),
00123         SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )));
00124     connect( d->startupInfo,
00125         SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )),
00126         SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )));
00127     connect( d->startupInfo,
00128         SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )),
00129         SLOT( killStartup( const KStartupInfoId& )));
00130 
00131     c = KConfigGroup(&_c, "TaskbarButtonSettings");
00132     d->startupInfo->setTimeout(c.readEntry( "Timeout", 30 ));
00133 }
00134 
00135 TaskPtr TaskManager::findTask(WId w)
00136 {
00137     TaskDict::const_iterator it = d->tasksByWId.constBegin();
00138     TaskDict::const_iterator itEnd = d->tasksByWId.constEnd();
00139 
00140     for (; it != itEnd; ++it) {
00141         if (it.key() == w || it.value()->hasTransient(w)) {
00142             return it.value();
00143         }
00144     }
00145 
00146     return TaskPtr();
00147 }
00148 
00149 TaskPtr TaskManager::findTask(int desktop, const QPoint& p)
00150 {
00151     QList<WId> list = KWindowSystem::stackingOrder();
00152 
00153     TaskPtr task;
00154     int currentIndex = -1;
00155     TaskDict::iterator itEnd = d->tasksByWId.end();
00156     for (TaskDict::iterator it = d->tasksByWId.begin(); it != itEnd; ++it)
00157     {
00158         TaskPtr t = it.value();
00159         if (!t->isOnAllDesktops() && t->desktop() != desktop)
00160         {
00161             continue;
00162         }
00163 
00164         if (t->isIconified() || t->isShaded())
00165         {
00166             continue;
00167         }
00168 
00169         if (t->geometry().contains(p))
00170         {
00171             int index = list.indexOf(t->window());
00172             if (index > currentIndex)
00173             {
00174                 currentIndex = index;
00175                 task = t;
00176             }
00177         }
00178     }
00179 
00180     return task;
00181 }
00182 
00183 void TaskManager::windowAdded(WId w )
00184 {
00185     NETWinInfo info(QX11Info::display(), w, QX11Info::appRootWindow(),
00186                     NET::WMWindowType | NET::WMPid | NET::WMState);
00187 
00188     // ignore NET::Tool and other special window types
00189     NET::WindowType wType = info.windowType(NET::NormalMask | NET::DesktopMask | NET::DockMask |
00190                                             NET::ToolbarMask | NET::MenuMask | NET::DialogMask |
00191                                             NET::OverrideMask | NET::TopMenuMask |
00192                                             NET::UtilityMask | NET::SplashMask);
00193 
00194     if (wType != NET::Normal && wType != NET::Override && wType != NET::Unknown &&
00195         wType != NET::Dialog && wType != NET::Utility) {
00196         return;
00197     }
00198 
00199     // ignore windows that want to be ignored by the taskbar
00200     if ((info.state() & NET::SkipTaskbar) != 0) {
00201         d->skiptaskbarWindows.insert(w); // remember them though
00202         return;
00203     }
00204 
00205     Window transient_for_tmp;
00206     if (XGetTransientForHint(QX11Info::display(), (Window)w, &transient_for_tmp)) {
00207         WId transient_for = (WId)transient_for_tmp;
00208 
00209         // check if it's transient for a skiptaskbar window
00210         if (d->skiptaskbarWindows.contains( transient_for )) {
00211             return;
00212         }
00213 
00214         // lets see if this is a transient for an existing task
00215         if (transient_for != QX11Info::appRootWindow() &&
00216             transient_for != 0 && wType != NET::Utility) {
00217             TaskPtr t = findTask(transient_for);
00218             if (t) {
00219                 if (t->window() != w) {
00220                     t->addTransient(w, info);
00221                     // kDebug() << "TM: Transient " << w << " added for Task: " << t->window();
00222                 }
00223                 return;
00224             }
00225         }
00226     }
00227 
00228     TaskPtr t(new Task(w, 0));
00229     d->tasksByWId[w] = t;
00230 
00231     connect(t.data(), SIGNAL(changed(::TaskManager::TaskChanges)),
00232             this, SLOT(taskChanged(::TaskManager::TaskChanges)));
00233 
00234     if (d->startupInfo) {
00235         KStartupInfoId startupInfoId;
00236         // checkStartup modifies startupInfoId
00237         d->startupInfo->checkStartup(w, startupInfoId);
00238         foreach (StartupPtr startup, d->startups) {
00239             if (startup->id() == startupInfoId) {
00240                 startup->addWindowMatch(w);
00241             }
00242         }
00243     }
00244 
00245     // kDebug() << "TM: Task added for WId: " << w;
00246     emit taskAdded(t);
00247 }
00248 
00249 void TaskManager::windowRemoved(WId w)
00250 {
00251     d->skiptaskbarWindows.remove(w);
00252 
00253     // find task
00254     TaskPtr t = findTask(w);
00255     if (!t)
00256     {
00257         return;
00258     }
00259 
00260     if (t->window() == w)
00261     {
00262         d->tasksByWId.remove(w);
00263         emit taskRemoved(t);
00264 
00265         if (t == d->active)
00266         {
00267             d->active = 0;
00268         }
00269 
00270         //kDebug() << "TM: Task for WId " << w << " removed.";
00271     }
00272     else
00273     {
00274         t->removeTransient(w);
00275         //kDebug() << "TM: Transient " << w << " for Task " << t->window() << " removed.";
00276     }
00277 }
00278 
00279 void TaskManager::windowChanged(WId w, unsigned int dirty)
00280 {
00281     if (dirty & NET::WMState) {
00282         NETWinInfo info (QX11Info::display(), w, QX11Info::appRootWindow(),
00283                          NET::WMState | NET::XAWMState);
00284 
00285         if (info.state() & NET::SkipTaskbar) {
00286             windowRemoved(w);
00287             d->skiptaskbarWindows.insert(w);
00288             return;
00289         } else {
00290             d->skiptaskbarWindows.remove(w);
00291             if (info.mappingState() != NET::Withdrawn && !findTask(w)) {
00292                 // skipTaskBar state was removed and the window is still
00293                 // mapped, so add this window
00294                 windowAdded(w);
00295             }
00296         }
00297     }
00298 
00299     // check if any state we are interested in is marked dirty
00300     if (!(dirty & (NET::WMVisibleName | NET::WMName |
00301                    NET::WMState | NET::WMIcon |
00302                    NET::XAWMState | NET::WMDesktop) ||
00303           (trackGeometry() && dirty & NET::WMGeometry))) {
00304         return;
00305     }
00306 
00307     // find task
00308     TaskPtr t = findTask(w);
00309     if (!t) {
00310         return;
00311     }
00312 
00313     //kDebug() << "TaskManager::windowChanged " << w << " " << dirty;
00314 
00315     if (dirty & NET::WMState) {
00316         t->updateDemandsAttentionState(w);
00317     }
00318 
00319     //kDebug() << "got changes, but will we refresh?" << dirty;
00320     if (dirty) {
00321         // only refresh this stuff if we have other changes besides icons
00322         t->refresh(dirty);
00323     }
00324 }
00325 
00326 void TaskManager::taskChanged(::TaskManager::TaskChanges changes)
00327 {
00328     Task *t = qobject_cast<Task*>(sender());
00329 
00330     if (!t || changes == TaskUnchanged || !d->tasksByWId.contains(t->info().win())) {
00331         return;
00332     }
00333 
00334     emit windowChanged(d->tasksByWId[t->info().win()], changes);
00335 }
00336 
00337 void TaskManager::activeWindowChanged(WId w)
00338 {
00339     //kDebug() << "TaskManager::activeWindowChanged" << w;
00340     TaskPtr t = findTask(w);
00341     if (!t) {
00342         if (d->active) {
00343             d->active->setActive(false);
00344             d->active = 0;
00345         }
00346         //kDebug() << "no active window";
00347     } else {
00348         if (t->info().windowType(NET::UtilityMask) == NET::Utility) {
00349             // we don't want to mark utility windows as active since task managers
00350             // actually care about the main window and skip utility windows; utility
00351             // windows are hidden when their associated window loses focus anyways
00352             // see http://bugs.kde.org/show_bug.cgi?id=178509
00353             return;
00354         }
00355 
00356         if (d->active) {
00357             d->active->setActive(false);
00358         }
00359 
00360         d->active = t;
00361         d->active->setActive(true);
00362         //kDebug() << "active window is" << t->name();
00363     }
00364 }
00365 
00366 void TaskManager::currentDesktopChanged(int desktop)
00367 {
00368     emit desktopChanged(desktop);
00369 }
00370 
00371 void TaskManager::gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data )
00372 {
00373     StartupPtr s( new Startup( id, data, 0 ) );
00374     d->startups.append(s);
00375 
00376     emit startupAdded(s);
00377 }
00378 
00379 void TaskManager::gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data )
00380 {
00381     StartupList::iterator itEnd = d->startups.end();
00382     for (StartupList::iterator sIt = d->startups.begin(); sIt != itEnd; ++sIt)
00383     {
00384         if ((*sIt)->id() == id)
00385         {
00386             (*sIt)->update(data);
00387             return;
00388         }
00389     }
00390 }
00391 
00392 void TaskManager::killStartup( const KStartupInfoId& id )
00393 {
00394     StartupList::iterator sIt = d->startups.begin();
00395     StartupList::iterator itEnd = d->startups.end();
00396     StartupPtr s;
00397     for (; sIt != itEnd; ++sIt)
00398     {
00399         if ((*sIt)->id() == id)
00400         {
00401             s = *sIt;
00402             break;
00403         }
00404     }
00405 
00406     if (!s) {
00407         return;
00408     }
00409 
00410     d->startups.erase(sIt);
00411     emit startupRemoved(s);
00412 }
00413 
00414 void TaskManager::killStartup(StartupPtr s)
00415 {
00416     if (!s)
00417     {
00418         return;
00419     }
00420 
00421     StartupList::iterator sIt = d->startups.begin();
00422     StartupList::iterator itEnd = d->startups.end();
00423     for (; sIt != itEnd; ++sIt)
00424     {
00425         if ((*sIt) == s)
00426         {
00427             d->startups.erase(sIt);
00428             break;
00429         }
00430     }
00431 
00432     emit startupRemoved(s);
00433 }
00434 
00435 QString TaskManager::desktopName(int desk) const
00436 {
00437     return KWindowSystem::desktopName(desk);
00438 }
00439 
00440 TaskDict TaskManager::tasks() const
00441 {
00442     return d->tasksByWId;
00443 }
00444 
00445 StartupList TaskManager::startups() const
00446 {
00447     return d->startups;
00448 }
00449 
00450 int TaskManager::numberOfDesktops() const
00451 {
00452     return KWindowSystem::numberOfDesktops();
00453 }
00454 
00455 bool TaskManager::isOnTop(const Task* task) const
00456 {
00457     if (!task) {
00458         return false;
00459     }
00460 
00461     QList<WId> list = KWindowSystem::stackingOrder();
00462     QList<WId>::const_iterator begin(list.constBegin());
00463     QList<WId>::const_iterator it = list.constBegin() + (list.size() - 1);
00464     do {
00465         TaskDict::const_iterator taskItEnd = d->tasksByWId.constEnd();
00466         for (TaskDict::const_iterator taskIt = d->tasksByWId.constBegin(); taskIt != taskItEnd; ++taskIt) {
00467             TaskPtr t = taskIt.value();
00468             if ((*it) == t->window()) {
00469                 if (t == task) {
00470                     return true;
00471                 }
00472 
00473                 if (!t->isIconified() && (t->isAlwaysOnTop() == task->isAlwaysOnTop())) {
00474                     return false;
00475                 }
00476 
00477                 break;
00478             }
00479         }
00480     } while (it-- != begin);
00481 
00482     return false;
00483 }
00484 
00485 void TaskManager::setTrackGeometry(bool track, const QUuid &token)
00486 {
00487     if (track) {
00488         if (!d->trackGeometryTokens.contains(token)) {
00489             d->trackGeometryTokens.insert(token);
00490         }
00491     } else {
00492         d->trackGeometryTokens.remove(token);
00493     }
00494 }
00495 
00496 bool TaskManager::trackGeometry() const
00497 {
00498     return !d->trackGeometryTokens.isEmpty();
00499 }
00500 
00501 bool TaskManager::isOnScreen(int screen, const WId wid)
00502 {
00503     if (screen == -1) {
00504         return true;
00505     }
00506 
00507     KWindowInfo wi = KWindowSystem::windowInfo(wid, NET::WMFrameExtents);
00508 
00509     // for window decos that fudge a bit and claim to extend beyond the
00510     // edge of the screen, we just contract a bit.
00511     QRect window = wi.frameGeometry();
00512     QRect desktop = QApplication::desktop()->screenGeometry(screen);
00513     desktop.adjust(5, 5, -5, -5);
00514     return window.intersects(desktop);
00515 }
00516 
00517 int TaskManager::currentDesktop() const
00518 {
00519     return KWindowSystem::currentDesktop();
00520 }
00521 
00522 } // TaskManager namespace
00523 
00524 
00525 #include "taskmanager.moc"

libtaskmanager

Skip menu "libtaskmanager"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal