npv:namespace cleanup, don't need that many short identifiers
[nyanmp.git] / npv / xcb / local / code.frag.c
blob600e27e2c373c2606af109deca6f0731849fa9e1
1 STATIC void npv_xcb_libs_load(void)
3 npv_xcb_lib_l = dlopen("libxcb.so.1", RTLD_LAZY);
4 if (npv_xcb_lib_l == 0)
5 FATALX("%s:unable to load the xcb dynamic shared library\n", dlerror());
6 npv_xcb_xfixes_lib_l = dlopen("libxcb-xfixes.so.0", RTLD_LAZY);
7 if (npv_xcb_xfixes_lib_l == 0)
8 FATALX("%s:unable to load the xcb xfixes dynamic shared library\n", dlerror());
10 #define XCB_DLSYM(x) \
11 npv_dl_##x = dlsym(npv_xcb_lib_l, #x); \
12 if (npv_dl_##x == 0) \
13 FATALX("%s:unable to find " #x "\n", dlerror());
14 #define XCB_XFIXES_DLSYM(x) \
15 npv_dl_##x = dlsym(npv_xcb_xfixes_lib_l, #x); \
16 if (npv_dl_##x == 0) \
17 FATALX("%s:unable to find " #x "\n", dlerror());
18 STATIC void npv_xcb_syms(void)
20 XCB_DLSYM(xcb_connect);
21 XCB_DLSYM(xcb_get_file_descriptor);
22 XCB_DLSYM(xcb_generate_id);
23 XCB_DLSYM(xcb_connection_has_error);
24 XCB_DLSYM(xcb_get_setup);
25 XCB_DLSYM(xcb_setup_roots_length);
26 XCB_DLSYM(xcb_setup_roots_iterator);
27 XCB_DLSYM(xcb_screen_next);
28 XCB_DLSYM(xcb_create_window);
29 XCB_DLSYM(xcb_map_window);
30 XCB_DLSYM(xcb_map_window_checked);
31 XCB_DLSYM(xcb_request_check);
32 XCB_DLSYM(xcb_flush);
33 XCB_DLSYM(xcb_wait_for_event);
34 XCB_DLSYM(xcb_poll_for_event);
35 XCB_DLSYM(xcb_change_property);
36 XCB_DLSYM(xcb_disconnect);
37 XCB_DLSYM(xcb_force_screen_saver);
38 XCB_DLSYM(xcb_get_extension_data);
39 XCB_DLSYM(xcb_query_pointer);
40 XCB_DLSYM(xcb_query_pointer_reply);
41 XCB_DLSYM(xcb_send_event);
42 XCB_DLSYM(xcb_intern_atom);
43 XCB_DLSYM(xcb_intern_atom_reply);
44 XCB_XFIXES_DLSYM(xcb_xfixes_id);
45 XCB_XFIXES_DLSYM(xcb_xfixes_query_version);
46 XCB_XFIXES_DLSYM(xcb_xfixes_show_cursor);
47 XCB_XFIXES_DLSYM(xcb_xfixes_hide_cursor);
49 #undef XCB_DLSYM
50 STATIC void npv_xcb_win_create(void)
52 u32 value_mask;
53 u32 value_list[2];
55 npv_xcb_p.win_id = npv_dl_xcb_generate_id(npv_xcb_p.c);
56 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:window id=%#x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.win_id);
58 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
59 value_list[0] = npv_xcb_p.scr->black_pixel;
60 value_list[1] = XCB_EVENT_MASK_KEY_RELEASE
61 | XCB_EVENT_MASK_STRUCTURE_NOTIFY
62 | XCB_EVENT_MASK_POINTER_MOTION
63 | XCB_EVENT_MASK_BUTTON_MOTION
64 | XCB_EVENT_MASK_LEAVE_WINDOW
65 | XCB_EVENT_MASK_ENTER_WINDOW;
66 npv_dl_xcb_create_window(npv_xcb_p.c, XCB_COPY_FROM_PARENT,
67 npv_xcb_p.win_id,
68 npv_xcb_p.scr->root, 0, 0,
69 npv_xcb_p.width, npv_xcb_p.height,
71 XCB_WINDOW_CLASS_INPUT_OUTPUT,
72 npv_xcb_p.scr->root_visual,
73 value_mask, value_list);
75 STATIC void npv_xcb_win_map(void)
77 xcb_void_cookie_t cookie;
78 xcb_generic_error_t *e;
80 cookie = npv_dl_xcb_map_window_checked(npv_xcb_p.c, npv_xcb_p.win_id);
81 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:window id:%#x:map window request cookie=%#x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.win_id, cookie);
83 e = npv_dl_xcb_request_check(npv_xcb_p.c, cookie);
84 if (e != 0)
85 FATALX("'%s':connection:%p:screen:%d:root window id:%#x:window id:%#x:unable to map window\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.win_id);
86 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:window id:%#x:window mapped\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.win_id);
89 * a disp is n scrs and 1 [set of] keyboard[s] and 1 [set of] mouse[s]
90 * 1 scr could be n monitors
91 * nowdays: usually 1 scr per display
92 * 1 scr has 1 root win
94 STATIC void npv_xcb_connect(void)
96 int r;
98 npv_xcb_p.disp_env = getenv("DISPLAY");
99 if (npv_xcb_p.disp_env == 0 || npv_xcb_p.disp_env[0] == 0)
100 FATALX("no x11 DISPLAY environment variable, exiting\n");
102 npv_xcb_p.scr_idx = 0;
103 /* should be 0 though */
104 npv_xcb_p.c = npv_dl_xcb_connect(0, &npv_xcb_p.scr_idx);
105 r = npv_dl_xcb_connection_has_error(npv_xcb_p.c);
106 if (r > 0)
107 FATALX("%d:%s:error while connecting to the x11 server\n", r, npv_xcb_p.disp_env);
108 POUTX("'%s':connection=%p, default screen index is %d (should be 0)\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx);
110 npv_xcb_p.fd = npv_dl_xcb_get_file_descriptor(npv_xcb_p.c);
111 if (npv_xcb_p.fd == -1)
112 FATALX("'%s':unable to get the connection file descriptor for epoll\n", npv_xcb_p.disp_env);
113 POUTX("'%s':connection:%p:file descriptor %d\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.fd);
115 STATIC void npv_xcb_scr_get(void)
117 xcb_screen_iterator_t iter;
118 int scrs_n;
119 int i;
121 npv_xcb_p.setup = npv_dl_xcb_get_setup(npv_xcb_p.c);
123 scrs_n = npv_dl_xcb_setup_roots_length(npv_xcb_p.setup);
124 POUTX("'%s':connection:%p:has %d screens (should be 1)\n", npv_xcb_p.disp_env, npv_xcb_p.c, scrs_n);
126 iter = npv_dl_xcb_setup_roots_iterator(npv_xcb_p.setup);
127 i = 0;
128 npv_xcb_p.scr = 0;
129 loop {
130 if (iter.rem == 0)
131 break; /* no more scr to iterate on */
133 if (i == npv_xcb_p.scr_idx) {
134 npv_xcb_p.scr = iter.data;
135 break;
137 npv_dl_xcb_screen_next(&iter);
139 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:width=%d pixels\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->width_in_pixels);
140 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:height=%d pixels\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->height_in_pixels);
141 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:white pixel=0x%08x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->white_pixel);
142 POUTX("'%s':connection:%p:screen:%d:root window id:%#x:black pixel=0x%08x\n", npv_xcb_p.disp_env, npv_xcb_p.c, npv_xcb_p.scr_idx, npv_xcb_p.scr->root, npv_xcb_p.scr->black_pixel);
144 #define MIN_SZ_BIT (1 << 4)
145 #define MAX_SZ_BIT (1 << 5)
146 #define BASE_SZ_BIT (1 << 8)
147 #define FLAGS 0
148 /* 4 padding dwords */
149 #define MIN_WIDTH 5
150 #define MIN_HEIGHT 6
151 #define MAX_WIDTH 7
152 #define MAX_HEIGHT 8
153 #define BASE_WIDTH 15
154 #define BASE_HEIGHT 16
155 #define DWORDS_N 18
156 STATIC void npv_xcb_wm_hints(void)
158 #if 0
159 /* the following will tell the wm the win is not resizable */
160 u32 data[DWORDS_N];
162 memset(data, 0, sizeof(data));
163 data[FLAGS] = MIN_SZ_BIT | MAX_SZ_BIT;
165 * XXX: min == max --> the wm must understand this information as the
166 * win being non-resizeable.
167 * next: unlock the size and recreate the vulkan swpchn at each x11
168 * resize evt.
170 data[MIN_WIDTH] = npv_xcb_p.width;
171 data[MIN_HEIGHT] = npv_xcb_p.height;
172 data[MAX_WIDTH] = npv_xcb_p.width;
173 data[MAX_HEIGHT] = npv_xcb_p.height;
174 npv_dl_xcb_change_property(npv_xcb_p.c, XCB_PROP_MODE_REPLACE,
175 npv_xcb_p.win_id, XCB_ATOM_WM_NORMAL_HINTS,
176 XCB_ATOM_WM_SIZE_HINTS, 32, DWORDS_N, data);
177 #endif
178 #if 0
179 /* the following will set the base size */
180 u32 data[DWORDS_N];
182 memset(data, 0, sizeof(data));
183 data[FLAGS] = BASE_SZ_BIT;
184 data[BASE_WIDTH] = npv_xcb_p.width;
185 data[BASE_HEIGHT] = npv_xcb_p.height;
187 npv_dl_xcb_change_property(npv_xcb_p.c, XCB_PROP_MODE_REPLACE,
188 npv_xcb_p.win_id, XCB_ATOM_WM_NORMAL_HINTS,
189 XCB_ATOM_WM_SIZE_HINTS, 32, DWORDS_N, data);
190 #endif
192 #undef MIN_SZ_BIT
193 #undef MAX_SZ_BIT
194 #undef BASE_SZ_BIT
195 #undef FLAGS
196 #undef MIN_WIDTH
197 #undef MIN_HEIGHT
198 #undef MAX_WIDTH
199 #undef MAX_HEIGHT
200 #undef BASE_WIDTH
201 #undef BASE_HEIGHT
202 #undef DWORDS_N
203 #define NPV_WM_CLASS "npv\0npv"
204 STATIC void npv_xcb_wm_class(void)
206 npv_dl_xcb_change_property(npv_xcb_p.c, XCB_PROP_MODE_REPLACE,
207 npv_xcb_p.win_id, XCB_ATOM_WM_CLASS,
208 XCB_ATOM_STRING, 8, sizeof(NPV_WM_CLASS),
209 NPV_WM_CLASS);
211 #undef NPV_WM_CLASS
212 #define NPV_WM_NAME "npv"
213 STATIC void npv_xcb_wm_name(void)
215 npv_dl_xcb_change_property(npv_xcb_p.c, XCB_PROP_MODE_REPLACE,
216 npv_xcb_p.win_id, XCB_ATOM_WM_NAME,
217 XCB_ATOM_STRING, 8, strlen(NPV_WM_NAME),
218 NPV_WM_NAME);
220 #undef NPV_WM_NAME
221 STATIC void npv_xcb_evt_key_release(xcb_generic_event_t *evt)
223 u8 b;
224 xcb_key_release_event_t *key;
226 key = (xcb_key_release_event_t*)evt;
227 b = 0;
228 loop {
229 if (b == ARRAY_N(npv_x11_binds))
230 break;
231 if (key->detail == npv_x11_binds[b].keycode) {
232 POUTX("'%s':connection:%p:event:key release:keycode:%#02x:running command for bind \"%s\"\n", npv_xcb_p.disp_env, npv_xcb_p.c, key->detail, npv_x11_binds[b].name);
233 npv_x11_binds[b].cmd();
234 return;
236 ++b;
238 POUTX("'%s':connection:%p:event:key release:keycode:%#02x\n", npv_xcb_p.disp_env, npv_xcb_p.c, key->detail);
240 STATIC void npv_xcb_evt_leave_win(xcb_generic_event_t *evt)
242 if (npv_xcb_p.mouse_hidden) {
243 npv_dl_xcb_xfixes_show_cursor(npv_xcb_p.c, npv_xcb_p.win_id);
244 npv_dl_xcb_flush(npv_xcb_p.c);
246 npv_xcb_p.mouse_hidden = false;
247 npv_xcb_p.last_root_x = -1;
248 npv_xcb_p.last_root_y = -1;
250 STATIC void npv_xcb_mouse_visibility_timer_start(void)
252 struct itimerspec t;
253 int r;
255 memset(&t, 0, sizeof(t));
256 t.it_value.tv_sec = npv_xcb_mouse_visibility_interval_s;
257 r = timerfd_settime(npv_xcb_p.mouse_visibility_timer_fd, 0, &t, 0);
258 if (r == -1)
259 FATALX("unable to arm the mouse visibility timer to %u seconds\n", npv_xcb_mouse_visibility_interval_s);
261 STATIC void npv_xcb_evt_enter_win(xcb_generic_event_t *evt)
263 xcb_enter_notify_event_t *ene;
265 ene = (xcb_enter_notify_event_t*)evt;
266 npv_dl_xcb_xfixes_show_cursor(npv_xcb_p.c, npv_xcb_p.win_id);
267 npv_dl_xcb_flush(npv_xcb_p.c);
268 npv_xcb_p.mouse_hidden = false;
269 npv_xcb_p.last_root_x = ene->root_x;
270 npv_xcb_p.last_root_y = ene->root_y;
271 npv_xcb_mouse_visibility_timer_start();
273 STATIC void npv_xcb_evt_motion(xcb_generic_event_t *evt)
275 xcb_motion_notify_event_t *mne;
277 mne = (xcb_motion_notify_event_t*)evt;
278 if (npv_xcb_p.mouse_hidden) {
279 npv_dl_xcb_xfixes_show_cursor(npv_xcb_p.c, npv_xcb_p.win_id);
280 npv_dl_xcb_flush(npv_xcb_p.c);
282 npv_xcb_p.mouse_hidden = false;
283 npv_xcb_p.last_root_x = mne->root_x;
284 npv_xcb_p.last_root_y = mne->root_y;
285 npv_xcb_mouse_visibility_timer_start();
287 #if 0
288 typedef struct xcb_configure_notify_event_t {
289 uint8_t response_type;
290 uint8_t pad0;
291 uint16_t sequence;
292 xcb_window_t event;
293 xcb_window_t window;
294 xcb_window_t above_sibling;
295 int16_t x;
296 int16_t y;
297 uint16_t width;
298 uint16_t height;
299 uint16_t border_width;
300 uint8_t override_redirect;
301 uint8_t pad1;
302 } xcb_configure_notify_event_t;
303 #endif
304 STATIC void npv_xcb_evt_cfg_notify(xcb_generic_event_t *evt)
306 xcb_configure_notify_event_t *cne;
308 cne = (xcb_configure_notify_event_t*)evt;
309 npv_xcb_p.width = cne->width;
310 npv_xcb_p.height = cne->height;
311 #if 0
312 PERR("CFG_NOTIFY_EVT:x=%d y=%d w=%u h=%u bw=%u\n", cne->x, cne->y, cne->width, cne->height, cne->border_width);
313 #endif
315 STATIC void npv_xcb_evt_handle(xcb_generic_event_t *evt)
317 u8 evt_code;
319 * do not discriminate evts generated by clients using sendevent
320 * requests (note: "client message" evts have always their most
321 * significant bit set)
323 evt_code = evt->response_type & 0x7f;
325 switch (evt_code) {
326 case XCB_KEY_RELEASE:
327 npv_xcb_evt_key_release(evt);
328 break;
329 case XCB_CONFIGURE_NOTIFY:
330 npv_xcb_evt_cfg_notify(evt);
331 break;
332 case XCB_MOTION_NOTIFY:
333 npv_xcb_evt_motion(evt);
334 break;
335 case XCB_LEAVE_NOTIFY:
336 npv_xcb_evt_leave_win(evt);
337 break;
338 case XCB_ENTER_NOTIFY:
339 npv_xcb_evt_enter_win(evt);
340 break;
341 default:
342 break;
345 STATIC void npv_xcb_screensaver_heartbeat_timer_init_once(void)
347 errno = 0;
348 npv_xcb_p.screensaver_heartbeat_timer_fd = timerfd_create(
349 CLOCK_MONOTONIC, TFD_NONBLOCK);
350 if (npv_xcb_p.screensaver_heartbeat_timer_fd == -1)
351 FATALX("unable to get a timer file descriptor for the screensaver heartbeat:%s\n", strerror(errno));
353 STATIC void npv_xcb_mouse_visibilty_init_once(void)
355 struct xcb_query_extension_reply_t const *xfixes;
356 xcb_xfixes_query_version_cookie_t qec;
358 xfixes = npv_dl_xcb_get_extension_data(npv_xcb_p.c,
359 npv_dl_xcb_xfixes_id);
360 if (xfixes->response_type != 1 || xfixes->present == 0)
361 WARNINGX("the server is missing xfixes extension\n");
362 /* the hice/show cursor is supported from version 4 */
363 npv_dl_xcb_xfixes_query_version(npv_xcb_p.c, 4, 0);
364 /*--------------------------------------------------------------------*/
365 npv_xcb_p.mouse_hidden = false;
366 npv_xcb_p.last_root_x = -1;
367 npv_xcb_p.last_root_y = -1;
369 errno = 0;
370 npv_xcb_p.mouse_visibility_timer_fd = timerfd_create(CLOCK_MONOTONIC,
371 TFD_NONBLOCK);
372 if (npv_xcb_p.mouse_visibility_timer_fd == -1)
373 FATALX("unable to get a timer file descriptor for the mouse visibility management:%s\n", strerror(errno));
375 #define NET_WM_STATE "_NET_WM_STATE"
376 #define NET_WM_STATE_FULLSCREEN "_NET_WM_STATE_FULLSCREEN"
377 #define SOURCE_NORMAL_APP 1
378 #define STRLEN(x) (sizeof(x)-1)
379 #define DONT_PROPAGATE_TO_ANCESTORS 0
380 STATIC void npv_xcb_fullscreen_action(u32 action)
382 xcb_intern_atom_cookie_t cookie_net_wm_state;
383 xcb_intern_atom_cookie_t cookie_net_wm_state_fullscreen;
384 xcb_intern_atom_reply_t *reply;
385 xcb_generic_error_t *err;
386 xcb_atom_t net_wm_state;
387 xcb_atom_t net_wm_state_fullscreen;
388 xcb_client_message_event_t cm_evt;
390 cookie_net_wm_state = npv_dl_xcb_intern_atom(npv_xcb_p.c, 1,
391 STRLEN(NET_WM_STATE), NET_WM_STATE);
392 cookie_net_wm_state_fullscreen = npv_dl_xcb_intern_atom(npv_xcb_p.c, 1,
393 STRLEN(NET_WM_STATE_FULLSCREEN), NET_WM_STATE_FULLSCREEN);
394 err = 0;
395 reply = npv_dl_xcb_intern_atom_reply(npv_xcb_p.c, cookie_net_wm_state,
396 &err);
397 if (reply == 0) {
398 WARNINGX("unable to set fullscreen:unable to get the _NET_WM_STATE atom:%d\n", err->error_code);
399 free(err);
400 return;
402 net_wm_state = reply->atom;
403 free(reply);
404 err = 0;
405 reply = npv_dl_xcb_intern_atom_reply(npv_xcb_p.c,
406 cookie_net_wm_state_fullscreen, &err);
407 if (reply == 0) {
408 WARNINGX("unable to set fullscreen:unable to get the _NET_WM_STATE_FULLSCREEN atom:%d\n", err->error_code);
409 free(err);
410 return;
412 net_wm_state_fullscreen = reply->atom;
413 free(reply);
414 /*--------------------------------------------------------------------*/
415 memset(&cm_evt, 0, sizeof(cm_evt));
416 cm_evt.response_type = XCB_CLIENT_MESSAGE;
417 cm_evt.format = 32;
418 cm_evt.window = npv_xcb_p.win_id;
419 cm_evt.type = net_wm_state;
420 cm_evt.data.data32[0] = action;
421 cm_evt.data.data32[1] = net_wm_state_fullscreen;
422 cm_evt.data.data32[3] = SOURCE_NORMAL_APP;
424 * client message send event req must use the evt mask below and must
425 * not propagate the evt, see ewmh specs
427 npv_dl_xcb_send_event(npv_xcb_p.c, DONT_PROPAGATE_TO_ANCESTORS,
428 npv_xcb_p.scr->root, XCB_EVENT_MASK_STRUCTURE_NOTIFY
429 | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT , (u8*)&cm_evt);
430 npv_dl_xcb_flush(npv_xcb_p.c);
432 #undef NET_WM_STATE
433 #undef NET_WM_STATE_FULLSCREEN
434 #undef NET_WM_STATE_ADD
435 #undef SOURCE_NORMAL_APP
436 #undef STRLEN
437 #undef DONT_PROPAGATE_TO_ANCESTORS
438 #define NET_WM_STATE_ADD 1
439 STATIC void npv_xcb_fullscreen_init_once(bool start_fullscreen)
441 xcb_intern_atom_cookie_t cookie_net_wm_state;
442 xcb_intern_atom_cookie_t cookie_net_wm_state_fullscreen;
443 xcb_intern_atom_reply_t *reply;
444 xcb_generic_error_t *err;
445 xcb_atom_t net_wm_state;
446 xcb_atom_t net_wm_state_fullscreen;
447 xcb_client_message_event_t cm_evt;
449 if (!start_fullscreen)
450 return;
451 npv_xcb_fullscreen_action(NET_WM_STATE_ADD);
453 #undef NET_WM_STATE_ADD