00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <kglobal.h>
00025 #include <klocale.h>
00026 #include <kdebug.h>
00027 #include <kconfig.h>
00028 #include <kiconloader.h>
00029 #include <kwinmodule.h>
00030 #include <netwm.h>
00031 #include <tqtimer.h>
00032 #include <tqimage.h>
00033
00034 #include <X11/X.h>
00035 #include <X11/Xlib.h>
00036 #include <X11/Xutil.h>
00037
00038 #include "taskmanager.h"
00039 #include "taskmanager.moc"
00040
00041 template class TQPtrList<Task>;
00042
00043
00044
00045
00046
00047
00048
00049 KWinModule* kwin_module = 0;
00050
00051 TaskManager::TaskManager(TQObject *parent, const char *name)
00052 : TQObject(parent, name), _active(0), _startup_info( NULL )
00053 {
00054
00055 kwin_module = new KWinModule();
00056
00057
00058 connect(kwin_module, TQT_SIGNAL(windowAdded(WId)), TQT_SLOT(windowAdded(WId)));
00059 connect(kwin_module, TQT_SIGNAL(windowRemoved(WId)), TQT_SLOT(windowRemoved(WId)));
00060 connect(kwin_module, TQT_SIGNAL(activeWindowChanged(WId)), TQT_SLOT(activeWindowChanged(WId)));
00061 connect(kwin_module, TQT_SIGNAL(currentDesktopChanged(int)), TQT_SLOT(currentDesktopChanged(int)));
00062 connect(kwin_module, TQT_SIGNAL(windowChanged(WId,unsigned int)), TQT_SLOT(windowChanged(WId,unsigned int)));
00063
00064
00065 const TQValueList<WId> windows = kwin_module->windows();
00066 TQValueList<WId>::ConstIterator end( windows.end() );
00067 for (TQValueList<WId>::ConstIterator it = windows.begin(); it != end; ++it )
00068 windowAdded(*it);
00069
00070
00071 WId win = kwin_module->activeWindow();
00072 activeWindowChanged(win);
00073
00074 configure_startup();
00075 }
00076
00077 TaskManager::~TaskManager()
00078 {
00079 }
00080
00081 void TaskManager::configure_startup()
00082 {
00083 KConfig c("klaunchrc", true);
00084 c.setGroup("FeedbackStyle");
00085 if (!c.readBoolEntry("TaskbarButton", true))
00086 return;
00087 _startup_info = new KStartupInfo( true, this );
00088 connect( _startup_info,
00089 TQT_SIGNAL( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )),
00090 TQT_SLOT( gotNewStartup( const KStartupInfoId&, const KStartupInfoData& )));
00091 connect( _startup_info,
00092 TQT_SIGNAL( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )),
00093 TQT_SLOT( gotStartupChange( const KStartupInfoId&, const KStartupInfoData& )));
00094 connect( _startup_info,
00095 TQT_SIGNAL( gotRemoveStartup( const KStartupInfoId&, const KStartupInfoData& )),
00096 TQT_SLOT( gotRemoveStartup( const KStartupInfoId& )));
00097 c.setGroup( "TaskbarButtonSettings" );
00098 _startup_info->setTimeout( c.readUnsignedNumEntry( "Timeout", 30 ));
00099 }
00100
00101 Task* TaskManager::findTask(WId w)
00102 {
00103 for (Task* t = _tasks.first(); t != 0; t = _tasks.next())
00104 if (t->window() == w || t->hasTransient(w))
00105 return t;
00106 return 0;
00107 }
00108
00109 #ifdef KDE_3_3
00110 #define NET_ALL_TYPES_MASK (NET::AllTypesMask)
00111 #else
00112 #define NET_ALL_TYPES_MASK (-1LU)
00113 #endif
00114
00115 void TaskManager::windowAdded(WId w )
00116 {
00117 NETWinInfo info(qt_xdisplay(), w, qt_xrootwin(),
00118 NET::WMWindowType | NET::WMPid | NET::WMState );
00119 #ifdef KDE_3_2
00120 NET::WindowType windowType = info.windowType(NET_ALL_TYPES_MASK);
00121 #else
00122 NET::WindowType windowType = info.windowType();
00123 #endif
00124
00125 if (windowType != NET::Normal && windowType != NET::Override
00126 && windowType != NET::Unknown && windowType != NET::Dialog)
00127 return;
00128
00129 if ((info.state() & NET::SkipTaskbar) != 0)
00130 {
00131 _skiptaskbar_windows.push_front( w );
00132 return;
00133 }
00134
00135 Window transient_for_tmp;
00136 if (XGetTransientForHint(qt_xdisplay(), (Window) w, &transient_for_tmp))
00137 {
00138 WId transient_for = (WId) transient_for_tmp;
00139
00140
00141 if (_skiptaskbar_windows.contains(transient_for))
00142 return;
00143
00144
00145 if (transient_for != qt_xrootwin() && transient_for != 0 )
00146 {
00147 Task* t = findTask(transient_for);
00148 if (t)
00149 {
00150 if (t->window() != w)
00151 {
00152 t->addTransient(w);
00153
00154 }
00155 return;
00156 }
00157 }
00158 }
00159 Task* t = new Task(w, this);
00160 _tasks.append(t);
00161
00162
00163 emit taskAdded(t);
00164 }
00165
00166 void TaskManager::windowRemoved(WId w )
00167 {
00168 _skiptaskbar_windows.remove( w );
00169
00170 Task* t = findTask(w);
00171 if (!t) return;
00172
00173 if (t->window() == w) {
00174 _tasks.removeRef(t);
00175
00176 emit taskRemoved(t);
00177
00178 if(t == _active) _active = 0;
00179 delete t;
00180
00181 }
00182 else {
00183 t->removeTransient( w );
00184
00185 }
00186 }
00187
00188 void TaskManager::windowChanged(WId w, unsigned int dirty)
00189 {
00190 if( dirty & NET::WMState ) {
00191 NETWinInfo info ( qt_xdisplay(), w, qt_xrootwin(), NET::WMState );
00192 if ( (info.state() & NET::SkipTaskbar) != 0 ) {
00193 windowRemoved( w );
00194 _skiptaskbar_windows.push_front( w );
00195 return;
00196 }
00197 else {
00198 _skiptaskbar_windows.remove( w );
00199 if( !findTask( w ))
00200 windowAdded( w );
00201 }
00202 }
00203
00204
00205 if(!(dirty & (NET::WMVisibleName|NET::WMName|NET::WMState|NET::WMIcon|NET::XAWMState|NET::WMDesktop)) )
00206 return;
00207
00208
00209 Task* t = findTask( w );
00210 if (!t) return;
00211
00212
00213
00214
00215
00216 if (dirty & NET::WMIcon)
00217 t->refresh(true);
00218 else
00219 t->refresh();
00220
00221 if(dirty & (NET::WMDesktop|NET::WMState|NET::XAWMState))
00222 emit windowChanged(w);
00223 }
00224
00225 void TaskManager::activeWindowChanged(WId w )
00226 {
00227
00228
00229 Task* t = findTask( w );
00230 if (!t) {
00231 if (_active) {
00232 _active->setActive(false);
00233 _active = 0;
00234
00235
00236 emit activeTaskChanged(0);
00237 }
00238 }
00239 else {
00240 if (_active)
00241 _active->setActive(false);
00242
00243 _active = t;
00244 _active->setActive(true);
00245
00246 emit activeTaskChanged(_active);
00247 }
00248 }
00249
00250 void TaskManager::currentDesktopChanged(int desktop)
00251 {
00252 emit desktopChanged(desktop);
00253 }
00254
00255 void TaskManager::gotNewStartup( const KStartupInfoId& id, const KStartupInfoData& data )
00256 {
00257 Startup* s = new Startup( id, data, this );
00258 _startups.append(s);
00259
00260 emit startupAdded(s);
00261 }
00262
00263 void TaskManager::gotStartupChange( const KStartupInfoId& id, const KStartupInfoData& data )
00264 {
00265 for( Startup* s = _startups.first(); s != 0; s = _startups.next()) {
00266 if ( s->id() == id ) {
00267 s->update( data );
00268 return;
00269 }
00270 }
00271 }
00272
00273 void TaskManager::gotRemoveStartup( const KStartupInfoId& id )
00274 {
00275 killStartup( id );
00276 }
00277
00278 void TaskManager::killStartup( const KStartupInfoId& id )
00279 {
00280 Startup* s = 0;
00281 for(s = _startups.first(); s != 0; s = _startups.next()) {
00282 if (s->id() == id)
00283 break;
00284 }
00285 if (s == 0) return;
00286
00287 _startups.removeRef(s);
00288 emit startupRemoved(s);
00289 delete s;
00290 }
00291
00292 void TaskManager::killStartup(Startup* s)
00293 {
00294 if (s == 0) return;
00295
00296 _startups.removeRef(s);
00297 emit startupRemoved(s);
00298 delete s;
00299 }
00300
00301 TQString TaskManager::desktopName(int desk) const
00302 {
00303 return kwin_module->desktopName(desk);
00304 }
00305
00306 int TaskManager::numberOfDesktops() const
00307 {
00308 return kwin_module->numberOfDesktops();
00309 }
00310
00311 bool TaskManager::isOnTop(const Task* task)
00312 {
00313 if(!task) return false;
00314
00315 for (TQValueList<WId>::ConstIterator it = kwin_module->stackingOrder().fromLast();
00316 it != kwin_module->stackingOrder().end(); --it ) {
00317 for (Task* t = _tasks.first(); t != 0; t = _tasks.next() ) {
00318 if ( (*it) == t->window() ) {
00319 if ( t == task )
00320 return true;
00321 if ( !t->isIconified() && (t->isAlwaysOnTop() == task->isAlwaysOnTop()) )
00322 return false;
00323 break;
00324 }
00325 }
00326 }
00327 return false;
00328 }
00329
00330
00331 Task::Task(WId win, TaskManager * parent, const char *name) :
00332 TQObject(parent, name),
00333 _active(false), _win(win),
00334 _lastWidth(0), _lastHeight(0), _lastResize(false), _lastIcon(),
00335 _thumbSize(0.2), _thumb(), _grab()
00336 {
00337 #ifdef KDE_3_2
00338 _info = KWin::windowInfo(_win, 0, 0);
00339 #else
00340 _info = KWin::info(_win);
00341 #endif
00342
00343 _pixmap = KWin::icon(_win, 16, 16, true);
00344
00345
00346 if(_pixmap.isNull())
00347 KGlobal::instance()->iconLoader()->loadIcon(className().lower(),
00348 KIcon::Small,KIcon::Small,
00349 KIcon::DefaultState, 0, true);
00350
00351
00352 if (_pixmap.isNull())
00353 _pixmap = SmallIcon("kcmx");
00354 }
00355
00356 Task::~Task()
00357 {
00358 }
00359
00360 void Task::refresh(bool icon)
00361 {
00362 #ifdef KDE_3_2
00363 _info = KWin::windowInfo(_win, 0, 0);
00364 #else
00365 _info = KWin::info(_win);
00366 #endif
00367 if (icon)
00368 {
00369
00370 _pixmap = KWin::icon(_win, 16, 16, true);
00371
00372
00373 if(_pixmap.isNull())
00374 {
00375 KGlobal::instance()->iconLoader()->loadIcon(className().lower(),
00376 KIcon::Small, KIcon::Small, KIcon::DefaultState, 0, true);
00377 }
00378
00379
00380 if (_pixmap.isNull())
00381 _pixmap = SmallIcon("kcmx");
00382
00383 _lastIcon.resize(0,0);
00384 emit iconChanged();
00385 }
00386 emit changed();
00387 }
00388
00389 void Task::setActive(bool a)
00390 {
00391 _active = a;
00392 emit changed();
00393 if ( a )
00394 emit activated();
00395 else
00396 emit deactivated();
00397 }
00398
00399 bool Task::isMaximized() const
00400 {
00401 #ifdef KDE_3_2
00402 return(_info.state() & NET::Max);
00403 #else
00404 return(_info.state & NET::Max);
00405 #endif
00406 }
00407
00408 bool Task::isIconified() const
00409 {
00410 #ifdef KDE_3_2
00411 return (_info.mappingState() == NET::Iconic);
00412 #else
00413 return (_info.mappingState == NET::Iconic);
00414 #endif
00415 }
00416
00417 bool Task::isAlwaysOnTop() const
00418 {
00419 #ifdef KDE_3_2
00420 return (_info.state() & NET::StaysOnTop);
00421 #else
00422 return (_info.state & NET::StaysOnTop);
00423 #endif
00424 }
00425
00426 bool Task::isShaded() const
00427 {
00428 #ifdef KDE_3_2
00429 return (_info.state() & NET::Shaded);
00430 #else
00431 return (_info.state & NET::Shaded);
00432 #endif
00433 }
00434
00435 bool Task::isOnCurrentDesktop() const
00436 {
00437 #ifdef KDE_3_2
00438 return (_info.onAllDesktops() || _info.desktop() == kwin_module->currentDesktop());
00439 #else
00440 return (_info.onAllDesktops || _info.desktop == kwin_module->currentDesktop());
00441 #endif
00442 }
00443
00444 bool Task::isOnAllDesktops() const
00445 {
00446 #ifdef KDE_3_2
00447 return _info.onAllDesktops();
00448 #else
00449 return _info.onAllDesktops;
00450 #endif
00451 }
00452
00453 bool Task::isActive() const
00454 {
00455 return _active;
00456 }
00457
00458 bool Task::isOnTop() const
00459 {
00460 return taskManager()->isOnTop( this );
00461 }
00462
00463 bool Task::isModified() const
00464 {
00465 static TQString modStr = TQString::fromUtf8("[") + i18n("modified") + TQString::fromUtf8("]");
00466 #ifdef KDE_3_2
00467 int modStrPos = _info.visibleName().find(modStr);
00468 #else
00469 int modStrPos = _info.visibleName.find(modStr);
00470 #endif
00471
00472 return ( modStrPos != -1 );
00473 }
00474
00475 TQString Task::iconName() const
00476 {
00477 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMIconName);
00478 return TQString::fromUtf8(ni.iconName());
00479 }
00480 TQString Task::visibleIconName() const
00481 {
00482 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMVisibleIconName);
00483 return TQString::fromUtf8(ni.visibleIconName());
00484 }
00485
00486 TQString Task::className()
00487 {
00488 XClassHint hint;
00489 if(XGetClassHint(qt_xdisplay(), _win, &hint)) {
00490 TQString nh( hint.res_name );
00491 XFree( hint.res_name );
00492 XFree( hint.res_class );
00493 return nh;
00494 }
00495 return TQString();
00496 }
00497
00498 TQString Task::classClass()
00499 {
00500 XClassHint hint;
00501 if(XGetClassHint(qt_xdisplay(), _win, &hint)) {
00502 TQString ch( hint.res_class );
00503 XFree( hint.res_name );
00504 XFree( hint.res_class );
00505 return ch;
00506 }
00507 return TQString();
00508 }
00509
00510 TQPixmap Task::icon( int width, int height, bool allowResize )
00511 {
00512 if ( (width == _lastWidth)
00513 && (height == _lastHeight)
00514 && (allowResize == _lastResize )
00515 && (!_lastIcon.isNull()) )
00516 return _lastIcon;
00517
00518 TQPixmap newIcon = KWin::icon( _win, width, height, allowResize );
00519 if ( !newIcon.isNull() ) {
00520 _lastIcon = newIcon;
00521 _lastWidth = width;
00522 _lastHeight = height;
00523 _lastResize = allowResize;
00524 }
00525
00526 return newIcon;
00527 }
00528
00529 TQPixmap Task::bestIcon( int size, bool &isStaticIcon )
00530 {
00531 TQPixmap pixmap;
00532 isStaticIcon = false;
00533
00534 switch( size ) {
00535 case KIcon::SizeSmall:
00536 {
00537 pixmap = icon( 16, 16, true );
00538
00539
00540 if( pixmap.isNull() ) {
00541 pixmap = KGlobal::iconLoader()->loadIcon( "go",
00542 KIcon::NoGroup,
00543 KIcon::SizeSmall );
00544 isStaticIcon = true;
00545 }
00546 }
00547 break;
00548 case KIcon::SizeMedium:
00549 {
00550
00551
00552
00553
00554 pixmap = icon( 34, 34, false );
00555
00556 if ( ( pixmap.width() != 34 ) || ( pixmap.height() != 34 ) ) {
00557 if ( ( pixmap.width() != 32 ) || ( pixmap.height() != 32 ) ) {
00558 pixmap = icon( 32, 32, true );
00559 }
00560 }
00561
00562
00563 if( pixmap.isNull() ) {
00564 pixmap = KGlobal::iconLoader()->loadIcon( "go",
00565 KIcon::NoGroup,
00566 KIcon::SizeMedium );
00567 isStaticIcon = true;
00568 }
00569 }
00570 break;
00571 case KIcon::SizeLarge:
00572 {
00573
00574 pixmap = icon( size, size, false );
00575
00576
00577 if ( pixmap.isNull() || pixmap.width() != size || pixmap.height() != size ) {
00578 pixmap = KGlobal::iconLoader()->loadIcon( className(),
00579 KIcon::NoGroup,
00580 size,
00581 KIcon::DefaultState,
00582 0L,
00583 true );
00584 isStaticIcon = true;
00585 }
00586
00587
00588 if ( pixmap.isNull() || ( pixmap.width() != size ) || ( pixmap.height() != size ) ) {
00589 pixmap = icon( size, size, true );
00590 isStaticIcon = false;
00591 }
00592
00593
00594 if( pixmap.isNull() ) {
00595 pixmap = KGlobal::iconLoader()->loadIcon( "go",
00596 KIcon::NoGroup,
00597 size );
00598 isStaticIcon = true;
00599 }
00600 }
00601 }
00602
00603 return pixmap;
00604 }
00605
00606 bool Task::idMatch( const TQString& id1, const TQString& id2 )
00607 {
00608 if ( id1.isEmpty() || id2.isEmpty() )
00609 return false;
00610
00611 if ( id1.contains( id2 ) > 0 )
00612 return true;
00613
00614 if ( id2.contains( id1 ) > 0 )
00615 return true;
00616
00617 return false;
00618 }
00619
00620
00621 void Task::maximize()
00622 {
00623 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
00624 ni.setState( NET::Max, NET::Max );
00625
00626 #ifdef KDE_3_2
00627 if (_info.mappingState() == NET::Iconic)
00628 #else
00629 if (_info.mappingState == NET::Iconic)
00630 #endif
00631 activate();
00632 }
00633
00634 void Task::restore()
00635 {
00636 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
00637 ni.setState( 0, NET::Max );
00638 #ifdef KDE_3_2
00639 if (_info.mappingState() == NET::Iconic)
00640 #else
00641 if (_info.mappingState == NET::Iconic)
00642 #endif
00643 activate();
00644 }
00645
00646 void Task::iconify()
00647 {
00648 XIconifyWindow( qt_xdisplay(), _win, qt_xscreen() );
00649 }
00650
00651 void Task::close()
00652 {
00653 NETRootInfo ri( qt_xdisplay(), NET::CloseWindow );
00654 ri.closeWindowRequest( _win );
00655 }
00656
00657 void Task::raise()
00658 {
00659
00660 XRaiseWindow( qt_xdisplay(), _win );
00661 }
00662
00663 void Task::lower()
00664 {
00665
00666 XLowerWindow( qt_xdisplay(), _win );
00667 }
00668
00669 void Task::activate()
00670 {
00671
00672 NETRootInfo ri( qt_xdisplay(), 0 );
00673 ri.setActiveWindow( _win );
00674 }
00675
00676 void Task::activateRaiseOrIconify()
00677 {
00678 if ( !isActive() || isIconified() ) {
00679 activate();
00680 } else if ( !isOnTop() ) {
00681 raise();
00682 } else {
00683 iconify();
00684 }
00685 }
00686
00687 void Task::toDesktop(int desk)
00688 {
00689 NETWinInfo ni(qt_xdisplay(), _win, qt_xrootwin(), NET::WMDesktop);
00690 if (desk == 0)
00691 {
00692 #ifdef KDE_3_2
00693 if (_info.onAllDesktops())
00694 {
00695 ni.setDesktop(kwin_module->currentDesktop());
00696 KWin::forceActiveWindow(_win);
00697 }
00698 #else
00699 if (_info.onAllDesktops)
00700 {
00701 ni.setDesktop(kwin_module->currentDesktop());
00702 KWin::setActiveWindow(_win);
00703 }
00704 #endif
00705 else
00706 ni.setDesktop(NETWinInfo::OnAllDesktops);
00707 return;
00708 }
00709 ni.setDesktop(desk);
00710 if (desk == kwin_module->currentDesktop())
00711 #ifdef KDE_3_2
00712 KWin::forceActiveWindow(_win);
00713 #else
00714 KWin::setActiveWindow(_win);
00715 #endif
00716 }
00717
00718 void Task::toCurrentDesktop()
00719 {
00720 toDesktop(kwin_module->currentDesktop());
00721 }
00722
00723 void Task::setAlwaysOnTop(bool stay)
00724 {
00725 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
00726 if(stay)
00727 ni.setState( NET::StaysOnTop, NET::StaysOnTop );
00728 else
00729 ni.setState( 0, NET::StaysOnTop );
00730 }
00731
00732 void Task::toggleAlwaysOnTop()
00733 {
00734 setAlwaysOnTop( !isAlwaysOnTop() );
00735 }
00736
00737 void Task::setShaded(bool shade)
00738 {
00739 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMState);
00740 if(shade)
00741 ni.setState( NET::Shaded, NET::Shaded );
00742 else
00743 ni.setState( 0, NET::Shaded );
00744 }
00745
00746 void Task::toggleShaded()
00747 {
00748 setShaded( !isShaded() );
00749 }
00750
00751 void Task::publishIconGeometry(TQRect rect)
00752 {
00753 NETWinInfo ni( qt_xdisplay(), _win, qt_xrootwin(), NET::WMIconGeometry);
00754 NETRect r;
00755 r.pos.x = rect.x();
00756 r.pos.y = rect.y();
00757 r.size.width = rect.width();
00758 r.size.height = rect.height();
00759 ni.setIconGeometry(r);
00760 }
00761
00762 void Task::updateThumbnail()
00763 {
00764 if ( !isOnCurrentDesktop() )
00765 return;
00766 if ( !isActive() )
00767 return;
00768 if ( !_grab.isNull() )
00769 return;
00770
00771
00772
00773
00774
00775
00776 TQWidget *rootWin = TQT_TQWIDGET(tqApp->desktop());
00777 TQRect geom = _info.geometry();
00778 _grab = TQPixmap::grabWindow( rootWin->winId(),
00779 geom.x(), geom.y(),
00780 geom.width(), geom.height() );
00781
00782 if ( !_grab.isNull() )
00783 TQTimer::singleShot( 200, this, TQT_SLOT( generateThumbnail() ) );
00784 }
00785
00786 void Task::generateThumbnail()
00787 {
00788 if ( _grab.isNull() )
00789 return;
00790
00791 TQImage img = _grab.convertToImage();
00792
00793 double width = img.width();
00794 double height = img.height();
00795 width = width * _thumbSize;
00796 height = height * _thumbSize;
00797
00798 img = img.smoothScale( (int) width, (int) height );
00799 _thumb = img;
00800 _grab.resize( 0, 0 );
00801
00802 emit thumbnailChanged();
00803 }
00804
00805 Startup::Startup( const KStartupInfoId& id, const KStartupInfoData& data,
00806 TQObject * parent, const char *name)
00807 : TQObject(parent, name), _id( id ), _data( data )
00808 {
00809 }
00810
00811 Startup::~Startup()
00812 {
00813
00814 }
00815
00816 void Startup::update( const KStartupInfoData& data )
00817 {
00818 _data.update( data );
00819 emit changed();
00820 }
00821
00822 int TaskManager::currentDesktop() const
00823 {
00824 return kwin_module->currentDesktop();
00825 }