libwm

library for X windows manipulations
git clone git://z3bra.org/libwm
Log | Files | Refs | LICENSE

commit 0d6908dc2e053a32979b693284727e3c6fe72922
Author: z3bra <willyatmailoodotorg>
Date:   Sat Nov 14 14:42:02 2015

First commit

Diffstat:
 Makefile  |  30 ++++++-
 config.mk |   7 +-
 libwm.c   | 336 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 wm.h      | 188 +++++++++++++++++++++++++++++++++++-
 4 files changed, 561 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -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) diff --git a/config.mk b/config.mk @@ -0,0 +1,7 @@ +PREFIX = /usr/local + +CC = cc +LD = $(CC) + +CFLAGS = -std=c99 -pedantic -Wall -fPIC -Os +LDFLAGS = -lxcb diff --git a/libwm.c b/libwm.c @@ -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; +} diff --git a/wm.h b/wm.h @@ -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__ */