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 <kapplication.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, SIGNAL( newOwner( Window )), SLOT( newOwner( Window )));
00036     connect( &module, SIGNAL( windowAdded( WId )), SLOT( windowAdded( WId )));
00037     selection.owner();
00038     for( QValueList< 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( qt_xdisplay(), "_NET_SYSTEM_TRAY_S" + QCString().setNum( qt_xscreen()), False );
00049     }
00050 
00051 extern Time qt_x_time;
00052 
00053 void KDETrayProxy::windowAdded( WId w )
00054     {
00055     NETWinInfo ni( qt_xdisplay(), w, qt_xrootwin(), NET::WMKDESystemTrayWinFor );
00056     WId trayWinFor = ni.kdeSystemTrayWinFor();
00057     if ( !trayWinFor ) 
00058         return;
00059 
00060     if( !tray_windows.contains( w ))
00061         tray_windows.append( w );
00062     withdrawWindow( w );
00063     
00064     if( !pending_windows.contains( w ))
00065         pending_windows.append( w );
00066     docked_windows.remove( w );
00067     Window owner = selection.owner();
00068     if( owner == None ) 
00069         {
00070 
00071         return;
00072         }
00073     dockWindow( w, owner );
00074     }
00075     
00076 void KDETrayProxy::newOwner( Window owner )
00077     {
00078 
00079     for( QValueList< Window >::ConstIterator it = pending_windows.begin();
00080          it != pending_windows.end();
00081          ++it )
00082         dockWindow( *it, owner );
00083     
00084     }
00085 
00086 bool KDETrayProxy::x11Event( XEvent* e )
00087     {
00088     if( tray_windows.isEmpty())
00089         return false;
00090     if( e->type == DestroyNotify && tray_windows.contains( e->xdestroywindow.window ))
00091         {
00092         tray_windows.remove( e->xdestroywindow.window );
00093         pending_windows.remove( e->xdestroywindow.window );
00094         docked_windows.remove( e->xdestroywindow.window );
00095         }
00096     if( e->type == ReparentNotify && tray_windows.contains( e->xreparent.window ))
00097         {
00098         if( e->xreparent.parent == qt_xrootwin())
00099             {
00100             if( !docked_windows.contains( e->xreparent.window ) || e->xreparent.serial >= docked_windows[ e->xreparent.window ] )
00101                 {
00102 
00103                 docked_windows.remove( e->xreparent.window );
00104                 if( !pending_windows.contains( e->xreparent.window ))
00105                     pending_windows.append( e->xreparent.window );
00106                 }
00107             }
00108         else
00109             {
00110 
00111             pending_windows.remove( e->xreparent.window );
00112             }
00113         }
00114     if( e->type == UnmapNotify && tray_windows.contains( e->xunmap.window ))
00115         {
00116         if( docked_windows.contains( e->xunmap.window ) && e->xunmap.serial >= docked_windows[ e->xunmap.window ] )
00117             {
00118 
00119             XReparentWindow( qt_xdisplay(), e->xunmap.window, qt_xrootwin(), 0, 0 );
00120             
00121             }
00122         }
00123     return false;
00124     }
00125 
00126 void KDETrayProxy::dockWindow( Window w, Window owner )
00127     {
00128 
00129     docked_windows[ w ] = XNextRequest( qt_xdisplay());
00130     static Atom prop = XInternAtom( qt_xdisplay(), "_XEMBED_INFO", False );
00131     long data[ 2 ] = { 0, 1 };
00132     XChangeProperty( qt_xdisplay(), w, prop, prop, 32, PropModeReplace, (unsigned char*)data, 2 );
00133     XSizeHints hints;
00134     hints.flags = PMinSize | PMaxSize;
00135     hints.min_width = 24;
00136     hints.max_width = 24;
00137     hints.min_height = 24;
00138     hints.max_height = 24;
00139     XSetWMNormalHints( qt_xdisplay(), w, &hints );
00140 
00141     XEvent ev;
00142     memset(&ev, 0, sizeof( ev ));
00143     static Atom atom = XInternAtom( qt_xdisplay(), "_NET_SYSTEM_TRAY_OPCODE", False );
00144     ev.xclient.type = ClientMessage;
00145     ev.xclient.window = owner;
00146     ev.xclient.message_type = atom;
00147     ev.xclient.format = 32;
00148     ev.xclient.data.l[ 0 ] = qt_x_time;
00149     ev.xclient.data.l[ 1 ] = 0; 
00150     ev.xclient.data.l[ 2 ] = w;
00151     ev.xclient.data.l[ 3 ] = 0; 
00152     ev.xclient.data.l[ 4 ] = 0; 
00153     XSendEvent( qt_xdisplay(), owner, False, NoEventMask, &ev );
00154     }
00155 
00156 void KDETrayProxy::withdrawWindow( Window w )
00157     {
00158     XWithdrawWindow( qt_xdisplay(), w, qt_xscreen());
00159     static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False );
00160     for(;;)
00161         {
00162         Atom type;
00163         int format;
00164         unsigned long length, after;
00165         unsigned char *data;
00166         int r = XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 2,
00167             False, AnyPropertyType, &type, &format,
00168             &length, &after, &data );
00169         bool withdrawn = true;
00170         if ( r == Success && data && format == 32 )
00171             {
00172             withdrawn = ( *( long* )data == WithdrawnState );
00173             XFree( (char *)data );
00174             }
00175         if( withdrawn )
00176             return; 
00177         struct timeval tm;
00178         tm.tv_sec = 0;
00179         tm.tv_usec = 10 * 1000; 
00180         select(0, NULL, NULL, NULL, &tm);
00181         }
00182     }
00183 
00184 #include "kdetrayproxy.moc"
00185 
00186 #if 0
00187 #include <kcmdlineargs.h>
00188 int main( int argc, char* argv[] )
00189     {
00190     KCmdLineArgs::init( argc, argv, "a", "b", "c", "d" );
00191     KApplication app( false ); 
00192     app.disableSessionManagement();
00193     KDETrayProxy proxy;
00194     return app.exec();
00195     }
00196 #endif