summaryrefslogtreecommitdiffstats
path: root/kdeui/kdetrayproxy/kdetrayproxy.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdeui/kdetrayproxy/kdetrayproxy.cpp')
-rw-r--r--kdeui/kdetrayproxy/kdetrayproxy.cpp196
1 files changed, 196 insertions, 0 deletions
diff --git a/kdeui/kdetrayproxy/kdetrayproxy.cpp b/kdeui/kdetrayproxy/kdetrayproxy.cpp
new file mode 100644
index 000000000..b41b337b3
--- /dev/null
+++ b/kdeui/kdetrayproxy/kdetrayproxy.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2004 Lubos Lunak <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kdetrayproxy.h"
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <netwm.h>
+#include <X11/Xlib.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+
+KDETrayProxy::KDETrayProxy()
+ : selection( makeSelectionAtom())
+ {
+ connect( &selection, SIGNAL( newOwner( Window )), SLOT( newOwner( Window )));
+ connect( &module, SIGNAL( windowAdded( WId )), SLOT( windowAdded( WId )));
+ selection.owner();
+ for( QValueList< WId >::ConstIterator it = module.windows().begin();
+ it != module.windows().end();
+ ++it )
+ windowAdded( *it );
+ kapp->installX11EventFilter( this ); // XSelectInput( StructureNotifyMask ) on windows is done by KWinModule
+// kdDebug() << "Init done" << endl;
+ }
+
+Atom KDETrayProxy::makeSelectionAtom()
+ {
+ return XInternAtom( qt_xdisplay(), "_NET_SYSTEM_TRAY_S" + QCString().setNum( qt_xscreen()), False );
+ }
+
+extern Time qt_x_time;
+
+void KDETrayProxy::windowAdded( WId w )
+ {
+ NETWinInfo ni( qt_xdisplay(), w, qt_xrootwin(), NET::WMKDESystemTrayWinFor );
+ WId trayWinFor = ni.kdeSystemTrayWinFor();
+ if ( !trayWinFor ) // not a KDE tray window
+ return;
+// kdDebug() << "New tray window:" << w << endl;
+ if( !tray_windows.contains( w ))
+ tray_windows.append( w );
+ withdrawWindow( w );
+ // window will be removed from pending_windows when after docked
+ if( !pending_windows.contains( w ))
+ pending_windows.append( w );
+ docked_windows.remove( w );
+ Window owner = selection.owner();
+ if( owner == None ) // no tray owner, sorry
+ {
+// kdDebug() << "No owner, left in pending" << endl;
+ return;
+ }
+ dockWindow( w, owner );
+ }
+
+void KDETrayProxy::newOwner( Window owner )
+ {
+// kdDebug() << "New owner:" << owner << endl;
+ for( QValueList< Window >::ConstIterator it = pending_windows.begin();
+ it != pending_windows.end();
+ ++it )
+ dockWindow( *it, owner );
+ // remove from pending_windows only in windowRemoved(), after it's really docked
+ }
+
+bool KDETrayProxy::x11Event( XEvent* e )
+ {
+ if( tray_windows.isEmpty())
+ return false;
+ if( e->type == DestroyNotify && tray_windows.contains( e->xdestroywindow.window ))
+ {
+ tray_windows.remove( e->xdestroywindow.window );
+ pending_windows.remove( e->xdestroywindow.window );
+ docked_windows.remove( e->xdestroywindow.window );
+ }
+ if( e->type == ReparentNotify && tray_windows.contains( e->xreparent.window ))
+ {
+ if( e->xreparent.parent == qt_xrootwin())
+ {
+ if( !docked_windows.contains( e->xreparent.window ) || e->xreparent.serial >= docked_windows[ e->xreparent.window ] )
+ {
+// kdDebug() << "Window released:" << e->xreparent.window << endl;
+ docked_windows.remove( e->xreparent.window );
+ if( !pending_windows.contains( e->xreparent.window ))
+ pending_windows.append( e->xreparent.window );
+ }
+ }
+ else
+ {
+// kdDebug() << "Window away:" << e->xreparent.window << ":" << e->xreparent.parent << endl;
+ pending_windows.remove( e->xreparent.window );
+ }
+ }
+ if( e->type == UnmapNotify && tray_windows.contains( e->xunmap.window ))
+ {
+ if( docked_windows.contains( e->xunmap.window ) && e->xunmap.serial >= docked_windows[ e->xunmap.window ] )
+ {
+// kdDebug() << "Window unmapped:" << e->xunmap.window << endl;
+ XReparentWindow( qt_xdisplay(), e->xunmap.window, qt_xrootwin(), 0, 0 );
+ // ReparentNotify will take care of the rest
+ }
+ }
+ return false;
+ }
+
+void KDETrayProxy::dockWindow( Window w, Window owner )
+ {
+// kdDebug() << "Docking " << w << " into " << owner << endl;
+ docked_windows[ w ] = XNextRequest( qt_xdisplay());
+ static Atom prop = XInternAtom( qt_xdisplay(), "_XEMBED_INFO", False );
+ long data[ 2 ] = { 0, 1 };
+ XChangeProperty( qt_xdisplay(), w, prop, prop, 32, PropModeReplace, (unsigned char*)data, 2 );
+ XSizeHints hints;
+ hints.flags = PMinSize | PMaxSize;
+ hints.min_width = 24;
+ hints.max_width = 24;
+ hints.min_height = 24;
+ hints.max_height = 24;
+ XSetWMNormalHints( qt_xdisplay(), w, &hints );
+// kxerrorhandler ?
+ XEvent ev;
+ memset(&ev, 0, sizeof( ev ));
+ static Atom atom = XInternAtom( qt_xdisplay(), "_NET_SYSTEM_TRAY_OPCODE", False );
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = owner;
+ ev.xclient.message_type = atom;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[ 0 ] = qt_x_time;
+ ev.xclient.data.l[ 1 ] = 0; // SYSTEM_TRAY_REQUEST_DOCK
+ ev.xclient.data.l[ 2 ] = w;
+ ev.xclient.data.l[ 3 ] = 0; // unused
+ ev.xclient.data.l[ 4 ] = 0; // unused
+ XSendEvent( qt_xdisplay(), owner, False, NoEventMask, &ev );
+ }
+
+void KDETrayProxy::withdrawWindow( Window w )
+ {
+ XWithdrawWindow( qt_xdisplay(), w, qt_xscreen());
+ static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False );
+ for(;;)
+ {
+ Atom type;
+ int format;
+ unsigned long length, after;
+ unsigned char *data;
+ int r = XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 2,
+ False, AnyPropertyType, &type, &format,
+ &length, &after, &data );
+ bool withdrawn = true;
+ if ( r == Success && data && format == 32 )
+ {
+ withdrawn = ( *( long* )data == WithdrawnState );
+ XFree( (char *)data );
+ }
+ if( withdrawn )
+ return; // --->
+ struct timeval tm;
+ tm.tv_sec = 0;
+ tm.tv_usec = 10 * 1000; // 10ms
+ select(0, NULL, NULL, NULL, &tm);
+ }
+ }
+
+#include "kdetrayproxy.moc"
+
+#if 0
+#include <kcmdlineargs.h>
+int main( int argc, char* argv[] )
+ {
+ KCmdLineArgs::init( argc, argv, "a", "b", "c", "d" );
+ KApplication app( false ); // no styles
+ app.disableSessionManagement();
+ KDETrayProxy proxy;
+ return app.exec();
+ }
+#endif