diff --git a/atoms.cpp b/atoms.cpp index 8f59950427..16c2d19986 100644 --- a/atoms.cpp +++ b/atoms.cpp @@ -59,6 +59,9 @@ Atoms::Atoms() atoms[n] = &kde_net_wm_user_creation_time; names[n++] = (char *) "_KDE_NET_WM_USER_CREATION_TIME"; + atoms[n] = &kde_system_tray_embedding; + names[n++] = (char*) "_KDE_SYSTEM_TRAY_EMBEDDING"; + Atom fake; atoms[n] = &fake; names[n++] = (char *) "_DT_SM_WINDOW_INFO"; diff --git a/atoms.h b/atoms.h index d498a210da..ab06a51532 100644 --- a/atoms.h +++ b/atoms.h @@ -35,6 +35,7 @@ class Atoms Atom kde_wm_change_state; Atom net_wm_user_time; Atom kde_net_wm_user_creation_time; + Atom kde_system_tray_embedding; }; diff --git a/events.cpp b/events.cpp index 93b29bea1f..9f2beb7ebe 100644 --- a/events.cpp +++ b/events.cpp @@ -259,7 +259,7 @@ bool Workspace::workspaceEvent( XEvent * e ) case UnmapNotify: { // check for system tray windows - if ( removeSystemTrayWin( e->xunmap.window ) ) + if ( removeSystemTrayWin( e->xunmap.window, true ) ) { // If the system tray gets destroyed, the system tray // icons automatically get unmapped, reparented and mapped @@ -296,7 +296,7 @@ bool Workspace::workspaceEvent( XEvent * e ) } case DestroyNotify: { - if ( removeSystemTrayWin( e->xdestroywindow.window ) ) + if ( removeSystemTrayWin( e->xdestroywindow.window, false ) ) return TRUE; return false; } diff --git a/workspace.cpp b/workspace.cpp index bd28af786a..009ace3141 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -1188,10 +1188,34 @@ bool Workspace::addSystemTrayWin( WId w ) Check whether \a w is a system tray window. If so, remove it from the respective datastructures and propagate this to the world. */ -bool Workspace::removeSystemTrayWin( WId w ) +bool Workspace::removeSystemTrayWin( WId w, bool check ) { if ( !systemTrayWins.contains( w ) ) return FALSE; + if( check ) + { + // When getting UnmapNotify, it's not clear if it's the systray + // reparenting the window into itself, or if it's the window + // going away. This is obviously a flaw in the design, and we were + // just lucky it worked for so long. Kicker's systray temporarily + // sets _KDE_SYSTEM_TRAY_EMBEDDING property on the window while + // embedding it, allowing KWin to figure out. Kicker just mustn't + // crash before removing it again ... *shrug* . + int num_props; + Atom* props = XListProperties( qt_xdisplay(), w, &num_props ); + if( props != NULL ) + { + for( int i = 0; + i < num_props; + ++i ) + if( props[ i ] == atoms->kde_system_tray_embedding ) + { + XFree( props ); + return false; + } + XFree( props ); + } + } systemTrayWins.remove( w ); propagateSystemTrayWins(); return TRUE; diff --git a/workspace.h b/workspace.h index 5df2a1a879..13d395c230 100644 --- a/workspace.h +++ b/workspace.h @@ -352,7 +352,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine void cascadePlacement(Client* c, bool re_init = false); bool addSystemTrayWin( WId w ); - bool removeSystemTrayWin( WId w ); + bool removeSystemTrayWin( WId w, bool check ); void propagateSystemTrayWins(); SystemTrayWindow findSystemTrayWin( WId w );