xcbutils.c (4533B)
1 /* 2 * kbgwm, a sucklessy floating window manager 3 * Copyright (c) 2020-2021, Kebigon <git@kebigon.xyz> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "xcbutils.h" 19 20 #include <assert.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <xcb/xcb_icccm.h> 25 #include <xcb/xproto.h> 26 27 #include "log.h" 28 29 extern xcb_connection_t *c; 30 extern xcb_screen_t *screen; 31 extern uint16_t numlockmask; 32 extern xcb_atom_t wm_protocols; 33 34 void *emalloc(size_t size) 35 { 36 void *p; 37 38 LOG_DEBUG_VA("emalloc size=%zu", size); 39 40 if (!(p = malloc(size))) 41 { 42 LOG_ERROR("Out of memory"); 43 exit(-1); 44 } 45 46 return p; 47 } 48 49 /* 50 * 51 */ 52 53 void xcb_register_key_events(struct Key key) 54 { 55 xcb_keycode_t *keycodes; 56 xcb_keycode_t keycode; 57 58 LOG_DEBUG_VA("Registering key press event for key %d / key %d", key.modifiers, key.keysym); 59 60 keycodes = xcb_get_keycodes(key.keysym); 61 uint16_t modifiers[] = {0, numlockmask, XCB_MOD_MASK_LOCK, numlockmask | XCB_MOD_MASK_LOCK}; 62 63 for (int i = 0; (keycode = keycodes[i]) != XCB_NO_SYMBOL; i++) 64 { 65 for (int j = 0; j != LENGTH(modifiers); j++) 66 xcb_grab_key(c, 1, screen->root, key.modifiers | modifiers[j], keycode, 67 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 68 } 69 70 free(keycodes); 71 } 72 73 /* 74 * Get keycodes from a keysym 75 * TODO: check if there's a way to keep keysyms 76 */ 77 xcb_keycode_t *xcb_get_keycodes(xcb_keysym_t keysym) 78 { 79 xcb_key_symbols_t *keysyms; 80 81 if (!(keysyms = xcb_key_symbols_alloc(c))) 82 { 83 perror("Not able to retrieve symbols"); 84 return (NULL); 85 } 86 87 xcb_keycode_t *keycode = xcb_key_symbols_get_keycode(keysyms, keysym); 88 89 xcb_key_symbols_free(keysyms); 90 return (keycode); 91 } 92 93 /* 94 * Get keysym from a keycode 95 * TODO: check if there's a way to keep keysyms 96 */ 97 xcb_keysym_t xcb_get_keysym(xcb_keycode_t keycode) 98 { 99 xcb_key_symbols_t *keysyms; 100 101 if (!(keysyms = xcb_key_symbols_alloc(c))) 102 { 103 perror("Not able to retrieve symbols"); 104 return (0); 105 } 106 107 xcb_keysym_t keysym = xcb_key_symbols_get_keysym(keysyms, keycode, 0); 108 109 xcb_key_symbols_free(keysyms); 110 return (keysym); 111 } 112 113 #define ONLY_IF_EXISTS 0 114 115 /* Get a defined atom from the X server. */ 116 xcb_atom_t xcb_get_atom(const char *atom_name) 117 { 118 xcb_intern_atom_cookie_t cookie = 119 xcb_intern_atom(c, ONLY_IF_EXISTS, strlen(atom_name), atom_name); 120 121 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(c, cookie, NULL); 122 123 /* XXX Note that we return 0 as an atom if anything goes wrong. 124 * Might become interesting.*/ 125 126 if (reply == NULL) 127 return 0; 128 129 xcb_atom_t atom = reply->atom; 130 free(reply); 131 return atom; 132 } 133 134 bool xcb_send_atom(struct client *client, xcb_atom_t atom) 135 { 136 assert(client != NULL); 137 138 bool supported = false; 139 xcb_get_property_cookie_t cookie = 140 xcb_icccm_get_wm_protocols_unchecked(c, client->id, wm_protocols); 141 142 // Get the supported atoms for this client 143 xcb_icccm_get_wm_protocols_reply_t protocols; 144 if (xcb_icccm_get_wm_protocols_reply(c, cookie, &protocols, NULL) == 1) 145 { 146 for (uint_fast32_t i = 0; i < protocols.atoms_len; i++) 147 { 148 if (protocols.atoms[i] == atom) 149 { 150 supported = true; 151 break; 152 } 153 } 154 } 155 156 xcb_icccm_get_wm_protocols_reply_wipe(&protocols); 157 158 // The client does not support WM_DELETE, let's kill it 159 if (!supported) 160 return false; 161 162 xcb_client_message_event_t ev; 163 ev.response_type = XCB_CLIENT_MESSAGE; 164 ev.format = 32; 165 ev.sequence = 0; 166 ev.window = client->id; 167 ev.type = wm_protocols; 168 ev.data.data32[0] = atom; 169 ev.data.data32[1] = XCB_CURRENT_TIME; 170 xcb_send_event(c, false, client->id, XCB_EVENT_MASK_NO_EVENT, (char *)&ev); 171 return true; 172 }