not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / ksystraycmd / ksystraycmd.cpp
blobb1dcfd7e37e67c38e98813f9ca2b387c1c5665a6
2 #include <QTextStream>
3 #include <QImage>
4 #include <QRegExp>
5 #include <QMouseEvent>
7 #include <kdebug.h>
8 #include <kapplication.h>
9 #include <kglobal.h>
10 #include <kicon.h>
11 #include <klocale.h>
12 #include <kmenu.h>
13 #include <k3process.h>
14 #include <kwindowsystem.h>
15 #include <kconfig.h>
16 #include <ksystemtrayicon.h>
17 #include <kconfiggroup.h>
18 #include <kaboutdata.h>
20 #include <netwm.h>
22 #include "ksystraycmd.h"
23 #include "ksystraycmd.moc"
24 #include <QX11Info>
27 KSysTrayCmd::KSysTrayCmd()
28 : KSystemTrayIcon( static_cast<QWidget*>(0) ),
29 isVisible(true), lazyStart( false ), noquit( false ), quitOnHide( false ), onTop(false), ownIcon(false),
30 win(0), client(0), top(0), left(0)
32 connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(mousePressEvent(QSystemTrayIcon::ActivationReason)));
33 refresh();
36 KSysTrayCmd::~KSysTrayCmd()
38 delete client;
42 // Main entry point to the class
45 bool KSysTrayCmd::start()
47 // If we have no command we must catching an existing window
48 if ( command.isEmpty() ) {
49 if ( win ) {
50 setTargetWindow( win );
51 return true;
54 checkExistingWindows();
55 if ( win ) {
56 // Window always on top
57 if (onTop) {
58 KWindowSystem::setState(win, NET::StaysOnTop);
60 return true;
63 errStr = i18n( "No window matching pattern '%1' and no command specified.\n" ,
64 window );
65 return false;
68 // Run the command and watch for its window
69 if ( !startClient() ) {
70 errStr = i18n( "KSysTrayCmd: K3ShellProcess cannot find a shell." );
71 clientExited();
72 return false;
75 return true;
79 // Window related functions.
82 void KSysTrayCmd::showWindow()
84 isVisible = true;
85 if ( !win )
86 return;
87 XMapWindow( QX11Info::display(), win );
88 // We move the window to the memorized position
89 XMoveWindow( QX11Info::display(), win, left, top);
91 // Window always on top
92 if (onTop)
94 KWindowSystem::setState(win, NET::StaysOnTop);
97 KWindowSystem::activateWindow( win );
101 void KSysTrayCmd::hideWindow()
103 isVisible = false;
104 if ( !win )
105 return;
106 //We memorize the position of the window
107 left = KWindowSystem::windowInfo(win, NET::WMFrameExtents).frameGeometry().left();
108 top=KWindowSystem::windowInfo(win, NET::WMFrameExtents).frameGeometry().top();
110 XUnmapWindow( QX11Info::display(), win );
113 void KSysTrayCmd::setTargetWindow( WId w )
115 disconnect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
116 connect( KWindowSystem::self(), SIGNAL(windowChanged(WId)), SLOT(windowChanged(WId)) );
117 win = w;
118 // KWindowSystem::setSystemTrayWindowFor( winId(), win );
119 refresh();
120 show();
122 if ( isVisible )
123 KWindowSystem::activateWindow( win );
124 else
125 hideWindow();
127 // Always on top ?
128 if (onTop)
130 KWindowSystem::setState(win, NET::StaysOnTop);
135 // Refresh the tray icon
138 void KSysTrayCmd::refresh()
140 // KWindowSystem::setSystemTrayWindowFor( winId(), win ? win : winId() );
142 if ( win ) {
143 if (ownIcon)
145 setIcon( KIcon( KGlobal::activeComponent().aboutData()->programIconName() ) );
147 else
149 setIcon( KWindowSystem::icon( win, 22, 22, true ) );
152 this->setToolTip( KWindowSystem::windowInfo( win, NET::WMName ).name() );
154 else {
155 if ( !tooltip.isEmpty() )
156 this->setToolTip( tooltip );
157 else if ( !command.isEmpty() )
158 this->setToolTip( command );
159 else
160 this->setToolTip( window );
162 setIcon( KIcon( qApp->applicationName() ) );
167 // Client related functions.
170 bool KSysTrayCmd::startClient()
172 client = new K3ShellProcess();
173 *client << command;
174 connect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), SLOT(windowAdded(WId)) );
175 connect( client, SIGNAL( processExited(K3Process *) ),
176 this, SLOT( clientExited() ) );
178 return client->start();
181 void KSysTrayCmd::clientExited()
183 delete client;
184 client = 0;
185 win = 0;
187 if ( lazyStart && noquit )
188 refresh();
189 else
190 qApp->quit();
193 void KSysTrayCmd::quitClient()
195 if ( win ) {
196 // Before sending the close request we have to show the window
197 XMapWindow( QX11Info::display(), win );
198 NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
199 ri.closeWindowRequest( win );
200 win=0;
201 noquit = false;
203 // We didn't give command, so we didn't open an application.
204 // That's why when the application is closed we aren't informed.
205 // So we quit now.
207 if ( command.isEmpty() ) {
208 qApp->quit();
211 else {
212 qApp->quit();
216 void KSysTrayCmd::quit()
218 if ( !isVisible ) {
219 showWindow();
221 qApp->quit();
224 void KSysTrayCmd::execContextMenu( const QPoint &pos )
226 KMenu *menu = new KMenu();
227 menu->addTitle( icon(), i18n( "KSysTrayCmd" ) );
228 QAction * hideShowId = menu->addAction( isVisible ? i18n( "&Hide" ) : i18n( "&Restore" ) );
229 QAction * undockId = menu->addAction( KIcon("dialog-close"), i18n( "&Undock" ) );
230 QAction * quitId = menu->addAction( KIcon("application-exit"), i18n( "&Quit" ) );
232 QAction * cmd = menu->exec( pos );
234 if ( cmd == quitId )
235 quitClient();
236 else if ( cmd == undockId )
237 quit();
238 else if ( cmd == hideShowId )
240 if ( lazyStart && ( !hasRunningClient() ) )
242 start();
243 isVisible=true;
245 else if ( quitOnHide && ( hasRunningClient() ) && isVisible )
247 NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
248 ri.closeWindowRequest( win );
249 isVisible=false;
251 else
252 toggleWindow();
255 delete menu;
258 void KSysTrayCmd::checkExistingWindows()
260 QList<WId>::ConstIterator it;
261 for ( it = KWindowSystem::windows().begin(); it != KWindowSystem::windows().end(); ++it ) {
262 windowAdded( *it );
263 if ( win )
264 break;
268 void KSysTrayCmd::windowAdded(WId w)
270 if ( !window.isEmpty() && ( QRegExp( window ).indexIn( KWindowSystem::windowInfo(w,NET::WMName).name() ) == -1 ) )
271 return; // no match
272 setTargetWindow( w );
275 void KSysTrayCmd::windowChanged( WId w )
277 if ( w != win )
278 return;
279 refresh();
283 // Tray icon event handlers
286 void KSysTrayCmd::mousePressEvent( QSystemTrayIcon::ActivationReason reason )
288 if ( reason == QSystemTrayIcon::Context )
289 execContextMenu( QCursor::pos() );
290 else if ( lazyStart && ( !hasRunningClient() ) )
292 start();
293 isVisible=true;
295 else if ( quitOnHide && ( hasRunningClient() ) && isVisible )
297 NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
298 ri.closeWindowRequest( win );
299 isVisible=false;
301 else if ( reason == QSystemTrayIcon::Trigger )
302 toggleWindow();
305 WId KSysTrayCmd::findRealWindow( WId w, int depth )
307 if( depth > 5 )
308 return None;
309 static Atom wm_state = XInternAtom( QX11Info::display(), "WM_STATE", False );
310 Atom type;
311 int format;
312 unsigned long nitems, after;
313 unsigned char* prop;
314 if( XGetWindowProperty( QX11Info::display(), w, wm_state, 0, 0, False, AnyPropertyType,
315 &type, &format, &nitems, &after, &prop ) == Success ) {
316 if( prop != NULL )
317 XFree( prop );
318 if( type != None )
319 return w;
321 Window root, parent;
322 Window* children;
323 unsigned int nchildren;
324 Window ret = None;
325 if( XQueryTree( QX11Info::display(), w, &root, &parent, &children, &nchildren ) != 0 ) {
326 for( unsigned int i = 0;
327 i < nchildren && ret == None;
328 ++i )
329 ret = findRealWindow( children[ i ], depth + 1 );
330 if( children != NULL )
331 XFree( children );
333 return ret;