/* * Copyright © 2009 Arnaud Fontaine * * 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 "xcb_ewmh.h" #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #define ssizeof(foo) (ssize_t)sizeof(foo) #define countof(foo) (ssizeof(foo) / ssizeof(foo[0])) /** * @brief The structure used on screen initialization including the * atoms name and its length */ typedef struct { /** The Atom name length */ uint8_t name_len; /** The Atom name string */ char *name; size_t m_offset; } ewmh_atom_t; define(`DO_ENTRY', ` { sizeof("$1") - 1, "$1", offsetof(xcb_ewmh_connection_t, $1) }ifelse(`$2', , , `,')')dnl define(`DO', `DO_ENTRY(`$1', `$2')ifelse(`$2', , , `DO(shift($@))')')dnl /** * @brief List of atoms where each entry contains the Atom name and * its length */ static ewmh_atom_t ewmh_atoms[] = {dnl include(atomlist.m4)dnl }; #define NB_EWMH_ATOMS countof(ewmh_atoms) /** * Common functions and macro */ #define DO_GET_PROPERTY(fname, property, type, length) \ xcb_get_property_cookie_t \ xcb_ewmh_get_##fname(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window) \ { \ return xcb_get_property(ewmh->connection, 0, window, \ ewmh->property, type, 0, length); \ } \ \ xcb_get_property_cookie_t \ xcb_ewmh_get_##fname##_unchecked(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window) \ { \ return xcb_get_property_unchecked(ewmh->connection, 0, window, \ ewmh->property, type, 0, length); \ } #define DO_GET_ROOT_PROPERTY(fname, property, atype, length) \ xcb_get_property_cookie_t \ xcb_ewmh_get_##fname(xcb_ewmh_connection_t *ewmh, \ int screen_nbr) \ { \ return xcb_get_property(ewmh->connection, 0, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, atype, 0, length); \ } \ \ xcb_get_property_cookie_t \ xcb_ewmh_get_##fname##_unchecked(xcb_ewmh_connection_t *ewmh, \ int screen_nbr) \ { \ return xcb_get_property_unchecked(ewmh->connection, 0, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, atype, 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 a generic function for reply with a single value, * considering that the value is 32-bit long (actually only used for * WINDOW and CARDINAL) */ #define DO_REPLY_SINGLE_VALUE(fname, atype, ctype) \ uint8_t \ xcb_ewmh_get_##fname##_from_reply(ctype *atom_value, \ xcb_get_property_reply_t *r) \ { \ if(!r || r->type != atype || r->format != 32 || \ xcb_get_property_value_length(r) != sizeof(ctype)) \ return 0; \ \ *atom_value = *((ctype *) xcb_get_property_value(r)); \ return 1; \ } \ \ uint8_t \ xcb_ewmh_get_##fname##_reply(xcb_ewmh_connection_t *ewmh, \ xcb_get_property_cookie_t cookie, \ ctype *atom_value, \ xcb_generic_error_t **e) \ { \ xcb_get_property_reply_t *r = \ xcb_get_property_reply(ewmh->connection, \ cookie, e); \ \ const uint8_t ret = xcb_ewmh_get_##fname##_from_reply(atom_value, r); \ \ free(r); \ return ret; \ } /** Define reply functions for common WINDOW Atom */ DO_REPLY_SINGLE_VALUE(window, XCB_ATOM_WINDOW, xcb_window_t) /** Define reply functions for common CARDINAL Atom */ DO_REPLY_SINGLE_VALUE(cardinal, XCB_ATOM_CARDINAL, uint32_t) #define DO_SINGLE_VALUE(fname, property, atype, ctype) \ DO_GET_PROPERTY(fname, property, atype, 1L) \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname##_checked(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window, \ ctype value) \ { \ return xcb_change_property_checked(ewmh->connection, \ XCB_PROP_MODE_REPLACE, \ window, ewmh->property, \ atype, 32, 1, &value); \ } \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window, \ ctype value) \ { \ return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, \ window, ewmh->property, atype, 32, 1, \ &value); \ } #define DO_ROOT_SINGLE_VALUE(fname, property, atype, ctype) \ DO_GET_ROOT_PROPERTY(fname, property, atype, 1L) \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname##_checked(xcb_ewmh_connection_t *ewmh, \ int screen_nbr, \ ctype value) \ { \ return xcb_change_property_checked(ewmh->connection, \ XCB_PROP_MODE_REPLACE, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, atype, 32, 1, \ &value); \ } \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname(xcb_ewmh_connection_t *ewmh, \ int screen_nbr, \ ctype value) \ { \ return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, atype, \ 32, 1, &value); \ } /** * 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[] */ /** * Macro defining a generic function for reply containing a list of * values and also defines a function to wipe the reply. */ #define DO_REPLY_LIST_VALUES(fname, atype, ctype) \ uint8_t \ xcb_ewmh_get_##fname##_from_reply(xcb_ewmh_get_##fname##_reply_t *data, \ xcb_get_property_reply_t *r) \ { \ if(!r || r->type != atype || r->format != 32) \ return 0; \ \ data->_reply = r; \ data->fname##_len = xcb_get_property_value_length(data->_reply) / \ sizeof(ctype); \ \ data->fname = (ctype *) xcb_get_property_value(data->_reply); \ return 1; \ } \ \ uint8_t \ xcb_ewmh_get_##fname##_reply(xcb_ewmh_connection_t *ewmh, \ xcb_get_property_cookie_t cookie, \ xcb_ewmh_get_##fname##_reply_t *data, \ xcb_generic_error_t **e) \ { \ xcb_get_property_reply_t *r = \ xcb_get_property_reply(ewmh->connection, \ cookie, e); \ \ const uint8_t ret = xcb_ewmh_get_##fname##_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_##fname##_reply_wipe(xcb_ewmh_get_##fname##_reply_t *data) \ { \ free(data->_reply); \ } #define DO_ROOT_LIST_VALUES(fname, property, atype, ctype) \ DO_GET_ROOT_PROPERTY(fname, property, atype, UINT_MAX) \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname##_checked(xcb_ewmh_connection_t *ewmh, \ int screen_nbr, \ uint32_t list_len, \ ctype *list) \ { \ return xcb_change_property_checked(ewmh->connection, \ XCB_PROP_MODE_REPLACE, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, atype, 32, \ list_len * (sizeof(ctype) >> 2), \ list); \ } \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname(xcb_ewmh_connection_t *ewmh, \ int screen_nbr, \ uint32_t list_len, \ ctype *list) \ { \ return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, atype, 32, \ list_len * (sizeof(ctype) >> 2), \ list); \ } #define DO_LIST_VALUES(fname, property, atype, kind) \ DO_GET_PROPERTY(fname, property, atype, UINT_MAX) \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname##_checked(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window, \ uint32_t list_len, \ xcb_##kind##_t *list) \ { \ return xcb_change_property_checked(ewmh->connection, \ XCB_PROP_MODE_REPLACE, window, \ ewmh->property, atype, 32, \ list_len, list); \ } \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window, \ uint32_t list_len, \ xcb_##kind##_t *list) \ { \ return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, \ window, ewmh->property, atype, 32, \ list_len, list); \ } \ \ uint8_t \ xcb_ewmh_get_##fname##_from_reply(xcb_ewmh_get_##kind##s_reply_t *name, \ xcb_get_property_reply_t *r) \ { \ return xcb_ewmh_get_##kind##s_from_reply(name, r); \ } \ \ uint8_t \ xcb_ewmh_get_##fname##_reply(xcb_ewmh_connection_t *ewmh, \ xcb_get_property_cookie_t cookie, \ xcb_ewmh_get_##kind##s_reply_t *name, \ xcb_generic_error_t **e) \ { \ return xcb_ewmh_get_##kind##s_reply(ewmh, cookie, name, e); \ } #define DO_REPLY_STRUCTURE(fname, ctype) \ uint8_t \ xcb_ewmh_get_##fname##_from_reply(ctype *out, \ xcb_get_property_reply_t *r) \ { \ if(!r || r->type != XCB_ATOM_CARDINAL || r->format != 32 || \ xcb_get_property_value_length(r) != sizeof(ctype)) \ return 0; \ \ memcpy(out, xcb_get_property_value(r), \ xcb_get_property_value_length(r)); \ \ return 1; \ } \ \ uint8_t \ xcb_ewmh_get_##fname##_reply(xcb_ewmh_connection_t *ewmh, \ xcb_get_property_cookie_t cookie, \ ctype *out, \ xcb_generic_error_t **e) \ { \ xcb_get_property_reply_t *r = \ xcb_get_property_reply(ewmh->connection, cookie, e); \ \ const uint8_t ret = xcb_ewmh_get_##fname##_from_reply(out, r); \ free(r); \ return ret; \ } /** * UTF8_STRING handling */ uint8_t xcb_ewmh_get_utf8_strings_from_reply(xcb_ewmh_connection_t *ewmh, xcb_ewmh_get_utf8_strings_reply_t *data, xcb_get_property_reply_t *r) { if(!r || r->type != ewmh->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; } uint8_t xcb_ewmh_get_utf8_strings_reply(xcb_ewmh_connection_t *ewmh, 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(ewmh->connection, cookie, e); const uint8_t ret = xcb_ewmh_get_utf8_strings_from_reply(ewmh, 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_ROOT_UTF8_STRING(fname, property) \ DO_GET_ROOT_PROPERTY(fname, property, 0, UINT_MAX) \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname(xcb_ewmh_connection_t *ewmh, \ int screen_nbr, \ uint32_t strings_len, \ const char *strings) \ { \ return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, ewmh->UTF8_STRING, 8, \ strings_len, strings); \ } \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname##_checked(xcb_ewmh_connection_t *ewmh, \ int screen_nbr, \ uint32_t strings_len, \ const char *strings) \ { \ return xcb_change_property_checked(ewmh->connection, \ XCB_PROP_MODE_REPLACE, \ ewmh->screens[screen_nbr]->root, \ ewmh->property, \ ewmh->UTF8_STRING, 8, \ strings_len, strings); \ } #define DO_UTF8_STRING(fname, property) \ DO_GET_PROPERTY(fname, property, 0, UINT_MAX) \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window, \ uint32_t strings_len, \ const char *strings) \ { \ return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, \ window, ewmh->property, \ ewmh->UTF8_STRING, 8, strings_len, \ strings); \ } \ \ xcb_void_cookie_t \ xcb_ewmh_set_##fname##_checked(xcb_ewmh_connection_t *ewmh, \ xcb_window_t window, \ uint32_t strings_len, \ const char *strings) \ { \ return xcb_change_property_checked(ewmh->connection, \ XCB_PROP_MODE_REPLACE, \ window, ewmh->property, \ ewmh->UTF8_STRING, 8, \ strings_len, strings); \ } /** * ClientMessage generic function */ xcb_void_cookie_t xcb_ewmh_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; assert(data_len <= (5 * sizeof(uint32_t))); memcpy(ev.data.data32, data, data_len); return xcb_send_event(c, 0, dest, XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (char *) &ev); } DO_REPLY_LIST_VALUES(windows, XCB_ATOM_WINDOW, xcb_window_t) DO_REPLY_LIST_VALUES(atoms, XCB_ATOM_ATOM, xcb_atom_t) /** * Atoms initialisation */ xcb_intern_atom_cookie_t * xcb_ewmh_init_atoms(xcb_connection_t *c, xcb_ewmh_connection_t *ewmh) { int screen_nbr, atom_nbr; ewmh->connection = c; const xcb_setup_t *setup = xcb_get_setup(c); ewmh->nb_screens = xcb_setup_roots_length(setup); if(!ewmh->nb_screens) return NULL; /* Allocate the data structures depending of the number of screens */ ewmh->screens = malloc(sizeof(xcb_screen_t *) * ewmh->nb_screens); ewmh->_NET_WM_CM_Sn = malloc(sizeof(xcb_atom_t) * ewmh->nb_screens); xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(setup); for(screen_iter = xcb_setup_roots_iterator(setup), screen_nbr = 0; screen_iter.rem; xcb_screen_next(&screen_iter)) ewmh->screens[screen_nbr++] = screen_iter.data; /* _NET_WM_CM_Sn atoms will be treated differently, by adding them at the end of this array, than other atoms as it depends on the number of screens */ xcb_intern_atom_cookie_t *ewmh_cookies = malloc(sizeof(xcb_intern_atom_cookie_t) * (NB_EWMH_ATOMS + ewmh->nb_screens)); /* First, send InternAtom request for all Atoms except _NET_WM_CM_Sn */ for(atom_nbr = 0; atom_nbr < NB_EWMH_ATOMS; atom_nbr++) ewmh_cookies[atom_nbr] = xcb_intern_atom(ewmh->connection, 0, ewmh_atoms[atom_nbr].name_len, ewmh_atoms[atom_nbr].name); /* Then, send InternAtom requests for _NET_WM_CM_Sn and compute _NET_WM_CM_Sn according to the screen number 'n' */ for(screen_nbr = 0; screen_nbr < ewmh->nb_screens; screen_nbr++) { 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); ewmh_cookies[atom_nbr++] = xcb_intern_atom(ewmh->connection, 0, wm_cm_sn_len, wm_cm_sn); } return ewmh_cookies; } uint8_t xcb_ewmh_init_atoms_replies(xcb_ewmh_connection_t *ewmh, xcb_intern_atom_cookie_t *ewmh_cookies, xcb_generic_error_t **e) { int atom_nbr; int screen_nbr = 0; uint8_t ret = 1; xcb_intern_atom_reply_t *reply; for(atom_nbr = 0; atom_nbr < NB_EWMH_ATOMS + ewmh->nb_screens; atom_nbr++) if((reply = xcb_intern_atom_reply(ewmh->connection, ewmh_cookies[atom_nbr], e))) { if(ret) { if(atom_nbr < NB_EWMH_ATOMS) *((xcb_atom_t *) (((char *) ewmh) + ewmh_atoms[atom_nbr].m_offset)) = reply->atom; else ewmh->_NET_WM_CM_Sn[screen_nbr++] = reply->atom; } free(reply); } else ret = 0; if(!ret) xcb_ewmh_connection_wipe(ewmh); free(ewmh_cookies); return ret; } /** * _NET_SUPPORTED */ DO_ROOT_LIST_VALUES(supported, _NET_SUPPORTED, XCB_ATOM_ATOM, xcb_atom_t) /** * _NET_CLIENT_LIST * _NET_CLIENT_LIST_STACKING */ DO_ROOT_LIST_VALUES(client_list, _NET_CLIENT_LIST, XCB_ATOM_WINDOW, xcb_window_t) DO_ROOT_LIST_VALUES(client_list_stacking, _NET_CLIENT_LIST_STACKING, XCB_ATOM_WINDOW, xcb_window_t) /** * _NET_NUMBER_OF_DESKTOPS */ DO_ROOT_SINGLE_VALUE(number_of_desktops, _NET_NUMBER_OF_DESKTOPS, XCB_ATOM_CARDINAL, uint32_t) /** * _NET_DESKTOP_GEOMETRY */ DO_GET_ROOT_PROPERTY(desktop_geometry, _NET_DESKTOP_GEOMETRY, XCB_ATOM_CARDINAL, 2L) xcb_void_cookie_t xcb_ewmh_set_desktop_geometry(xcb_ewmh_connection_t *ewmh, int screen_nbr, uint32_t new_width, uint32_t new_height) { const uint32_t data[] = { new_width, new_height }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, ewmh->screens[screen_nbr]->root, ewmh->_NET_DESKTOP_GEOMETRY, XCB_ATOM_CARDINAL, 32, 2, data); } xcb_void_cookie_t xcb_ewmh_set_desktop_geometry_checked(xcb_ewmh_connection_t *ewmh, int screen_nbr, uint32_t new_width, uint32_t new_height) { const uint32_t data[] = { new_width, new_height }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, ewmh->screens[screen_nbr]->root, ewmh->_NET_DESKTOP_GEOMETRY, XCB_ATOM_CARDINAL, 32, 2, data); } xcb_void_cookie_t xcb_ewmh_request_change_desktop_geometry(xcb_ewmh_connection_t *ewmh, int screen_nbr, uint32_t new_width, uint32_t new_height) { const uint32_t data[] = { new_width, new_height }; return xcb_ewmh_send_client_message(ewmh->connection, XCB_NONE, ewmh->screens[screen_nbr]->root, ewmh->_NET_DESKTOP_GEOMETRY, sizeof(data), 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 != XCB_ATOM_CARDINAL || r->format != 32 || xcb_get_property_value_length(r) != (sizeof(uint32_t) * 2)) 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_ewmh_connection_t *ewmh, 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(ewmh->connection, cookie, e); const uint8_t ret = xcb_ewmh_get_desktop_geometry_from_reply(width, height, r); free(r); return ret; } /** * _NET_DESKTOP_VIEWPORT */ DO_ROOT_LIST_VALUES(desktop_viewport, _NET_DESKTOP_VIEWPORT, XCB_ATOM_CARDINAL, xcb_ewmh_coordinates_t) DO_REPLY_LIST_VALUES(desktop_viewport, XCB_ATOM_CARDINAL, xcb_ewmh_coordinates_t) xcb_void_cookie_t xcb_ewmh_request_change_desktop_viewport(xcb_ewmh_connection_t *ewmh, int screen_nbr, uint32_t x, uint32_t y) { const uint32_t data[] = { x, y }; return xcb_ewmh_send_client_message(ewmh->connection, XCB_NONE, ewmh->screens[screen_nbr]->root, ewmh->_NET_DESKTOP_VIEWPORT, sizeof(data), data); } /** * _NET_CURRENT_DESKTOP */ DO_ROOT_SINGLE_VALUE(current_desktop, _NET_CURRENT_DESKTOP, XCB_ATOM_CARDINAL, uint32_t) xcb_void_cookie_t xcb_ewmh_request_change_current_desktop(xcb_ewmh_connection_t *ewmh, int screen_nbr, uint32_t new_desktop, xcb_timestamp_t timestamp) { const uint32_t data[] = { new_desktop, timestamp }; return xcb_ewmh_send_client_message(ewmh->connection, XCB_NONE, ewmh->screens[screen_nbr]->root, ewmh->_NET_CURRENT_DESKTOP, sizeof(data), data); } /** * _NET_DESKTOP_NAMES */ DO_ROOT_UTF8_STRING(desktop_names, _NET_DESKTOP_NAMES) /** * _NET_ACTIVE_WINDOW */ DO_ROOT_SINGLE_VALUE(active_window, _NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, xcb_window_t) xcb_void_cookie_t xcb_ewmh_request_change_active_window(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, window_to_activate, ewmh->screens[screen_nbr]->root, ewmh->_NET_ACTIVE_WINDOW, sizeof(data), data); } /** * _NET_WORKAREA */ DO_ROOT_LIST_VALUES(workarea, _NET_WORKAREA, XCB_ATOM_CARDINAL, xcb_ewmh_geometry_t) DO_REPLY_LIST_VALUES(workarea, XCB_ATOM_CARDINAL, xcb_ewmh_geometry_t) /** * _NET_SUPPORTING_WM_CHECK */ DO_ROOT_SINGLE_VALUE(supporting_wm_check, _NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, xcb_window_t) /** * _NET_VIRTUAL_ROOTS */ DO_ROOT_LIST_VALUES(virtual_roots, _NET_VIRTUAL_ROOTS, XCB_ATOM_WINDOW, xcb_window_t) /** * _NET_DESKTOP_LAYOUT */ DO_GET_ROOT_PROPERTY(desktop_layout, _NET_DESKTOP_LAYOUT, XCB_ATOM_CARDINAL, 4) DO_REPLY_STRUCTURE(desktop_layout, xcb_ewmh_get_desktop_layout_reply_t) xcb_void_cookie_t xcb_ewmh_set_desktop_layout(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, ewmh->screens[screen_nbr]->root, ewmh->_NET_DESKTOP_LAYOUT, XCB_ATOM_CARDINAL, 32, countof(data), data); } xcb_void_cookie_t xcb_ewmh_set_desktop_layout_checked(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, ewmh->screens[screen_nbr]->root, ewmh->_NET_DESKTOP_LAYOUT, XCB_ATOM_CARDINAL, 32, countof(data), data); } /** * _NET_SHOWING_DESKTOP */ DO_ROOT_SINGLE_VALUE(showing_desktop, _NET_SHOWING_DESKTOP, XCB_ATOM_CARDINAL, uint32_t) /** * _NET_CLOSE_WINDOW */ xcb_void_cookie_t xcb_ewmh_request_close_window(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, window_to_close, ewmh->screens[screen_nbr]->root, ewmh->_NET_CLOSE_WINDOW, sizeof(data), data); } /** * _NET_MOVERESIZE_WINDOW */ /* x, y, width, height may be equal to -1 */ xcb_void_cookie_t xcb_ewmh_request_moveresize_window(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 | source_indication << 12), x, y, width, height }; return xcb_ewmh_send_client_message(ewmh->connection, moveresize_window, ewmh->screens[screen_nbr]->root, ewmh->_NET_MOVERESIZE_WINDOW, sizeof(data), data); } /** * _NET_WM_MOVERESIZE */ xcb_void_cookie_t xcb_ewmh_request_wm_moveresize(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, moveresize_window, ewmh->screens[screen_nbr]->root, ewmh->_NET_WM_MOVERESIZE, sizeof(data), data); } /** * _NET_RESTACK_WINDOW */ xcb_void_cookie_t xcb_ewmh_request_restack_window(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, window_to_restack, ewmh->screens[screen_nbr]->root, ewmh->_NET_RESTACK_WINDOW, sizeof(data), data); } /** * _NET_WM_NAME */ DO_UTF8_STRING(wm_name, _NET_WM_NAME) /** * _NET_WM_VISIBLE_NAME */ DO_UTF8_STRING(wm_visible_name, _NET_WM_VISIBLE_NAME) /** * _NET_WM_ICON_NAME */ DO_UTF8_STRING(wm_icon_name, _NET_WM_ICON_NAME) /** * _NET_WM_VISIBLE_ICON_NAME */ DO_UTF8_STRING(wm_visible_icon_name, _NET_WM_VISIBLE_ICON_NAME) /** * _NET_WM_DESKTOP */ DO_SINGLE_VALUE(wm_desktop, _NET_WM_DESKTOP, XCB_ATOM_CARDINAL, uint32_t) xcb_void_cookie_t xcb_ewmh_request_change_wm_desktop(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, client_window, ewmh->screens[screen_nbr]->root, ewmh->_NET_WM_DESKTOP, sizeof(data), data); } /** * _NET_WM_WINDOW_TYPE * * TODO: check possible atoms? */ DO_LIST_VALUES(wm_window_type, _NET_WM_WINDOW_TYPE, XCB_ATOM_ATOM, atom) /** * _NET_WM_STATE * * TODO: check possible atoms? */ DO_LIST_VALUES(wm_state, _NET_WM_STATE, XCB_ATOM_ATOM, atom) xcb_void_cookie_t xcb_ewmh_request_change_wm_state(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, client_window, ewmh->screens[screen_nbr]->root, ewmh->_NET_WM_STATE, sizeof(data), data); } /** * _NET_WM_ALLOWED_ACTIONS * * TODO: check possible atoms? */ DO_LIST_VALUES(wm_allowed_actions, _NET_WM_ALLOWED_ACTIONS, XCB_ATOM_ATOM, atom) /** * _NET_WM_STRUT */ xcb_void_cookie_t xcb_ewmh_set_wm_strut(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { const uint32_t data[] = { left, right, top, bottom }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, countof(data), data); } xcb_void_cookie_t xcb_ewmh_set_wm_strut_checked(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { const uint32_t data[] = { left, right, top, bottom }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_STRUT, XCB_ATOM_CARDINAL, 32, countof(data), data); } DO_GET_PROPERTY(wm_strut, _NET_WM_STRUT, XCB_ATOM_CARDINAL, 4) DO_REPLY_STRUCTURE(wm_strut, xcb_ewmh_get_extents_reply_t) /* * _NET_WM_STRUT_PARTIAL */ xcb_void_cookie_t xcb_ewmh_set_wm_strut_partial(xcb_ewmh_connection_t *ewmh, xcb_window_t window, xcb_ewmh_wm_strut_partial_t wm_strut) { return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, &wm_strut); } xcb_void_cookie_t xcb_ewmh_set_wm_strut_partial_checked(xcb_ewmh_connection_t *ewmh, xcb_window_t window, xcb_ewmh_wm_strut_partial_t wm_strut) { return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 32, 12, &wm_strut); } DO_GET_PROPERTY(wm_strut_partial, _NET_WM_STRUT_PARTIAL, XCB_ATOM_CARDINAL, 12) DO_REPLY_STRUCTURE(wm_strut_partial, xcb_ewmh_wm_strut_partial_t) /** * _NET_WM_ICON_GEOMETRY */ xcb_void_cookie_t xcb_ewmh_set_wm_icon_geometry_checked(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { const uint32_t data[] = { left, right, top, bottom }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_ICON_GEOMETRY, XCB_ATOM_CARDINAL, 32, countof(data), data); } xcb_void_cookie_t xcb_ewmh_set_wm_icon_geometry(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { const uint32_t data[] = { left, right, top, bottom }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_ICON_GEOMETRY, XCB_ATOM_CARDINAL, 32, countof(data), data); } DO_GET_PROPERTY(wm_icon_geometry, _NET_WM_ICON_GEOMETRY, XCB_ATOM_CARDINAL, 4) DO_REPLY_STRUCTURE(wm_icon_geometry, xcb_ewmh_geometry_t) /** * _NET_WM_ICON */ 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); } xcb_void_cookie_t xcb_ewmh_set_wm_icon_checked(xcb_ewmh_connection_t *ewmh, 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); return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_ICON, XCB_ATOM_CARDINAL, 32, data_len, data); } xcb_void_cookie_t xcb_ewmh_set_wm_icon(xcb_ewmh_connection_t *ewmh, 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); return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_ICON, XCB_ATOM_CARDINAL, 32, data_len, data); } DO_GET_PROPERTY(wm_icon, _NET_WM_ICON, XCB_ATOM_CARDINAL, UINT_MAX) 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 != XCB_ATOM_CARDINAL || r->format != 32 || xcb_get_property_value_length(r) <= (sizeof(uint32_t) * 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_ewmh_connection_t *ewmh, 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(ewmh->connection, 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_SINGLE_VALUE(wm_pid, _NET_WM_PID, XCB_ATOM_CARDINAL, uint32_t) /** * _NET_WM_HANDLED_ICONS */ DO_SINGLE_VALUE(wm_handled_icons, _NET_WM_HANDLED_ICONS, XCB_ATOM_CARDINAL, uint32_t) /** * _NET_WM_USER_TIME */ DO_SINGLE_VALUE(wm_user_time, _NET_WM_USER_TIME, XCB_ATOM_CARDINAL, uint32_t) /** * _NET_WM_USER_TIME_WINDOW */ DO_SINGLE_VALUE(wm_user_time_window, _NET_WM_USER_TIME_WINDOW, XCB_ATOM_CARDINAL, uint32_t) /** * _NET_FRAME_EXTENTS */ xcb_void_cookie_t xcb_ewmh_set_frame_extents(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { const uint32_t data[] = { left, right, top, bottom }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_FRAME_EXTENTS, XCB_ATOM_CARDINAL, 32, countof(data), data); } xcb_void_cookie_t xcb_ewmh_set_frame_extents_checked(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { const uint32_t data[] = { left, right, top, bottom }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_FRAME_EXTENTS, XCB_ATOM_CARDINAL, 32, countof(data), data); } DO_GET_PROPERTY(frame_extents, _NET_FRAME_EXTENTS, XCB_ATOM_CARDINAL, 4) DO_REPLY_STRUCTURE(frame_extents, xcb_ewmh_get_extents_reply_t) /** * _NET_WM_PING * * TODO: client resend function? */ xcb_void_cookie_t xcb_ewmh_send_wm_ping(xcb_ewmh_connection_t *ewmh, xcb_window_t window, xcb_timestamp_t timestamp) { const uint32_t data[] = { ewmh->_NET_WM_PING, timestamp, window }; return xcb_ewmh_send_client_message(ewmh->connection, window, window, ewmh->WM_PROTOCOLS, sizeof(data), data); } /** * _NET_WM_SYNC_REQUEST * _NET_WM_SYNC_REQUEST_COUNTER */ xcb_void_cookie_t xcb_ewmh_set_wm_sync_request_counter(xcb_ewmh_connection_t *ewmh, xcb_window_t window, xcb_atom_t wm_sync_request_counter_atom, uint32_t low, uint32_t high) { const uint32_t data[] = { low, high }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_SYNC_REQUEST_COUNTER, XCB_ATOM_CARDINAL, 32, countof(data), data); } xcb_void_cookie_t xcb_ewmh_set_wm_sync_request_counter_checked(xcb_ewmh_connection_t *ewmh, xcb_window_t window, xcb_atom_t wm_sync_request_counter_atom, uint32_t low, uint32_t high) { const uint32_t data[] = { low, high }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_SYNC_REQUEST_COUNTER, XCB_ATOM_CARDINAL, 32, countof(data), data); } DO_GET_PROPERTY(wm_sync_request_counter, _NET_WM_SYNC_REQUEST_COUNTER, XCB_ATOM_CARDINAL, 2) 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 != XCB_ATOM_CARDINAL || r->format != 32 || xcb_get_property_value_length(r) != sizeof(uint64_t)) return 0; uint32_t *r_value = (uint32_t *) xcb_get_property_value(r); *counter = (r_value[0] | ((uint64_t) r_value[1]) << 32); return 1; } uint8_t xcb_ewmh_get_wm_sync_request_counter_reply(xcb_ewmh_connection_t *ewmh, xcb_get_property_cookie_t cookie, uint64_t *counter, xcb_generic_error_t **e) { xcb_get_property_reply_t *r = xcb_get_property_reply(ewmh->connection, cookie, e); const uint8_t ret = xcb_ewmh_get_wm_sync_request_counter_from_reply(counter, r); free(r); return ret; } xcb_void_cookie_t xcb_ewmh_send_wm_sync_request(xcb_ewmh_connection_t *ewmh, 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[] = { ewmh->_NET_WM_SYNC_REQUEST, timestamp, counter, counter >> 32 }; return xcb_ewmh_send_client_message(ewmh->connection, window, window, ewmh->WM_PROTOCOLS, sizeof(data), data); } /** * _NET_WM_FULLSCREEN_MONITORS */ xcb_void_cookie_t xcb_ewmh_set_wm_fullscreen_monitors(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t top, uint32_t bottom, uint32_t left, uint32_t right) { const uint32_t data[] = { top, bottom, left, right }; return xcb_change_property(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_FULLSCREEN_MONITORS, XCB_ATOM_CARDINAL, 32, countof(data), data); } xcb_void_cookie_t xcb_ewmh_set_wm_fullscreen_monitors_checked(xcb_ewmh_connection_t *ewmh, xcb_window_t window, uint32_t top, uint32_t bottom, uint32_t left, uint32_t right) { const uint32_t data[] = { top, bottom, left, right }; return xcb_change_property_checked(ewmh->connection, XCB_PROP_MODE_REPLACE, window, ewmh->_NET_WM_FULLSCREEN_MONITORS, XCB_ATOM_CARDINAL, 32, countof(data), data); } DO_GET_PROPERTY(wm_fullscreen_monitors, _NET_WM_FULLSCREEN_MONITORS, XCB_ATOM_CARDINAL, 4) DO_REPLY_STRUCTURE(wm_fullscreen_monitors, xcb_ewmh_get_wm_fullscreen_monitors_reply_t) xcb_void_cookie_t xcb_ewmh_request_change_wm_fullscreen_monitors(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 }; return xcb_ewmh_send_client_message(ewmh->connection, window, ewmh->screens[screen_nbr]->root, ewmh->_NET_WM_FULLSCREEN_MONITORS, sizeof(data), data); } /** * _NET_WM_FULL_PLACEMENT */ /** * _NET_WM_CM_Sn */ xcb_get_selection_owner_cookie_t xcb_ewmh_get_wm_cm_owner(xcb_ewmh_connection_t *ewmh, int screen_nbr) { return xcb_get_selection_owner(ewmh->connection, ewmh->_NET_WM_CM_Sn[screen_nbr]); } xcb_get_selection_owner_cookie_t xcb_ewmh_get_wm_cm_owner_unchecked(xcb_ewmh_connection_t *ewmh, int screen_nbr) { return xcb_get_selection_owner_unchecked(ewmh->connection, ewmh->_NET_WM_CM_Sn[screen_nbr]); } 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_ewmh_connection_t *ewmh, 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(ewmh->connection, cookie, e); return xcb_ewmh_get_wm_cm_owner_from_reply(owner, r); } /* TODO: section 2.1, 2.2 */ static xcb_void_cookie_t set_wm_cm_owner_client_message(xcb_ewmh_connection_t *ewmh, int screen_nbr, 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 = ewmh->MANAGER; ev.data.data32[0] = timestamp; ev.data.data32[1] = ewmh->_NET_WM_CM_Sn[screen_nbr]; ev.data.data32[2] = owner; ev.data.data32[3] = selection_data1; ev.data.data32[4] = selection_data2; return xcb_send_event(ewmh->connection, 0, ewmh->screens[screen_nbr]->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (char *) &ev); } /* TODO: check both */ xcb_void_cookie_t xcb_ewmh_set_wm_cm_owner(xcb_ewmh_connection_t *ewmh, int screen_nbr, xcb_window_t owner, xcb_timestamp_t timestamp, uint32_t selection_data1, uint32_t selection_data2) { xcb_set_selection_owner(ewmh->connection, owner, ewmh->_NET_WM_CM_Sn[screen_nbr], 0); return set_wm_cm_owner_client_message(ewmh, screen_nbr, owner, timestamp, selection_data1, selection_data2); } xcb_void_cookie_t xcb_ewmh_set_wm_cm_owner_checked(xcb_ewmh_connection_t *ewmh, int screen_nbr, xcb_window_t owner, xcb_timestamp_t timestamp, uint32_t selection_data1, uint32_t selection_data2) { xcb_set_selection_owner_checked(ewmh->connection, owner, ewmh->_NET_WM_CM_Sn[screen_nbr], 0); return set_wm_cm_owner_client_message(ewmh, screen_nbr, owner, timestamp, selection_data1, selection_data2); }