Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window Manager Information should not require wmctrl #9

Open
grtcdr opened this issue Apr 4, 2021 · 9 comments
Open

Window Manager Information should not require wmctrl #9

grtcdr opened this issue Apr 4, 2021 · 9 comments
Assignees
Labels
optimization Optimizations for clarity and/or performance top-priority

Comments

@grtcdr
Copy link
Member

grtcdr commented Apr 4, 2021

libmacchina currently fetches the window manager name through wmctrl, this call is expensive compared to accessing it through more efficient means.

A new implementation must return the window manager name for X and Wayland.

Why?

Not requiring wmctrl is one less dependency to worry about, and it's always faster not to call commands.

@grtcdr grtcdr added the help wanted Extra attention is needed label Apr 4, 2021
@grtcdr grtcdr self-assigned this Apr 4, 2021
@grtcdr grtcdr changed the title No longer require wmctrl Window Manager Information should not require wmctrl Apr 4, 2021
@uttarayan21
Copy link
Member

I took a look at this.
wmctrl seems to be only for Xorg.
It uses the x11 libraries
This is the function which gets the wmctrl -m info (source)

wm_info function

static int wm_info (Display *disp) {/*{{{*/
    Window *sup_window = NULL;
    gchar *wm_name = NULL;
    gchar *wm_class = NULL;
    unsigned long *wm_pid = NULL;
    unsigned long *showing_desktop = NULL;
    gboolean name_is_utf8 = TRUE;
    gchar *name_out;
    gchar *class_out;
    
    if (! (sup_window = (Window *)get_property(disp, DefaultRootWindow(disp),
                    XA_WINDOW, "_NET_SUPPORTING_WM_CHECK", NULL))) {
        if (! (sup_window = (Window *)get_property(disp, DefaultRootWindow(disp),
                        XA_CARDINAL, "_WIN_SUPPORTING_WM_CHECK", NULL))) {
            fputs("Cannot get window manager info properties.\n"
                  "(_NET_SUPPORTING_WM_CHECK or _WIN_SUPPORTING_WM_CHECK)\n", stderr);
            return EXIT_FAILURE;
        }
    }

    /* WM_NAME */
    if (! (wm_name = get_property(disp, *sup_window,
            XInternAtom(disp, "UTF8_STRING", False), "_NET_WM_NAME", NULL))) {
        name_is_utf8 = FALSE;
        if (! (wm_name = get_property(disp, *sup_window,
                XA_STRING, "_NET_WM_NAME", NULL))) {
            p_verbose("Cannot get name of the window manager (_NET_WM_NAME).\n");
        }
    }
    name_out = get_output_str(wm_name, name_is_utf8);
  
    /* WM_CLASS */
    if (! (wm_class = get_property(disp, *sup_window,
            XInternAtom(disp, "UTF8_STRING", False), "WM_CLASS", NULL))) {
        name_is_utf8 = FALSE;
        if (! (wm_class = get_property(disp, *sup_window,
                XA_STRING, "WM_CLASS", NULL))) {
            p_verbose("Cannot get class of the window manager (WM_CLASS).\n");
        }
    }
    class_out = get_output_str(wm_class, name_is_utf8);
  

    /* WM_PID */
    if (! (wm_pid = (unsigned long *)get_property(disp, *sup_window,
                    XA_CARDINAL, "_NET_WM_PID", NULL))) {
        p_verbose("Cannot get pid of the window manager (_NET_WM_PID).\n");
    }
    
    /* _NET_SHOWING_DESKTOP */
    if (! (showing_desktop = (unsigned long *)get_property(disp, DefaultRootWindow(disp),
                    XA_CARDINAL, "_NET_SHOWING_DESKTOP", NULL))) {
        p_verbose("Cannot get the _NET_SHOWING_DESKTOP property.\n");
    }
    
    /* print out the info */
    printf("Name: %s\n", name_out ? name_out : "N/A");
    printf("Class: %s\n", class_out ? class_out : "N/A");
    
    if (wm_pid) {
        printf("PID: %lu\n", *wm_pid);
    }
    else {
        printf("PID: N/A\n");
    }
    
    if (showing_desktop) {
        printf("Window manager's \"showing the desktop\" mode: %s\n",
                *showing_desktop == 1 ? "ON" : "OFF");
    }
    else {
        printf("Window manager's \"showing the desktop\" mode: N/A\n");
    }
    
    g_free(name_out);
    g_free(sup_window);
    g_free(wm_name);
	g_free(wm_class);
    g_free(wm_pid);
    g_free(showing_desktop);
    
    return EXIT_SUCCESS;
}/*}}}*/

Will also have to handle the wayland stuff seperately.

@grtcdr
Copy link
Member Author

grtcdr commented Apr 14, 2021

I've taken a look at wmctrl's source code before, and although simple, it scared me a bit. But I'll give it another go.

Will also have to handle the wayland stuff seperately.

We can try to establish a connection with the X server, and if that fails, we can then try and check if the user is running Wayland, so we don't necessarily have to handle them separately.

If both checks fail, we can safely assume the user is in a TTY session, so we fail the readout.

@uttarayan21
Copy link
Member

I've taken a look at wmctrl's source code before, and although simple, it scared me a bit.

Yeah C code is really intimidating and hard to read.

We can try to establish a connection with the X server, and if that fails, we can then try and check if the user is running Wayland, so we don't necessarily have to handle them separately.

This might fail if the user is running xwayland since many applications aren't supported. But I'm not sure.

@grtcdr
Copy link
Member Author

grtcdr commented Apr 15, 2021

I totally forgot about xwayland.

I'll have to invest some time to get some knowledge on xwayland just enough to be able to dive in and start hacking a new implementation together.

@uttarayan21
Copy link
Member

Good luck !
I'll let you know If I find something related.

@grtcdr grtcdr added optimization Optimizations for clarity and/or performance top-priority and removed help wanted Extra attention is needed labels Apr 19, 2021
@uttarayan21
Copy link
Member

uttarayan21 commented Apr 22, 2021

@grtcdr What if you compiled wmctrl to a shared object and used rust ffi to get the wm_info from that shared object.
It would probably be easier than to implement it yourself.
That should remove the overhead of calling it via the shell.

@grtcdr
Copy link
Member Author

grtcdr commented Apr 22, 2021

@grtcdr What if you compiled wmctrl to a shared object

I wouldn't know how to do that, and wmctrl does a lot more than what we need from it.

Wait, like a .so file?

@uttarayan21
Copy link
Member

Like an *.o file.

clang -c wminfo.c
outputs a wminfo.o

It contains all the references to all the code of your program but hasn't been linked into any library yet by the linker.

We can remove most of the stuff other that wm_info and make it return a pointer to a struct or something.

But If you can use rust to make the x11 calls all this won't be necessary, however I find x11 programming extremely confusing so that's why I suggested this.

@Absolpega
Copy link
Contributor

Now to try and tackle this problem.
I think the approach in the current xprop implementation is based on this stack overflow question
https://stackoverflow.com/a/1115292

No idea how xlib and xcb actually work but I would guess it is similar to xprop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
optimization Optimizations for clarity and/or performance top-priority
Development

No branches or pull requests

3 participants