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
00027
00028 #include <QApplication>
00029 #include <QDesktopWidget>
00030 #include <QUuid>
00031
00032
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
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
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
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
00200 if ((info.state() & NET::SkipTaskbar) != 0) {
00201 d->skiptaskbarWindows.insert(w);
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
00210 if (d->skiptaskbarWindows.contains( transient_for )) {
00211 return;
00212 }
00213
00214
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
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
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
00246 emit taskAdded(t);
00247 }
00248
00249 void TaskManager::windowRemoved(WId w)
00250 {
00251 d->skiptaskbarWindows.remove(w);
00252
00253
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
00271 }
00272 else
00273 {
00274 t->removeTransient(w);
00275
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
00293
00294 windowAdded(w);
00295 }
00296 }
00297 }
00298
00299
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
00308 TaskPtr t = findTask(w);
00309 if (!t) {
00310 return;
00311 }
00312
00313
00314
00315 if (dirty & NET::WMState) {
00316 t->updateDemandsAttentionState(w);
00317 }
00318
00319
00320 if (dirty) {
00321
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
00340 TaskPtr t = findTask(w);
00341 if (!t) {
00342 if (d->active) {
00343 d->active->setActive(false);
00344 d->active = 0;
00345 }
00346
00347 } else {
00348 if (t->info().windowType(NET::UtilityMask) == NET::Utility) {
00349
00350
00351
00352
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
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
00510
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 }
00523
00524
00525 #include "taskmanager.moc"