tFirst commit - libwm - X windows manipulation library
 (HTM) git clone git://z3bra.org/libwm
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 0d6908dc2e053a32979b693284727e3c6fe72922
 (HTM) Author: z3bra <willyatmailoodotorg>
       Date:   Sat, 14 Nov 2015 14:42:02 +0100
       
       First commit
       
       Diffstat:
         A Makefile                            |      30 ++++++++++++++++++++++++++++++
         A config.mk                           |       7 +++++++
         A libwm.c                             |     336 +++++++++++++++++++++++++++++++
         A wm.h                                |     188 +++++++++++++++++++++++++++++++
       
       4 files changed, 561 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -0,0 +1,30 @@
       +include config.mk
       +
       +LIB = libwm.a
       +HDR = wm.h
       +
       +.POSIX:
       +.SUFFIXES: .a .o
       +
       +all: $(LIB)
       +
       +.o.a:
       +        @echo "AR $@"
       +        @$(AR) rcs $@ $< 
       +
       +.c.o:
       +        @echo "CC $<"
       +        @$(CC) -c $< $(CFLAGS)
       +
       +install: $(LIB) $(HDR)
       +        mkdir -p $(DESTDIR)$(PREFIX)/lib
       +        mkdir -p $(DESTDIR)$(PREFIX)/include
       +        cp -f $(LIB) $(DESTDIR)$(PREFIX)/lib/
       +        cp -f $(HDR) $(DESTDIR)$(PREFIX)/include/
       +
       +uninstall:
       +        rm -f $(DESTDIR)$(PREFIX)/lib/$(LIB)
       +        rm -f $(DESTDIR)$(PREFIX)/include/$(HDR) 
       +
       +clean :
       +        rm -f $(LIB)
 (DIR) diff --git a/config.mk b/config.mk
       t@@ -0,0 +1,7 @@
       +PREFIX    = /usr/local
       +
       +CC      = cc
       +LD      = $(CC)
       +
       +CFLAGS  = -std=c99 -pedantic -Wall -fPIC -Os
       +LDFLAGS = -lxcb
 (DIR) diff --git a/libwm.c b/libwm.c
       t@@ -0,0 +1,336 @@
       +#include <xcb/xcb.h>
       +#include <stdlib.h>
       +#include <stdio.h>
       +#include <string.h>
       +
       +#include "wm.h"
       +
       +int
       +init_xcb()
       +{
       +        conn = xcb_connect(NULL, NULL);
       +        if (xcb_connection_has_error(conn))
       +                return 0;
       +        return 1;
       +}
       +
       +int
       +kill_xcb()
       +{
       +        if (conn) {
       +                xcb_disconnect(conn);
       +                return 1;
       +        }
       +        return 0;
       +}
       +
       +int
       +is_alive(xcb_window_t w)
       +{
       +        xcb_get_window_attributes_cookie_t c;
       +        xcb_get_window_attributes_reply_t  *r;
       +
       +        c = xcb_get_window_attributes(conn, w);
       +        r = xcb_get_window_attributes_reply(conn, c, NULL);
       +
       +        if (r == NULL)
       +                return 0;
       +
       +        free(r);
       +        return 1;
       +}
       +
       +int
       +is_mapped(xcb_window_t w)
       +{
       +        int ms;
       +        xcb_get_window_attributes_cookie_t c;
       +        xcb_get_window_attributes_reply_t  *r;
       +
       +        c = xcb_get_window_attributes(conn, w);
       +        r = xcb_get_window_attributes_reply(conn, c, NULL);
       +
       +        if (r == NULL)
       +                return 0;
       +
       +        ms = r->map_state;
       +
       +        free(r);
       +        return ms == XCB_MAP_STATE_VIEWABLE;
       +}
       +
       +int
       +is_ignored(xcb_window_t wid)
       +{
       +        int or;
       +        xcb_get_window_attributes_cookie_t c;
       +        xcb_get_window_attributes_reply_t  *r;
       +
       +        c = xcb_get_window_attributes(conn, wid);
       +        r = xcb_get_window_attributes_reply(conn, c, NULL);
       +
       +        if (r == NULL)
       +                return 0;
       +
       +        or = r->override_redirect;
       +
       +        free(r);
       +        return or;
       +}
       +
       +int
       +get_screen()
       +{
       +        scrn = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
       +        if (scrn == NULL)
       +                return 0;
       +        return 1;
       +}
       +
       +int
       +get_windows(xcb_window_t w, xcb_window_t **l)
       +{
       +        uint32_t childnum = 0;
       +        xcb_query_tree_cookie_t c;
       +        xcb_query_tree_reply_t *r;
       +
       +        c = xcb_query_tree(conn, w);
       +        r = xcb_query_tree_reply(conn, c, NULL);
       +        if (r == NULL)
       +                return -1;
       +
       +        *l = malloc(sizeof(xcb_window_t) * r->children_len);
       +        memcpy(*l, xcb_query_tree_children(r),
       +                        sizeof(xcb_window_t) * r->children_len);
       +
       +        childnum = r->children_len;
       +
       +        free(r);
       +        return childnum;
       +}
       +
       +int
       +get_attribute(xcb_window_t w, int attr)
       +{
       +        xcb_get_geometry_cookie_t c;
       +        xcb_get_geometry_reply_t *r;
       +
       +        c = xcb_get_geometry(conn, w);
       +        r = xcb_get_geometry_reply(conn, c, NULL);
       +
       +        if (r == NULL)
       +                return -1;
       +
       +        switch (attr) {
       +                case ATTR_X: attr = r->x; break;
       +                case ATTR_Y: attr = r->y; break;
       +                case ATTR_W: attr = r->width; break;
       +                case ATTR_H: attr = r->height; break;
       +                case ATTR_B: attr = r->border_width; break;
       +        }
       +
       +        free(r);
       +        return attr;
       +}
       +
       +int
       +get_cursor(int mode, uint32_t wid, int *x, int *y)
       +{
       +        xcb_query_pointer_reply_t *r;
       +        xcb_query_pointer_cookie_t c;
       +
       +        c = xcb_query_pointer(conn, wid);
       +        r = xcb_query_pointer_reply(conn, c, NULL);
       +
       +        if (r == NULL)
       +                return 0;
       +
       +        if (r->child != XCB_NONE) {
       +                *x = r->win_x;
       +                *y = r->win_y;
       +        } else {
       +                *x = r->root_x;
       +                *y = r->root_y;
       +        }
       +
       +        return 1;
       +}
       +
       +int
       +set_border(int width, int color, xcb_window_t win)
       +{
       +        uint32_t values[1];
       +        int mask, retval = 0;
       +        /* change width if > 0 */
       +        if (width > -1) {
       +                values[0] = width;
       +                mask = XCB_CONFIG_WINDOW_BORDER_WIDTH;
       +                xcb_configure_window(conn, win, mask, values);
       +                retval++;
       +        }
       +
       +        /* change color if > 0 */
       +        if (color > -1) {
       +                values[0] = color;
       +                mask = XCB_CW_BORDER_PIXEL;
       +                xcb_change_window_attributes(conn, win, mask, values);
       +                retval++;
       +        }
       +
       +        xcb_flush(conn);
       +        return retval;
       +}
       +
       +int
       +set_cursor(int x, int y, int mode)
       +{
       +        xcb_warp_pointer(conn, XCB_NONE, mode ? XCB_NONE : scrn->root,
       +                        0, 0, 0, 0, x, y);
       +        return 1;
       +}
       +
       +int
       +is_listable(xcb_window_t w, int mask)
       +{
       +        if ((mask & LIST_ALL)
       +                || (!is_mapped (w) && mask & LIST_HIDDEN)
       +                || ( is_ignored(w) && mask & LIST_IGNORE)
       +                || ( is_mapped (w) && !is_ignored(w) && mask == 0))
       +                return 1;
       +
       +        return 0;
       +}
       +
       +int
       +teleport(xcb_window_t wid, int x, int y, int w, int h)
       +{
       +        uint32_t values[4];
       +        uint32_t mask =   XCB_CONFIG_WINDOW_X
       +                        | XCB_CONFIG_WINDOW_Y
       +                        | XCB_CONFIG_WINDOW_WIDTH
       +                        | XCB_CONFIG_WINDOW_HEIGHT;
       +        values[0] = x;
       +        values[1] = y;
       +        values[2] = w;
       +        values[3] = h;
       +        xcb_configure_window(conn, wid, mask, values);
       +
       +        xcb_flush(conn);
       +        return 1;
       +}
       +
       +int
       +move(xcb_window_t wid, int mode, int x, int y)
       +{
       +        int curx, cury, curw, curh, curb;
       +
       +        if (!is_mapped(wid) || wid == scrn->root)
       +                return -1;
       +        
       +        curb = get_attribute(wid, ATTR_B);
       +        curx = get_attribute(wid, ATTR_X);
       +        cury = get_attribute(wid, ATTR_Y);
       +        curw = get_attribute(wid, ATTR_W);
       +        curh = get_attribute(wid, ATTR_H);
       +
       +        if (mode == ABSOLUTE) {
       +                x -= curx + curw /2;
       +                y -= cury + curh /2;
       +        } else {
       +                x += curx;
       +                y += cury;
       +        }
       +
       +        /* the following prevent windows from moving off the screen */
       +        if (x < 0)
       +                x = 0;
       +        else if (x > scrn->width_in_pixels - curw - 2*curb)
       +                x = scrn->width_in_pixels - curw - 2*curb;
       +
       +        if (y < 0)
       +                y = 0;
       +        else if (y > scrn->height_in_pixels - curh - 2*curb)
       +                y = scrn->height_in_pixels - curh - 2*curb;
       +
       +        teleport(wid, x, y, curw, curh);
       +        return 1;
       +}
       +
       +int
       +remap(xcb_window_t wid, int mode)
       +{
       +        switch (mode) {
       +        case MAP:
       +                xcb_map_window(conn, wid);
       +                break;
       +        case UNMAP:
       +                xcb_unmap_window(conn, wid);
       +                break;
       +        case TOGGLE:
       +                if (is_mapped(wid))
       +                        xcb_unmap_window(conn, wid);
       +                else
       +                        xcb_map_window(conn, wid);
       +                break;
       +        }
       +        xcb_flush(conn);
       +        return 1;
       +}
       +
       +int
       +resize(xcb_window_t wid, int mode, int w, int h)
       +{
       +        int curx, cury, curw, curh, curb;
       +
       +        if (!is_mapped(wid) || wid == scrn->root)
       +                return -1;
       +        
       +        curb = get_attribute(wid, ATTR_B);
       +        curx = get_attribute(wid, ATTR_X);
       +        cury = get_attribute(wid, ATTR_Y);
       +        curw = get_attribute(wid, ATTR_W);
       +        curh = get_attribute(wid, ATTR_H);
       +
       +        if (mode == ABSOLUTE) {
       +                w -= curx + 2*curb;
       +                h -= cury + 2*curb;
       +        } else {
       +                w += curw;
       +                h += curh;
       +        }
       +
       +        /*
       +         * The following prevent windows from growing out of the screen, or
       +         * having a negative size
       +         */
       +        if (w < 0)
       +                w = curw;
       +        if (curx + w >  scrn->width_in_pixels)
       +                w = scrn->width_in_pixels - curx - 2*curb;
       +
       +        if (h < 0)
       +                h = cury;
       +        if (cury + h > scrn->height_in_pixels)
       +                h = scrn->height_in_pixels - cury - 2*curb;
       +
       +        teleport(wid, curx, cury, w, h);
       +        return 1;
       +}
       +
       +int
       +restack(xcb_window_t wid, uint32_t mode)
       +{
       +        uint32_t values[1] = { mode };
       +        xcb_configure_window(conn, wid, XCB_CONFIG_WINDOW_STACK_MODE, values);
       +        xcb_flush(conn);
       +        return 1;
       +}
       +
       +int
       +set_focus(xcb_window_t wid)
       +{
       +        xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, wid,
       +                            XCB_CURRENT_TIME);
       +        xcb_flush(conn);
       +        return 1;
       +}
 (DIR) diff --git a/wm.h b/wm.h
       t@@ -0,0 +1,188 @@
       +#ifndef __LIBWM_H__
       +#define __LIBWM_H__
       +
       +/*
       + * Varialbes used to hold the connection to the X server, and the first screen
       + * of this connection. Both have to be defined as `extern`.
       + */
       +extern xcb_connection_t *conn;
       +extern xcb_screen_t     *scrn;
       +
       +/*
       + * Mask attributes used to select which windows have to be listed by the
       + * function `is_listable(wid, mask)`.
       + */
       +enum {
       +        LIST_HIDDEN = 1 << 0, /* windows that are not on-screen */
       +        LIST_IGNORE = 1 << 1, /* windows with override_redirect set to 1 */
       +        LIST_ALL    = 1 << 2  /* All existing windows */
       +};
       +
       +/*
       + * Actions used by the `remap(wid, mode)` function to select what needs to be
       + * done.
       + */
       +enum {
       +        MAP     = 1 << 0,
       +        UNMAP   = 1 << 1,
       +        TOGGLE  = 1 << 2
       +};
       +
       +/*
       + * Attributes used internally by different functions to refer to windows
       + * attributes, and select them.
       + */
       +enum {
       +        ATTR_W = 1 << 0,
       +        ATTR_H = 1 << 1,
       +        ATTR_X = 1 << 2,
       +        ATTR_Y = 1 << 3,
       +        ATTR_B = 1 << 4,
       +        ATTR_M = 1 << 5,
       +        ATTR_I = 1 << 6,
       +        ATTR_MAX
       +};
       +
       +/*
       + * Selector used  by both `move(wid, mode, x, y)` and `resize(wid, mode, w, h)`
       + * to choose between relative or absolute coordinates
       + */
       +enum {
       +        ABSOLUTE = 0,
       +        RELATIVE = 1
       +};
       +
       +/*
       + * Initialize the connection to the X server. The connection could then be
       + * accessed by other functions through the "conn" variable.
       + */
       +int init_xcb();
       +
       +/*
       + * Close connection to the X server.
       + */
       +int kill_xcb();
       +
       +/*
       + * Check existence of a window.
       + * + 1 - window exists
       + * + 0 - window doesn't exist
       + */
       +int is_alive(xcb_window_t wid);
       +
       +/*
       + * Returns the value of the "override_redirect" attribute of a window.
       + * When this attribute is set to 1, it means the window manager should NOT
       + * handle this window.
       + */
       +int is_ignored(xcb_window_t wid);
       +
       +/*
       + * Returns 1 if a window match the mask, 0 otherwise.
       + * Possible value for the masks are:
       + *         LIST_HIDDEN
       + *         LIST_IGNORE
       + *         LIST_ALL
       + */
       +int is_listable(xcb_window_t wid, int mask);
       +
       +/*
       + * Returns 1 if the window is mapped on screen, 0 otherwise
       + */
       +int is_mapped(xcb_window_t wid);
       +
       +/*
       + * Get the first screen, and set the `scrn` global variable accordingly.
       + */
       +int get_screen();
       +
       +/*
       + * Ask the list of all existing windows to the X server, and fills the `*list`
       + * argument with them.
       + * The windows are listed in stacking order, from lower to upper window.
       + */
       +int get_windows(xcb_window_t wid, xcb_window_t **list);
       +
       +/*
       + * Retrive the value of an attribute for a specific windows.
       + * The possible values for the attributes are:
       + *         ATTR_W - width
       + *         ATTR_H - height
       + *         ATTR_X - X offset
       + *         ATTR_Y - Y offset
       + *         ATTR_B - border width
       + *         ATTR_M - map state
       + *         ATTR_I - ignore state (override_redirect)
       + */
       +int get_attribute(xcb_window_t wid, int attr);
       +
       +/*
       + * Get the cursor position, and store its coordinates in the `x` and `y`
       + * pointers.
       + * The `mode` attribute isn't used yet, but is reserved to ask for either
       + * absolute or relative coordinates
       + */
       +int get_cursor(int mode, uint32_t wid, int *x, int *y);
       +
       +/*
       + * Set a window's border.
       + * The color should be an hexadecimal number, eg: 0xdeadca7
       + */
       +int set_border(int width, int color, xcb_window_t wid);
       +
       +/*
       + * Give the input focus to the specified window
       + */
       +int set_focus(xcb_window_t wid);
       +
       +/*
       + * Change the cursor position, either relatively or absolutely, eg:
       + *         set_cursor(10, 10, ABSOLUTE);
       + *         set_cursor(-10, 20, RELATIVE);
       + */
       +int set_cursor(int x, int y, int mode);
       +
       +/*
       + * Teleport a window to the given position.
       + */
       +int teleport(xcb_window_t wid, int w, int h, int x, int y);
       +
       +/*
       + * Move a window to the given position, either relatively or absolutely.
       + * If the move is supposed to move the window outside the screen, then the
       + * windows will only be moved to the edge of the screen.
       + *
       + * You cannot move windows outside the screen with this method. Use
       + * `teleport()` instead.
       + */
       +int move(xcb_window_t wid, int mode, int x, int y);
       +
       +/*
       + * Change the mapping state of a window. The `mode` attribute can be as follow:
       + *         MAP
       + *         UNMAP
       + *         TOGGLE
       + */
       +int remap(xcb_window_t wid, int mode);
       +
       +/*
       + * Resize a window to the given size, either relatively or absolutely.
       + * If the resize is supposed to put an area of the window outside the screen,
       + * then the windows will only be resized to the edge of the screen.
       + *
       + * You cannot resize windows farther than the screen edge with this method. Use
       + * `teleport()` instead.
       + */
       +int resize(xcb_window_t wid, int mode, int w, int h);
       +
       +/*
       + * Change the position of the given window in the stack order.
       + * You can either put it at the top, or at the bottom.
       + * The possible values for the mode are:
       + *         XCB_STACK_MODE_ABOVE
       + *         XCB_STACK_MODE_BELOW
       + *         XCB_STACK_MODE_OPPOSITE
       + */
       +int restack(xcb_window_t wid, uint32_t mode);
       +
       +#endif /* __LIBWM_H__ */