From kde-core-devel Fri Apr 15 16:46:32 2005 From: Lubos Lunak Date: Fri, 15 Apr 2005 16:46:32 +0000 To: kde-core-devel Subject: Thoughts on the systray II. Message-Id: <200504151846.32493.l.lunak () suse ! cz> X-MARC-Message: https://marc.info/?l=kde-core-devel&m=111358766213242 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_o/+XCZm40TGtZ7D" --Boundary-00=_o/+XCZm40TGtZ7D Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello, this is more or less a followup to http://lists.kde.org/?l=kde-core-devel&m=110841124008784&w=2 , which died out (because of a certain person being a bit busy, I guess :-/ ). I'd like to revive and continue with it, and present also some "show me the code". To quickly summarize (see the link above for full details), the things I suggested were: 1) not using systray for apps minimizing, using another taskbar instead, which may in the end even look a lot like a systray from the user's point of view. As you'll see below this in practice mainly means replacing KSystemTray and the underlying protocol. People in general seemed(?) to like this part, so see below about the code. 2) converting applet-like systray apps to real applets. Aaron had some issues with this because of having bad nightmares about XEmbed, so this needs more discussion, the remaining complains can be basically solved by saying "so that needs fixing/improving" if my memory serves me well. 3) improving KNotify so that apps that now use systray just to notify about things will stop using systray, will stop rolling their own notification implementations, and will simply use KNotify. This seemed to be generally like as well. 4) not using the systray for daemons, quick access and such stuff, instead simply not having any GUI for those, or using applets/whatever. I'm not actually sure what was the opinion on this. Ok, now the more interesting part, i.e. the one with patches. See attachments with patches for kdelibs/kdecore, kdebase/kicker/applets/systemtray and kdebase/kwin . They kind of implement 1), it still needs quite some work and they're a bit hackish in some places, but it's good enough for seeing the idea in practice. Note that you need current CVS of kdecore for them to work properly. With the patches now KWin has a new titlebar button which controls whether a window should be trayed or not. In order to save me some work the patch actually now uses the button for keeping a window below others, you need to enable it in the decoration config if you don't see it. Systemtray is patched to also provide an icon for such windows. Window have two new flags, NET::Trayed and NET::TrayedHidden, first one meaning the window should show in the systray, the second meaning it's in the systray and hidden. I.e. nothing is set, it's a normal window, only Trayed is set, the window is visible, it has an icon in the systray and it has also a taskbar entry, both flags are set, it's hidden in the systray and has no taskbar entry. Works for any application, blah blah (see the URL above for all the benefits). It still needs doing something with the KSystemTray class. First of all there's something like this class needed to show the RMB menu, probably some KNewTray class that will provide the tray the menu and all the other things it might need from the app. And secondly, KSystemTray and the attached patches clash in quite ugly ways, so having this in 3.5 would be ... interesting from the user's point of view. Basically, the apps again roll too many things on their own, so they e.g. block quiting when one closes the main window, which means that if KSystemTray functionality is mapped to this new functionality, the app may end up running in the background, if KSystemTray is left as it is, such apps may have two systray icons. Not that the remapping of the KSystemTray functionality would be that trivial without dumping it completely and starting anew. Anyway, if people will like this, the plan would be something like - finishing the patches, so that there really is a separate titlebar button, that there would be the RMB menu, and who knows what - deciding on the exact GUI behaviour (which can be enforced to be consistent between the apps), e.g. I think the titlebar button should perhaps just put the icon into the tray for LMB and additionally also "minimize" the window for RMB. Currently one has to toggle the KeepBelow button and then minimize. This also includes deciding whether the icons should be in a separate systray applet, or should be perhaps in a separate part of the taskbar, or so. - proving a KSystemTray-like class that'd provide the RMB menu, and perhaps icon, tooltip or whatever. - (the "I'm bored case") making it work somewhat reasonably even for 3.5 without having two systray icons and so on Ok. Comments, flames, threats, cookies, and similar stuff related to this? Now going to reply to Aaron's mail[*]. (The "XEMBED" case, AKA "beat Aaron until he likes my idea" ;) ). [*] http://lists.kde.org/?l=kde-core-devel&m=110841412418641&w=2 -- Lubos Lunak KDE developer --------------------------------------------------------------------- SuSE CR, s.r.o. e-mail: l.lunak@suse.cz , l.lunak@kde.org Drahobejlova 27 tel: +420 2 9654 2373 190 00 Praha 9 fax: +420 2 9654 2374 Czech Republic http://www.suse.cz/ --Boundary-00=_o/+XCZm40TGtZ7D Content-Type: text/x-diff; charset="utf-8"; name="kdecore.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kdecore.patch" --- kdecore/netwm.cpp.sav 2005-04-14 11:36:21.000000000 +0200 +++ kdecore/netwm.cpp 2005-04-14 22:16:52.316133760 +0200 @@ -82,12 +82,15 @@ static Atom net_wm_allowed_actions = 0 static Atom wm_window_role = 0; // KDE extensions -static Atom kde_net_system_tray_windows = 0; -static Atom kde_net_wm_system_tray_window_for = 0; static Atom kde_net_wm_frame_strut = 0; static Atom kde_net_wm_window_type_override = 0; static Atom kde_net_wm_window_type_topmenu = 0; static Atom kde_net_wm_temporary_rules = 0; +static Atom kde_net_wm_trayed_windows = 0; +static Atom kde_net_wm_state_trayed = 0; +static Atom kde_net_wm_state_trayed_hidden = 0; +static Atom kde_net_system_tray_windows = 0; +static Atom kde_net_wm_system_tray_window_for = 0; // application protocols static Atom wm_protocols = 0; @@ -227,7 +230,7 @@ static int wcmp(const void *a, const voi } -static const int netAtomCount = 75; +static const int netAtomCount = 78; static void create_atoms(Display *d) { static const char * const names[netAtomCount] = { @@ -304,12 +307,15 @@ static void create_atoms(Display *d) { "_NET_WM_STATE_STAYS_ON_TOP", - "_KDE_NET_SYSTEM_TRAY_WINDOWS", - "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", "_KDE_NET_WM_FRAME_STRUT", "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", "_KDE_NET_WM_WINDOW_TYPE_TOPMENU", "_KDE_NET_WM_TEMPORARY_RULES", + "_KDE_NET_WM_TRAYED_WINDOWS", + "_KDE_NET_WM_TRAYED", + "_KDE_NET_WM_TRAYED_HIDDEN", + "_KDE_NET_SYSTEM_TRAY_WINDOWS", + "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", "WM_STATE", "WM_PROTOCOLS" @@ -390,12 +396,15 @@ static void create_atoms(Display *d) { &net_wm_state_stays_on_top, - &kde_net_system_tray_windows, - &kde_net_wm_system_tray_window_for, &kde_net_wm_frame_strut, &kde_net_wm_window_type_override, &kde_net_wm_window_type_topmenu, &kde_net_wm_temporary_rules, + &kde_net_wm_trayed_windows, + &kde_net_wm_state_trayed, + &kde_net_wm_state_trayed_hidden, + &kde_net_system_tray_windows, + &kde_net_wm_system_tray_window_for, &xa_wm_state, &wm_protocols @@ -586,8 +595,8 @@ NETRootInfo::NETRootInfo(Display *displa p->active = None; p->clients = p->stacking = p->virtual_roots = (Window *) 0; p->clients_count = p->stacking_count = p->virtual_roots_count = 0; - p->kde_system_tray_windows = 0; - p->kde_system_tray_windows_count = 0; + p->trayed_windows = p->kde_system_tray_windows = 0; + p->trayed_windows_count = p->kde_system_tray_windows_count = 0; setDefaultProperties(); if( properties_size > PROPERTIES_SIZE ) { fprintf( stderr, "NETRootInfo::NETRootInfo(): properties array too large\n"); @@ -634,8 +643,8 @@ NETRootInfo::NETRootInfo(Display *displa p->active = None; p->clients = p->stacking = p->virtual_roots = (Window *) 0; p->clients_count = p->stacking_count = p->virtual_roots_count = 0; - p->kde_system_tray_windows = 0; - p->kde_system_tray_windows_count = 0; + p->trayed_windows = p->kde_system_tray_windows = 0; + p->trayed_windows_count = p->kde_system_tray_windows_count = 0; setDefaultProperties(); p->properties[ PROTOCOLS ] = properties; // force support for Supported and SupportingWMCheck for window managers @@ -682,8 +691,8 @@ NETRootInfo::NETRootInfo(Display *displa p->active = None; p->clients = p->stacking = p->virtual_roots = (Window *) 0; p->clients_count = p->stacking_count = p->virtual_roots_count = 0; - p->kde_system_tray_windows = 0; - p->kde_system_tray_windows_count = 0; + p->trayed_windows = p->kde_system_tray_windows = 0; + p->trayed_windows_count = p->kde_system_tray_windows_count = 0; setDefaultProperties(); if( properties_size > 2 ) { fprintf( stderr, "NETWinInfo::NETWinInfo(): properties array too large\n"); @@ -739,8 +748,8 @@ NETRootInfo::NETRootInfo(Display *displa p->active = None; p->clients = p->stacking = p->virtual_roots = (Window *) 0; p->clients_count = p->stacking_count = p->virtual_roots_count = 0; - p->kde_system_tray_windows = 0; - p->kde_system_tray_windows_count = 0; + p->trayed_windows = p->kde_system_tray_windows = 0; + p->trayed_windows_count = p->kde_system_tray_windows_count = 0; setDefaultProperties(); p->client_properties[ PROTOCOLS ] = properties; for( int i = 0; i < PROPERTIES_SIZE; ++i ) @@ -762,6 +771,12 @@ NETRootInfo2::NETRootInfo2(Display *disp { } +NETRootInfo2::NETRootInfo2(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo( display, properties, properties_size, screen, doActivate ) +{ +} + NETRootInfo3::NETRootInfo3(Display *display, Window supportWindow, const char *wmName, unsigned long properties[], int properties_size, int screen, bool doActivate) @@ -770,6 +785,26 @@ NETRootInfo3::NETRootInfo3(Display *disp { } +NETRootInfo3::NETRootInfo3(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo2( display, properties, properties_size, screen, doActivate ) +{ +} + +NETRootInfo4::NETRootInfo4(Display *display, Window supportWindow, const char *wmName, + unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo3( display, supportWindow, wmName, properties, properties_size, + screen, doActivate ) +{ +} + +NETRootInfo4::NETRootInfo4(Display *display, const unsigned long properties[], int properties_size, + int screen, bool doActivate) + : NETRootInfo3( display, properties, properties_size, screen, doActivate ) +{ +} + // Copy an existing NETRootInfo object. NETRootInfo::NETRootInfo(const NETRootInfo &rootinfo) { @@ -868,6 +903,25 @@ void NETRootInfo::setClientListStacking( } +void NETRootInfo::setTrayedWindows(Window *windows, unsigned int count) { + if (role != WindowManager) return; + + p->trayed_windows_count = count; + delete [] p->trayed_windows; + p->trayed_windows = nwindup(windows, count); + +#ifdef NETWMDEBUG + fprintf(stderr, + "NETRootInfo::setTrayedWindows: setting list with %ld windows\n", + p->trayed_windows_count); +#endif + + XChangeProperty(p->display, p->root, kde_net_wm_trayed_windows, XA_WINDOW, 32, + PropModeReplace, + (unsigned char *) p->trayed_windows, + p->trayed_windows_count); +} + void NETRootInfo::setKDESystemTrayWindows(Window *windows, unsigned int count) { if (role != WindowManager) return; @@ -1198,6 +1252,10 @@ void NETRootInfo::setSupported() { if (p->properties[ STATES ] & StaysOnTop) atoms[pnum++] = net_wm_state_stays_on_top; + if (p->properties[ STATES ] & Trayed) + atoms[pnum++] = kde_net_wm_state_trayed; + if (p->properties[ STATES ] & TrayedHidden) + atoms[pnum++] = kde_net_wm_state_trayed_hidden; } if (p->properties[ PROTOCOLS ] & WMStrut) @@ -1257,6 +1315,9 @@ void NETRootInfo::setSupported() { } // KDE specific extensions + if (p->properties[ PROTOCOLS2 ] & WM2TrayedWindows) + atoms[pnum++] = kde_net_wm_trayed_windows; + if (p->properties[ PROTOCOLS ] & KDESystemTrayWindows) atoms[pnum++] = kde_net_system_tray_windows; @@ -1413,6 +1474,10 @@ void NETRootInfo::updateSupportedPropert else if( atom == net_wm_state_stays_on_top ) p->properties[ STATES ] |= StaysOnTop; + else if( atom == kde_net_wm_state_trayed ) + p->properties[ STATES ] |= Trayed; + else if( atom == kde_net_wm_state_trayed_hidden ) + p->properties[ STATES ] |= TrayedHidden; else if( atom == net_wm_strut ) p->properties[ PROTOCOLS ] |= WMStrut; @@ -1470,6 +1535,9 @@ void NETRootInfo::updateSupportedPropert p->properties[ ACTIONS ] |= ActionClose; // KDE specific extensions + else if( atom == kde_net_wm_trayed_windows ) + p->properties[ PROTOCOLS2 ] |= WM2TrayedWindows; + else if( atom == kde_net_system_tray_windows ) p->properties[ PROTOCOLS ] |= KDESystemTrayWindows; @@ -1751,8 +1819,6 @@ void NETRootInfo::event(XEvent *event, u unsigned long& dirty2 = props[ PROTOCOLS2 ]; bool do_update = false; - Q_UNUSED( dirty2 ); // for now - // the window manager will be interested in client messages... no other // client should get these messages if (role == WindowManager && event->type == ClientMessage && @@ -1940,6 +2006,8 @@ void NETRootInfo::event(XEvent *event, u dirty |= ClientList; else if (pe.xproperty.atom == net_client_list_stacking) dirty |= ClientListStacking; + else if (pe.xproperty.atom == kde_net_wm_trayed_windows) + dirty2 |= WM2TrayedWindows; else if (pe.xproperty.atom == kde_net_system_tray_windows) dirty |= KDESystemTrayWindows; else if (pe.xproperty.atom == net_desktop_names) @@ -2009,8 +2077,6 @@ void NETRootInfo::update( const unsigned const unsigned long& dirty = props[ PROTOCOLS ]; const unsigned long& dirty2 = props[ PROTOCOLS2 ]; - Q_UNUSED( dirty2 ); // for now - if (dirty & Supported ) { // only in Client mode for( int i = 0; i < PROPERTIES_SIZE; ++i ) @@ -2102,6 +2168,73 @@ void NETRootInfo::update( const unsigned #endif } + if (dirty2 & WM2TrayedWindows) { + bool read_ok = false; + if (XGetWindowProperty(p->display, p->root, kde_net_wm_trayed_windows, + 0l, MAX_PROP_SIZE, False, XA_WINDOW, &type_ret, + &format_ret, &nitems_ret, &unused, &data_ret) + == Success) { + if (type_ret == XA_WINDOW && format_ret == 32) { + Window *wins = (Window *) data_ret; + + qsort(wins, nitems_ret, sizeof(Window), wcmp); + + if( NETRootInfo4* this4 = dynamic_cast< NETRootInfo4* >( this )) { + if (p->trayed_windows) { + if (role == Client) { + unsigned long new_index = 0, new_count = nitems_ret; + unsigned long old_index = 0, + old_count = p->trayed_windows_count; + + while(old_index < old_count || new_index < new_count) { + if (old_index == old_count) { + this4->addTrayedWin(wins[new_index++]); + } else if (new_index == new_count) { + this4->removeTrayedWin(p->trayed_windows[old_index++]); + } else { + if (p->trayed_windows[old_index] < + wins[new_index]) { + this4->removeTrayedWin(p->trayed_windows[old_index++]); + } else if (wins[new_index] < + p->trayed_windows[old_index]) { + this4->addTrayedWin(wins[new_index++]); + } else { + new_index++; + old_index++; + } + } + } + } + + } else { + unsigned long n; + for (n = 0; n < nitems_ret; n++) { + this4->addTrayedWin(wins[n]); + } + } + } + + p->trayed_windows_count = nitems_ret; + delete [] p->trayed_windows; + p->trayed_windows = + nwindup(wins, p->trayed_windows_count); + read_ok = true; + } + + if ( data_ret ) + XFree(data_ret); + } + if( !read_ok ) { + if( NETRootInfo4* this4 = dynamic_cast< NETRootInfo4* >( this )) { + for( unsigned int i = 0; i < p->trayed_windows_count; ++i ) + this4->removeTrayedWin(p->trayed_windows[i]); + } + p->trayed_windows_count = 0; + delete [] p->trayed_windows; + p->trayed_windows = NULL; + } + } + if (dirty & KDESystemTrayWindows) { bool read_ok = false; if (XGetWindowProperty(p->display, p->root, kde_net_system_tray_windows, @@ -2505,6 +2638,16 @@ int NETRootInfo::clientListStackingCount } +const Window *NETRootInfo::trayedWindows() const { + return p->trayed_windows; +} + + +int NETRootInfo::trayedWindowsCount() const { + return p->trayed_windows_count; +} + + const Window *NETRootInfo::kdeSystemTrayWindows() const { return p->kde_system_tray_windows; } @@ -3005,6 +3148,24 @@ void NETWinInfo::setState(unsigned long XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); } + if ((mask & Trayed) && + ((p->state & Trayed) != (state & Trayed))) { + e.xclient.data.l[0] = (state & Trayed) ? 1 : 0; + e.xclient.data.l[1] = kde_net_wm_state_trayed; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + + if ((mask & TrayedHidden) && // must be after the handling of Trayed, because it relies on it + ((p->state & TrayedHidden) != (state & TrayedHidden))) { + e.xclient.data.l[0] = (state & TrayedHidden) ? 1 : 0; + e.xclient.data.l[1] = kde_net_wm_state_trayed_hidden; + e.xclient.data.l[2] = 0l; + + XSendEvent(p->display, p->root, False, netwm_sendevent_mask, &e); + } + } else { p->state &= ~mask; p->state |= state; @@ -3028,6 +3189,8 @@ void NETWinInfo::setState(unsigned long if (p->state & Sticky) data[count++] = net_wm_state_sticky; if (p->state & SkipTaskbar) data[count++] = net_wm_state_skip_taskbar; if (p->state & SkipPager) data[count++] = net_wm_state_skip_pager; + if (p->state & Trayed) data[count++] = kde_net_wm_state_trayed; + if (p->state & TrayedHidden) data[count++] = kde_net_wm_state_trayed_hidden; #ifdef NETWMDEBUG fprintf(stderr, "NETWinInfo::setState: setting state property (%d)\n", count); @@ -3445,6 +3608,10 @@ void NETWinInfo::event(XEvent *event, un mask |= DemandsAttention; else if ((Atom) event->xclient.data.l[i] == net_wm_state_stays_on_top) mask |= StaysOnTop; + else if ((Atom) event->xclient.data.l[i] == kde_net_wm_state_trayed) + mask |= Trayed; + else if ((Atom) event->xclient.data.l[i] == kde_net_wm_state_trayed_hidden) + mask |= TrayedHidden; } // when removing, we just leave newstate == 0 @@ -3693,6 +3860,10 @@ void NETWinInfo::update(const unsigned l p->state |= DemandsAttention; else if ((Atom) states[count] == net_wm_state_stays_on_top) p->state |= StaysOnTop; + else if ((Atom) states[count] == kde_net_wm_state_trayed) + p->state |= Trayed; + else if ((Atom) states[count] == kde_net_wm_state_trayed_hidden) + p->state |= TrayedHidden; } } if ( data_ret ) --- kdecore/netwm.h.sav 2005-01-11 11:46:04.000000000 +0100 +++ kdecore/netwm.h 2005-04-14 11:43:59.000000000 +0200 @@ -297,7 +297,27 @@ public: int clientListStackingCount() const; /** - Returns an array of Window id's, which contain all KDE system tray windows. + Returns an array of Window id's, which contains all windows marked to be included in tray. + + @return the array of Window id's of system tray windows + + @see trayedWindowsCount() + @since 3.5 + **/ + const Window *trayedWindows() const; + + /** + Returns the number of windows in the kdeSystemTrayWindows array. + + @return the number of Window id's in the system tray list + + @see trayedWindows() + @since 3.5 + **/ + int trayedWindowsCount() const; + + /** + Returns an array of Window id's, which contains all (old) KDE system tray windows. @return the array of Window id's of system tray windows @@ -423,6 +443,16 @@ public: void setClientListStacking(Window *windows, unsigned int count); /** + Sets the list of windows marked for tray on the root window. + + @param windows The array of window id's + + @param count The number of windows in the array. + @since 3.5 + **/ + void setTrayedWindows(Window *windows, unsigned int count); + + /** Sets the list of KDE system tray windows on the root window. @param windows The array of window id's @@ -748,6 +778,11 @@ public: unsigned long properties[], int properties_size, int screen = -1, bool doActivate = true); /** + * @since 3.5 + */ + NETRootInfo2(Display *display, const unsigned long properties[], int properties_size, + int screen = -1, bool doActivate = true); + /** Sends a ping with the given timestamp to the window, using the _NET_WM_PING protocol. */ @@ -815,6 +850,11 @@ public: unsigned long properties[], int properties_size, int screen = -1, bool doActivate = true); /** + * @since 3.5 + */ + NETRootInfo3(Display *display, const unsigned long properties[], int properties_size, + int screen = -1, bool doActivate = true); + /** Sends a take activity message with the given timestamp to the window, using the _NET_WM_TAKE_ACTIVITY protocol (see the WM spec for details). @param window the window to which the message should be sent @@ -849,6 +889,43 @@ protected: }; /** + This class is an extension of the NETRootInfo class, and exists solely + for binary compatibility reasons (adds new virtual methods). Simply + use it instead of NETRootInfo and override also the added virtual methods. + @since 3.5 +*/ +class KDECORE_EXPORT NETRootInfo4 + : public NETRootInfo3 +{ +public: + NETRootInfo4(Display *display, Window supportWindow, const char *wmName, + unsigned long properties[], int properties_size, + int screen = -1, bool doActivate = true); + NETRootInfo4(Display *display, const unsigned long properties[], int properties_size, + int screen = -1, bool doActivate = true); + +protected: + friend class NETRootInfo; + /** + A Client should subclass NETRootInfo and reimplement this function when + it wants to know when a window has been marked to be included in the tray. + + @param window the id of the window to add + **/ + virtual void addTrayedWin(Window window) { Q_UNUSED(window); } + + /** + A Client should subclass NETRootInfo and reimplement this function when + it wants to know when a window is no longer marked to be included in the tray. + + @param window the id of the window to remove + **/ + virtual void removeTrayedWin(Window window) { Q_UNUSED(window); } +// no private data, use NETRootInfoPrivate +}; + + +/** Common API for application window properties/protocols. The NETWinInfo class provides a common API for clients and window managers to --- kdecore/netwm_def.h.sav 2004-11-23 16:08:29.000000000 +0100 +++ kdecore/netwm_def.h 2005-04-14 09:55:10.000000000 +0200 @@ -376,7 +376,9 @@ public: Hidden = 1<<8, ///< @since 3.2 FullScreen = 1<<9, ///< @since 3.2 KeepBelow = 1<<10, ///< @since 3.2 - DemandsAttention = 1<<11 ///< @since 3.2 + DemandsAttention = 1<<11, ///< @since 3.2 + Trayed = 1<<12, ///< @since 3.5 + TrayedHidden = 1<<13 ///< @since 3.5 }; /** @@ -578,7 +580,8 @@ public: WM2KDETemporaryRules = 1<<9, // NOT STANDARD WM2WindowClass = 1<<10, ///< @since 3.3 WM2WindowRole = 1<<11, ///< @since 3.3 - WM2ClientMachine = 1<<12 ///< @since 3.3 + WM2ClientMachine = 1<<12, ///< @since 3.3 + WM2TrayedWindows = 1<<13 ///< @since 3.5 }; /** --- kdecore/netwm_p.h.sav 2004-08-03 17:10:06.000000000 +0200 +++ kdecore/netwm_p.h 2005-04-14 09:55:10.000000000 +0200 @@ -95,13 +95,13 @@ struct NETRootInfoPrivate { NETRArray workarea; NETSize geometry; Window active; - Window *clients, *stacking, *virtual_roots, *kde_system_tray_windows; + Window *clients, *stacking, *virtual_roots, *trayed_windows, *kde_system_tray_windows; NETRArray desktop_names; int number_of_desktops; int current_desktop; unsigned long clients_count, stacking_count, virtual_roots_count, - kde_system_tray_windows_count; + trayed_windows_count, kde_system_tray_windows_count; unsigned long properties[ 5 ]; unsigned long client_properties[ 5 ]; // properties the client is interested in --- kdecore/kwinmodule.cpp.sav 2004-11-29 11:39:33.000000000 +0100 +++ kdecore/kwinmodule.cpp 2005-04-14 11:11:50.000000000 +0200 @@ -36,21 +36,34 @@ static KWinModulePrivate* static_d = 0; -class KWinModulePrivate : public QWidget, public NETRootInfo +static unsigned long windows_properties[ 2 ] = { NET::ClientList | NET::ClientListStacking | + NET::NumberOfDesktops | + NET::DesktopGeometry | + NET::CurrentDesktop | + NET::DesktopNames | + NET::ActiveWindow | + NET::WorkArea | + NET::KDESystemTrayWindows, + NET::WM2TrayedWindows }; + +static unsigned long desktop_properties[ 2 ] = { + NET::NumberOfDesktops | + NET::DesktopGeometry | + NET::CurrentDesktop | + NET::DesktopNames | + NET::ActiveWindow | + NET::WorkArea | + NET::KDESystemTrayWindows, + 0 }; + +class KWinModulePrivate : public QWidget, public NETRootInfo4 { public: KWinModulePrivate(int _what) - : QWidget(0,0), NETRootInfo( qt_xdisplay(), - ( _what >= KWinModule::INFO_WINDOWS ? - (ClientList | ClientListStacking) : 0 - ) | - NumberOfDesktops | - DesktopGeometry | - CurrentDesktop | - DesktopNames | - ActiveWindow | - WorkArea | - KDESystemTrayWindows, + : QWidget(0,0), NETRootInfo4( qt_xdisplay(), + _what >= KWinModule::INFO_WINDOWS ? + windows_properties : desktop_properties, + 2, -1, false ), strutSignalConnected( false ), @@ -68,6 +81,7 @@ public: QValueList windows; QValueList stackingOrder; + QValueList trayedWindows; QValueList systemTrayWindows; struct StrutData @@ -86,6 +100,8 @@ public: void addClient(Window); void removeClient(Window); + void addTrayedWin(Window); + void removeTrayedWin(Window); void addSystemTrayWin(Window); void removeSystemTrayWin(Window); @@ -158,6 +174,11 @@ bool KWinModule::hasWId(WId w) const return d->windows.findIndex( w ) != -1; } +const QValueList& KWinModule::trayedWindows() const +{ + return d->trayedWindows; +} + const QValueList& KWinModule::systemTrayWindows() const { return d->systemTrayWindows; @@ -282,6 +303,20 @@ void KWinModulePrivate::removeClient(Win } } +void KWinModulePrivate::addTrayedWin(Window w) +{ + trayedWindows.append( w ); + for ( QPtrListIterator mit( modules ); mit.current(); ++mit ) + emit (*mit)->trayedWindowAdded( w ); +} + +void KWinModulePrivate::removeTrayedWin(Window w) +{ + trayedWindows.remove( w ); + for ( QPtrListIterator mit( modules ); mit.current(); ++mit ) + emit (*mit)->trayedWindowRemoved( w ); +} + void KWinModulePrivate::addSystemTrayWin(Window w) { systemTrayWindows.append( w ); --- kdecore/kwinmodule.h.sav 2005-02-22 17:55:23.000000000 +0100 +++ kdecore/kwinmodule.h 2005-04-14 10:55:34.000000000 +0200 @@ -81,6 +81,9 @@ public: * systemTrayWindows, * systemTrayWindowAdded, * systemTrayWindowRemoved, + * trayedWindows, + * trayedWindowAdded, + * trayedWindowRemoved, * windowChanged, * strutChanged, * workArea(const QValueList &excludes, int desktop) @@ -134,6 +137,13 @@ public: bool hasWId(WId id) const; /** + * Returns a list of the trayed windows. + * @return a list of all trayed windows + * @since 3.5 + **/ + const QValueList& trayedWindows() const; + + /** * Returns a list of the system tray windows. * @return a list of all system tray windows **/ @@ -245,6 +255,20 @@ signals: /** * Emitted when a dock window has been added. + * @param id the id of the new trayed window + * @since 3.5 + */ + void trayedWindowAdded(WId id); + + /** + * Emitted when a dock window has been removed. + * @param id the id of the former trayed window + * @since 3.5 + */ + void trayedWindowRemoved(WId id); + + /** + * Emitted when a dock window has been added. * @param id the id of the new system tray window */ void systemTrayWindowAdded(WId id); --Boundary-00=_o/+XCZm40TGtZ7D Content-Type: text/x-diff; charset="utf-8"; name="kwin.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kwin.patch" --- kwin/workspace.h.sav 2005-02-02 20:06:01.000000000 +0100 +++ kwin/workspace.h 2001-01-01 01:01:00.000000000 +0100 @@ -148,6 +148,7 @@ class Workspace : public QObject, public void clientHidden( Client* ); void clientAttentionChanged( Client* c, bool set ); + void updateTrayed(); void clientMoved(const QPoint &pos, Time time); @@ -622,7 +623,7 @@ class StackingUpdatesBlocker }; // NET WM Protocol handler class -class RootInfo : public NETRootInfo3 +class RootInfo : public NETRootInfo4 { private: typedef KWinInternal::Client Client; // because of NET::Client --- kwin/sm.h.sav 2005-01-17 17:12:17.000000000 +0100 +++ kwin/sm.h 2005-04-14 09:55:54.000000000 +0200 @@ -44,6 +44,8 @@ struct SessionInfo bool skipTaskbar; bool skipPager; bool userNoBorder; + bool trayed; + bool trayedHidden; NET::WindowType windowType; QString shortcut; bool active; // means 'was active in the saved session' --- kwin/bridge.h.sav 2004-12-15 12:04:44.000000000 +0100 +++ kwin/bridge.h 2005-04-14 09:55:54.000000000 +0200 @@ -60,6 +60,7 @@ class Bridge : public KDecorationBridge virtual void setShade( bool set ); virtual void setKeepAbove( bool ); virtual void setKeepBelow( bool ); + // TODOTRAY virtual int currentDesktop() const; virtual QWidget* initialParentWidget() const; virtual Qt::WFlags initialWFlags() const; --- kwin/manage.cpp.sav 2005-04-12 19:44:18.000000000 +0200 +++ kwin/manage.cpp 2005-04-14 09:55:54.000000000 +0200 @@ -357,6 +357,8 @@ bool Client::manage( Window w, bool isMa setFullScreen( true, false ); geom_fs_restore = session->fsrestore; } + setTrayed( session->trayed ); + setTrayedHidden( session->trayedHidden ); } else { @@ -402,6 +404,7 @@ bool Client::manage( Window w, bool isMa // read other initial states setShade( rules()->checkShade( info->state() & NET::Shaded ? ShadeNormal : ShadeNone, !isMapped )); setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped )); + // TODOTRAY setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped )); setSkipTaskbar( rules()->checkSkipTaskbar( info->state() & NET::SkipTaskbar, !isMapped ), true ); setSkipPager( rules()->checkSkipPager( info->state() & NET::SkipPager, !isMapped )); @@ -411,6 +414,7 @@ bool Client::manage( Window w, bool isMa setModal( true ); if( fullscreen_mode != FullScreenHack && isFullScreenable()) setFullScreen( rules()->checkFullScreen( info->state() & NET::FullScreen, !isMapped ), false ); + // TODOTRAY } updateAllowedActions( true ); --- kwin/client.h.sav 2005-04-12 19:23:46.000000000 +0200 +++ kwin/client.h 2005-04-14 10:28:45.000000000 +0200 @@ -143,6 +143,10 @@ class Client : public QObject, public KD bool skipTaskbar( bool from_outside = false ) const; void setSkipTaskbar( bool set, bool from_outside ); + bool trayed() const; + void setTrayed( bool set ); + bool trayedHidden() const; + void setTrayedHidden( bool set ); bool skipPager() const; void setSkipPager( bool ); @@ -480,6 +484,8 @@ class Client : public QObject, public KD uint not_obscured : 1; uint urgency : 1; // XWMHints, UrgencyHint uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client + uint is_trayed : 1; + uint trayed_hidden : 1; WindowRules client_rules; void getWMHints(); void readIcons(); @@ -670,7 +676,7 @@ inline bool Client::isOnDesktop( int d ) inline bool Client::isShown( bool shaded_is_shown ) const { - return !isMinimized() && ( !isShade() || shaded_is_shown ) && !hidden; + return !isMinimized() && ( !isShade() || shaded_is_shown ) && !hidden && !trayed_hidden; } inline @@ -710,6 +716,16 @@ inline bool Client::skipTaskbar( bool fr return from_outside ? original_skip_taskbar : skip_taskbar; } +inline bool Client::trayed() const + { + return is_trayed; + } + +inline bool Client::trayedHidden() const + { + return trayed_hidden; + } + inline bool Client::skipPager() const { return skip_pager; --- kwin/client.cpp.sav 2005-04-12 19:23:46.000000000 +0200 +++ kwin/client.cpp 2005-04-14 18:56:56.000000000 +0200 @@ -127,6 +127,8 @@ Client::Client( Workspace *ws ) not_obscured = false; urgency = false; ignore_focus_stealing = false; + is_trayed = false; + trayed_hidden = false; check_active_modal = false; Pdeletewindow = 0; @@ -527,6 +529,12 @@ bool Client::isMinimizable() const */ void Client::minimize( bool avoid_animation ) { + if( trayed()) + { + setTrayedHidden( true ); + return; + } + if ( !isMinimizable() || isMinimized()) return; @@ -546,6 +554,11 @@ void Client::minimize( bool avoid_animat void Client::unminimize( bool avoid_animation ) { + if( trayed()) + { + setTrayedHidden( false ); + return; + } if( !isMinimized()) return; @@ -835,6 +848,19 @@ void Client::updateVisibility() { setSkipTaskbar( original_skip_taskbar, false ); } + if( trayed_hidden ) + { + setMappingState( IconicState ); + info->setState( NET::Hidden, NET::Hidden ); + setSkipTaskbar( true, false ); // also hide from taskbar + rawHide(); + show = false; + } + else + { + if( !hidden ) + setSkipTaskbar( original_skip_taskbar, false ); + } if( minimized ) { setMappingState( IconicState ); @@ -1109,6 +1135,47 @@ void Client::setSkipTaskbar( bool b, boo updateWindowRules(); } +void Client::setTrayed( bool set ) + { +// TODOTRAY set = rules()->checkTrayed( set ); + if( set == trayed() ) + return; + is_trayed = set; + info->setState( set ? NET::Trayed : 0, NET::Trayed ); + if( isManaged()) + workspace()->updateTrayed(); + if( decoration != NULL ) + decoration->emitKeepBelowChanged( trayed()); + if( minimized ) + { + if( set ) + { + setTrayedHidden( true ); + unminimize( true ); + } + else + { + setTrayedHidden( false ); + minimize( true ); + } + } + if( !set ) + setTrayedHidden( false ); + updateWindowRules(); + } + +void Client::setTrayedHidden( bool set ) + { + if( set == trayedHidden() ) + return; + if( !trayed()) + set = false; + trayed_hidden = set; + info->setState( set ? NET::TrayedHidden : 0, NET::TrayedHidden ); + updateVisibility(); + updateWindowRules(); + } + void Client::setSkipPager( bool b ) { b = rules()->checkSkipPager( b ); --- kwin/sm.cpp.sav 2005-01-17 17:12:17.000000000 +0100 +++ kwin/sm.cpp 2005-04-14 09:55:54.000000000 +0200 @@ -112,6 +112,8 @@ void Workspace::storeSession( KConfig* c config->writeEntry( QString("skipTaskbar")+n, c->skipTaskbar( true ) ); config->writeEntry( QString("skipPager")+n, c->skipPager() ); config->writeEntry( QString("userNoBorder")+n, c->isUserNoBorder() ); + config->writeEntry( QString("trayed")+n, c->trayed() ); + config->writeEntry( QString("trayedHidden")+n, c->trayedHidden() ); config->writeEntry( QString("windowType")+n, windowTypeToTxt( c->windowType())); config->writeEntry( QString("shortcut")+n, c->shortcut().toStringInternal()); } @@ -177,6 +179,8 @@ void Workspace::loadSessionInfo() info->skipTaskbar = config->readBoolEntry( QString("skipTaskbar")+n, FALSE ); info->skipPager = config->readBoolEntry( QString("skipPager")+n, FALSE ); info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE ); + info->trayed = config->readBoolEntry( QString("trayed")+n, FALSE ); + info->trayedHidden = config->readBoolEntry( QString("trayedHidden")+n, FALSE ); info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1()); info->shortcut = config->readEntry( QString("shortcut")+n ); info->active = ( active_client == i ); --- kwin/workspace.cpp.sav 2005-04-12 19:23:46.000000000 +0200 +++ kwin/workspace.cpp 2005-04-14 11:07:22.000000000 +0200 @@ -272,6 +272,8 @@ void Workspace::init() NET::FullScreen | NET::KeepBelow | NET::DemandsAttention | + NET::Trayed | + NET::TrayedHidden | 0 , NET::WM2UserTime | @@ -281,6 +283,7 @@ void Workspace::init() NET::WM2MoveResizeWindow | NET::WM2ExtendedStrut | NET::WM2KDETemporaryRules | + NET::WM2TrayedWindows | 0 , NET::ActionMove | @@ -525,6 +528,8 @@ void Workspace::addClient( Client* c, al c->checkActiveModal(); checkTransients( c->window()); // SELI does this really belong here? updateStackingOrder( true ); // propagate new client + if( c->trayed()) + updateTrayed(); if( c->isUtility() || c->isMenu() || c->isToolbar()) updateToolWindows( true ); } @@ -556,6 +561,8 @@ void Workspace::removeClient( Client* c, attention_chain.remove( c ); if( c->isTopMenu()) removeTopMenu( c ); + if( c->trayed()) + updateTrayed(); Group* group = findGroup( c->window()); if( group != NULL ) group->lostLeader(); @@ -771,6 +778,21 @@ void Workspace::slotUpdateToolWindows() updateToolWindows( true ); } +void Workspace::updateTrayed() + { + Window* prop = new Window[ clients.count() ]; + int cnt = 0; + for( ClientList::ConstIterator it = clients.begin(); + it != clients.end(); + ++it ) + { + if( (*it)->trayed()) + prop[ cnt++ ] = (*it)->window(); + } + kdDebug() << "TRAYED:" << cnt << endl; + rootInfo->setTrayedWindows( prop, cnt ); + } + /*! Updates the current colormap according to the currently active client */ --- kwin/events.cpp.sav 2005-01-17 17:12:17.000000000 +0100 +++ kwin/events.cpp 2005-04-14 10:06:05.000000000 +0200 @@ -82,6 +82,10 @@ void WinInfo::changeState( unsigned long // unsetting fullscreen first, setting it last (because e.g. maximize works only for !isFullScreen() ) if(( mask & NET::FullScreen ) != 0 && ( state & NET::FullScreen ) != 0 ) m_client->setFullScreen( true, false ); + if( mask & NET::Trayed ) + m_client->setTrayed(( state & NET::Trayed ) != 0 ); + if( mask & NET::TrayedHidden ) + m_client->setTrayedHidden(( state & NET::TrayedHidden ) != 0 ); } @@ -90,7 +94,7 @@ void WinInfo::changeState( unsigned long // **************************************** RootInfo::RootInfo( Workspace* ws, Display *dpy, Window w, const char *name, unsigned long pr[], int pr_num, int scr ) - : NETRootInfo3( dpy, w, name, pr, pr_num, scr ) + : NETRootInfo4( dpy, w, name, pr, pr_num, scr ) { workspace = ws; } --- kwin/bridge.cpp.sav 2004-12-15 12:04:44.000000000 +0100 +++ kwin/bridge.cpp 2005-04-14 18:48:15.000000000 +0200 @@ -38,7 +38,12 @@ BRIDGE_HELPER( bool, isModal,,, const ) BRIDGE_HELPER( bool, isShadeable,,, const ) BRIDGE_HELPER( bool, isShade,,, const ) BRIDGE_HELPER( bool, keepAbove,,, const ) -BRIDGE_HELPER( bool, keepBelow,,, const ) +//BRIDGE_HELPER( bool, keepBelow,,, const ) +bool Bridge::keepBelow() const + { + return c->trayed(); + } + BRIDGE_HELPER( bool, isMovable,,, const ) BRIDGE_HELPER( bool, isResizable,,, const ) BRIDGE_HELPER( QString, caption,,, const ) @@ -50,7 +55,11 @@ BRIDGE_HELPER( void, minimize,,, ) BRIDGE_HELPER( void, showContextHelp,,, ) BRIDGE_HELPER( void, setDesktop, int desktop, desktop, ) BRIDGE_HELPER( void, setKeepAbove, bool set, set, ) -BRIDGE_HELPER( void, setKeepBelow, bool set, set, ) +//BRIDGE_HELPER( void, setKeepBelow, bool set, set, ) +void Bridge::setKeepBelow( bool set ) + { + c->setTrayed( set ); + } NET::WindowType Bridge::windowType( unsigned long supported_types ) const { --Boundary-00=_o/+XCZm40TGtZ7D Content-Type: text/x-diff; charset="utf-8"; name="systemtray.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="systemtray.patch" --- systemtray/systemtrayapplet.cpp.sav 2005-03-15 14:00:39.000000000 +0100 +++ systemtray/systemtrayapplet.cpp 2005-04-14 18:36:38.000000000 +0200 @@ -95,6 +95,13 @@ void SystemTrayApplet::initialize() embedWindow(*it, true); existing = true; } + const QValueList trayedWindows = kwin_module->trayedWindows(); + for (QValueList::ConstIterator it = trayedWindows.begin(); + it != trayedWindows.end(); ++it ) + { + trayWindow(*it); + existing = true; + } showExpandButton(!m_hiddenWins.isEmpty()); @@ -109,6 +116,10 @@ void SystemTrayApplet::initialize() this, SLOT( systemTrayWindowAdded(WId) ) ); connect( kwin_module, SIGNAL( systemTrayWindowRemoved(WId) ), this, SLOT( updateTrayWindows() ) ); + connect( kwin_module, SIGNAL( trayedWindowAdded(WId) ), + this, SLOT( trayedWindowAdded(WId) ) ); + connect( kwin_module, SIGNAL( trayedWindowRemoved(WId) ), + this, SLOT( trayedWindowRemoved(WId) ) ); QCString screenstr; screenstr.setNum(qt_xscreen()); @@ -163,7 +174,7 @@ bool SystemTrayApplet::x11Event( XEvent e->xclient.data.l[1] == SYSTEM_TRAY_REQUEST_DOCK) { if( isWinManaged( (WId)e->xclient.data.l[2] ) ) // we already manage it return true; - embedWindow( e->xclient.data.l[2], false ); + embedWindow( e->xclient.data.l[2], false); layoutTray(); emit updateLayout(); return true; @@ -225,14 +236,14 @@ void SystemTrayApplet::preferences() QListBox *shownListBox = m_iconSelector->availableListBox(); QListBox *hiddenListBox = m_iconSelector->selectedListBox(); - TrayEmbedList::const_iterator it = m_shownWins.begin(); - TrayEmbedList::const_iterator itEnd = m_shownWins.end(); + TrayWidgetList::const_iterator it = m_shownWins.begin(); + TrayWidgetList::const_iterator itEnd = m_shownWins.end(); for (; it != itEnd; ++it) { - QString name = KWin::windowInfo((*it)->embeddedWinId()).name(); + QString name = KWin::windowInfo((*it)->windowId()).name(); if(!shownListBox->findItem(name, Qt::ExactMatch | Qt::CaseSensitive)) { - shownListBox->insertItem(KWin::icon((*it)->embeddedWinId(), 22, 22, true), name); + shownListBox->insertItem(KWin::icon((*it)->windowId(), 22, 22, true), name); } } @@ -240,10 +251,10 @@ void SystemTrayApplet::preferences() itEnd = m_hiddenWins.end(); for (; it != itEnd; ++it) { - QString name = KWin::windowInfo((*it)->embeddedWinId()).name(); + QString name = KWin::windowInfo((*it)->windowId()).name(); if(!hiddenListBox->findItem(name, Qt::ExactMatch | Qt::CaseSensitive)) { - hiddenListBox->insertItem(KWin::icon((*it)->embeddedWinId(), 22, 22, true), name); + hiddenListBox->insertItem(KWin::icon((*it)->windowId(), 22, 22, true), name); } } @@ -289,9 +300,9 @@ void SystemTrayApplet::applySettings() conf->writeEntry("Hidden", m_hiddenIconList); conf->sync(); - for (TrayEmbed* emb = m_shownWins.first(); emb != 0; ) + for (TrayWidget* emb = m_shownWins.first(); emb != 0; ) { - if (shouldHide(emb->embeddedWinId())) + if (shouldHide(emb->windowId())) { emb = m_shownWins.take(); // Next item becomes current m_hiddenWins.append(emb); @@ -303,9 +314,9 @@ void SystemTrayApplet::applySettings() } } - for (TrayEmbed* emb = m_hiddenWins.first(); emb != 0; ) + for (TrayWidget* emb = m_hiddenWins.first(); emb != 0; ) { - if (!shouldHide(emb->embeddedWinId())) + if (!shouldHide(emb->windowId())) { emb = m_hiddenWins.take(); // Next item becomes current m_shownWins.append(emb); @@ -409,7 +420,7 @@ void SystemTrayApplet::loadSettings() m_hiddenIconList = conf->readListEntry("Hidden"); } -void SystemTrayApplet::systemTrayWindowAdded( WId w ) +void SystemTrayApplet::windowAdded( WId w, bool kde_tray, bool xdg ) { if (isWinManaged(w)) { @@ -417,7 +428,10 @@ void SystemTrayApplet::systemTrayWindowA return; } - embedWindow(w, true); + if( kde_tray || xdg ) + embedWindow(w, kde_tray); + else + trayWindow( w ); updateVisibleWins(); layoutTray(); emit updateLayout(); @@ -429,7 +443,17 @@ void SystemTrayApplet::systemTrayWindowA } } -void SystemTrayApplet::embedWindow( WId w, bool kde_tray ) +void SystemTrayApplet::systemTrayWindowAdded( WId w ) +{ + windowAdded( w, true, false ); +} + +void SystemTrayApplet::trayedWindowAdded( WId w ) +{ + windowAdded( w, false, false ); +} + +void SystemTrayApplet::embedWindow( WId w, bool kde_tray) { TrayEmbed* emb = new TrayEmbed(kde_tray, this); emb->setAutoDelete(false); @@ -448,7 +472,7 @@ void SystemTrayApplet::embedWindow( WId emb->embed(w); } - if (emb->embeddedWinId() == 0) // error embedding + if (emb->windowId() == 0) // error embedding { delete emb; return; @@ -470,21 +494,81 @@ void SystemTrayApplet::embedWindow( WId } } +void SystemTrayApplet::trayWindow( WId w ) +{ + TrayIcon* emb = new TrayIcon(w, this); + emb->setBackgroundOrigin(AncestorOrigin); + emb->setBackgroundMode(X11ParentRelative); + + QPixmap p = KWin::icon( w, 24, 24, true ); + if (p.isNull()) + { + delete emb; + return; + } + + emb->resize(24, 24); + emb->setPixmap( p ); + if (shouldHide(w)) + { + emb->hide(); + m_hiddenWins.append(emb); + showExpandButton(true); + } + else + { + emb->hide(); + emb->show(); + m_shownWins.append(emb); + } +} + +void SystemTrayApplet::trayedWindowRemoved( WId w ) +{ + TrayWidget* emb = m_shownWins.first(); + while ((emb = m_shownWins.current()) != 0) + { + WId wid = emb->windowId(); + if( wid == w ) + m_shownWins.remove(emb); + else + { + m_shownWins.next(); + } + } + + emb = m_hiddenWins.first(); + while ((emb = m_hiddenWins.current()) != 0L) + { + WId wid = emb->windowId(); + if( wid == w ) + m_hiddenWins.remove(emb); + else + m_hiddenWins.next(); + } + + showExpandButton(!m_hiddenWins.isEmpty()); + + updateVisibleWins(); + layoutTray(); + emit updateLayout(); +} + bool SystemTrayApplet::isWinManaged(WId w) { - TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); - for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_shownWins.end(); + for (TrayWidgetList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) { - if ((*emb)->embeddedWinId() == w) // we already manage it + if ((*emb)->windowId() == w) // we already manage it { return true; } } lastEmb = m_hiddenWins.end(); - for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + for (TrayWidgetList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) { - if ((*emb)->embeddedWinId() == w) // we already manage it + if ((*emb)->windowId() == w) // we already manage it { return true; } @@ -500,8 +584,8 @@ bool SystemTrayApplet::shouldHide(WId w) void SystemTrayApplet::updateVisibleWins() { - TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end(); - TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); + TrayWidgetList::const_iterator lastEmb = m_hiddenWins.end(); + TrayWidgetList::const_iterator emb = m_hiddenWins.begin(); if (m_showHidden) { @@ -574,10 +658,10 @@ void SystemTrayApplet::retract() void SystemTrayApplet::updateTrayWindows() { - TrayEmbed* emb = m_shownWins.first(); + TrayWidget* emb = m_shownWins.first(); while ((emb = m_shownWins.current()) != 0) { - WId wid = emb->embeddedWinId(); + WId wid = emb->windowId(); if ((wid == 0) || (emb->kdeTray() && !kwin_module->systemTrayWindows().contains(wid))) { @@ -593,7 +677,7 @@ void SystemTrayApplet::updateTrayWindows emb = m_hiddenWins.first(); while ((emb = m_hiddenWins.current()) != 0L) { - WId wid = emb->embeddedWinId(); + WId wid = emb->windowId(); if ((wid == 0) || (emb->kdeTray() && !kwin_module->systemTrayWindows().contains(wid))) m_hiddenWins.remove(emb); @@ -612,8 +696,8 @@ int SystemTrayApplet::maxIconWidth() con { int largest = 24; - TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); - for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_shownWins.end(); + for (TrayWidgetList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) { if (*emb == 0) { @@ -630,7 +714,7 @@ int SystemTrayApplet::maxIconWidth() con if (m_showHidden) { lastEmb = m_hiddenWins.end(); - for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + for (TrayWidgetList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) { if (*emb == 0) { @@ -652,8 +736,8 @@ int SystemTrayApplet::maxIconHeight() co { int largest = 24; - TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); - for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != m_shownWins.end(); ++emb) + TrayWidgetList::const_iterator lastEmb = m_shownWins.end(); + for (TrayWidgetList::const_iterator emb = m_shownWins.begin(); emb != m_shownWins.end(); ++emb) { if (*emb == 0) { @@ -670,7 +754,7 @@ int SystemTrayApplet::maxIconHeight() co if (m_showHidden) { lastEmb = m_hiddenWins.end(); - for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != m_hiddenWins.end(); ++emb) + for (TrayWidgetList::const_iterator emb = m_hiddenWins.begin(); emb != m_hiddenWins.end(); ++emb) { if (*emb == 0) { @@ -817,8 +901,8 @@ void SystemTrayApplet::layoutTray() if (m_showHidden) { - TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end(); - for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_hiddenWins.end(); + for (TrayWidgetList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) { line = i % nbrOfLines; (*emb)->hide(); @@ -832,8 +916,8 @@ void SystemTrayApplet::layoutTray() } } - TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); - for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_shownWins.end(); + for (TrayWidgetList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) { line = i % nbrOfLines; (*emb)->hide(); @@ -855,8 +939,8 @@ void SystemTrayApplet::layoutTray() if (m_showHidden) { - TrayEmbedList::const_iterator lastEmb = m_hiddenWins.end(); - for (TrayEmbedList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_hiddenWins.end(); + for (TrayWidgetList::const_iterator emb = m_hiddenWins.begin(); emb != lastEmb; ++emb) { line = i % nbrOfLines; (*emb)->hide(); @@ -870,8 +954,8 @@ void SystemTrayApplet::layoutTray() } } - TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); - for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_shownWins.end(); + for (TrayWidgetList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) { line = i % nbrOfLines; (*emb)->hide(); @@ -898,8 +982,8 @@ void SystemTrayApplet::layoutTray() void SystemTrayApplet::paletteChange(const QPalette & /* oldPalette */) { - TrayEmbedList::const_iterator lastEmb = m_shownWins.end(); - for (TrayEmbedList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) + TrayWidgetList::const_iterator lastEmb = m_shownWins.end(); + for (TrayWidgetList::const_iterator emb = m_shownWins.begin(); emb != lastEmb; ++emb) { (*emb)->hide(); (*emb)->show(); @@ -912,3 +996,24 @@ TrayEmbed::TrayEmbed( bool kdeTray, QWid // if( kde_tray ) // after QXEmbed reparents windows to the root window as unmapped. // setMapAfterRelease( true ); // systray one will have to be made visible somehow } + +TrayIcon::TrayIcon( WId w, QWidget* parent ) + : QLabel( parent ), window( w ) +{ +} + +void TrayIcon::mousePressEvent( QMouseEvent* e ) +{ + if( e->button() == LeftButton ) + { + if( KWin::windowInfo( window, NET::WMState ).hasState( NET::TrayedHidden )) + { + KWin::clearState( window, NET::TrayedHidden ); + KWin::forceActiveWindow( window ); + return; + } + else + KWin::setState( window, NET::TrayedHidden ); + } + return QLabel::mousePressEvent( e ); +} --- systemtray/systemtrayapplet.h.sav 2005-02-21 15:38:58.000000000 +0100 +++ systemtray/systemtrayapplet.h 2005-04-14 18:41:42.000000000 +0200 @@ -27,6 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE #include #include #include +#include #include #include @@ -34,7 +35,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE class QTimer; class KWinModule; -class TrayEmbed; +class TrayWidget; class KDialogBase; class KActionSelector; class HideButton; @@ -43,7 +44,7 @@ class SystemTrayApplet : public KPanelAp { Q_OBJECT K_DCOP - typedef QPtrList TrayEmbedList; + typedef QPtrList TrayWidgetList; public: @@ -70,6 +71,8 @@ protected: protected slots: void initialize(); void systemTrayWindowAdded( WId ); + void trayedWindowAdded( WId ); + void trayedWindowRemoved( WId ); void updateTrayWindows(); void layoutTray(); void paletteChange(const QPalette & /* oldPalette */); @@ -79,7 +82,9 @@ protected slots: void applySettings(); private: - void embedWindow( WId w, bool kde_tray ); + void windowAdded( WId w, bool kde_tray, bool xdg ); + void embedWindow( WId w, bool kde_tray); + void trayWindow( WId w ); bool isWinManaged( WId w); bool shouldHide( WId w); void updateVisibleWins(); @@ -88,8 +93,8 @@ private: void showExpandButton(bool show); void refreshExpandButton(); - TrayEmbedList m_shownWins; - TrayEmbedList m_hiddenWins; + TrayWidgetList m_shownWins; + TrayWidgetList m_hiddenWins; QStringList m_hiddenIconList; KWinModule *kwin_module; Atom net_system_tray_selection; @@ -102,14 +107,48 @@ private: KActionSelector* m_iconSelector; }; -class TrayEmbed : public QXEmbed +class TrayWidget +{ +public: + virtual ~TrayWidget() {}; + virtual WId windowId() const = 0; + virtual bool kdeTray() const = 0; + virtual void show() = 0; + virtual void hide() = 0; + virtual QSize sizeHint() const = 0; + virtual void move( int x, int y ) = 0; +}; + +class TrayEmbed : public QXEmbed, public TrayWidget { Q_OBJECT public: TrayEmbed( bool kdeTray, QWidget* parent = NULL ); - bool kdeTray() const { return kde_tray; } + virtual WId windowId() const { return embeddedWinId(); } + virtual bool kdeTray() const { return kde_tray; } + virtual void show() { QXEmbed::show(); } + virtual void hide() { QXEmbed::hide(); } + virtual QSize sizeHint() const { return QXEmbed::sizeHint(); } + virtual void move( int x, int y ) { return QXEmbed::move( x, y ); } private: bool kde_tray; }; +class TrayIcon : public QLabel, public TrayWidget +{ + Q_OBJECT +public: + TrayIcon( WId window, QWidget* parent = NULL ); + virtual WId windowId() const { return window; } + virtual bool kdeTray() const { return false; } + virtual void show() { QLabel::show(); } + virtual void hide() { QLabel::hide(); } + virtual QSize sizeHint() const { return QLabel::sizeHint(); } + virtual void move( int x, int y ) { return QLabel::move( x, y ); } +protected: + virtual void mousePressEvent( QMouseEvent* e ); +private: + WId window; +}; + #endif --Boundary-00=_o/+XCZm40TGtZ7D--