8 #include <kapplication.h>
13 #include <k3process.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 ), 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
)));
36 KSysTrayCmd::~KSysTrayCmd()
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() ) {
50 setTargetWindow( win
);
54 checkExistingWindows();
56 // Window always on top
58 KWindowSystem::setState(win
, NET::StaysOnTop
);
63 errStr
= i18n( "No window matching pattern '%1' and no command specified.\n" ,
68 // Run the command and watch for its window
69 if ( !startClient() ) {
70 errStr
= i18n( "KSysTrayCmd: K3ShellProcess cannot find a shell." );
79 // Window related functions.
82 void KSysTrayCmd::showWindow()
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
94 KWindowSystem::setState(win
, NET::StaysOnTop
);
97 KWindowSystem::activateWindow( win
);
101 void KSysTrayCmd::hideWindow()
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
)) );
118 // KWindowSystem::setSystemTrayWindowFor( winId(), win );
123 KWindowSystem::activateWindow( win
);
130 KWindowSystem::setState(win
, NET::StaysOnTop
);
135 // Refresh the tray icon
138 void KSysTrayCmd::refresh()
140 // KWindowSystem::setSystemTrayWindowFor( winId(), win ? win : winId() );
145 setIcon( KIcon( KGlobal::activeComponent().aboutData()->programIconName() ) );
149 setIcon( KWindowSystem::icon( win
, 22, 22, true ) );
152 this->setToolTip( KWindowSystem::windowInfo( win
, NET::WMName
).name() );
155 if ( !tooltip
.isEmpty() )
156 this->setToolTip( tooltip
);
157 else if ( !command
.isEmpty() )
158 this->setToolTip( command
);
160 this->setToolTip( window
);
162 setIcon( KIcon( qApp
->applicationName() ) );
167 // Client related functions.
170 bool KSysTrayCmd::startClient()
172 client
= new K3ShellProcess();
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()
187 if ( lazyStart
&& noquit
)
193 void KSysTrayCmd::quitClient()
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
);
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.
207 if ( command
.isEmpty() ) {
216 void KSysTrayCmd::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
);
236 else if ( cmd
== undockId
)
238 else if ( cmd
== hideShowId
)
240 if ( lazyStart
&& ( !hasRunningClient() ) )
245 else if ( quitOnHide
&& ( hasRunningClient() ) && isVisible
)
247 NETRootInfo
ri( QX11Info::display(), NET::CloseWindow
);
248 ri
.closeWindowRequest( win
);
258 void KSysTrayCmd::checkExistingWindows()
260 QList
<WId
>::ConstIterator it
;
261 for ( it
= KWindowSystem::windows().begin(); it
!= KWindowSystem::windows().end(); ++it
) {
268 void KSysTrayCmd::windowAdded(WId w
)
270 if ( !window
.isEmpty() && ( QRegExp( window
).indexIn( KWindowSystem::windowInfo(w
,NET::WMName
).name() ) == -1 ) )
272 setTargetWindow( w
);
275 void KSysTrayCmd::windowChanged( WId w
)
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() ) )
295 else if ( quitOnHide
&& ( hasRunningClient() ) && isVisible
)
297 NETRootInfo
ri( QX11Info::display(), NET::CloseWindow
);
298 ri
.closeWindowRequest( win
);
301 else if ( reason
== QSystemTrayIcon::Trigger
)
305 WId
KSysTrayCmd::findRealWindow( WId w
, int depth
)
309 static Atom wm_state
= XInternAtom( QX11Info::display(), "WM_STATE", False
);
312 unsigned long nitems
, after
;
314 if( XGetWindowProperty( QX11Info::display(), w
, wm_state
, 0, 0, False
, AnyPropertyType
,
315 &type
, &format
, &nitems
, &after
, &prop
) == Success
) {
323 unsigned int nchildren
;
325 if( XQueryTree( QX11Info::display(), w
, &root
, &parent
, &children
, &nchildren
) != 0 ) {
326 for( unsigned int i
= 0;
327 i
< nchildren
&& ret
== None
;
329 ret
= findRealWindow( children
[ i
], depth
+ 1 );
330 if( children
!= NULL
)