#include <tqtooltip.h> #include <tqtextstream.h> #include <tqimage.h> #include <tqregexp.h> #include <kdebug.h> #include <kapplication.h> #include <kglobal.h> #include <kiconloader.h> #include <klocale.h> #include <kpopupmenu.h> #include <kprocess.h> #include <twinmodule.h> #include <kconfig.h> #include <ksystemtray.h> #include <netwm.h> #include "ksystraycmd.h" #include "ksystraycmd.moc" KSysTrayCmd::KSysTrayCmd() : TQLabel( 0, "systray_cmd" ), isVisible(true), lazyStart( false ), noquit( false ), quitOnHide( false ), onTop(false), ownIcon(false), win(0), client(0), twinmodule(0), top(0), left(0) { setAlignment( AlignCenter ); twinmodule = new KWinModule( TQT_TQOBJECT(this) ); refresh(); } KSysTrayCmd::~KSysTrayCmd() { delete client; } // // Main entry point to the class // bool KSysTrayCmd::start() { // If we have no command we must catching an existing window if ( !command ) { if ( win ) { setTargetWindow( win ); return true; } checkExistingWindows(); if ( win ) { // Window always on top if (onTop) { KWin::setState(win, NET::StaysOnTop); } return true; } errStr = i18n( "No window matching pattern '%1' and no command specified.\n" ) .arg( window ); return false; } // Run the command and watch for its window if ( !startClient() ) { errStr = i18n( "KSysTrayCmd: KShellProcess cannot find a shell." ); clientExited(); return false; } return true; } // // Window related functions. // void KSysTrayCmd::showWindow() { isVisible = true; if ( !win ) return; XMapWindow( tqt_xdisplay(), win ); // We move the window to the memorized position XMoveWindow( tqt_xdisplay(), win, left, top); // Window always on top if (onTop) { KWin::setState(win, NET::StaysOnTop); } KWin::activateWindow( win ); } void KSysTrayCmd::hideWindow() { isVisible = false; if ( !win ) return; //We memorize the position of the window left = KWin::windowInfo(win).frameGeometry().left(); top=KWin::windowInfo(win).frameGeometry().top(); XUnmapWindow( tqt_xdisplay(), win ); } void KSysTrayCmd::setTargetWindow( WId w ) { setTargetWindow( KWin::windowInfo( w ) ); } void KSysTrayCmd::setTargetWindow( const KWin::WindowInfo &info ) { disconnect( twinmodule, TQT_SIGNAL(windowAdded(WId)), this, TQT_SLOT(windowAdded(WId)) ); connect( twinmodule, TQT_SIGNAL(windowChanged(WId)), TQT_SLOT(windowChanged(WId)) ); win = info.win(); KWin::setSystemTrayWindowFor( winId(), win ); refresh(); show(); if ( isVisible ) KWin::activateWindow( win ); else hideWindow(); // Always on top ? if (onTop) { KWin::setState(win, NET::StaysOnTop); } } // // Refresh the tray icon // void KSysTrayCmd::refresh() { KWin::setSystemTrayWindowFor( winId(), win ? win : winId() ); TQToolTip::remove( this ); if ( win ) { KConfig *appCfg = kapp->config(); KConfigGroupSaver configSaver(appCfg, "System Tray"); int iconWidth = appCfg->readNumEntry("systrayIconWidth", 22); // ksystraycmd's icon or app's icon if (ownIcon) { setPixmap( KSystemTray::loadIcon( kapp->iconName() ) ); } else { setPixmap( KWin::icon( win, iconWidth, iconWidth, true ) ); } TQToolTip::add( this, KWin::windowInfo( win ).name() ); } else { if ( !tooltip.isEmpty() ) TQToolTip::add( this, tooltip ); else if ( !command.isEmpty() ) TQToolTip::add( this, command ); else TQToolTip::add( this, window ); setPixmap( KSystemTray::loadIcon( kapp->iconName() ) ); } } // // Client related functions. // bool KSysTrayCmd::startClient() { client = new KShellProcess(); *client << command; connect( twinmodule, TQT_SIGNAL(windowAdded(WId)), TQT_SLOT(windowAdded(WId)) ); connect( client, TQT_SIGNAL( processExited(KProcess *) ), this, TQT_SLOT( clientExited() ) ); return client->start(); } void KSysTrayCmd::clientExited() { delete client; client = 0; win = 0; if ( lazyStart && noquit ) refresh(); else tqApp->quit(); } void KSysTrayCmd::quitClient() { if ( win ) { // Before sending the close request we have to show the window XMapWindow( tqt_xdisplay(), win ); NETRootInfo ri( tqt_xdisplay(), NET::CloseWindow ); ri.closeWindowRequest( win ); win=0; noquit = false; // We didn't give command, so we didn't open an application. // That's why when the application is closed we aren't informed. // So we quit now. if ( !command ) { tqApp->quit(); } } else { tqApp->quit(); } } void KSysTrayCmd::quit() { if ( !isVisible ) { showWindow(); } tqApp->quit(); } void KSysTrayCmd::execContextMenu( const TQPoint &pos ) { KPopupMenu *menu = new KPopupMenu(); menu->insertTitle( *pixmap(), i18n( "KSysTrayCmd" ) ); int hideShowId = menu->insertItem( isVisible ? i18n( "&Hide" ) : i18n( "&Restore" ) ); int undockId = menu->insertItem( SmallIcon("close"), i18n( "&Undock" ) ); int quitId = menu->insertItem( SmallIcon("exit"), i18n( "&Quit" ) ); int cmd = menu->exec( pos ); if ( cmd == quitId ) quitClient(); else if ( cmd == undockId ) quit(); else if ( cmd == hideShowId ) { if ( lazyStart && ( !hasRunningClient() ) ) { start(); isVisible=true; } else if ( quitOnHide && ( hasRunningClient() ) && isVisible ) { NETRootInfo ri( tqt_xdisplay(), NET::CloseWindow ); ri.closeWindowRequest( win ); isVisible=false; } else toggleWindow(); } delete menu; } void KSysTrayCmd::checkExistingWindows() { TQValueList<WId>::ConstIterator it; for ( it = twinmodule->windows().begin(); it != twinmodule->windows().end(); ++it ) { windowAdded( *it ); if ( win ) break; } } void KSysTrayCmd::windowAdded(WId w) { if ( !window.isEmpty() && ( TQRegExp( window ).search( KWin::windowInfo(w).name() ) == -1 ) ) return; // no match setTargetWindow( w ); } void KSysTrayCmd::windowChanged( WId w ) { if ( w != win ) return; refresh(); } // // Tray icon event handlers // void KSysTrayCmd::mousePressEvent( TQMouseEvent *e ) { if ( e->button() == Qt::RightButton ) execContextMenu( e->globalPos() ); else if ( lazyStart && ( !hasRunningClient() ) ) { start(); isVisible=true; } else if ( quitOnHide && ( hasRunningClient() ) && isVisible ) { NETRootInfo ri( tqt_xdisplay(), NET::CloseWindow ); ri.closeWindowRequest( win ); isVisible=false; } else toggleWindow(); } WId KSysTrayCmd::findRealWindow( WId w, int depth ) { if( depth > 5 ) return None; static Atom wm_state = XInternAtom( tqt_xdisplay(), "WM_STATE", False ); Atom type; int format; unsigned long nitems, after; unsigned char* prop; if( XGetWindowProperty( tqt_xdisplay(), w, wm_state, 0, 0, False, AnyPropertyType, &type, &format, &nitems, &after, &prop ) == Success ) { if( prop != NULL ) XFree( prop ); if( type != None ) return w; } Window root, parent; Window* children; unsigned int nchildren; Window ret = None; if( XQueryTree( tqt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) { for( unsigned int i = 0; i < nchildren && ret == None; ++i ) ret = findRealWindow( children[ i ], depth + 1 ); if( children != NULL ) XFree( children ); } return ret; }