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