kbgwm

sucklessy floating window manager
git clone https://git.neuralcrash.com/kbgwm.git
Log | Files | Refs | README | LICENSE

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 }