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__ */