kdeui Library API Documentation

kdetrayproxy.cpp

00001 /*
00002  *   Copyright (C) 2004 Lubos Lunak <l.lunak@kde.org>
00003  *
00004  *   This program is free software; you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation; either version 2 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with this program; if not, write to the Free Software
00016  *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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 // XXX: FreeBSD 4.x has a buggy time.h and doesn't like the _POSIX_C_SOURCE hacks above.
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 // nanosleep is the protoype crunched by the _POSIX_C_SOURCE hack above
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 ); // XSelectInput( StructureNotifyMask ) on windows is done by KWinModule
00058 //    kdDebug() << "Init done" << endl;
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 ) // not a KDE tray window
00073         return;
00074 //    kdDebug() << "New tray window:" << w << endl;
00075     if( !tray_windows.contains( w ))
00076         tray_windows.append( w );
00077     withdrawWindow( w );
00078     // window will be removed from pending_windows when after docked
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 ) // no tray owner, sorry
00084         {
00085 //        kdDebug() << "No owner, left in pending" << endl;
00086         return;
00087         }
00088     dockWindow( w, owner );
00089     }
00090     
00091 void KDETrayProxy::newOwner( Window owner )
00092     {
00093 //    kdDebug() << "New owner:" << owner << endl;
00094     for( QValueList< Window >::ConstIterator it = pending_windows.begin();
00095          it != pending_windows.end();
00096          ++it )
00097         dockWindow( *it, owner );
00098     // remove from pending_windows only in windowRemoved(), after it's really docked
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 //                kdDebug() << "Window released:" << e->xreparent.window << endl;
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 //            kdDebug() << "Window away:" << e->xreparent.window << ":" << e->xreparent.parent << endl;
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 //            kdDebug() << "Window unmapped:" << e->xunmap.window << endl;
00134             XReparentWindow( qt_xdisplay(), e->xunmap.window, qt_xrootwin(), 0, 0 );
00135             // ReparentNotify will take care of the rest
00136             }
00137         }
00138     return false;
00139     }
00140 
00141 void KDETrayProxy::dockWindow( Window w, Window owner )
00142     {
00143 //    kdDebug() << "Docking " << w << " into " << owner << endl;
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 //    kxerrorhandler ?
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; // SYSTEM_TRAY_REQUEST_DOCK
00165     ev.xclient.data.l[ 2 ] = w;
00166     ev.xclient.data.l[ 3 ] = 0; // unused
00167     ev.xclient.data.l[ 4 ] = 0; // unused
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; // 10ms
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 ); // no styles
00207     app.disableSessionManagement();
00208     KDETrayProxy proxy;
00209     return app.exec();
00210     }
00211 #endif
KDE Logo
This file is part of the documentation for kdeui Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 23 17:11:53 2004 by doxygen 1.3.8-20040913 written by Dimitri van Heesch, © 1997-2003