[Rd] Possible x11 window manager window aggregation under one icon?

Duncan Murdoch murdoch@dunc@n @end|ng |rom gm@||@com
Tue Mar 23 16:41:39 CET 2021


On 23/03/2021 6:18 a.m., Ivan Krylov wrote:
> On Mon, 22 Mar 2021 16:57:48 -0500
> Dirk Eddelbuettel <edd using debian.org> wrote:
> 
>> Do you want to send a proper patch to bugzilla?
> 
> Would be glad to, especially if we manage to solve that problem you
> uncovered while I was asleep.
> 
> On Mon, 22 Mar 2021 22:23:47 -0500
> Dirk Eddelbuettel <edd using debian.org> wrote:
> 
>> Close, close, close but no cigar yet: For a given R process, x11()
>> windows group for a that process. But we often run multiple R
>> processes.  Have you seen anything for grouping under the
>> "program" (in some sense) but not the concrete process from it?
> 
> Do windows from different Emacs processes group together the way you
> want them to group? What other applications group together for you
> despite running from different processes? Do they have the same window
> id # of group leader in `xprop WM_HINTS`? I checked Firefox, but its
> windows all seem to have the same _NET_WM_PID.

In Ubuntu 18.04, all terminal windows display the same _NET_WM_PID, and 
that PID corresponds to gnome-terminal-server.  So I think it's not 
going to be possible to do what Dirk wants without really major changes 
to the way different R processes create graphics windows.

On the other hand, R doesn't set the _NET_WM_PID value.

I've put a version of your code into rgl, and it does what you'd expect: 
  it groups all rgl windows from the same R process together, but 
different R processes get different groups.  It would probably be nice 
to have rgl windows and other R graphics windows in the same group, but 
I don't see a way for rgl to know the group_leader that R is using (and 
it's probably not worth adding this to the API to be able to request it).

Am I missing an easier solution?

Duncan Murdoch

> 
> I decided to copy the way GVim sets its group leader ID (because I know
> the windows are different processes _and_ that they group in Xfce) and
> spent a while chasing this red herring before realising that (1) on my
> PC, different x11() windows are still grouped together, even from
> different R processes, even without the patch (I never used the "group
> windows" option in xfce4-panel before) and (2) different GVim windows
> actually have different group leader XIDs in their WM_HINTS properties.
> Oops.
> 
> Apparently Xfce uses libwnck [*] which groups windows by WM_CLASS in
> addition to WM_HINTS (as far as understand the code).
> 
> Here is what GNOME Shell does [**] besides looking at
> WM_HINTS.window_group:
> 
>   - looks up the window's WM_CLASS in .desktop files known to it
>   - looks up the window's _NET_WM_PID among running applications (?)
>   - looks for an XDG startup notification matching the window
>   - checks other things not likely applicable to R, such as sandbox IDs
>     and GApplication IDs
> 
> Adding StartupWMClass=R_x11 to R.desktop (not part of R sources, but
> part of the .deb package, I believe) should help GNOME Shell match all
> x11() windows to a single application without any changes to devX11.c,
> but I don't have GNOME installed to check it.
> 
> Alternatively, we can also add a _NET_WM_PID property to x11() windows
> (in the hope that GNOME Shell matches the PIDs to the same binary), but
> then we'd have to add the WM_CLIENT_MACHINE property too [***], which
> is way more hacky than I would prefer it to be:
> 
> -----------------------------------8<-----------------------------------
> Index: src/modules/X11/devX11.c
> ===================================================================
> --- src/modules/X11/devX11.c	(revision 80104)
> +++ src/modules/X11/devX11.c	(working copy)
> @@ -52,6 +52,8 @@
>   #endif
>   #include <X11/keysymdef.h>
>   
> +#include <sys/utsname.h> /* for uname -> WM_CLIENT_MACHINE -> _NET_WM_PID */
> +#include <unistd.h> /* getpid -> _NET_WM_PID */
>   
>   #define R_USE_PROTOTYPES 1
>   #include <R_ext/GraphicsEngine.h>
> @@ -105,7 +107,7 @@
>   static Display *display;			/* Display */
>   static char dspname[101]="";
>   static int screen;				/* Screen */
> -static Window rootwin;				/* Root Window */
> +static Window rootwin, group_leader;		/* Root Window */
>   static Visual *visual;				/* Visual */
>   static int depth;				/* Pixmap depth */
>   static int Vclass;				/* Visual class */
> @@ -1617,6 +1619,39 @@
>                               PropModeReplace,
>                               (const unsigned char*) rlogo_icon, 2 + 99*77);
>   
> +	    /* set the window group leader */
> +	    XWMHints * hints;
> +	    hints = XAllocWMHints();
> +	    if (hints) {
> +		hints->window_group = group_leader;
> +		hints->flags |= WindowGroupHint;
> +		XSetWMHints(display, xd->window, hints);
> +		XFree(hints);
> +	    }
> +
> +	    /* Provide WM_CLIENT_MACHINE to set a valid _NET_WM_PID */
> +	    struct utsname unm;
> +	    if (uname(&unm)) goto no_wm_pid;
> +	    char * nodename = &unm.nodename[0];
> +	    XTextProperty hostname = {0}; /* initialise the value pointer */
> +	    if (Success != XmbTextListToTextProperty(
> +		display, &nodename, 1, XStringStyle, &hostname
> +	    )) {
> +		if (hostname.value) XFree(hostname.value);
> +		goto no_wm_pid;
> +	    }
> +	    XSetWMClientMachine(display, xd->window, &hostname);
> +	    XFree(hostname.value);
> +
> +	    /* set _NET_WM_PID */
> +	    uint32_t mypid = (uint32_t)getpid(); /* must be CARDINAL(32) */
> +            XChangeProperty(display, xd->window,
> +                            XInternAtom(display, "_NET_WM_PID", False),
> +                            XInternAtom(display, "CARDINAL", False), 32,
> +                            PropModeReplace,
> +                            (const unsigned char*) &mypid, 1);
> +	    no_wm_pid:
> +
>   	    /* set up protocols so that window manager sends */
>   	    /* me an event when user "destroys" window */
>   	    _XA_WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0);
> @@ -2109,6 +2144,7 @@
>       if (numX11Devices == 0)  {
>   	int fd = ConnectionNumber(display);
>   	/* Free Resources Here */
> +	XDestroyWindow(display, group_leader);
>   	while (nfonts--)
>   	      R_XFreeFont(display, fontcache[nfonts].font);
>   	nfonts = 0;
> @@ -3133,6 +3169,9 @@
>   #endif
>       screen = DefaultScreen(display);
>       rootwin = DefaultRootWindow(display);
> +    group_leader = XCreateSimpleWindow(
> +	display, rootwin, 0, 0, 1, 1, 0, 0, 0
> +    );
>       depth = DefaultDepth(display, screen);
>       visual = DefaultVisual(display, screen);
>       colormap = DefaultColormap(display, screen);
> -----------------------------------8<-----------------------------------
>



More information about the R-devel mailing list