Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Linux equivalent of SetWindowPos?

Tags:

c

linux

windows

A while ago I wrote a script in C that used the Windows API functions EnumWindows, SetWindowPos and SetForegroundWindow to automatically arrange windows (by title) in a particular layout that I commonly wanted.

Are there Linux equivalents for these functions? I will be using Kubuntu, so KDE-specific and/or Ubuntu-specific solutions are fine.

like image 993
Mark Raymond Avatar asked May 09 '13 20:05

Mark Raymond


3 Answers

The best way to do this is either in the window manager itself (if yours supports extensions) or with the protocols and hints designed to support "pagers" (pager = any non-window-manager process that does window organization or navigation things).

The EWMH spec includes a _NET_MOVERESIZE_WINDOW designed for use by pagers. http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html#id2731465

Raw Xlib or Xcb is pretty rough but there's a library called libwnck specifically designed to do the kind of thing you're talking about. (I wrote the original library long ago but it's been maintained by others forever.) Even if you don't use it, read the code to see how to do stuff. KDE may have an equivalent with KDE-style APIs I'm not sure.

There should be no need to use anything KDE or GNOME or distribution specific since the needed stuff is all spelled out in EWMH. That said, for certain window managers doing this as an extension may be easier than writing a separate app.

Using old school X calls directly can certainly be made to work but there are lots of details to handle there that require significant expertise if you want to iron out all the bugs and corner cases, in my opinion, so using a WM extension API or pager library would be my advice.

like image 90
Havoc P Avatar answered Oct 22 '22 23:10

Havoc P


@andrewdotn has a fine answer there but you can do this old school as well fairly simply by walking the tree starting at the root window of the display using XQueryTree and fetching the window name with XFetchName then moving it with XMoveWindow. Here is an example that will list all the windows and if any are called 'xeyes' they get moved to the top left. Like most X programs, there is more to it and this should probably be calling XGetWindowProperty to fetch the _NET_WM_NAME extended window manager property but the example works ok as a starter. Compile with gcc -Wall -g -o demo demo.c -lX11

#include <X11/Xlib.h>
#include <stdio.h>
#include <string.h>

static int
EnumWindows(Display *display, Window window, int depth)
{
    Window parent, *children;
    unsigned int count = 0;
    int r = 1, n = 0;
    char *name = NULL;

    XFetchName(display, window, &name);
    for (n = 0; n < depth; ++n) putchar(' ');
    printf("%08x %s\n", (int)window, name?name:"(null)");
    if (name && strcmp("xeyes", name) == 0) {
        XMoveWindow(display, window, 5, 5);
    }
    if (name) XFree(name);

    if (XQueryTree(display, window, &window, &parent, &children, &count) == 0) {
        fprintf(stderr, "error: XQueryTree error\n");
        return 0;
    }
    for (n = 0; r && n < count; ++n) {
        r = EnumWindows(display, children[n], depth+1);
    }
    XFree(children);
    return r;
}

int
main(int argc, char *const argv[])
{
    Display *display = NULL;

    if ((display = XOpenDisplay(NULL)) == NULL) {
        fprintf(stderr, "error: cannot connect to X server\n");
        return 1;
    }

    EnumWindows(display, DefaultRootWindow(display), 0);
    XCloseDisplay(display);
    return 0;
}
like image 33
patthoyts Avatar answered Oct 22 '22 22:10

patthoyts


Yes, you can do this using the X Windows protocol. It’s a very low-level protocol so it will take some work. You can use xcb_query_tree to find the window to operate on, and then move it with xcb_configure_window. This page gives some details on how to do it. There’s a basic tutorial on using the library those functions come from, but you’ll probably want to Google for a better one.

It may seem daunting, but it’s not too bad. Here’s a 50-line C program that will move all your xterms 10px to the right:

#include <stdio.h>
#include <string.h>
#include <xcb/xcb.h>

void handle(xcb_connection_t* connection, xcb_window_t window) {

    xcb_query_tree_reply_t *tree = xcb_query_tree_reply(connection,
        xcb_query_tree(connection, window), NULL);
    xcb_window_t *children = xcb_query_tree_children(tree);

    for (int i = 0;  i < xcb_query_tree_children_length(tree); i++) {

        xcb_get_property_reply_t *class_reply = xcb_get_property_reply(
            connection,
            xcb_get_property(connection, 0, children[i], XCB_ATOM_WM_CLASS,
                XCB_ATOM_STRING, 0, 512), NULL);
        char* class = (char*)xcb_get_property_value(class_reply);
        class[xcb_get_property_value_length(class_reply)] = '\0';

        if (!strcmp(class, "xterm")) {
            /* Get geometry relative to parent window */
            xcb_get_geometry_reply_t* geom = xcb_get_geometry_reply(
                connection,
                xcb_get_geometry(connection, window),
                NULL);

            /* Move 10 pixels right */
            uint32_t values[] = {geom->x + 10};
            xcb_configure_window(connection, children[i],
                XCB_CONFIG_WINDOW_X, values);
        }

        /* Recurse down window tree */
        handle(connection, children[i]);
    }
}

int main() {
    xcb_connection_t *connection;
    const xcb_setup_t *setup;

    connection = xcb_connect(NULL, NULL);
    setup = xcb_get_setup(connection);
    xcb_screen_iterator_t screen = xcb_setup_roots_iterator(setup);
    handle(connection, screen.data->root);

    return 0;
}

There’s no error-checking or memory management, and what it can do is pretty limited. But it should be straightforward to update into a program that does what you want, or to turn it into a general-purpose helper program by adding command-line options to specify which windows to operate on and which operations to perform on them.

like image 39
andrewdotn Avatar answered Oct 22 '22 22:10

andrewdotn