]> git.sur5r.net Git - i3/i3lock/blob - xcb.c
Raise the i3lock window upon visibility notifies
[i3/i3lock] / xcb.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * © 2010 Michael Stapelberg
5  *
6  * xcb.c: contains all functions which use XCB to talk to X11. Mostly wrappers
7  *        around the rather complicated/ugly parts of the XCB API.
8  *
9  */
10 #include <xcb/xcb.h>
11 #include <xcb/xcb_keysyms.h>
12 #include <xcb/dpms.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdbool.h>
16 #include <assert.h>
17 #include <err.h>
18
19 static uint32_t get_colorpixel(char *hex) {
20     char strgroups[3][3] = {{hex[0], hex[1], '\0'},
21                             {hex[2], hex[3], '\0'},
22                             {hex[4], hex[5], '\0'}};
23     uint32_t rgb16[3] = {(strtol(strgroups[0], NULL, 16)),
24                          (strtol(strgroups[1], NULL, 16)),
25                          (strtol(strgroups[2], NULL, 16))};
26
27     return (rgb16[0] << 16) + (rgb16[1] << 8) + rgb16[2];
28 }       
29
30 xcb_visualtype_t *get_root_visual_type(xcb_screen_t *screen) {
31     xcb_visualtype_t *visual_type = NULL;
32     xcb_depth_iterator_t depth_iter;
33     xcb_visualtype_iterator_t visual_iter;
34
35     for (depth_iter = xcb_screen_allowed_depths_iterator(screen);
36          depth_iter.rem;
37          xcb_depth_next(&depth_iter)) {
38
39         for (visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
40              visual_iter.rem;
41              xcb_visualtype_next(&visual_iter)) {
42             if (screen->root_visual != visual_iter.data->visual_id)
43                 continue;
44
45             visual_type = visual_iter.data;
46             return visual_type;
47         }
48     }
49
50     return NULL;
51 }
52
53 xcb_window_t open_fullscreen_window(xcb_connection_t *conn, xcb_screen_t *scr, char *color) {
54     uint32_t mask = 0;
55     uint32_t values[3];
56     xcb_window_t win = xcb_generate_id(conn);
57
58     mask |= XCB_CW_BACK_PIXEL;
59     values[0] = get_colorpixel(color);
60
61     mask |= XCB_CW_OVERRIDE_REDIRECT;
62     values[1] = 1;
63
64     mask |= XCB_CW_EVENT_MASK;
65     values[2] = XCB_EVENT_MASK_EXPOSURE |
66                 XCB_EVENT_MASK_KEY_PRESS |
67                 XCB_EVENT_MASK_KEY_RELEASE |
68                 XCB_EVENT_MASK_VISIBILITY_CHANGE;
69
70     xcb_create_window(conn,
71                       24,
72                       win, /* the window id */
73                       scr->root, /* parent == root */
74                       0, 0,
75                       scr->width_in_pixels,
76                       scr->height_in_pixels, /* dimensions */
77                       0, /* border = 0, we draw our own */
78                       XCB_WINDOW_CLASS_INPUT_OUTPUT,
79                       XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */
80                       mask,
81                       values);
82
83     /* Map the window (= make it visible) */
84     xcb_map_window(conn, win);
85
86     /* Raise window (put it on top) */
87     values[0] = XCB_STACK_MODE_ABOVE;
88     xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
89
90     return win;
91 }
92
93 /*
94  * Returns the mask for Mode_switch (to be used for looking up keysymbols by
95  * keycode).
96  *
97  */
98 uint32_t get_mod_mask(xcb_connection_t *conn, xcb_key_symbols_t *symbols, uint32_t keycode) {
99     xcb_get_modifier_mapping_reply_t *modmap_r;
100     xcb_keycode_t *modmap, kc;
101     xcb_keycode_t *modeswitchcodes = xcb_key_symbols_get_keycode(symbols, keycode);
102     if (modeswitchcodes == NULL)
103         return 0;
104
105     modmap_r = xcb_get_modifier_mapping_reply(conn, xcb_get_modifier_mapping(conn), NULL);
106     modmap = xcb_get_modifier_mapping_keycodes(modmap_r);
107
108     for (int i = 0; i < 8; i++)
109         for (int j = 0; j < modmap_r->keycodes_per_modifier; j++) {
110             kc = modmap[i * modmap_r->keycodes_per_modifier + j];
111             for (xcb_keycode_t *ktest = modeswitchcodes; *ktest; ktest++) {
112                 if (*ktest != kc)
113                     continue;
114
115                 free(modeswitchcodes);
116                 free(modmap_r);
117                 return (1 << i);
118             }
119         }
120
121     return 0;
122 }
123
124 void dpms_turn_off_screen(xcb_connection_t *conn) {
125     xcb_dpms_enable(conn);
126     xcb_dpms_force_level(conn, XCB_DPMS_DPMS_MODE_OFF);
127     xcb_flush(conn);
128 }
129
130 /*
131  * Repeatedly tries to grab pointer and keyboard (up to 1000 times).
132  *
133  */
134 void grab_pointer_and_keyboard(xcb_connection_t *conn, xcb_screen_t *screen) {
135     xcb_grab_pointer_cookie_t pcookie;
136     xcb_grab_pointer_reply_t *preply;
137
138     xcb_grab_keyboard_cookie_t kcookie;
139     xcb_grab_keyboard_reply_t *kreply;
140
141     int tries = 1000;
142
143     while (tries-- > 0) {
144         pcookie = xcb_grab_pointer(
145             conn,
146             false,               /* get all pointer events specified by the following mask */
147             screen->root,        /* grab the root window */
148             XCB_NONE,            /* which events to let through */
149             XCB_GRAB_MODE_ASYNC, /* pointer events should continue as normal */
150             XCB_GRAB_MODE_ASYNC, /* keyboard mode */
151             XCB_NONE,            /* confine_to = in which window should the cursor stay */
152             XCB_NONE,            /* don’t display a special cursor */
153             XCB_CURRENT_TIME
154         );
155
156         if ((preply = xcb_grab_pointer_reply(conn, pcookie, NULL)) &&
157             preply->status == XCB_GRAB_STATUS_SUCCESS) {
158             free(preply);
159             break;
160         }
161     }
162
163     while (tries-- > 0) {
164         kcookie = xcb_grab_keyboard(
165             conn,
166             true,                /* report events */
167             screen->root,        /* grab the root window */
168             XCB_CURRENT_TIME,
169             XCB_GRAB_MODE_ASYNC, /* process events as normal, do not require sync */
170             XCB_GRAB_MODE_ASYNC
171         );
172
173         if ((kreply = xcb_grab_keyboard_reply(conn, kcookie, NULL)) &&
174             kreply->status == XCB_GRAB_STATUS_SUCCESS) {
175             free(kreply);
176             break;
177         }
178     }
179
180     if (tries == 0)
181         errx(EXIT_FAILURE, "Cannot grab pointer/keyboard");
182 }