I guessed that this one wouldn't be as simple as the first one, so I'll break it down to you and explain (WARNING: This will be a long post):
Index: utils/linux/traydock/libtray.c
===================================================================
--- utils/linux/traydock/libtray.c (revision 10522)
+++ utils/linux/traydock/libtray.c (working copy)
@@ -81,6 +81,14 @@
//static int tooltip=0;
Tcl_Interp * globalinterp;
+static Window GetParentWindow(Window w) {
+ Window root, parent, *children;
+ unsigned int n;
+ XQueryTree(display, w, &root, &parent, &children, &n);
+ XFree(children);
+ return parent;
+}
+
/* Set embed information */
static void
xembed_set_info (Tk_Window window, unsigned long flags)
@@ -161,30 +169,24 @@
DockIcon(ClientData clientData)
{
- Window root, parent, *children;
- unsigned int n, ret, atom;
+ Window parent;
+ unsigned int ret, atom;
TrayIcon *icon= clientData;
char* wm_name;
- Tk_MapWindow(icon->win);
+ Tk_MakeWindowExist(icon->win);
- XQueryTree(display, Tk_WindowId(icon->win), &root, &parent, &children, &n);
- XFree(children);
-
Tk_SetWindowBackgroundPixmap(icon->win, ParentRelative);
- XSetWindowBackgroundPixmap(display, parent, ParentRelative);
xembed_set_info(icon->win,XEMBED_MAPPED);
- Tk_UnmapWindow(icon->win);
-
- if ( (atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", True )) == None ) {
+ if ( (atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False )) == None ) {
wm_name = get_wm_name();
if (wm_name != NULL && !strcmp(wm_name, "KWin")) {
atom = XInternAtom(display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False);
+ parent = GetParentWindow(Tk_WindowId(icon->win));
ret = XChangeProperty(display, parent, atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&parent, 1);
- Tk_MapWindow(icon->win);
}
XFree(wm_name);
} else {
Here I created a new function to get the parent window. This is why you see a lot of deletions, but I mostly moved code in the function; what I removed/modified is:
- Tk_MapWindow(icon->win);
+ Tk_MakeWindowExist(icon->win);
Here instead of mapping the window I only make it exist. This is because XFCE doesn't seems to accept changes to the size of the window after it has been mapped, so instead of Mapping (showing) the XWindow, I only make sure that Tk creates the XWindow unmapped (because Tk caches Window creations)
Tk_SetWindowBackgroundPixmap(icon->win, ParentRelative);
- XSetWindowBackgroundPixmap(display, parent, ParentRelative);
This is because the first function call makes the exact same thing and it is a Tk Function, so it is preferable to the direct X call.
- Tk_UnmapWindow(icon->win);
-
Window is not mapped so useless to Unmap it. And besides this is what it prevented from showing up in stalonetray.
- if ( (atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", True )) == None ) {
+ if ( (atom = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False )) == None ) {
wm_name = get_wm_name();
Here the change from True to False means "if there is no such Atom, try to create it". This is according to the systemtray specification and it is necessary for Fluxbox: if aMSN is the first app you launch, it won't go into the system tray if you don't create the "_NET_SYSTEM_TRAY_OPCODE" atom.
This if will most likely always end up in the else branch, so this is why it MAY change behaviour on KDE. I'll go get my laptop and check it out

ret = XChangeProperty(display, parent, atom,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&parent, 1);
- Tk_MapWindow(icon->win);
}
Same reason as above
@@ -245,6 +246,8 @@
if (heightImg > h)
heightImg = h;
+ if( !Tk_IsMapped(icon->win) )
+ Tk_MapWindow(icon->win);
Tk_RedrawImage(icon->pixmap, 0, 0, widthImg, heightImg, Tk_WindowId(icon->win), (w-widthImg)/2 , (h-heightImg)/2 );
}
Since we do not map the window in the above code anymore (because XFCE doesn't like it), we do it now, otherwise the icon won't show up in stalonetray (and possibly other trays)
@@ -351,6 +354,12 @@
XSizeHints *hint;
char cmdBuffer[1024];
+ /* systemtray was not available in Init */
+ if (systemtray==0) {
+ Tcl_AppendResult (interp, "cannot create a tray icon without a system tray", (char *) NULL);
+ return TCL_ERROR;
+ }
+
/* Get memory for trayicon data and zero it*/
icon = (TrayIcon *) malloc(sizeof(TrayIcon));
memset((void *) icon, 0, (sizeof(TrayIcon)));
@@ -358,18 +367,11 @@
mainw=Tk_MainWindow(interp);
- /* systemtray was not available in Init */
- if (systemtray==0) {
- Tcl_AppendResult (interp, "cannot create a tray icon without a system tray", (char *) NULL);
- return TCL_ERROR;
- }
-
/* Get the first argument string (object name) and check it */
arg=Tcl_GetStringFromObj(objv[1],(int *) &length);
//printf("Arg: %s\n",arg);
- if (strncmp(arg,".",1)) {
- Tcl_AppendResult (interp, "bad path name: ",
- Tcl_GetStringFromObj(objv[1],(int *) &length) , (char *) NULL);
+ if (length >= 1 && arg[0] != '.') {
+ Tcl_AppendResult (interp, "bad path name: ", arg , (char *) NULL);
return TCL_ERROR;
}
Here I moved the check on systemtray before the memory allocations to prevent some memory leak. The other modification is equivalent code, just a little more readable.
@@ -431,10 +433,12 @@
if (pixmap != NULL) {
/* Create the window */
icon->win=Tk_CreateWindowFromPath(interp,mainw,
- Tcl_GetStringFromObj(objv[1],(int *) &length),"");
+ Tcl_GetStringFromObj(objv[1],(int *) &length),NULL);
Here I substituted "" with NULL so that instead of creating a topLevel window, we create a window inside the main window. This is because if we create a topLevel window the window manager decorations will appear in some systems (i.e. Flux or Openbox + Stalonetray). I couldn't find any difference in the main window, if you spot something let me know and I'll find some other solution.
DockIcon((ClientData)icon);
+ Tk_GeometryRequest( icon->win, 24, 24);
+
icon->pixmap=Tk_GetImage(interp,icon->win,pixmap,ImageChangedProc, (ClientData)icon);
/* Create callback function for event handling */
@@ -444,9 +448,11 @@
/* Set default icon size hint */
hint = XAllocSizeHints();
- hint->flags |=PMinSize;
- hint->min_width=24;
- hint->min_height=24;
+ hint->flags |=PMinSize|PMaxSize;
+ hint->min_width=16;
+ hint->max_width=64;
+ hint->min_height=16;
+ hint->max_height=64;
XSetWMNormalHints(display,Tk_WindowId(icon->win),hint);
XFree(hint);
Here is set the initial window size to 24x24 and I set the XWMNormalHints to a minimum and maximum size (these values should be reasonable, but we'll always be in time to change them should the necessity arise!)
If you still have other concerns I'll gladly try to address them, meanwhile I'll try to test this on Gnome and KDE. If you want me to comment more the code I can do that too