Re: [dev] [dwm] Obtain focused monitor

From: A Farzat <a_AT_farzat.xyz>
Date: Sat, 14 Jan 2023 12:32:01 +0900

On 23/01/12 11:35am, Gauthier Östervall wrote:
> On Sun, 8 Jan 2023 at 11:21, A Farzat <a_AT_farzat.xyz> wrote:
> >
> > Is there a way to obtain the currently focused monitor in dwm? I want to
> > use it in my script to control which monitor gets its brightness
> > modified.
>
> Do you mean obtain from outside the dwm process? Not directly, that I
> am aware of. But you could try and query X for that. This SO answer
> might be of interest: https://unix.stackexchange.com/a/677884
>
> selmon is not a command, it's a global variable. It's not accessible
> outside the dwm process, if you don't make it accessible by modifying
> dwm. It also points to a dwm monitor struct, it holds data for the
> internals of dwm. You could probably use it to find out what you need,
> but I'm not sure it would be the simplest way.

Thank you for your elaboration. Yes, querying X is much simpler and more
portable, but the best answers I found tell you on which monitor your
cursor is, which in dwm is not necessarily your focused monitor.

I was actually thinking about doing what you suggested in your second
paragraph. My plan was to make dwm listen for a signal, at which it
writes the value of the current monitor to a file. The problem is that
is too complex for such a simple function. There is also the question of
portability.

My other approach would be trying to copy what dmenu does - it checks
the position of the currently focused window, or the cursor if no window
is focused. Not fool-proof but much simpler and more portable. The
problem is I hardly know anything about X. I tried copying the code from
dmenu and removing the extra parts, and this is what I got:

```c
#include <stdio.h>
#include <string.h>
#include <X11/extensions/Xinerama.h>
#include <X11/Xft/Xft.h>

#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - \
            MAX((x),(r).x_org)) * MAX(0, MIN((y)+(h),(r).y_org+(r).height) - \
            MAX((y),(r).y_org)))

static int screen;
static Display *dpy;
static Window root;

int main(void)
{
    if (!(dpy = XOpenDisplay(NULL))) {
        fputs("cannot open display\n", stderr);
        return 1;
    }
    screen = DefaultScreen(dpy);
    root = RootWindow(dpy, screen);
    int x, y, i, j;
    unsigned int du;
    Window w, dw, *dws;
    XWindowAttributes wa;
    XineramaScreenInfo *info;
    Window pw;
    int a, di, n, area = 0;

    i = 0;
    if ((info = XineramaQueryScreens(dpy, &n))) {
        XGetInputFocus(dpy, &w, &di);
        if (w != root && w != PointerRoot && w != None) {
            /* find top-level window containing current input focus */
            do {
                if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
                    XFree(dws);
            } while (w != root && w != pw);
            /* find xinerama screen with which the window intersects most */
            if (XGetWindowAttributes(dpy, pw, &wa))
                for (j = 0; j < n; j++)
                    if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
                        area = a;
                        i = j;
                    }
        }
        /* no focused window is on screen, so use pointer location instead */
        if (!area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
            for (i = 0; i < n; i++)
                if (INTERSECT(x, y, 1, 1, info[i]))
                    break;

        XFree(info);
    }

    printf("Monitor: %d\n", i);
}
```

If there is any improvement I can do, I would be grateful for letting me
know.

> What's not clear is what format you need for your script. What does
> the script need, in order to work? If you only need stuff from X,
> asking X directly is probably simpler, there's already an API. It also
> would make your tool more agnostic, it would probably work with other
> WM using X.

What I need is the number of the focused monitor, so that when I press
my keybinding, the script adjusts the current monitor instead of all the
monitors. I call also use the program to obtain the correct brightness
for the statusbar based on which monitor it is currently appearing on.

I'm sorry for making this bigger than it is supposed to be, but I think
this is also an oppurtunity for me to learn a thing or two about how
these programs work.

Best regards,
Farzat

Received on Sat Jan 14 2023 - 04:32:01 CET

This archive was generated by hypermail 2.3.0 : Sat Jan 14 2023 - 04:36:08 CET