8
#include <kapplication.h>
14
#include <kwindowsystem.h>
16
#include <ksystemtrayicon.h>
17
#include <kconfiggroup.h>
18
#include <kaboutdata.h>
22
#include "ksystraycmd.h"
23
#include "ksystraycmd.moc"
27
KSysTrayCmd::KSysTrayCmd()
28
: KSystemTrayIcon( static_cast<QWidget*>(0) ),
29
isVisible(true), lazyStart( false ), noquit( false ),
30
quitOnHide( false ), onTop(false), ownIcon(false),
31
waitingForWindow( false ),
32
win(0), client(0), top(0), left(0)
34
connect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
38
connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), SLOT(mousePressEvent(QSystemTrayIcon::ActivationReason)));
42
KSysTrayCmd::~KSysTrayCmd()
47
if( client->state() == QProcess::Running )
51
client->waitForFinished( 5000 );
58
// Main entry point to the class
61
bool KSysTrayCmd::start()
63
// If we have no command we must catching an existing window
64
if ( command.isEmpty() ) {
66
setTargetWindow( win );
70
waitingForWindow = true;
71
checkExistingWindows();
73
// Window always on top
75
KWindowSystem::setState(win, NET::StaysOnTop);
80
errStr = i18n( "No window matching pattern '%1' and no command specified.\n" ,
85
// Run the command and watch for its window
86
if ( !startClient() ) {
87
errStr = i18n( "KSysTrayCmd: K3ShellProcess cannot find a shell." );
96
// Window related functions.
99
void KSysTrayCmd::showWindow()
104
XMapWindow( QX11Info::display(), win );
105
// We move the window to the memorized position
106
XMoveWindow( QX11Info::display(), win, left, top);
108
// Window always on top
111
KWindowSystem::setState(win, NET::StaysOnTop);
114
KWindowSystem::activateWindow( win );
118
void KSysTrayCmd::hideWindow()
123
//We memorize the position of the window
124
left = KWindowSystem::windowInfo(win, NET::WMFrameExtents).frameGeometry().left();
125
top=KWindowSystem::windowInfo(win, NET::WMFrameExtents).frameGeometry().top();
127
XUnmapWindow( QX11Info::display(), win );
130
void KSysTrayCmd::setTargetWindow( WId w )
132
disconnect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
133
connect( KWindowSystem::self(), SIGNAL(windowChanged(WId)), SLOT(windowChanged(WId)) );
135
// KWindowSystem::setSystemTrayWindowFor( winId(), win );
140
KWindowSystem::activateWindow( win );
147
KWindowSystem::setState(win, NET::StaysOnTop);
152
// Refresh the tray icon
155
void KSysTrayCmd::refresh()
157
// KWindowSystem::setSystemTrayWindowFor( winId(), win ? win : winId() );
162
setIcon( KApplication::windowIcon() );
166
setIcon( KWindowSystem::icon( win, 22, 22, true ) );
169
if ( tooltip.isEmpty() )
170
this->setToolTip( KWindowSystem::windowInfo( win, NET::WMName ).name() );
173
if ( !tooltip.isEmpty() )
174
this->setToolTip( tooltip );
175
else if ( !command.isEmpty() )
176
this->setToolTip( command );
178
this->setToolTip( window );
180
setIcon( KApplication::windowIcon() );
185
// Client related functions.
188
bool KSysTrayCmd::startClient()
190
kDebug() << "startClient()";
191
client = new KProcess();
192
client->setShellCommand( command );
193
//connect( KWindowSystem::self(), SIGNAL(windowAdded(WId)), this, SLOT(windowAdded(WId)) );
194
waitingForWindow = true;
195
connect( client, SIGNAL( finished(int,QProcess::ExitStatus) ), this, SLOT( clientExited() ) );
198
return client->waitForStarted( -1 );
201
void KSysTrayCmd::clientExited()
206
waitingForWindow = false;
208
if ( lazyStart && noquit )
214
void KSysTrayCmd::quitClient()
217
// Before sending the close request we have to show the window
218
XMapWindow( QX11Info::display(), win );
219
NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
220
ri.closeWindowRequest( win );
224
// We didn't give command, so we didn't open an application.
225
// That's why when the application is closed we aren't informed.
228
if ( command.isEmpty() ) {
237
void KSysTrayCmd::quit()
245
void KSysTrayCmd::execContextMenu( const QPoint &pos )
248
menu->addTitle( icon(), i18n( "KSysTrayCmd" ) );
249
QAction * hideShowId = menu->addAction( isVisible ? i18n( "&Hide" ) : i18n( "&Restore" ) );
250
QAction * undockId = menu->addAction( KIcon("dialog-close"), i18n( "&Undock" ) );
251
QAction * quitId = menu->addAction( KIcon("application-exit"), i18n( "&Quit" ) );
253
QAction * cmd = menu->exec( pos );
257
else if ( cmd == undockId )
259
else if ( cmd == hideShowId )
261
if ( lazyStart && ( !hasRunningClient() ) )
266
else if ( quitOnHide && ( hasRunningClient() ) && isVisible )
268
NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
269
ri.closeWindowRequest( win );
277
void KSysTrayCmd::checkExistingWindows()
279
kDebug() << "checkExistingWindows()";
280
QList<WId>::ConstIterator it;
281
for ( it = KWindowSystem::windows().begin(); it != KWindowSystem::windows().end(); ++it ) {
288
const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
289
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
290
| NET::UtilityMask | NET::SplashMask;
292
void KSysTrayCmd::windowAdded(WId w)
294
if ( !waitingForWindow )
297
KWindowInfo info = KWindowSystem::windowInfo( w, NET::WMWindowType | NET::WMName );
298
kDebug() << "windowAdded, id" << w << "pattern is " << window << " window is " << info.name();
300
// always ignore these window types
301
if( info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::TopMenu
302
|| info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::Toolbar
303
|| info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) == NET::Desktop )
306
// If we're grabbing the first window we see
307
if( window.isEmpty() ) {
308
// accept only "normal" windows
309
if( info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) != NET::Unknown
310
&& info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) != NET::Normal
311
&& info.windowType( SUPPORTED_WINDOW_TYPES_MASK ) != NET::Dialog )
314
else if ( QRegExp( window ).indexIn( info.name() ) == -1 ) {
318
kDebug() << "windowAdded, setting target " << (int) w;
319
setTargetWindow( w );
322
void KSysTrayCmd::windowChanged( WId w )
330
// Tray icon event handlers
333
void KSysTrayCmd::mousePressEvent( QSystemTrayIcon::ActivationReason reason )
335
if ( reason == QSystemTrayIcon::Context )
336
execContextMenu( QCursor::pos() );
337
else if ( lazyStart && ( !hasRunningClient() ) )
342
else if ( quitOnHide && ( hasRunningClient() ) && isVisible )
344
NETRootInfo ri( QX11Info::display(), NET::CloseWindow );
345
ri.closeWindowRequest( win );
348
else if ( reason == QSystemTrayIcon::Trigger )
352
WId KSysTrayCmd::findRealWindow( WId w, int depth )
356
static Atom wm_state = XInternAtom( QX11Info::display(), "WM_STATE", False );
359
unsigned long nitems, after;
361
if( XGetWindowProperty( QX11Info::display(), w, wm_state, 0, 0, False, AnyPropertyType,
362
&type, &format, &nitems, &after, &prop ) == Success ) {
370
unsigned int nchildren;
372
if( XQueryTree( QX11Info::display(), w, &root, &parent, &children, &nchildren ) != 0 ) {
373
for( unsigned int i = 0;
374
i < nchildren && ret == None;
376
ret = findRealWindow( children[ i ], depth + 1 );
377
if( children != NULL )