00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "taskmanager.h"
00026 #include "taskmanager_p.h"
00027
00028
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
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
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
00127
00128
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
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
00200 if ((info.state() & NET::SkipTaskbar) != 0)
00201 {
00202 d->skiptaskbarWindows.push_front( w );
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
00212 if( d->skiptaskbarWindows.contains( transient_for ))
00213 return;
00214
00215
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
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
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
00248
00249 emit taskAdded(t);
00250 }
00251
00252 void TaskManager::windowRemoved(WId w)
00253 {
00254 d->skiptaskbarWindows.removeAll(w);
00255
00256
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
00274 }
00275 else
00276 {
00277 t->removeTransient(w);
00278
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
00300
00301 windowAdded( w );
00302 }
00303 }
00304 }
00305
00306
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
00316 TaskPtr t = findTask(w);
00317 if (!t)
00318 {
00319 return;
00320 }
00321
00322
00323
00324 if (dirty & NET::WMState)
00325 {
00326 t->updateDemandsAttentionState(w);
00327 }
00328
00329
00330 if (dirty & NET::WMIcon)
00331 {
00332 t->refreshIcon();
00333 dirty ^= NET::WMIcon;
00334 }
00335
00336 if (dirty)
00337 {
00338
00339 t->refresh(dirty);
00340 }
00341
00342 if (dirty & (NET::WMDesktop | NET::WMState | NET::XAWMState))
00343 {
00344
00345 emit windowChanged(t);
00346
00347 #if 0
00348 if (KWindowSystem::compositingActive() && dirty & NET::WMState)
00349 {
00350
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
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
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
00548
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 }
00556
00557
00558 #include "taskmanager.moc"