• Skip to content
  • Skip to link menu
KDE 4.1 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 #include "taskmanager_p.h"
00027 
00028 // KDE
00029 #include <KConfig>
00030 #include <KConfigGroup>
00031 #include <KGlobal>
00032 #include <KLocale>
00033 
00034 namespace TaskManager
00035 {
00036 
00037 class TaskManagerSingleton
00038 {
00039 public:
00040    TaskManager self;
00041 };
00042 
00043 K_GLOBAL_STATIC( TaskManagerSingleton, privateTaskManagerSelf )
00044 
00045 TaskManager* TaskManager::self()
00046 {
00047     return &privateTaskManagerSelf->self;
00048 }
00049 
00050 class TaskManager::Private
00051 {
00052 public:
00053     Private()
00054         : active(0),
00055           startupInfo(0),
00056           trackGeometry(false)
00057     {
00058     }
00059 
00060     TaskPtr active;
00061     KStartupInfo* startupInfo;
00062     TaskDict tasksByWId;
00063     StartupList startups;
00064     WindowList skiptaskbarWindows;
00065     bool trackGeometry;
00066 };
00067 
00068 TaskManager::TaskManager()
00069     : QObject(),
00070       d(new Private)
00071 {
00072     KGlobal::locale()->insertCatalog("libtaskmanager");
00073     connect(KWindowSystem::self(), SIGNAL(windowAdded(WId)),
00074             this,       SLOT(windowAdded(WId)));
00075     connect(KWindowSystem::self(), SIGNAL(windowRemoved(WId)),
00076             this,       SLOT(windowRemoved(WId)));
00077     connect(KWindowSystem::self(), SIGNAL(activeWindowChanged(WId)),
00078             this,       SLOT(activeWindowChanged(WId)));
00079     connect(KWindowSystem::self(), SIGNAL(currentDesktopChanged(int)),
00080             this,       SLOT(currentDesktopChanged(int)));
00081     connect(KWindowSystem::self(), SIGNAL(windowChanged(WId,unsigned int)),
00082             this,       SLOT(windowChanged(WId,unsigned int)));
00083 
00084     // register existing windows
00085     const QList<WId> windows = KWindowSystem::windows();
00086     QList<WId>::ConstIterator end(windows.end());
00087     for (QList<WId>::ConstIterator it = windows.begin(); it != end; ++it)
00088     {
00089         windowAdded(*it);
00090     }
00091 
00092     // set active window
00093     WId win = KWindowSystem::activeWindow();
00094     activeWindowChanged(win);
00095     configure_startup();
00096 }
00097 
00098 TaskManager::~TaskManager()
00099 {
00100     KGlobal::locale()->removeCatalog("libtaskmanager");
00101     delete d;
00102 }
00103 
00104 void TaskManager::configure_startup()
00105 {
00106     KConfig _c( "klaunchrc" );
00107     KConfigGroup c(&_c, "FeedbackStyle");
00108     if (!c.readEntry("TaskbarButton", true))
00109         return;
00110     d->startupInfo = new KStartupInfo( KStartupInfo::CleanOnCantDetect, this );
00111     connect( d->startupInfo,
00112         SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )),
00113         SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )));
00114     connect( d->startupInfo,
00115         SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )),
00116         SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )));
00117     connect( d->startupInfo,
00118         SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )),
00119         SLOT( killStartup( const KStartupInfoId& )));
00120     c=KConfigGroup(&_c, "TaskbarButtonSettings");
00121     d->startupInfo->setTimeout( c.readEntry( "Timeout", 30 ));
00122 }
00123 
00124 TaskPtr TaskManager::findTask(WId w)
00125 {
00126     // TODO: might be able to be made more efficient if
00127     // we check to see if w is a transient first?
00128     // profiling would say whether this is worth the effort
00129 
00130     TaskDict::iterator it = d->tasksByWId.begin();
00131     TaskDict::iterator itEnd = d->tasksByWId.end();
00132 
00133     for (; it != itEnd; ++it)
00134     {
00135         if (it.key() == w || it.value()->hasTransient(w))
00136         {
00137             return it.value();
00138         }
00139     }
00140 
00141     return TaskPtr();
00142 }
00143 
00144 TaskPtr TaskManager::findTask(int desktop, const QPoint& p)
00145 {
00146     QList<WId> list = KWindowSystem::stackingOrder();
00147 
00148     TaskPtr task;
00149     int currentIndex = -1;
00150     TaskDict::iterator itEnd = d->tasksByWId.end();
00151     for (TaskDict::iterator it = d->tasksByWId.begin(); it != itEnd; ++it)
00152     {
00153         TaskPtr t = it.value();
00154         if (!t->isOnAllDesktops() && t->desktop() != desktop)
00155         {
00156             continue;
00157         }
00158 
00159         if (t->isIconified() || t->isShaded())
00160         {
00161             continue;
00162         }
00163 
00164         if (t->geometry().contains(p))
00165         {
00166             int index = list.indexOf(t->window());
00167             if (index > currentIndex)
00168             {
00169                 currentIndex = index;
00170                 task = t;
00171             }
00172         }
00173     }
00174 
00175     return task;
00176 }
00177 
00178 void TaskManager::windowAdded(WId w )
00179 {
00180     NETWinInfo info(QX11Info::display(), w, QX11Info::appRootWindow(),
00181                     NET::WMWindowType | NET::WMPid | NET::WMState);
00182 
00183     // ignore NET::Tool and other special window types
00184     NET::WindowType wType =
00185         info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask |
00186                          NET::ToolbarMask | NET::MenuMask | NET::DialogMask |
00187                          NET::OverrideMask | NET::TopMenuMask |
00188                          NET::UtilityMask | NET::SplashMask );
00189 
00190     if (wType != NET::Normal &&
00191         wType != NET::Override &&
00192         wType != NET::Unknown &&
00193         wType != NET::Dialog &&
00194         wType != NET::Utility)
00195     {
00196         return;
00197     }
00198 
00199     // ignore windows that want to be ignored by the taskbar
00200     if ((info.state() & NET::SkipTaskbar) != 0)
00201     {
00202         d->skiptaskbarWindows.push_front( w ); // remember them though
00203         return;
00204     }
00205 
00206     Window transient_for_tmp;
00207     if (XGetTransientForHint( QX11Info::display(), (Window) w, &transient_for_tmp ))
00208     {
00209         WId transient_for = (WId) transient_for_tmp;
00210 
00211         // check if it's transient for a skiptaskbar window
00212         if( d->skiptaskbarWindows.contains( transient_for ))
00213             return;
00214 
00215         // lets see if this is a transient for an existing task
00216         if( transient_for != QX11Info::appRootWindow()
00217             && transient_for != 0
00218             && wType != NET::Utility )
00219         {
00220             TaskPtr t = findTask(transient_for);
00221             if (t)
00222             {
00223                 if (t->window() != w)
00224                 {
00225                     t->addTransient(w, info);
00226                     // kDebug() << "TM: Transient " << w << " added for Task: " << t->window();
00227                 }
00228                 return;
00229             }
00230         }
00231     }
00232 
00233     TaskPtr t( new Task( w, 0 ) );
00234     d->tasksByWId[w] = t;
00235 
00236     if (d->startupInfo) {
00237         KStartupInfoId startupInfoId;
00238         // checkStartup modifies startupInfoId
00239         d->startupInfo->checkStartup(w, startupInfoId);
00240         foreach (StartupPtr startup, d->startups) {
00241             if (startup->id() == startupInfoId) {
00242                 startup->addWindowMatch(w);
00243             }
00244         }
00245     }
00246 
00247     // kDebug() << "TM: Task added for WId: " << w;
00248 
00249     emit taskAdded(t);
00250 }
00251 
00252 void TaskManager::windowRemoved(WId w)
00253 {
00254     d->skiptaskbarWindows.removeAll(w);
00255 
00256     // find task
00257     TaskPtr t = findTask(w);
00258     if (!t)
00259     {
00260         return;
00261     }
00262 
00263     if (t->window() == w)
00264     {
00265         d->tasksByWId.remove(w);
00266         emit taskRemoved(t);
00267 
00268         if (t == d->active)
00269         {
00270             d->active = 0;
00271         }
00272 
00273         //kDebug() << "TM: Task for WId " << w << " removed.";
00274     }
00275     else
00276     {
00277         t->removeTransient(w);
00278         //kDebug() << "TM: Transient " << w << " for Task " << t->window() << " removed.";
00279     }
00280 }
00281 
00282 void TaskManager::windowChanged(WId w, unsigned int dirty)
00283 {
00284     if (dirty & NET::WMState)
00285     {
00286         NETWinInfo info (QX11Info::display(), w, QX11Info::appRootWindow(),
00287                          NET::WMState | NET::XAWMState);
00288         if (info.state() & NET::SkipTaskbar)
00289         {
00290             windowRemoved(w);
00291             d->skiptaskbarWindows.push_front(w);
00292             return;
00293         }
00294         else
00295         {
00296             d->skiptaskbarWindows.removeAll(w);
00297             if (info.mappingState() != NET::Withdrawn && !findTask(w))
00298             {
00299                 // skipTaskBar state was removed and the window is still
00300                 // mapped, so add this window
00301                 windowAdded( w );
00302             }
00303         }
00304     }
00305 
00306     // check if any state we are interested in is marked dirty
00307     if (!(dirty & (NET::WMVisibleName |NET::WMName |
00308                    NET::WMState | NET::WMIcon |
00309                    NET::XAWMState | NET::WMDesktop) ||
00310           (d->trackGeometry && dirty & NET::WMGeometry)))
00311     {
00312         return;
00313     }
00314 
00315     // find task
00316     TaskPtr t = findTask(w);
00317     if (!t)
00318     {
00319         return;
00320     }
00321 
00322     //kDebug() << "TaskManager::windowChanged " << w << " " << dirty;
00323 
00324     if (dirty & NET::WMState)
00325     {
00326         t->updateDemandsAttentionState(w);
00327     }
00328 
00329     // refresh icon pixmap if necessary
00330     if (dirty & NET::WMIcon)
00331     {
00332         t->refreshIcon();
00333         dirty ^= NET::WMIcon;
00334     }
00335 
00336     if (dirty)
00337     {
00338         // only refresh this stuff if we have other changes besides icons
00339         t->refresh(dirty);
00340     }
00341 
00342     if (dirty & (NET::WMDesktop | NET::WMState | NET::XAWMState))
00343     {
00344         // moved to different desktop or is on all or change in iconification/withdrawnnes
00345         emit windowChanged(t);
00346 
00347 #if 0
00348         if (KWindowSystem::compositingActive() && dirty & NET::WMState)
00349         {
00350             // update on restoring a minimized window
00351             updateWindowPixmap(w);
00352         }
00353 #endif
00354 
00355     }
00356     else if (dirty & NET::WMGeometry)
00357     {
00358         emit windowChangedGeometry(t);
00359 
00360 #if 0
00361         if (KWindowSystem::compositingActive())
00362         {
00363             // update on size changes, not on task drags
00364             updateWindowPixmap(w);
00365         }
00366 #endif
00367 
00368     }
00369 }
00370 
00371 void TaskManager::updateWindowPixmap(WId w)
00372 {
00373     if (!KWindowSystem::compositingActive())
00374     {
00375         return;
00376     }
00377 
00378     TaskPtr task = findTask(w);
00379     if (task)
00380     {
00381         task->updateWindowPixmap();
00382     }
00383 }
00384 
00385 void TaskManager::activeWindowChanged(WId w )
00386 {
00387     //kDebug() << "TaskManager::activeWindowChanged";
00388 
00389     TaskPtr t = findTask( w );
00390     if (!t) {
00391         if (d->active) {
00392             d->active->setActive(false);
00393             d->active = 0;
00394         }
00395     }
00396     else {
00397         if (d->active)
00398             d->active->setActive(false);
00399 
00400         d->active = t;
00401         d->active->setActive(true);
00402     }
00403 }
00404 
00405 void TaskManager::currentDesktopChanged(int desktop)
00406 {
00407     emit desktopChanged(desktop);
00408 }
00409 
00410 void TaskManager::gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data )
00411 {
00412     StartupPtr s( new Startup( id, data, 0 ) );
00413     d->startups.append(s);
00414 
00415     emit startupAdded(s);
00416 }
00417 
00418 void TaskManager::gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data )
00419 {
00420     StartupList::iterator itEnd = d->startups.end();
00421     for (StartupList::iterator sIt = d->startups.begin(); sIt != itEnd; ++sIt)
00422     {
00423         if ((*sIt)->id() == id)
00424         {
00425             (*sIt)->update(data);
00426             return;
00427         }
00428     }
00429 }
00430 
00431 void TaskManager::killStartup( const KStartupInfoId& id )
00432 {
00433     StartupList::iterator sIt = d->startups.begin();
00434     StartupList::iterator itEnd = d->startups.end();
00435     StartupPtr s;
00436     for (; sIt != itEnd; ++sIt)
00437     {
00438         if ((*sIt)->id() == id)
00439         {
00440             s = *sIt;
00441             break;
00442         }
00443     }
00444 
00445     if (!s)
00446     {
00447         return;
00448     }
00449 
00450     d->startups.erase(sIt);
00451     emit startupRemoved(s);
00452 }
00453 
00454 void TaskManager::killStartup(StartupPtr s)
00455 {
00456     if (!s)
00457     {
00458         return;
00459     }
00460 
00461     StartupList::iterator sIt = d->startups.begin();
00462     StartupList::iterator itEnd = d->startups.end();
00463     for (; sIt != itEnd; ++sIt)
00464     {
00465         if ((*sIt) == s)
00466         {
00467             d->startups.erase(sIt);
00468             break;
00469         }
00470     }
00471 
00472     emit startupRemoved(s);
00473 }
00474 
00475 QString TaskManager::desktopName(int desk) const
00476 {
00477     return KWindowSystem::desktopName(desk);
00478 }
00479 
00480 TaskDict TaskManager::tasks() const
00481 {
00482     return d->tasksByWId;
00483 }
00484 
00485 StartupList TaskManager::startups() const
00486 {
00487     return d->startups;
00488 }
00489 
00490 int TaskManager::numberOfDesktops() const
00491 {
00492     return KWindowSystem::numberOfDesktops();
00493 }
00494 
00495 bool TaskManager::isOnTop(const Task* task)
00496 {
00497     if (!task)
00498     {
00499         return false;
00500     }
00501 
00502     QList<WId> list = KWindowSystem::stackingOrder();
00503     QList<WId>::const_iterator begin(list.constBegin());
00504     QList<WId>::const_iterator it = list.begin() + (list.size() - 1);
00505     do
00506     {
00507         TaskDict::iterator taskItEnd = d->tasksByWId.end();
00508         for (TaskDict::iterator taskIt = d->tasksByWId.begin();
00509              taskIt != taskItEnd; ++taskIt)
00510         {
00511             TaskPtr t = taskIt.value();
00512             if ((*it) == t->window())
00513             {
00514                 if (t == task)
00515                 {
00516                     return true;
00517                 }
00518 
00519                 if (!t->isIconified() &&
00520                     (t->isAlwaysOnTop() == task->isAlwaysOnTop()))
00521                 {
00522                     return false;
00523                 }
00524 
00525                 break;
00526             }
00527         }
00528     } while (it-- != begin);
00529 
00530     return false;
00531 }
00532 
00533 void TaskManager::trackGeometry()
00534 {
00535     d->trackGeometry = true;
00536 }
00537 
00538 bool TaskManager::isOnScreen(int screen, const WId wid)
00539 {
00540     if (screen == -1)
00541     {
00542         return true;
00543     }
00544 
00545     KWindowInfo wi = KWindowSystem::windowInfo(wid, NET::WMFrameExtents);
00546 
00547     // for window decos that fudge a bit and claim to extend beyond the
00548     // edge of the screen, we just contract a bit.
00549     QRect window = wi.frameGeometry();
00550     QRect desktop = QApplication::desktop()->screenGeometry(screen);
00551     desktop.adjust(5, 5, -5, -5);
00552     return window.intersects(desktop);
00553 }
00554 
00555 } // TaskManager namespace
00556 
00557 
00558 #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
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
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