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 Wed Sep 29 09:43:27 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003