summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaud Fontaine <arnau@debian.org>2009-09-17 12:45:43 +0100
committerArnaud Fontaine <arnau@debian.org>2010-11-14 20:22:27 +0900
commit7343b7d906ecc86da000a48edb1facd145d66641 (patch)
tree6a835e2b783387f8a932e68d77119233f97a1a21
parentc0f6f9a18421f98defb6c1668f65afab894b00b2 (diff)
Add xcb-util/ewmh library
-rw-r--r--Doxyfile1
-rw-r--r--configure.ac7
-rw-r--r--ewmh/Makefile.am25
-rw-r--r--ewmh/atomlist.m483
-rw-r--r--ewmh/ewmh.c.m41534
-rw-r--r--ewmh/xcb-ewmh.pc.in11
-rw-r--r--ewmh/xcb_ewmh.h.m4596
7 files changed, 2256 insertions, 1 deletions
diff --git a/Doxyfile b/Doxyfile
index ffb0602..46a2380 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -486,6 +486,7 @@ WARN_LOGFILE =
INPUT = xcb_util_intro \
event/ \
icccm/ \
+ ewmh/ \
image/ \
property/ \
reply/
diff --git a/configure.ac b/configure.ac
index f827a01..07f9bbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,12 +82,16 @@ XCB_ATOM_CFLAGS='-I$(top_srcdir)/atom -I$(top_builddir)/atom'
XCB_ATOM_LIBS='$(top_builddir)/atom/libxcb-atom.la'
XCB_ICCCM_CFLAGS='-I$(top_srcdir)/icccm'
XCB_ICCCM_LIBS='$(top_builddir)/icccm/libxcb-icccm.la'
+XCB_EWMH_CFLAGS='-I$(top_srcdir)/ewmh'
+XCB_EWMH_LIBS='$(top_builddir)/ewmh/libxcb-ewmh.la'
AC_SUBST(XCB_AUX_CFLAGS)
AC_SUBST(XCB_AUX_LIBS)
AC_SUBST(XCB_ATOM_CFLAGS)
AC_SUBST(XCB_ATOM_LIBS)
AC_SUBST(XCB_ICCCM_CFLAGS)
AC_SUBST(XCB_ICCCM_LIBS)
+AC_SUBST(XCB_EWMH_CFLAGS)
+AC_SUBST(XCB_EWMH_LIBS)
AC_OUTPUT([Makefile
aux/Makefile aux/xcb-aux.pc
@@ -96,6 +100,7 @@ AC_OUTPUT([Makefile
event/Makefile event/xcb-event.pc
keysyms/Makefile keysyms/xcb-keysyms.pc
icccm/Makefile icccm/xcb-icccm.pc
- wm/Makefile wm/xcb-wm.pc
+ ewmh/Makefile ewmh/xcb-ewmh.pc
+ renderutil/Makefile renderutil/xcb-renderutil.pc
xcb_util_intro
])
diff --git a/ewmh/Makefile.am b/ewmh/Makefile.am
new file mode 100644
index 0000000..3e5f739
--- /dev/null
+++ b/ewmh/Makefile.am
@@ -0,0 +1,25 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+lib_LTLIBRARIES = libxcb-ewmh.la
+
+xcbinclude_HEADERS = xcb_ewmh.h
+
+AM_CFLAGS = $(CWARNFLAGS)
+
+libxcb_ewmh_la_SOURCES = ewmh.c ewmh.c.m4 atomlist.m4 xcb_ewmh.h.m4
+libxcb_ewmh_la_CPPFLAGS = $(XCB_CFLAGS) $(XCB_ATOM_CFLAGS) $(XCB_AUX_CFLAGS)
+libxcb_ewmh_la_LIBADD = $(XCB_LIBS) $(XCB_ATOM_LIBS) $(XCB_AUX_LIBS)
+libxcb_ewmh_la_LDFLAGS = -version-info 1:0:0
+
+pkgconfig_DATA = xcb-ewmh.pc
+
+EXTRA_DIST = xcb-ewmh.pc.in
+
+BUILT_SOURCES = ewmh.c xcb_ewmh.h
+CLEANFILES = $(BUILT_SOURCES)
+
+ewmh.c: ewmh.c.m4 atomlist.m4
+ $(M4) -I$(srcdir) $< >$@
+
+xcb_ewmh.h: xcb_ewmh.h.m4 atomlist.m4
+ $(M4) -I$(srcdir) $< >$@
diff --git a/ewmh/atomlist.m4 b/ewmh/atomlist.m4
new file mode 100644
index 0000000..d0af08d
--- /dev/null
+++ b/ewmh/atomlist.m4
@@ -0,0 +1,83 @@
+DO(
+_NET_SUPPORTED,
+_NET_CLIENT_LIST,
+_NET_CLIENT_LIST_STACKING,
+_NET_NUMBER_OF_DESKTOPS,
+_NET_DESKTOP_GEOMETRY,
+_NET_DESKTOP_VIEWPORT,
+_NET_CURRENT_DESKTOP,
+_NET_DESKTOP_NAMES,
+_NET_ACTIVE_WINDOW,
+_NET_WORKAREA,
+_NET_SUPPORTING_WM_CHECK,
+_NET_VIRTUAL_ROOTS,
+_NET_DESKTOP_LAYOUT,
+_NET_SHOWING_DESKTOP,
+_NET_CLOSE_WINDOW,
+_NET_MOVERESIZE_WINDOW,
+_NET_WM_MOVERESIZE,
+_NET_RESTACK_WINDOW,
+_NET_REQUEST_FRAME_EXTENTS,
+_NET_WM_NAME,
+_NET_WM_VISIBLE_NAME,
+_NET_WM_ICON_NAME,
+_NET_WM_VISIBLE_ICON_NAME,
+_NET_WM_DESKTOP,
+_NET_WM_WINDOW_TYPE,
+_NET_WM_STATE,
+_NET_WM_ALLOWED_ACTIONS,
+_NET_WM_STRUT,
+_NET_WM_STRUT_PARTIAL,
+_NET_WM_ICON_GEOMETRY,
+_NET_WM_ICON,
+_NET_WM_PID,
+_NET_WM_HANDLED_ICONS,
+_NET_WM_USER_TIME,
+_NET_WM_USER_TIME_WINDOW,
+_NET_FRAME_EXTENTS,
+_NET_WM_PING,
+_NET_WM_SYNC_REQUEST,
+_NET_WM_FULLSCREEN_MONITORS,
+_NET_WM_FULL_PLACEMENT,
+UTF8_STRING,
+WM_PROTOCOLS,
+MANAGER,
+_NET_WM_CM_Sn,
+_NET_WM_WINDOW_TYPE_DESKTOP,
+_NET_WM_WINDOW_TYPE_DOCK,
+_NET_WM_WINDOW_TYPE_TOOLBAR,
+_NET_WM_WINDOW_TYPE_MENU,
+_NET_WM_WINDOW_TYPE_UTILITY,
+_NET_WM_WINDOW_TYPE_SPLASH,
+_NET_WM_WINDOW_TYPE_DIALOG,
+_NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
+_NET_WM_WINDOW_TYPE_POPUP_MENU,
+_NET_WM_WINDOW_TYPE_TOOLTIP,
+_NET_WM_WINDOW_TYPE_NOTIFICATION,
+_NET_WM_WINDOW_TYPE_COMBO,
+_NET_WM_WINDOW_TYPE_DND,
+_NET_WM_WINDOW_TYPE_NORMAL,
+_NET_WM_STATE_MODAL,
+_NET_WM_STATE_STICKY,
+_NET_WM_STATE_MAXIMIZED_VERT,
+_NET_WM_STATE_MAXIMIZED_HORZ,
+_NET_WM_STATE_SHADED,
+_NET_WM_STATE_SKIP_TASKBAR,
+_NET_WM_STATE_SKIP_PAGER,
+_NET_WM_STATE_HIDDEN,
+_NET_WM_STATE_FULLSCREEN,
+_NET_WM_STATE_ABOVE,
+_NET_WM_STATE_BELOW,
+_NET_WM_STATE_DEMANDS_ATTENTION,
+_NET_WM_ACTION_MOVE,
+_NET_WM_ACTION_RESIZE,
+_NET_WM_ACTION_MINIMIZE,
+_NET_WM_ACTION_SHADE,
+_NET_WM_ACTION_STICK,
+_NET_WM_ACTION_MAXIMIZE_HORZ,
+_NET_WM_ACTION_MAXIMIZE_VERT,
+_NET_WM_ACTION_FULLSCREEN,
+_NET_WM_ACTION_CHANGE_DESKTOP,
+_NET_WM_ACTION_CLOSE,
+_NET_WM_ACTION_ABOVE,
+_NET_WM_ACTION_BELOW)
diff --git a/ewmh/ewmh.c.m4 b/ewmh/ewmh.c.m4
new file mode 100644
index 0000000..1b293c5
--- /dev/null
+++ b/ewmh/ewmh.c.m4
@@ -0,0 +1,1534 @@
+/*
+ * Copyright © 2009 Arnaud Fontaine <arnau@debian.org>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the authors or
+ * their institutions shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without
+ * prior written authorization from the authors.
+ */
+
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "xcb_ewmh.h"
+#include "xcb_atom.h"
+#include "xcb_aux.h"
+#include "../xcb-util-common.h"
+
+/** Store the root window as it won't change */
+static xcb_window_t root_window;
+
+#define ROOT_WINDOW_MESSAGE_EVENT_MASK (XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |\
+ XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT)
+
+define(`DO', `ifelse(`$1', , , `xcb_atom_t $1;
+DO(shift($@))')')dnl
+include(atomlist.m4)dnl
+
+/**
+ * @brief The structure used on initialization
+ */
+typedef struct {
+ /** Pointer to the Atom declared above */
+ xcb_atom_t *value;
+ /** The InternAtom request cookie */
+ xcb_intern_atom_cookie_t cookie;
+ /** The Atom name length */
+ uint8_t name_len;
+ /** The Atom name string */
+ char *name;
+} ewmh_atom_t;
+
+define(`DO_ENTRY', `
+ { &$1, { 0 }, sizeof("$1") - 1, "$1" }ifelse(`$2', , , `,')')dnl
+
+define(`DO', `DO_ENTRY(`$1', `$2')ifelse(`$2', , , `DO(shift($@))')')dnl
+
+static ewmh_atom_t ewmh_atoms_list[] = {dnl
+ include(atomlist.m4)dnl
+};
+
+#define NB_EWMH_ATOMS countof(ewmh_atoms_list)
+
+#define GET_NB_FROM_LEN(len, shift_value) ((len) >> (shift_value))
+#define GET_LEN_FROM_NB(nb, shift_value) ((len) << (shift_value))
+
+/**
+ * Common functions and macro
+ */
+
+#define DO_GET_PROPERTY(atom, name, request_type, length) \
+ xcb_get_property_cookie_t \
+ xcb_ewmh_get_##name(xcb_connection_t *c, \
+ xcb_window_t window) \
+ { \
+ return xcb_get_property(c, 0, window, atom, request_type, 0, \
+ length); \
+ } \
+ \
+ xcb_get_property_cookie_t \
+ xcb_ewmh_get_##name##_unchecked(xcb_connection_t *c, \
+ xcb_window_t window) \
+ { \
+ return xcb_get_property_unchecked(c, 0, window, atom, \
+ request_type, 0, length); \
+ }
+
+#define DO_GET_ROOT_PROPERTY(atom, name, request_type, length) \
+ xcb_get_property_cookie_t \
+ xcb_ewmh_get_##name(xcb_connection_t *c) \
+ { \
+ return xcb_get_property(c, 0, root_window, atom, request_type, 0, \
+ length); \
+ } \
+ \
+ xcb_get_property_cookie_t \
+ xcb_ewmh_get_##name##_unchecked(xcb_connection_t *c) \
+ { \
+ return xcb_get_property_unchecked(c, 0, root_window, atom, \
+ request_type, 0, length); \
+ }
+
+/**
+ * Generic function for EWMH atoms with a single value which may
+ * actually be either WINDOW or CARDINAL
+ *
+ * _NET_NUMBER_OF_DESKTOPS, CARDINAL/32
+ * _NET_CURRENT_DESKTOP desktop, CARDINAL/32
+ * _NET_ACTIVE_WINDOW, WINDOW/32
+ * _NET_SUPPORTING_WM_CHECK, WINDOW/32
+ * _NET_SHOWING_DESKTOP desktop, CARDINAL/32
+ * _NET_WM_DESKTOP desktop, CARDINAL/32
+ * _NET_WM_PID CARDINAL/32
+ * _NET_WM_USER_TIME CARDINAL/32
+ * _NET_WM_USER_TIME_WINDOW WINDOW/32
+ */
+
+/**
+ * Macro defining function for set_property and get_property functions
+ */
+#define DO_SET_SINGLE_VALUE_PROPERTY(atom, name, name_type, request_type) \
+ void \
+ xcb_ewmh_set_##name##_checked(xcb_connection_t *c, \
+ xcb_window_t window, \
+ name_type value) \
+ { \
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window, atom, \
+ request_type, 32, 1, &value); \
+ } \
+ \
+ void \
+ xcb_ewmh_set_##name(xcb_connection_t *c, \
+ xcb_window_t window, \
+ name_type value) \
+ { \
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, atom, \
+ request_type, 32, 1, &value); \
+ }
+
+#define DO_SET_ROOT_SINGLE_VALUE_PROPERTY(atom, name, name_type, request_type) \
+ void \
+ xcb_ewmh_set_##name##_checked(xcb_connection_t *c, \
+ name_type value) \
+ { \
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root_window, atom, \
+ request_type, 32, 1, &value); \
+ } \
+ \
+ void \
+ xcb_ewmh_set_##name(xcb_connection_t *c, \
+ name_type value) \
+ { \
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root_window, atom, \
+ request_type, 32, 1, &value); \
+ }
+
+/**
+ * Macro defining a generic function for reply containing a single
+ * value
+ */
+#define DO_REPLY_SINGLE_VALUE_ATOM(name, name_type, reply_type) \
+ static uint8_t \
+ get_single_##name##_from_reply(name_type *atom_value, \
+ xcb_get_property_reply_t *r) \
+ { \
+ if(!r || r->type != reply_type || r->format != 32 || \
+ xcb_get_property_value_length(r) != 4) \
+ return 0; \
+ \
+ *atom_value = *((name_type *) xcb_get_property_value(r)); \
+ return 1; \
+ } \
+ \
+ static uint8_t \
+ get_single_##name##_reply(xcb_connection_t *c, \
+ xcb_get_property_cookie_t cookie, \
+ name_type *atom_value, \
+ xcb_generic_error_t **e) \
+ { \
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e); \
+ const uint8_t ret = get_single_##name##_from_reply(atom_value, r); \
+ free(r); \
+ return ret; \
+ }
+
+DO_REPLY_SINGLE_VALUE_ATOM(window, xcb_window_t, WINDOW)
+DO_REPLY_SINGLE_VALUE_ATOM(cardinal, uint32_t, CARDINAL)
+
+#define DO_ACCESSORS_SINGLE_VALUE_ATOM(atom, name, reply_type, out_type, func_reply) \
+ DO_GET_PROPERTY(atom, name, reply_type, 1L) \
+ DO_SET_SINGLE_VALUE_PROPERTY(atom, name, out_type, reply_type) \
+ DO_ACCESSORS_GET_SINGLE_VALUE_ATOM(atom, name, reply_type, out_type, func_reply)
+
+#define DO_ACCESSORS_ROOT_SINGLE_VALUE_ATOM(atom, name, reply_type, out_type, func_reply) \
+ DO_GET_ROOT_PROPERTY(atom, name, reply_type, 1L) \
+ DO_SET_ROOT_SINGLE_VALUE_PROPERTY(atom, name, out_type, reply_type) \
+ DO_ACCESSORS_GET_SINGLE_VALUE_ATOM(atom, name, reply_type, out_type, func_reply)
+
+#define DO_ACCESSORS_GET_SINGLE_VALUE_ATOM(atom, name, reply_type, out_type, func_reply) \
+ uint8_t \
+ xcb_ewmh_get_##name##_from_reply(out_type *out, \
+ xcb_get_property_reply_t *r) \
+ { \
+ return get_single_##func_reply##_from_reply(out, r); \
+ } \
+ \
+ uint8_t \
+ xcb_ewmh_get_##name##_reply(xcb_connection_t *c, \
+ xcb_get_property_cookie_t cookie, \
+ out_type *out, \
+ xcb_generic_error_t **e) \
+ { \
+ return get_single_##func_reply##_reply(c, cookie, out, e); \
+ }
+
+/**
+ * Generic function for EWMH atoms with a list of values which may be
+ * actually WINDOW or ATOM.
+ *
+ * _NET_SUPPORTED, ATOM[]/32
+ * _NET_CLIENT_LIST, WINDOW[]/32
+ * _NET_CLIENT_LIST_STACKING, WINDOW[]/32
+ * _NET_VIRTUAL_ROOTS, WINDOW[]/32
+ * _NET_WM_WINDOW_TYPE, ATOM[]/32
+ * _NET_WM_ALLOWED_ACTIONS, ATOM[]
+ */
+
+#define DO_SET_LIST_VALUES_PROPERTY(atom, name, name_type, request_type, len_shift) \
+ void \
+ xcb_ewmh_set_##name##_checked(xcb_connection_t *c, \
+ xcb_window_t window, \
+ uint32_t list_len, \
+ name_type *list) \
+ { \
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window, \
+ atom, request_type, 32, \
+ GET_LEN_FROM_NB(list_len, len_shift), list); \
+ } \
+ \
+ void \
+ xcb_ewmh_set_##name(xcb_connection_t *c, \
+ xcb_window_t window, \
+ uint32_t list_len, \
+ name_type *list) \
+ { \
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, atom, \
+ request_type, 32, \
+ GET_LEN_FROM_NB(list_len, len_shift), \
+ list); \
+ }
+
+#define DO_SET_ROOT_LIST_VALUES_PROPERTY(atom, name, name_type, request_type, len_shift) \
+ void \
+ xcb_ewmh_set_##name##_checked(xcb_connection_t *c, \
+ uint32_t list_len, \
+ name_type *list) \
+ { \
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root_window, \
+ atom, request_type, 32, \
+ GET_LEN_FROM_NB(list_len, len_shift), \
+ list); \
+ } \
+ \
+ void \
+ xcb_ewmh_set_##name(xcb_connection_t *c, \
+ uint32_t list_len, \
+ name_type *list) \
+ { \
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root_window, atom, \
+ request_type, 32, \
+ GET_LEN_FROM_NB(list_len, len_shift), \
+ list); \
+ }
+
+/**
+ * Macro defining a generic function for reply containing a list of
+ * values and also defines a function to wipe the reply.
+ *
+ * The length is right-shifted by (len_shift + 2) respectively to get
+ * the actual length of a list values from a value made from multiple
+ * component (such as coordinates), and divide by (r->format / 8)
+ * where r->format always equals to 32 in this case.
+ */
+#define DO_REPLY_LIST_VALUES_ATOM(visibility, name, name_type, reply_type, len_shift) \
+ visibility uint8_t \
+ xcb_ewmh_get_##name##_from_reply(xcb_ewmh_get_##name##_reply_t *data, \
+ xcb_get_property_reply_t *r) \
+ { \
+ if(!r || r->type != reply_type || r->format != 32) \
+ return 0; \
+ \
+ data->_reply = r; \
+ data->name##_len = GET_NB_FROM_LEN(xcb_get_property_value_length(data->_reply), len_shift + 2); \
+ data->name = (name_type *) xcb_get_property_value(data->_reply); \
+ return 1; \
+ } \
+ \
+ visibility uint8_t \
+ xcb_ewmh_get_##name##_reply(xcb_connection_t *c, \
+ xcb_get_property_cookie_t cookie, \
+ xcb_ewmh_get_##name##_reply_t *data, \
+ xcb_generic_error_t **e) \
+ { \
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e); \
+ const uint8_t ret = xcb_ewmh_get_##name##_from_reply(data, r); \
+ \
+ /* If the last call was not successful (ret equals to 0), then \
+ just free the reply as the data value is not consistent */ \
+ if(!ret) \
+ free(r); \
+ \
+ return ret; \
+ } \
+ \
+ void \
+ xcb_ewmh_get_##name##_reply_wipe(xcb_ewmh_get_##name##_reply_t *data) \
+ { \
+ free(data->_reply); \
+ }
+
+DO_REPLY_LIST_VALUES_ATOM(static, windows, xcb_window_t, WINDOW, 0)
+DO_REPLY_LIST_VALUES_ATOM(static, atoms, xcb_atom_t, ATOM, 0)
+
+/**
+ * UTF8_STRING handling
+ */
+
+static uint8_t
+get_utf8_from_reply(xcb_ewmh_get_utf8_strings_reply_t *data,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != UTF8_STRING || r->format != 8)
+ return 0;
+
+ data->_reply = r;
+ data->strings_len = xcb_get_property_value_length(data->_reply);
+ data->strings = (char *) xcb_get_property_value(data->_reply);
+
+ return 1;
+}
+
+static uint8_t
+get_utf8_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_utf8_strings_reply_t *data,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = get_utf8_from_reply(data, r);
+
+ /* If the last call was not successful (ret equals to 0), then just
+ free the reply as the data value is not consistent */
+ if(!ret)
+ free(r);
+
+ return ret;
+}
+
+void
+xcb_ewmh_get_utf8_strings_reply_wipe(xcb_ewmh_get_utf8_strings_reply_t *data)
+{
+ free(data->_reply);
+}
+
+#define DO_ACCESSORS_COMMON_UTF8_STRING(atom, name) \
+ uint8_t \
+ xcb_ewmh_get_##name##_from_reply(xcb_ewmh_get_utf8_strings_reply_t *data, \
+ xcb_get_property_reply_t *r) \
+ { \
+ return get_utf8_from_reply(data, r); \
+ } \
+ \
+ uint8_t \
+ xcb_ewmh_get_##name##_reply(xcb_connection_t *c, \
+ xcb_get_property_cookie_t cookie, \
+ xcb_ewmh_get_utf8_strings_reply_t *data, \
+ xcb_generic_error_t **e) \
+ { \
+ return get_utf8_reply(c, cookie, data, e); \
+ }
+
+#define DO_ACCESSORS_ROOT_UTF8_STRING(atom, name) \
+ DO_GET_ROOT_PROPERTY(atom, name, 0, UINT_MAX) \
+ DO_ACCESSORS_COMMON_UTF8_STRING(atom, name) \
+ \
+ void \
+ xcb_ewmh_set_##name(xcb_connection_t *c, \
+ uint32_t strings_len, \
+ const char *strings) \
+ { \
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root_window, atom, \
+ UTF8_STRING, 8, strings_len, strings); \
+ } \
+ \
+ void \
+ xcb_ewmh_set_##name##_checked(xcb_connection_t *c, \
+ uint32_t strings_len, \
+ const char *strings) \
+ { \
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root_window, atom, \
+ UTF8_STRING, 8, strings_len, strings); \
+ }
+
+#define DO_ACCESSORS_UTF8_STRING(atom, name) \
+ DO_GET_PROPERTY(atom, name, 0, UINT_MAX) \
+ DO_ACCESSORS_COMMON_UTF8_STRING(atom, name) \
+ \
+ void \
+ xcb_ewmh_set_##name(xcb_connection_t *c, \
+ xcb_window_t window, \
+ uint32_t strings_len, \
+ const char *strings) \
+ { \
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, atom, \
+ UTF8_STRING, 8, strings_len, strings); \
+ } \
+ \
+ void \
+ xcb_ewmh_set_##name##_checked(xcb_connection_t *c, \
+ xcb_window_t window, \
+ uint32_t strings_len, \
+ const char *strings) \
+ { \
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window, atom, \
+ UTF8_STRING, 8, strings_len, strings); \
+ }
+
+/**
+ * ClientMessage generic function
+ */
+void
+send_client_message(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_window_t dest,
+ xcb_atom_t atom,
+ uint32_t data_len,
+ const uint32_t *data)
+{
+ xcb_client_message_event_t ev;
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.window = window;
+ ev.format = 32;
+ ev.type = atom;
+
+ for(; data_len != 0; data_len--)
+ ev.data.data32[0] = data[1];
+
+ xcb_send_event(c, 0, dest, ROOT_WINDOW_MESSAGE_EVENT_MASK,
+ (char *) &ev);
+}
+
+/**
+ * Atoms initialisation
+ */
+
+void
+xcb_ewmh_init_atoms_list(xcb_connection_t *c,
+ const int screen_nbr)
+{
+ xcb_screen_t *screen = xcb_aux_get_screen(c, screen_nbr);
+ if(!screen)
+ return;
+
+ /* Compute _NET_WM_CM_Sn according to the screen number 'n' */
+ char wm_cm_sn[32];
+ const int wm_cm_sn_len = snprintf(wm_cm_sn, 32, "_NET_WM_CM_S%d",
+ screen_nbr);
+
+ assert(wm_cm_sn_len > 0 && wm_cm_sn_len < 32);
+
+ root_window = screen->root;
+
+ uint8_t i;
+ for(i = 0; i < NB_EWMH_ATOMS; i++)
+ {
+ if(ewmh_atoms_list[i].value == &_NET_WM_CM_Sn)
+ ewmh_atoms_list[i].cookie = xcb_intern_atom(c, 0,
+ wm_cm_sn_len,
+ wm_cm_sn);
+ else
+ ewmh_atoms_list[i].cookie = xcb_intern_atom(c, 0,
+ ewmh_atoms_list[i].name_len,
+ ewmh_atoms_list[i].name);
+ }
+}
+
+uint8_t
+xcb_ewmh_init_atoms_list_replies(xcb_connection_t *c,
+ xcb_generic_error_t **e)
+{
+ uint8_t i;
+ xcb_intern_atom_reply_t *reply;
+ for(i = 0; i < NB_EWMH_ATOMS; i++)
+ {
+ if((reply = xcb_intern_atom_reply(c, ewmh_atoms_list[i].cookie, e)) == NULL)
+ return 0;
+
+ *(ewmh_atoms_list[i].value) = reply->atom;
+ free(reply);
+ }
+
+ return 1;
+}
+
+/**
+ * _NET_SUPPORTED
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_SUPPORTED, supported, ATOM, UINT_MAX)
+DO_SET_ROOT_LIST_VALUES_PROPERTY(_NET_SUPPORTED, supported, xcb_atom_t, ATOM, 0)
+
+uint8_t
+xcb_ewmh_get_supported_from_reply(xcb_ewmh_get_atoms_reply_t *supported,
+ xcb_get_property_reply_t *r)
+{
+ return xcb_ewmh_get_atoms_from_reply(supported, r);
+}
+
+uint8_t
+xcb_ewmh_get_supported_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_atoms_reply_t *supported,
+ xcb_generic_error_t **e)
+{
+ return xcb_ewmh_get_atoms_reply(c, cookie, supported, e);
+}
+
+/**
+ * _NET_CLIENT_LIST
+ * _NET_CLIENT_LIST_STACKING
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_CLIENT_LIST, client_list, WINDOW, UINT_MAX)
+DO_SET_ROOT_LIST_VALUES_PROPERTY(_NET_CLIENT_LIST, client_list, xcb_window_t,
+ WINDOW, 0)
+
+DO_GET_ROOT_PROPERTY(_NET_CLIENT_LIST_STACKING, client_list_stacking, WINDOW, UINT_MAX)
+DO_SET_ROOT_LIST_VALUES_PROPERTY(_NET_CLIENT_LIST_STACKING, client_list_stacking,
+ xcb_window_t, WINDOW, 0)
+
+uint8_t
+xcb_ewmh_get_client_list_from_reply(xcb_ewmh_get_windows_reply_t *clients,
+ xcb_get_property_reply_t *r)
+{
+ return xcb_ewmh_get_windows_from_reply(clients, r);
+}
+
+uint8_t
+xcb_ewmh_get_client_list_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_windows_reply_t *clients,
+ xcb_generic_error_t **e)
+{
+ return xcb_ewmh_get_windows_reply(c, cookie, clients, e);
+}
+
+/**
+ * _NET_NUMBER_OF_DESKTOPS
+ */
+
+DO_ACCESSORS_ROOT_SINGLE_VALUE_ATOM(_NET_NUMBER_OF_DESKTOPS, number_of_desktops,
+ CARDINAL, uint32_t, cardinal)
+
+void
+xcb_ewmh_request_change_number_of_desktops(xcb_connection_t *c,
+ uint32_t new_number_of_desktops)
+{
+ send_client_message(c, XCB_NONE, root_window, _NET_NUMBER_OF_DESKTOPS, 1,
+ &new_number_of_desktops);
+}
+
+/**
+ * _NET_DESKTOP_GEOMETRY
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_DESKTOP_GEOMETRY, desktop_geometry, CARDINAL, 2L)
+
+void
+xcb_ewmh_set_desktop_geometry(xcb_connection_t *c,
+ uint32_t new_width, uint32_t new_height)
+{
+ const uint32_t data[] = { new_width, new_height };
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root_window,
+ _NET_DESKTOP_GEOMETRY, CARDINAL, 32, 2, data);
+}
+
+void
+xcb_ewmh_set_desktop_geometry_checked(xcb_connection_t *c,
+ uint32_t new_width, uint32_t new_height)
+{
+ const uint32_t data[] = { new_width, new_height };
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root_window,
+ _NET_DESKTOP_GEOMETRY, CARDINAL, 32, 2, data);
+}
+
+void
+xcb_ewmh_request_change_desktop_geometry(xcb_connection_t *c,
+ uint32_t new_width, uint32_t new_height)
+{
+ const uint32_t data[] = { new_width, new_height };
+ send_client_message(c, XCB_NONE, root_window, _NET_DESKTOP_GEOMETRY, 2, data);
+}
+
+uint8_t
+xcb_ewmh_get_desktop_geometry_from_reply(uint32_t *width, uint32_t *height,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ xcb_get_property_value_length(r) != 8)
+ return 0;
+
+ uint32_t *value = (uint32_t *) xcb_get_property_value(r);
+
+ *width = value[0];
+ *height = value[1];
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_desktop_geometry_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ uint32_t *width, uint32_t *height,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_desktop_geometry_from_reply(width, height, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_DESKTOP_VIEWPORT
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_DESKTOP_VIEWPORT, desktop_viewport, CARDINAL, UINT_MAX)
+DO_SET_ROOT_LIST_VALUES_PROPERTY(_NET_DESKTOP_VIEWPORT, desktop_viewport,
+ xcb_ewmh_coordinates_t, CARDINAL, 1)
+
+void
+xcb_ewmh_request_change_desktop_viewport(xcb_connection_t *c,
+ uint32_t x, uint32_t y)
+{
+ const uint32_t data[] = { x, y };
+ send_client_message(c, XCB_NONE, root_window, _NET_DESKTOP_VIEWPORT, 2, data);
+}
+
+DO_REPLY_LIST_VALUES_ATOM(extern, desktop_viewport, xcb_ewmh_coordinates_t, CARDINAL, 1)
+
+/**
+ * _NET_CURRENT_DESKTOP
+ */
+
+DO_ACCESSORS_ROOT_SINGLE_VALUE_ATOM(_NET_CURRENT_DESKTOP, current_desktop,
+ CARDINAL, uint32_t, cardinal)
+
+void
+xcb_ewmh_request_change_current_desktop(xcb_connection_t *c,
+ uint32_t new_desktop,
+ xcb_timestamp_t timestamp)
+{
+ const uint32_t data[] = { new_desktop, timestamp };
+ send_client_message(c, XCB_NONE, root_window, _NET_CURRENT_DESKTOP, 2, data);
+}
+
+/**
+ * _NET_DESKTOP_NAMES
+ */
+DO_ACCESSORS_ROOT_UTF8_STRING(_NET_DESKTOP_NAMES, desktop_names)
+
+/**
+ * _NET_ACTIVE_WINDOW
+ */
+
+DO_ACCESSORS_ROOT_SINGLE_VALUE_ATOM(_NET_ACTIVE_WINDOW, active_window,
+ WINDOW, xcb_window_t, window)
+
+void
+xcb_ewmh_request_change_active_window(xcb_connection_t *c,
+ xcb_window_t window_to_activate,
+ xcb_ewmh_client_source_type_t source_indication,
+ xcb_timestamp_t timestamp,
+ xcb_window_t current_active_window)
+{
+ const uint32_t data[] = { source_indication, timestamp, current_active_window };
+ send_client_message(c, window_to_activate, root_window, _NET_ACTIVE_WINDOW, 3,
+ data);
+}
+
+/**
+ * _NET_WORKAREA
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_WORKAREA, workarea, CARDINAL, UINT_MAX)
+DO_SET_ROOT_LIST_VALUES_PROPERTY(_NET_WORKAREA, workarea, xcb_ewmh_geometry_t, CARDINAL, 2)
+DO_REPLY_LIST_VALUES_ATOM(extern, workarea, xcb_ewmh_geometry_t, CARDINAL, 2)
+
+/**
+ * _NET_SUPPORTING_WM_CHECK
+ */
+
+DO_ACCESSORS_ROOT_SINGLE_VALUE_ATOM(_NET_SUPPORTING_WM_CHECK, supporting_wm_check,
+ WINDOW, xcb_window_t, window)
+
+/**
+ * _NET_VIRTUAL_ROOTS
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_VIRTUAL_ROOTS, virtual_roots, WINDOW, UINT_MAX)
+DO_SET_LIST_VALUES_PROPERTY(_NET_VIRTUAL_ROOTS, virtual_roots, xcb_window_t, WINDOW, 0)
+
+uint8_t
+xcb_ewmh_get_virtual_roots_from_reply(xcb_ewmh_get_windows_reply_t *virtual_roots,
+ xcb_get_property_reply_t *r)
+{
+ return xcb_ewmh_get_windows_from_reply(virtual_roots, r);
+}
+
+uint8_t
+xcb_ewmh_get_virtual_roots_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_windows_reply_t *virtual_roots,
+ xcb_generic_error_t **e)
+{
+ return xcb_ewmh_get_windows_reply(c, cookie, virtual_roots, e);
+}
+
+/**
+ * _NET_DESKTOP_LAYOUT
+ */
+
+DO_GET_ROOT_PROPERTY(_NET_DESKTOP_LAYOUT, desktop_layout, CARDINAL, 4)
+
+void
+xcb_ewmh_set_desktop_layout(xcb_connection_t *c,
+ xcb_ewmh_desktop_layout_orientation_t orientation,
+ uint32_t columns, uint32_t rows,
+ xcb_ewmh_desktop_layout_starting_corner_t starting_corner)
+{
+ const uint32_t data[] = { orientation, columns, rows, starting_corner };
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, root_window,
+ _NET_DESKTOP_LAYOUT, CARDINAL, 32, 2, data);
+}
+
+void
+xcb_ewmh_set_desktop_layout_checked(xcb_connection_t *c,
+ xcb_ewmh_desktop_layout_orientation_t orientation,
+ uint32_t columns, uint32_t rows,
+ xcb_ewmh_desktop_layout_starting_corner_t starting_corner)
+{
+ const uint32_t data[] = { orientation, columns, rows, starting_corner };
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, root_window,
+ _NET_DESKTOP_LAYOUT, CARDINAL, 32, 2, data);
+}
+
+uint8_t
+xcb_ewmh_get_desktop_layout_from_reply(xcb_ewmh_get_desktop_layout_reply_t *desktop_layout,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) != 4)
+ return 0;
+
+ memcpy(desktop_layout, xcb_get_property_value(r),
+ xcb_get_property_value_length(r));
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_desktop_layout_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_desktop_layout_reply_t *desktop_layout,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_desktop_layout_from_reply(desktop_layout, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_SHOWING_DESKTOP
+ */
+
+DO_ACCESSORS_ROOT_SINGLE_VALUE_ATOM(_NET_SHOWING_DESKTOP, showing_desktop, CARDINAL,
+ uint32_t, cardinal)
+
+void
+xcb_ewmh_request_change_showing_desktop(xcb_connection_t *c,
+ uint32_t enter)
+{
+ send_client_message(c, XCB_NONE, root_window, _NET_SHOWING_DESKTOP, 1,
+ &enter);
+}
+
+/**
+ * _NET_CLOSE_WINDOW
+ */
+
+void
+xcb_ewmh_request_close_window(xcb_connection_t *c,
+ xcb_window_t window_to_close,
+ xcb_timestamp_t timestamp,
+ xcb_ewmh_client_source_type_t source_indication)
+{
+ const uint32_t data[] = { timestamp, source_indication };
+ send_client_message(c, window_to_close, root_window, _NET_CLOSE_WINDOW, 2,
+ data);
+}
+
+/**
+ * _NET_MOVERESIZE_WINDOW
+ */
+
+/* x, y, width, height may be equal to -1 */
+void
+xcb_ewmh_request_moveresize_window(xcb_connection_t *c,
+ xcb_window_t moveresize_window,
+ xcb_gravity_t gravity,
+ xcb_ewmh_client_source_type_t source_indication,
+ xcb_ewmh_moveresize_window_opt_flags_t flags,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ const uint32_t data[] = { (gravity | flags | GET_LEN_FROM_NB(source_indication, 12)),
+ x, y, width, height };
+
+ send_client_message(c, moveresize_window, root_window, _NET_MOVERESIZE_WINDOW,
+ 5, data);
+}
+
+/**
+ * _NET_WM_MOVERESIZE
+ */
+
+void
+xcb_ewmh_request_wm_moveresize(xcb_connection_t *c,
+ xcb_window_t moveresize_window,
+ uint32_t x_root, uint32_t y_root,
+ xcb_ewmh_moveresize_direction_t direction,
+ xcb_button_index_t button,
+ xcb_ewmh_client_source_type_t source_indication)
+{
+ const uint32_t data[] = { x_root, y_root, direction, button, source_indication };
+
+ send_client_message(c, moveresize_window, root_window, _NET_WM_MOVERESIZE, 5,
+ data);
+}
+
+/**
+ * _NET_RESTACK_WINDOW
+ */
+
+void
+xcb_ewmh_request_restack_window(xcb_connection_t *c,
+ xcb_window_t window_to_restack,
+ xcb_window_t sibling_window,
+ xcb_stack_mode_t detail)
+{
+ const uint32_t data[] = { XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER, sibling_window,
+ detail };
+
+ send_client_message(c, window_to_restack, root_window, _NET_RESTACK_WINDOW, 3,
+ data);
+}
+
+void
+xcb_ewmh_request_frame_extents(xcb_connection_t *c,
+ xcb_window_t client_window)
+{
+ send_client_message(c, client_window, root_window, _NET_REQUEST_FRAME_EXTENTS,
+ 0, NULL);
+}
+
+/**
+ * _NET_WM_NAME
+ */
+
+DO_ACCESSORS_UTF8_STRING(_NET_WM_NAME, wm_name)
+
+/**
+ * _NET_WM_VISIBLE_NAME
+ */
+
+DO_ACCESSORS_UTF8_STRING(_NET_WM_VISIBLE_NAME, wm_visible_name)
+
+/**
+ * _NET_WM_ICON_NAME
+ */
+
+DO_ACCESSORS_UTF8_STRING(_NET_WM_ICON_NAME, wm_icon_name)
+
+/**
+ * _NET_WM_VISIBLE_ICON_NAME
+ */
+
+DO_ACCESSORS_UTF8_STRING(_NET_WM_VISIBLE_ICON_NAME, wm_visible_icon_name)
+
+/**
+ * _NET_WM_DESKTOP
+ */
+
+DO_ACCESSORS_SINGLE_VALUE_ATOM(_NET_WM_DESKTOP, wm_desktop, CARDINAL, uint32_t, cardinal)
+
+void
+xcb_ewmh_request_change_wm_desktop(xcb_connection_t *c,
+ xcb_window_t client_window,
+ uint32_t new_desktop,
+ xcb_ewmh_client_source_type_t source_indication)
+{
+ const uint32_t data[] = { new_desktop, source_indication };
+
+ send_client_message(c, client_window, root_window, _NET_WM_DESKTOP, 2, data);
+}
+
+/**
+ * _NET_WM_WINDOW_TYPE
+ *
+ * TODO: check possible atoms?
+ */
+
+DO_GET_PROPERTY(_NET_WM_WINDOW_TYPE, wm_window_type, ATOM, UINT_MAX)
+DO_SET_LIST_VALUES_PROPERTY(_NET_WM_WINDOW_TYPE, wm_window_type, xcb_atom_t, ATOM, 0)
+
+uint8_t
+xcb_ewmh_get_wm_window_type_from_reply(xcb_ewmh_get_atoms_reply_t *window_types,
+ xcb_get_property_reply_t *r)
+{
+ return xcb_ewmh_get_atoms_from_reply(window_types, r);
+}
+
+uint8_t
+xcb_ewmh_get_wm_window_type_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_atoms_reply_t *window_types,
+ xcb_generic_error_t **e)
+{
+ return xcb_ewmh_get_atoms_reply(c, cookie, window_types, e);
+}
+
+/**
+ * _NET_WM_STATE
+ *
+ * TODO: check possible atoms?
+ */
+
+DO_GET_PROPERTY(_NET_WM_STATE, wm_state, ATOM, UINT_MAX)
+DO_SET_LIST_VALUES_PROPERTY(_NET_WM_STATE, wm_state, xcb_atom_t, ATOM, 0)
+
+void
+xcb_ewmh_request_change_wm_state(xcb_connection_t *c,
+ xcb_window_t client_window,
+ xcb_ewmh_wm_state_action_t action,
+ xcb_atom_t first_property,
+ xcb_atom_t second_property,
+ xcb_ewmh_client_source_type_t source_indication)
+{
+ const uint32_t data[] = { action, first_property, second_property, source_indication };
+
+ send_client_message(c, client_window, root_window, _NET_WM_STATE, 4, data);
+}
+
+uint8_t
+xcb_ewmh_get_wm_state_from_reply(xcb_ewmh_get_atoms_reply_t *wm_states,
+ xcb_get_property_reply_t *r)
+{
+ return xcb_ewmh_get_atoms_from_reply(wm_states, r);
+}
+
+uint8_t
+xcb_ewmh_get_wm_state_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_atoms_reply_t *wm_states,
+ xcb_generic_error_t **e)
+{
+ return xcb_ewmh_get_atoms_reply(c, cookie, wm_states, e);
+}
+
+/**
+ * _NET_WM_ALLOWED_ACTIONS
+ *
+ * TODO: check possible atoms?
+ */
+
+DO_GET_PROPERTY(_NET_WM_ALLOWED_ACTIONS, wm_allowed_actions, ATOM, UINT_MAX)
+DO_SET_LIST_VALUES_PROPERTY(_NET_WM_ALLOWED_ACTIONS, wm_allowed_actions, xcb_atom_t, ATOM, 0)
+
+uint8_t
+xcb_ewmh_get_wm_allowed_actions_from_reply(xcb_ewmh_get_atoms_reply_t *wm_allowed_actions,
+ xcb_get_property_reply_t *r)
+{
+ return xcb_ewmh_get_atoms_from_reply(wm_allowed_actions, r);
+}
+
+uint8_t
+xcb_ewmh_get_wm_allowed_actions_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_atoms_reply_t *wm_allowed_actions,
+ xcb_generic_error_t **e)
+{
+ return xcb_ewmh_get_atoms_reply(c, cookie, wm_allowed_actions, e);
+}
+
+/**
+ * _NET_WM_STRUT
+ * _NET_WM_STRUT_PARTIAL
+ */
+
+DO_GET_PROPERTY(_NET_WM_STRUT, wm_strut, CARDINAL, 12)
+
+void
+xcb_ewmh_set_wm_strut_checked(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_ewmh_wm_strut_t wm_strut)
+{
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window, _NET_WM_STRUT,
+ CARDINAL, 32, 12, &wm_strut);
+}
+
+void
+xcb_ewmh_set_wm_strut(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_ewmh_wm_strut_t wm_strut)
+{
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, _NET_WM_STRUT, CARDINAL,
+ 32, 12, &wm_strut);
+}
+
+uint8_t
+xcb_ewmh_get_wm_strut_from_reply(xcb_ewmh_wm_strut_t *wm_strut,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) != 12)
+ return 0;
+
+ memset(wm_strut, 0, sizeof(wm_strut));
+
+ memcpy(wm_strut, xcb_get_property_value(r),
+ xcb_get_property_value_length(r));
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_wm_strut_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_wm_strut_t *wm_strut,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_wm_strut_from_reply(wm_strut, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_WM_ICON_GEOMETRY
+ */
+
+DO_GET_PROPERTY(_NET_WM_ICON_GEOMETRY, wm_icon_geometry, CARDINAL, 4)
+
+void
+xcb_ewmh_set_wm_icon_geometry_checked(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t left, uint32_t right,
+ uint32_t top, uint32_t bottom)
+{
+ const uint32_t data[] = { left, right, top, bottom };
+
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window,
+ _NET_WM_ICON_GEOMETRY, CARDINAL, 32, 4, data);
+}
+
+void
+xcb_ewmh_set_wm_icon_geometry(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t left, uint32_t right,
+ uint32_t top, uint32_t bottom)
+{
+ const uint32_t data[] = { left, right, top, bottom };
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, _NET_WM_ICON_GEOMETRY,
+ CARDINAL, 32, 4, data);
+}
+
+uint8_t
+xcb_ewmh_get_wm_icon_geometry_from_reply(xcb_ewmh_geometry_t *wm_icon_geometry,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) != 4)
+ return 0;
+
+ memcpy(wm_icon_geometry, xcb_get_property_value(r),
+ xcb_get_property_value_length(r));
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_wm_icon_geometry_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_geometry_t *wm_icon_geometry,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_wm_icon_geometry_from_reply(wm_icon_geometry, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_WM_ICON
+ */
+
+DO_GET_PROPERTY(_NET_WM_ICON, wm_icon, CARDINAL, UINT_MAX)
+
+static inline void
+set_wm_icon_data(uint32_t data[], uint32_t width, uint32_t height,
+ uint32_t img_len, uint32_t *img)
+{
+ data[0] = width;
+ data[1] = height;
+
+ memcpy(data + 2, img, img_len);
+}
+
+void
+xcb_ewmh_set_wm_icon_checked(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t width, uint32_t height,
+ uint32_t img_len, uint32_t *img)
+{
+ const uint32_t data_len = img_len + 2;
+ uint32_t data[data_len];
+
+ set_wm_icon_data(data, width, height, img_len, img);
+
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window, _NET_WM_ICON,
+ CARDINAL, 32, data_len, data);
+}
+
+void
+xcb_ewmh_set_wm_icon(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t width, uint32_t height,
+ uint32_t img_len, uint32_t *img)
+{
+ const uint32_t data_len = img_len + 2;
+ uint32_t data[data_len];
+
+ set_wm_icon_data(data, width, height, img_len, img);
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, _NET_WM_ICON, CARDINAL,
+ 32, data_len, data);
+}
+
+uint8_t
+xcb_ewmh_get_wm_icon_from_reply(xcb_ewmh_get_wm_icon_reply_t *wm_icon,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) <= 2)
+ return 0;
+
+ wm_icon->_reply = r;
+ uint32_t *r_value = (uint32_t *) xcb_get_property_value(wm_icon->_reply);
+
+ wm_icon->width = r_value[0];
+ wm_icon->height = r_value[1];
+ wm_icon->data = r_value + 2;
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_wm_icon_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_wm_icon_reply_t *wm_icon,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_wm_icon_from_reply(wm_icon, r);
+ if(!ret)
+ free(r);
+
+ return ret;
+}
+
+void
+xcb_ewmh_get_wm_icon_reply_wipe(xcb_ewmh_get_wm_icon_reply_t *wm_icon)
+{
+ free(wm_icon->_reply);
+}
+
+/**
+ * _NET_WM_PID
+ */
+
+DO_ACCESSORS_SINGLE_VALUE_ATOM(_NET_WM_PID, wm_pid, CARDINAL, uint32_t,
+ cardinal)
+
+/**
+ * _NET_WM_USER_TIME
+ */
+
+DO_ACCESSORS_SINGLE_VALUE_ATOM(_NET_WM_USER_TIME, wm_user_time, CARDINAL,
+ uint32_t, cardinal)
+
+/**
+ * _NET_WM_USER_TIME_WINDOW
+ */
+
+DO_ACCESSORS_SINGLE_VALUE_ATOM(_NET_WM_USER_TIME_WINDOW, wm_user_time_window,
+ CARDINAL, uint32_t, cardinal)
+
+/**
+ * _NET_FRAME_EXTENTS
+ */
+
+DO_GET_PROPERTY(_NET_FRAME_EXTENTS, frame_extents, CARDINAL, 4)
+
+void
+xcb_ewmh_set_frame_extents(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t left, uint32_t right,
+ uint32_t top, uint32_t bottom)
+{
+ const uint32_t data[] = { left, right, top, bottom };
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, _NET_FRAME_EXTENTS,
+ CARDINAL, 32, 4, data);
+}
+
+void
+xcb_ewmh_set_frame_extents_checked(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t left, uint32_t right,
+ uint32_t top, uint32_t bottom)
+{
+ const uint32_t data[] = { left, right, top, bottom };
+
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window,
+ _NET_FRAME_EXTENTS, CARDINAL, 32, 4, data);
+}
+
+uint8_t
+xcb_ewmh_get_frame_extents_from_reply(xcb_ewmh_get_frame_extents_reply_t *frame_extents,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) != 4)
+ return 0;
+
+ memcpy(frame_extents, xcb_get_property_value(r),
+ xcb_get_property_value_length(r));
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_frame_extents_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_frame_extents_reply_t *frame_extents,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_frame_extents_from_reply(frame_extents, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_WM_PING
+ *
+ * TODO: client resend function?
+ */
+
+void
+xcb_ewmh_send_wm_ping(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_timestamp_t timestamp)
+{
+ const uint32_t data[] = { _NET_WM_PING, timestamp, window };
+
+ send_client_message(c, window, window, WM_PROTOCOLS, 3, data);
+}
+
+/**
+ * _NET_WM_SYNC_REQUES
+ * _NET_WM_SYNC_REQUEST_COUNTER
+ */
+
+DO_GET_PROPERTY(_NET_WM_SYNC_REQUEST, wm_sync_request_counter, CARDINAL, 2)
+
+void
+xcb_ewmh_set_wm_sync_request_counter(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_atom_t wm_sync_request_counter_atom,
+ uint32_t low, uint32_t high)
+{
+ const uint32_t data[] = { low, high };
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, _NET_WM_SYNC_REQUEST,
+ CARDINAL, 32, 2, data);
+}
+
+void
+xcb_ewmh_set_wm_sync_request_counter_checked(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_atom_t wm_sync_request_counter_atom,
+ uint32_t low, uint32_t high)
+{
+ const uint32_t data[] = { low, high };
+
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window,
+ _NET_WM_SYNC_REQUEST, CARDINAL, 32, 2, data);
+}
+
+void
+xcb_ewmh_send_wm_sync_request(xcb_connection_t *c,
+ xcb_window_t window,
+ xcb_atom_t wm_protocols_atom,
+ xcb_atom_t wm_sync_request_atom,
+ xcb_timestamp_t timestamp,
+ uint64_t counter)
+{
+ const uint32_t data[] = { _NET_WM_SYNC_REQUEST, timestamp, counter,
+ GET_NB_FROM_LEN(counter, 32) };
+
+ send_client_message(c, window, window, WM_PROTOCOLS, 4, data);
+}
+
+uint8_t
+xcb_ewmh_get_wm_sync_request_counter_from_reply(uint64_t *counter,
+ xcb_get_property_reply_t *r)
+{
+ /* 2 cardinals? */
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) != 2)
+ return 0;
+
+ uint32_t *r_value = (uint32_t *) xcb_get_property_value(r);
+ *counter = (r_value[0] | GET_LEN_FROM_NB(r_value[1], 8));
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_wm_sync_request_counter_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ uint64_t *counter,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_wm_sync_request_counter_from_reply(counter, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_WM_FULLSCREEN_MONITORS
+ */
+
+DO_GET_PROPERTY(_NET_WM_FULLSCREEN_MONITORS, wm_fullscreen_monitors, CARDINAL, 4)
+
+void
+xcb_ewmh_set_wm_fullscreen_monitors(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t top, uint32_t bottom,
+ uint32_t left, uint32_t right)
+{
+ const uint32_t data[] = { top, bottom, left, right };
+
+ xcb_change_property(c, XCB_PROP_MODE_REPLACE, window,
+ _NET_WM_FULLSCREEN_MONITORS, CARDINAL, 32, 4, data);
+}
+
+void
+xcb_ewmh_set_wm_fullscreen_monitors_checked(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t top, uint32_t bottom,
+ uint32_t left, uint32_t right)
+{
+ const uint32_t data[] = { top, bottom, left, right };
+
+ xcb_change_property_checked(c, XCB_PROP_MODE_REPLACE, window,
+ _NET_WM_FULLSCREEN_MONITORS, CARDINAL, 32, 4,
+ data);
+}
+
+void
+xcb_ewmh_request_change_wm_fullscreen_monitors(xcb_connection_t *c,
+ xcb_window_t window,
+ uint32_t top, uint32_t bottom,
+ uint32_t left, uint32_t right,
+ xcb_ewmh_client_source_type_t source_indication)
+{
+ const uint32_t data[] = { top, bottom, left, right, source_indication };
+
+ send_client_message(c, window, root_window, _NET_WM_FULLSCREEN_MONITORS, 5,
+ data);
+}
+
+uint8_t
+xcb_ewmh_get_wm_fullscreen_monitors_from_reply(xcb_ewmh_get_wm_fullscreen_monitors_reply_t *wm_fullscreen_monitors,
+ xcb_get_property_reply_t *r)
+{
+ if(!r || r->type != CARDINAL || r->format != 32 ||
+ GET_NB_FROM_LEN(xcb_get_property_value_length(r), 2) != 4)
+ return 0;
+
+ memcpy(wm_fullscreen_monitors, xcb_get_property_value(r),
+ xcb_get_property_value_length(r));
+
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_wm_fullscreen_monitors_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_wm_fullscreen_monitors_reply_t *wm_fullscreen_monitors,
+ xcb_generic_error_t **e)
+{
+ xcb_get_property_reply_t *r = xcb_get_property_reply(c, cookie, e);
+ const uint8_t ret = xcb_ewmh_get_wm_fullscreen_monitors_from_reply(wm_fullscreen_monitors, r);
+ free(r);
+ return ret;
+}
+
+/**
+ * _NET_WM_FULL_PLACEMENT
+ */
+
+/**
+ * _NET_WM_CM_Sn
+ */
+
+xcb_get_selection_owner_cookie_t
+xcb_ewmh_get_wm_cm_owner(xcb_connection_t *c)
+{
+ return xcb_get_selection_owner(c, _NET_WM_CM_Sn);
+}
+
+xcb_get_selection_owner_cookie_t
+xcb_ewmh_get_wm_cm_owner_unchecked(xcb_connection_t *c)
+{
+ return xcb_get_selection_owner_unchecked(c, _NET_WM_CM_Sn);
+}
+
+uint8_t
+xcb_ewmh_get_wm_cm_owner_from_reply(xcb_window_t *owner,
+ xcb_get_selection_owner_reply_t *r)
+{
+ if(!r)
+ return 0;
+
+ *owner = r->owner;
+ free(r);
+ return 1;
+}
+
+uint8_t
+xcb_ewmh_get_wm_cm_owner_reply(xcb_connection_t *c,
+ xcb_get_selection_owner_cookie_t cookie,
+ xcb_window_t *owner,
+ xcb_generic_error_t **e)
+{
+ xcb_get_selection_owner_reply_t *r = xcb_get_selection_owner_reply(c, cookie, e);
+ return xcb_ewmh_get_wm_cm_owner_from_reply(owner, r);
+}
+
+/* TODO: section 2.1, 2.2 */
+static void
+set_wm_cm_owner_client_message(xcb_connection_t *c,
+ xcb_window_t owner,
+ xcb_timestamp_t timestamp,
+ uint32_t selection_data1,
+ uint32_t selection_data2)
+{
+ xcb_client_message_event_t ev;
+ memset(&ev, 0, sizeof(xcb_client_message_event_t));
+
+ ev.response_type = XCB_CLIENT_MESSAGE;
+ ev.format = 32;
+ ev.type = MANAGER;
+ ev.data.data32[0] = timestamp;
+ ev.data.data32[1] = _NET_WM_CM_Sn;
+ ev.data.data32[2] = owner;
+ ev.data.data32[3] = selection_data1;
+ ev.data.data32[4] = selection_data2;
+
+ xcb_send_event(c, 0, root_window, XCB_EVENT_MASK_STRUCTURE_NOTIFY,
+ (char *) &ev);
+}
+
+void
+xcb_ewmh_set_wm_cm_owner(xcb_connection_t *c,
+ xcb_window_t owner,
+ xcb_timestamp_t timestamp,
+ uint32_t selection_data1,
+ uint32_t selection_data2)
+{
+ xcb_set_selection_owner(c, owner, _NET_WM_CM_Sn, 0);
+ set_wm_cm_owner_client_message(c, owner, timestamp,
+ selection_data1, selection_data2);
+}
+
+void
+xcb_ewmh_set_wm_cm_owner_checked(xcb_connection_t *c,
+ xcb_window_t owner,
+ xcb_timestamp_t timestamp,
+ uint32_t selection_data1,
+ uint32_t selection_data2)
+{
+ xcb_set_selection_owner_checked(c, owner, _NET_WM_CM_Sn, 0);
+ set_wm_cm_owner_client_message(c, owner, timestamp,
+ selection_data1, selection_data2);
+}
diff --git a/ewmh/xcb-ewmh.pc.in b/ewmh/xcb-ewmh.pc.in
new file mode 100644
index 0000000..7f44214
--- /dev/null
+++ b/ewmh/xcb-ewmh.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: XCB EWMH library
+Description: XCB EWMH binding
+Version: @PACKAGE_VERSION@
+Requires: xcb xcb-atom xcb-property
+Libs: -L${libdir} -lxcb-ewmh @LIBS@
+Cflags: -I${includedir}
diff --git a/ewmh/xcb_ewmh.h.m4 b/ewmh/xcb_ewmh.h.m4
new file mode 100644
index 0000000..15ede02
--- /dev/null
+++ b/ewmh/xcb_ewmh.h.m4
@@ -0,0 +1,596 @@
+#ifndef __XCB_EWMH_H__
+#define __XCB_EWMH_H__
+
+/*
+ * Copyright (C) 2009 Arnaud Fontaine <arnau@debian.org>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the names of the authors or
+ * their institutions shall not be used in advertising or otherwise to
+ * promote the sale, use or other dealings in this Software without
+ * prior written authorization from the authors.
+ */
+
+/**
+ * @defgroup xcb__ewmh_t XCB EWMH Functions
+ *
+ * These functions allow easy handling of the protocol described in
+ * the Extended Window Manager Hints specification. The list of Atoms
+ * is stored as an M4 file (atomlist.m4) where each Atom is stored as
+ * a variable defined in the header.
+ *
+ * Replies of requests generating a list of pointers (such as list of
+ * windows, atoms and UTF-8 strings) are simply stored as a structure
+ * holding the XCB reply which should (usually) never be accessed
+ * directly and has to be wipe afterwards. This structure provides a
+ * convenient access to the list given in the reply itself.
+ *
+ * \todo Add missing prototypes but asks for advices on XCB mailing
+ * list before.
+ *
+ * @{
+ */
+
+#include <xcb/xcb.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** All the Atoms XIDs */
+define(`DO', `ifelse(`$1', , , `extern xcb_atom_t $1;
+DO(shift($@))')')dnl
+include(atomlist.m4)dnl
+
+/**
+ * @brief Hold a GetProperty reply containing a list of Atoms
+ */
+typedef struct {
+ /** The number of Atoms */
+ uint32_t atoms_len;
+ /** The list of Atoms */
+ xcb_atom_t *atoms;
+ /** The actual GetProperty reply */
+ xcb_get_property_reply_t *_reply;
+} xcb_ewmh_get_atoms_reply_t;
+
+/**
+ * @brief Hold a GetProperty reply containing a list of Windows
+ */
+typedef struct {
+ /** The number of Windows */
+ uint32_t windows_len;
+ /** The list of Windows */
+ xcb_window_t *windows;
+ /** The actual GetProperty reply */
+ xcb_get_property_reply_t *_reply;
+} xcb_ewmh_get_windows_reply_t;
+
+/**
+ * @brief Hold a GetProperty reply containg a list of UTF-8 strings
+ */
+typedef struct {
+ /** The number of UTF-8 strings */
+ uint32_t strings_len;
+ /** The list of UTF-8 strings */
+ char *strings;
+ /** The actual GetProperty reply */
+ xcb_get_property_reply_t *_reply;
+} xcb_ewmh_get_utf8_strings_reply_t;
+
+/**
+ * @brief Property values as coordinates
+ */
+typedef struct {
+ /** The x coordinate */
+ uint32_t x;
+ /** The y coordinate */
+ uint32_t y;
+} xcb_ewmh_coordinates_t;
+
+/**
+ * @brief Hold reply of _NET_DESKTOP_VIEWPORT GetProperty
+ */
+typedef struct {
+ /** The number of desktop viewports */
+ uint32_t desktop_viewport_len;
+ /** The desktop viewports */
+ xcb_ewmh_coordinates_t *desktop_viewport;
+ /** The actual GetProperty reply */
+ xcb_get_property_reply_t *_reply;
+} xcb_ewmh_get_desktop_viewport_reply_t;
+
+/**
+ * @brief Property values as a geometry
+ */
+typedef struct {
+ /** The x coordinate */
+ uint32_t x;
+ /** The y coordinate */
+ uint32_t y;
+ /** The width */
+ uint32_t width;
+ /** The height */
+ uint32_t height;
+} xcb_ewmh_geometry_t;
+
+/**
+ * @brief Hold reply of a _NET_WORKAREA GetProperty
+ */
+typedef struct {
+ /** The number of desktop workarea */
+ uint32_t workarea_len;
+ /** The list of desktop workarea */
+ xcb_ewmh_geometry_t *workarea;
+ /** The actual GetProperty reply */
+ xcb_get_property_reply_t *_reply;
+} xcb_ewmh_get_workarea_reply_t;
+
+/**
+ * @brief Source indication in requests
+ */
+typedef enum {
+ /** No source at all (for clients supporting an older version of
+ EWMH specification) */
+ XCB_EWMH_CLIENT_SOURCE_TYPE_NONE = 0,
+ /** Normal application */
+ XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL = 1,
+ /** Pagers and other clients that represent direct user actions */
+ XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER = 2
+} xcb_ewmh_client_source_type_t;
+
+/**
+ * @brief _NET_DESKTOP_LAYOUT orientation
+ */
+typedef enum {
+ /** Horizontal orientation (desktops laid out in rows) */
+ XCB_EWMH_WM_ORIENTATION_HORZ = 0,
+ /** Vertical orientation (desktops laid out in columns) */
+ XCB_EWMH_WM_ORIENTATION_VERT = 1
+} xcb_ewmh_desktop_layout_orientation_t;
+
+/**
+ * @brief _NET_DESKTOP_LAYOUT starting corner
+ */
+typedef enum {
+ /** Starting corner on the top left */
+ XCB_EWMH_WM_TOPLEFT = 0,
+ /** Starting corner on the top right */
+ XCB_EWMH_WM_TOPRIGHT = 1,
+ /** Starting corner on the bottom right */
+ XCB_EWMH_WM_BOTTOMRIGHT = 2,
+ /** Starting corner on the bottom left */
+ XCB_EWMH_WM_BOTTOMLEFT = 3
+} xcb_ewmh_desktop_layout_starting_corner_t;
+
+/**
+ * @brief Hold reply of a _NET_DESKTOP_LAYOUT GetProperty
+ * @see xcb_ewmh_desktop_layout_orientation_t
+ * @see xcb_ewmh_desktop_layout_starting_corner_t
+ */
+typedef struct {
+ /** The desktops orientation */
+ uint32_t orientation;
+ /** The number of columns */
+ uint32_t columns;
+ /** The number of rows */
+ uint32_t rows;
+ /** The desktops starting corner */
+ uint32_t starting_corner;
+} xcb_ewmh_get_desktop_layout_reply_t;
+
+/**
+ * @brief _NET_WM_MOVERESIZE value when moving via keyboard
+ * @see xcb_ewmh_moveresize_direction_t
+ */
+typedef enum {
+ /** The window x coordinate */
+ XCB_EWMH_MOVERESIZE_WINDOW_X = (1 << 8),
+ /** The window y coordinate */
+ XCB_EWMH_MOVERESIZE_WINDOW_Y = (1 << 9),
+ /** The window width */
+ XCB_EWMH_MOVERESIZE_WINDOW_WIDTH = (1 << 10),
+ /** The window height */
+ XCB_EWMH_MOVERESIZE_WINDOW_HEIGHT = (1 << 11)
+} xcb_ewmh_moveresize_window_opt_flags_t;
+
+/**
+ * @brief _NET_WM_MOVERESIZE window movement or resizing
+ */
+typedef enum {
+ /** Resizing applied on the top left edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_TOPLEFT = 0,
+ /** Resizing applied on the top edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_TOP = 1,
+ /** Resizing applied on the top right edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_TOPRIGHT = 2,
+ /** Resizing applied on the right edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_RIGHT = 3,
+ /** Resizing applied on the bottom right edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_BOTTOMRIGHT = 4,
+ /** Resizing applied on the bottom edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_BOTTOM = 5,
+ /** Resizing applied on the bottom left edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6,
+ /** Resizing applied on the left edge */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_LEFT = 7,
+ /* Movement only */
+ XCB_EWMH_WM_MOVERESIZE_MOVE = 8,
+ /* Size via keyboard */
+ XCB_EWMH_WM_MOVERESIZE_SIZE_KEYBOARD = 9,
+ /* Move via keyboard */
+ XCB_EWMH_WM_MOVERESIZE_MOVE_KEYBOARD = 10,
+ /* Cancel operation */
+ XCB_EWMH_WM_MOVERESIZE_CANCEL = 11
+} xcb_ewmh_moveresize_direction_t;
+
+/**
+ * @brief Action on the _NET_WM_STATE property
+ */
+typedef enum {
+ /* Remove/unset property */
+ XCB_EWMH_WM_STATE_REMOVE = 0,
+ /* Add/set property */
+ XCB_EWMH_WM_STATE_ADD = 1,
+ /* Toggle property */
+ XCB_EWMH_WM_STATE_TOGGLE = 2
+} xcb_ewmh_wm_state_action_t;
+
+/**
+ * @brief Hold reply of _NET_WM_STRUT_PARTIAL GetProperty
+ */
+typedef struct {
+ /** Reserved space on the left border of the screen */
+ uint32_t left;
+ /** Reserved space on the right border of the screen */
+ uint32_t right;
+ /** Reserved space on the top border of the screen */
+ uint32_t top;
+ /** Reserved space on the bottom border of the screen */
+ uint32_t bottom;
+ /** Beginning y coordinate of the left strut */
+ uint32_t left_start_y;
+ /** Ending y coordinate of the left strut */
+ uint32_t left_end_y;
+ /** Beginning y coordinate of the right strut */
+ uint32_t right_start_y;
+ /** Ending y coordinate of the right strut */
+ uint32_t right_end_y;
+ /** Beginning x coordinate of the top strut */
+ uint32_t top_start_x;
+ /** Ending x coordinate of the top strut */
+ uint32_t top_end_x;
+ /** Beginning x coordinate of the bottom strut */
+ uint32_t bottom_start_x;
+ /** Ending x coordinate of the bottom strut */
+ uint32_t bottom_end_x;
+} xcb_ewmh_wm_strut_t;
+
+/**
+ * @brief Hold reply of _NET_WM_ICON GetProperty
+ */
+typedef struct {
+ /** Icon width */
+ uint32_t width;
+ /** Icon height */
+ uint32_t height;
+ /** Rows, left to right and top to bottom of the CARDINAL ARGB */
+ uint32_t *data;
+ /** The actual GetProperty reply */
+ xcb_get_property_reply_t *_reply;
+} xcb_ewmh_get_wm_icon_reply_t;
+
+/**
+ * @brief Hold reply of _NET_REQUEST_FRAME_EXTENTS GetProperty
+ */
+typedef struct {
+ /** Width of the left border */
+ uint32_t left;
+ /** Width of the right border */
+ uint32_t right;
+ /** Width of the top border */
+ uint32_t top;
+ /** Width of the bottom border */
+ uint32_t bottom;
+} xcb_ewmh_get_frame_extents_reply_t;
+
+/**
+ * @brief Hold reply of _NET_WM_FULLSCREEN_MONITORS GetProperty
+ */
+typedef struct {
+ /** Monitor whose top edge defines the top edge of the fullscreen
+ window */
+ uint32_t top;
+ /** Monitor whose bottom edge defines the bottom edge of the
+ fullscreen window */
+ uint32_t bottom;
+ /** Monitor whose left edge defines the left edge of the fullscreen
+ window */
+ uint32_t left;
+ /** Monitor whose right edge defines the right edge of the
+ fullscreen window */
+ uint32_t right;
+} xcb_ewmh_get_wm_fullscreen_monitors_reply_t;
+
+/**
+ * @brief Send InternAtom requests for the EWMH atoms and its required atoms.
+ * @param c The connection to the X server.
+ * @param screen_nbr The screen number.
+ */
+void xcb_ewmh_init_atoms_list(xcb_connection_t *c,
+ const int screen_nbr);
+
+/**
+ * @brief Process the replies previously sent
+ * @param c The connection to the X server.
+ * @param e Error if any.
+ * @return Return 1 on success, 0 otherwise.
+ */
+uint8_t xcb_ewmh_init_atoms_list_replies(xcb_connection_t *c,
+ xcb_generic_error_t **e);
+
+/**
+ * @brief Wipe the Atoms list reply.
+ *
+ * This function must be called to free the memory allocated for atoms
+ * when the reply is requested in '_reply' functions.
+ *
+ * @param data The X reply to be freed.
+ */
+void xcb_ewmh_get_atoms_reply_wipe(xcb_ewmh_get_atoms_reply_t *data);
+
+/**
+ * @brief Wipe the Windows list reply.
+ *
+ * This function must be called to the free the memory allocated for
+ * windows when the reply is requested in '_reply' functions.
+ *
+ * @param data The X reply to be freed.
+ */
+void xcb_ewmh_get_windows_reply_wipe(xcb_ewmh_get_windows_reply_t *data);
+
+/**
+ * @brief Send GetProperty request to get _NET_SUPPORTED root window
+ * property
+ *
+ * _NET_SUPPORTED, ATOM[]/32
+ *
+ * This property MUST be set by the Window Manager to indicate which
+ * hints it supports. For example: considering _NET_WM_STATE both this
+ * atom and all supported states e.g. _NET_WM_STATE_MODAL,
+ * _NET_WM_STATE_STICKY, would be listed. This assumes that backwards
+ * incompatible changes will not be made to the hints (without being
+ * renamed).
+ *
+ * This form can be used only if the request will cause a reply to be
+ * generated. Any returned error will be placed in the event queue.
+ *
+ * @param c The connection to the X server.
+ * @return The _NET_SUPPORTED cookie of the GetProperty request.
+ */
+xcb_get_property_cookie_t xcb_ewmh_get_supported_unchecked(xcb_connection_t *c);
+
+/**
+ * @brief Send GetProperty request to get _NET_SUPPORTED root window
+ * property
+ *
+ * @see xcb_ewmh_get_supported_unchecked
+ * @param c The connection to the X server.
+ * @return The _NET_SUPPORTED cookie of the GetProperty request.
+ */
+xcb_get_property_cookie_t xcb_ewmh_get_supported(xcb_connection_t *c);
+
+/**
+ * @brief Get reply from the GetProperty _NET_SUPPORTED cookie
+ *
+ * The parameter e supplied to this function must be NULL if
+ * xcb_get_window_supported_unchecked() is used. Otherwise, it stores
+ * the error if any.
+ *
+ * @param c The connection to the X server.
+ * @param cookie The _NET_SUPPORTED GetProperty request cookie.
+ * @param supported The reply to be filled.
+ * @param The xcb_generic_error_t supplied.
+ * @return Return 1 on success, 0 otherwise.
+ */
+uint8_t xcb_ewmh_get_supported_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_atoms_reply_t *supported,
+ xcb_generic_error_t **e);
+
+/**
+ * @brief Send GetProperty request to get _NET_CLIENT_LIST root window
+ * property
+ *
+ * This array contains all X Windows managed by the Window
+ * Manager. _NET_CLIENT_LIST has initial mapping order, starting with
+ * the oldest window. This property SHOULD be set and updated by the
+ * Window Manager.
+ *
+ * @param c The connection to the X server.
+ * @return The _NET_CLIENT_LIST cookie of the GetProperty request.
+ */
+xcb_get_property_cookie_t xcb_ewmh_get_client_list_unchecked(xcb_connection_t *c);
+
+/**
+ * @brief Send GetProperty request to get _NET_CLIENT_LIST root window
+ * property
+ *
+ * @see xcb_ewmh_get_client_list_unchecked
+ * @param c The connection to the X server.
+ * @return The _NET_CLIENT_LIST cookie of the GetProperty request.
+ */
+xcb_get_property_cookie_t xcb_ewmh_get_client_list(xcb_connection_t *c);
+
+/**
+ * @brief Get reply from the GetProperty _NET_CLIENT_LIST cookie
+ *
+ * The parameter e supplied to this function must be NULL if
+ * xcb_get_window_client_list_unchecked() is used. Otherwise, it
+ * stores the error if any.
+ *
+ * @param c The connection to the X server.
+ * @param cookie The _NET_CLIENT_LIST GetProperty request cookie.
+ * @param clients The list of clients to be filled.
+ * @param The xcb_generic_error_t supplied.
+ * @return Return 1 on success, 0 otherwise.
+ */
+uint8_t xcb_ewmh_get_client_list_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_ewmh_get_windows_reply_t *clients,
+ xcb_generic_error_t **e);
+
+/**
+ * @brief Send GetProperty request to get _NET_ACTIVE_WINDOW root
+ * window property
+ *
+ * The window ID of the currently active window or None if no window
+ * has the focus. This is a read-only property set by the Window
+ * Manager. This property SHOULD be set and updated by the Window
+ * Manager.
+ *
+ * This form can be used only if the request will cause a reply to be
+ * generated. Any returned error will be placed in the event queue.
+ *
+ * @param c The connection to the X server.
+ * @return The _NET_ACTIVE_WINDOW cookie of the GetProperty request.
+ */
+xcb_get_property_cookie_t xcb_ewmh_get_active_window_unchecked(xcb_connection_t *c);
+
+/**
+ * @brief Send GetProperty request to get _NET_ACTIVE_WINDOW root
+ * window property
+ *
+ * @see xcb_ewmh_get_active_window_unchecked
+ * @param c The connection to the X server.
+ * @return The _NET_ACTIVE_WINDOW cookie of the GetProperty request.
+ */
+xcb_get_property_cookie_t xcb_ewmh_get_active_window(xcb_connection_t *c);
+
+/**
+ * @brief Get reply from the GetProperty _NET_ACTIVE_WINDOW cookie
+ *
+ * The parameter e supplied to this function must be NULL if
+ * xcb_get_active_window_unchecked() is used. Otherwise, it stores
+ * the error if any.
+ *
+ * @param c The connection to the X server.
+ * @param cookie The _NET_ACTIVE_WINDOW GetProperty request cookie.
+ * @param active_window The reply to be filled.
+ * @param The xcb_generic_error_t supplied.
+ * @return Return 1 on success, 0 otherwise.
+ */
+uint8_t xcb_ewmh_get_active_window_reply(xcb_connection_t *c,
+ xcb_get_property_cookie_t cookie,
+ xcb_window_t *active_window,
+ xcb_generic_error_t **e);
+
+/**
+ * @brief Send ClientMessage requesting to change the _NET_ACTIVE_WINDOW
+ *
+ * The window ID of the currently active window or None if no window
+ * has the focus. This is a read-only property set by the Window
+ * Manager. If a Client wants to activate another window, it MUST send
+ * a _NET_ACTIVE_WINDOW client message to the root window. The
+ * timestamp is Client's last user activity timestamp at the time of
+ * the request, and the currently active window is the Client's active
+ * toplevel window, if any (the Window Manager may be e.g. more likely
+ * to obey the request if it will mean transferring focus from one
+ * active window to another).
+ *
+ * @see xcb_ewmh_client_source_type_t
+ * @param c The connection to the X server.
+ * @param window_to_active The window ID to activate.
+ * @param source_indication The source indication.
+ * @param timestamp The client's last user activity timestamp.
+ * @param current_active_window The currently active window or None
+ */
+void xcb_ewmh_request_change_active_window(xcb_connection_t *c,
+ xcb_window_t window_to_activate,
+ xcb_ewmh_client_source_type_t source_indication,
+ xcb_timestamp_t timestamp,
+ xcb_window_t current_active_window);
+
+/**
+ * @brief Send GetSelectOwner request to get the owner of
+ * _NET_WM_CM_Sn root window property
+ *
+ * @param c The connection to the X server.
+ * @return The _NET_WM_CM_Sn cookie of the GetSelectionOwner request.
+ */
+xcb_get_selection_owner_cookie_t xcb_ewmh_get_wm_cm_owner_unchecked(xcb_connection_t *c);
+
+/**
+ * @brief Send GetSelectOwner request to get the owner of
+ * _NET_WM_CM_Sn root window property
+ *
+ * @see xcb_ewmh_get_wm_cm_owner_unchecked
+ * @param c The connection to the X server.
+ * @return The _NET_WM_CM_Sn cookie of the GetSelectionOwner request.
+ */
+xcb_get_selection_owner_cookie_t xcb_ewmh_get_wm_cm_owner(xcb_connection_t *c);
+
+/**
+ * @brief Get reply from the GetProperty _NET_CLIENT_LIST cookie
+ *
+ * The parameter e supplied to this function must be NULL if
+ * xcb_get_window_client_list_unchecked() is used. Otherwise, it
+ * stores the error if any.
+ *
+ * @param c The connection to the X server.
+ * @param cookie The _NET_WM_CM_Sn GetSelectionOwner request cookie.
+ * @param owner The window ID which owns the selection or None.
+ * @param The xcb_generic_error_t supplied.
+ * @return Return 1 on success, 0 otherwise.
+ */
+uint8_t xcb_ewmh_get_wm_cm_owner_reply(xcb_connection_t *c,
+ xcb_get_selection_owner_cookie_t cookie,
+ xcb_window_t *owner,
+ xcb_generic_error_t **e);
+
+/**
+ * @brief Set _NET_WM_CM_Sn ownership to the given window
+ *
+ * For each screen they manage, compositing manager MUST acquire
+ * ownership of a selection named _NET_WM_CM_Sn, where n is the screen
+ * number.
+ *
+ * @param c The connection to the X server.
+ * @param owner The new owner of _NET_WM_CM_Sn selection.
+ * @param timestamp The client's last user activity timestamp.
+ * @param selection_data1 Optional data described by ICCCM
+ * @param selection_data2 Optional data described by ICCCM
+ */
+void xcb_ewmh_set_wm_cm_owner(xcb_connection_t *c,
+ xcb_window_t owner,
+ xcb_timestamp_t timestamp,
+ uint32_t selection_data1,
+ uint32_t selection_data2);
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @}
+ */
+
+#endif /* __XCB_EWMH_H__ */