00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
#if !defined(_POSIX_C_SOURCE)
00021
#define _POSIX_C_SOURCE 199309
00022
#elif _POSIX_C_SOURCE < 199309
00023
#undef _POSIX_C_SOURCE
00024
#define _POSIX_C_SOURCE 199309
00025
#endif
00026
00027
#include "kdetrayproxy.h"
00028
00029
#include <kapplication.h>
00030
#include <kdebug.h>
00031
#include <netwm.h>
00032
#include <X11/Xlib.h>
00033
#include <time.h>
00034
#include <assert.h>
00035
00036
00037
#if defined(__FreeBSD__)
00038
#include <osreldate.h>
00039
#if __FreeBSD_version < 500042
00040
#warning FreeBSD 4.x compatibility shims in effect
00041
#include <sys/time.h>
00042
00043
int nanosleep(
const struct timespec *,
struct timespec *);
00044
#endif
00045
#endif
00046
00047 KDETrayProxy::KDETrayProxy()
00048 : selection( makeSelectionAtom())
00049 {
00050 connect( &selection, SIGNAL( newOwner( Window )), SLOT( newOwner( Window )));
00051 connect( &module, SIGNAL( windowAdded( WId )), SLOT( windowAdded( WId )));
00052 selection.owner();
00053
for(
QValueList< WId >::ConstIterator it = module.windows().begin();
00054 it != module.windows().end();
00055 ++it )
00056 windowAdded( *it );
00057 kapp->installX11EventFilter(
this );
00058
00059 }
00060
00061 Atom KDETrayProxy::makeSelectionAtom()
00062 {
00063
return XInternAtom( qt_xdisplay(),
"_NET_SYSTEM_TRAY_S" +
QCString().setNum( qt_xscreen()), False );
00064 }
00065
00066
extern Time qt_x_time;
00067
00068
void KDETrayProxy::windowAdded( WId w )
00069 {
00070
NETWinInfo ni( qt_xdisplay(), w, qt_xrootwin(), NET::WMKDESystemTrayWinFor );
00071 WId trayWinFor = ni.kdeSystemTrayWinFor();
00072
if ( !trayWinFor )
00073
return;
00074
00075
if( !tray_windows.contains( w ))
00076 tray_windows.append( w );
00077 withdrawWindow( w );
00078
00079
if( !pending_windows.contains( w ))
00080 pending_windows.append( w );
00081 docked_windows.remove( w );
00082 Window owner = selection.owner();
00083
if( owner == None )
00084 {
00085
00086
return;
00087 }
00088 dockWindow( w, owner );
00089 }
00090
00091
void KDETrayProxy::newOwner( Window owner )
00092 {
00093
00094
for(
QValueList< Window >::ConstIterator it = pending_windows.begin();
00095 it != pending_windows.end();
00096 ++it )
00097 dockWindow( *it, owner );
00098
00099 }
00100
00101
bool KDETrayProxy::x11Event( XEvent* e )
00102 {
00103
if( tray_windows.isEmpty())
00104
return false;
00105
if( e->type == DestroyNotify && tray_windows.contains( e->xdestroywindow.window ))
00106 {
00107 tray_windows.remove( e->xdestroywindow.window );
00108 pending_windows.remove( e->xdestroywindow.window );
00109 docked_windows.remove( e->xdestroywindow.window );
00110 }
00111
if( e->type == ReparentNotify && tray_windows.contains( e->xreparent.window ))
00112 {
00113
if( e->xreparent.parent == qt_xrootwin())
00114 {
00115
if( !docked_windows.contains( e->xreparent.window ) || e->xreparent.serial >= docked_windows[ e->xreparent.window ] )
00116 {
00117
00118 docked_windows.remove( e->xreparent.window );
00119
if( !pending_windows.contains( e->xreparent.window ))
00120 pending_windows.append( e->xreparent.window );
00121 }
00122 }
00123
else
00124 {
00125
00126 pending_windows.remove( e->xreparent.window );
00127 }
00128 }
00129
if( e->type == UnmapNotify && tray_windows.contains( e->xunmap.window ))
00130 {
00131
if( docked_windows.contains( e->xunmap.window ) && e->xunmap.serial >= docked_windows[ e->xunmap.window ] )
00132 {
00133
00134 XReparentWindow( qt_xdisplay(), e->xunmap.window, qt_xrootwin(), 0, 0 );
00135
00136 }
00137 }
00138
return false;
00139 }
00140
00141
void KDETrayProxy::dockWindow( Window w, Window owner )
00142 {
00143
00144 docked_windows[ w ] = XNextRequest( qt_xdisplay());
00145
static Atom prop = XInternAtom( qt_xdisplay(),
"_XEMBED_INFO", False );
00146
long data[ 2 ] = { 0, 1 };
00147 XChangeProperty( qt_xdisplay(), w, prop, prop, 32, PropModeReplace, (
unsigned char*)data, 2 );
00148 XSizeHints hints;
00149 hints.flags = PMinSize | PMaxSize;
00150 hints.min_width = 24;
00151 hints.max_width = 24;
00152 hints.min_height = 24;
00153 hints.max_height = 24;
00154 XSetWMNormalHints( qt_xdisplay(), w, &hints );
00155
00156 XEvent ev;
00157 memset(&ev, 0,
sizeof( ev ));
00158
static Atom atom = XInternAtom( qt_xdisplay(),
"_NET_SYSTEM_TRAY_OPCODE", False );
00159 ev.xclient.type = ClientMessage;
00160 ev.xclient.window = owner;
00161 ev.xclient.message_type = atom;
00162 ev.xclient.format = 32;
00163 ev.xclient.data.l[ 0 ] = qt_x_time;
00164 ev.xclient.data.l[ 1 ] = 0;
00165 ev.xclient.data.l[ 2 ] = w;
00166 ev.xclient.data.l[ 3 ] = 0;
00167 ev.xclient.data.l[ 4 ] = 0;
00168 XSendEvent( qt_xdisplay(), owner, False, NoEventMask, &ev );
00169 }
00170
00171
void KDETrayProxy::withdrawWindow( Window w )
00172 {
00173 XWithdrawWindow( qt_xdisplay(), w, qt_xscreen());
00174
static Atom wm_state = XInternAtom( qt_xdisplay(),
"WM_STATE", False );
00175
for(;;)
00176 {
00177 Atom type;
00178
int format;
00179
unsigned long length, after;
00180
unsigned char *data;
00181
int r = XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 2,
00182 False, AnyPropertyType, &type, &format,
00183 &length, &after, &data );
00184
bool withdrawn =
true;
00185
if ( r == Success && data && format == 32 )
00186 {
00187 withdrawn = ( *(
long* )data == WithdrawnState );
00188 XFree( (
char *)data );
00189 }
00190
if( withdrawn )
00191
return;
00192
struct timespec tm;
00193 tm.tv_sec = 0;
00194 tm.tv_nsec = 10 * 1000 * 1000;
00195 nanosleep( &tm, NULL );
00196 }
00197 }
00198
00199
#include "kdetrayproxy.moc"
00200
00201
#if 0
00202
#include <kcmdlineargs.h>
00203
int main(
int argc,
char* argv[] )
00204 {
00205
KCmdLineArgs::init( argc, argv,
"a",
"b",
"c",
"d" );
00206
KApplication app(
false );
00207 app.disableSessionManagement();
00208 KDETrayProxy proxy;
00209
return app.exec();
00210 }
00211
#endif