tlibwm.c - libwm - X windows manipulation library
(HTM) git clone git://z3bra.org/libwm
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
tlibwm.c (11292B)
---
1 #include <xcb/xcb.h>
2 #include <xcb/xcb_cursor.h>
3 #include <xcb/randr.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "wm.h"
9
10 int
11 wm_init_xcb()
12 {
13 conn = xcb_connect(NULL, NULL);
14 if (xcb_connection_has_error(conn))
15 return -1;
16 return 0;
17 }
18
19 int
20 wm_kill_xcb()
21 {
22 if (!conn)
23 return -1;
24 xcb_disconnect(conn);
25 return 0;
26 }
27
28 int
29 wm_is_alive(xcb_window_t wid)
30 {
31 xcb_get_window_attributes_cookie_t c;
32 xcb_get_window_attributes_reply_t *r;
33
34 c = xcb_get_window_attributes(conn, wid);
35 r = xcb_get_window_attributes_reply(conn, c, NULL);
36
37 if (r == NULL)
38 return 0;
39
40 free(r);
41 return 1;
42 }
43
44 int
45 wm_is_mapped(xcb_window_t wid)
46 {
47 int ms;
48 xcb_get_window_attributes_cookie_t c;
49 xcb_get_window_attributes_reply_t *r;
50
51 c = xcb_get_window_attributes(conn, wid);
52 r = xcb_get_window_attributes_reply(conn, c, NULL);
53
54 if (r == NULL)
55 return 0;
56
57 ms = r->map_state;
58
59 free(r);
60 return ms == XCB_MAP_STATE_VIEWABLE;
61 }
62
63 int
64 wm_is_ignored(xcb_window_t wid)
65 {
66 int or;
67 xcb_get_window_attributes_cookie_t c;
68 xcb_get_window_attributes_reply_t *r;
69
70 c = xcb_get_window_attributes(conn, wid);
71 r = xcb_get_window_attributes_reply(conn, c, NULL);
72
73 if (r == NULL)
74 return 0;
75
76 or = r->override_redirect;
77
78 free(r);
79 return or;
80 }
81
82 int
83 wm_is_listable(xcb_window_t wid, int mask)
84 {
85 if (!mask && wm_is_mapped (wid) && !wm_is_ignored(wid))
86 return 1;
87 if ((mask & LIST_ALL))
88 return 1;
89 if (!wm_is_mapped (wid) && mask & LIST_HIDDEN)
90 return 1;
91 if (wm_is_ignored(wid) && mask & LIST_IGNORE)
92 return 1;
93
94 return 0;
95 }
96
97 int
98 wm_get_screen()
99 {
100 scrn = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
101 if (scrn == NULL)
102 return -1;
103 return 0;
104 }
105
106 int
107 wm_get_windows(xcb_window_t wid, xcb_window_t **l)
108 {
109 uint32_t childnum = 0;
110 xcb_query_tree_cookie_t c;
111 xcb_query_tree_reply_t *r;
112
113 c = xcb_query_tree(conn, wid);
114 r = xcb_query_tree_reply(conn, c, NULL);
115 if (r == NULL)
116 return -1;
117
118 *l = malloc(sizeof(xcb_window_t) * r->children_len);
119 memcpy(*l, xcb_query_tree_children(r),
120 sizeof(xcb_window_t) * r->children_len);
121
122 childnum = r->children_len;
123
124 free(r);
125 return childnum;
126 }
127
128 xcb_window_t
129 wm_get_focus(void)
130 {
131 xcb_window_t wid = 0;
132 xcb_get_input_focus_cookie_t c;
133 xcb_get_input_focus_reply_t *r;
134
135 c = xcb_get_input_focus(conn);
136 r = xcb_get_input_focus_reply(conn, c, NULL);
137 if (r == NULL)
138 return scrn->root;
139
140 wid = r->focus;
141 free(r);
142 return wid;
143 }
144
145
146 int
147 wm_get_attribute(xcb_window_t wid, int attr)
148 {
149 xcb_get_geometry_cookie_t c;
150 xcb_get_geometry_reply_t *r;
151
152 c = xcb_get_geometry(conn, wid);
153 r = xcb_get_geometry_reply(conn, c, NULL);
154
155 if (r == NULL)
156 return -1;
157
158 switch (attr) {
159 case ATTR_X:
160 attr = r->x;
161 break;
162 case ATTR_Y:
163 attr = r->y;
164 break;
165 case ATTR_W:
166 attr = r->width;
167 break;
168 case ATTR_H:
169 attr = r->height;
170 break;
171 case ATTR_B:
172 attr = r->border_width;
173 break;
174 case ATTR_D:
175 attr = r->depth;
176 break;
177 }
178
179 free(r);
180 return attr;
181 }
182
183 xcb_atom_t
184 wm_add_atom(char *name, size_t len)
185 {
186 xcb_atom_t atom;
187 xcb_intern_atom_cookie_t c;
188 xcb_intern_atom_reply_t *r;
189
190 c = xcb_intern_atom(conn, 0, len, name);
191 r = xcb_intern_atom_reply(conn, c, NULL);
192 if (!r)
193 return 0;
194
195 atom = r->atom;
196 free(r);
197
198 return atom;
199 }
200
201 int
202 wm_set_atom(xcb_window_t wid, xcb_atom_t atom, xcb_atom_t type, size_t len, void *data)
203 {
204 int errcode;
205 xcb_void_cookie_t c;
206 xcb_generic_error_t *e;
207
208 c = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE,
209 wid, atom, type, 32, len, data);
210 e = xcb_request_check(conn, c);
211 if (!e)
212 return 0;
213
214 errcode = e->error_code;
215 free(e);
216
217 return errcode;
218 }
219
220 void *
221 wm_get_atom(xcb_window_t wid, xcb_atom_t atom, xcb_atom_t type, size_t *len)
222 {
223 void *d;
224 size_t n;
225 xcb_get_property_cookie_t c;
226 xcb_get_property_reply_t *r;
227
228 c = xcb_get_property(conn, 0, wid, atom, type, 0, 32);
229 r = xcb_get_property_reply(conn, c, NULL);
230 if (!r)
231 return NULL;
232
233 if (!(n = xcb_get_property_value_length(r))) {
234 free(r);
235 return NULL;
236 }
237
238 if (len)
239 *len = n;
240
241 d = xcb_get_property_value(r);
242
243 return d;
244 }
245
246 char *
247 wm_get_atom_name(xcb_atom_t atom, size_t *len)
248 {
249 size_t n;
250 char *name;
251 xcb_get_atom_name_cookie_t c;
252 xcb_get_atom_name_reply_t *r;
253
254 c = xcb_get_atom_name(conn, atom);
255 r = xcb_get_atom_name_reply(conn, c, NULL);
256 if (!r)
257 return NULL;
258
259 n = xcb_get_atom_name_name_length(r) + 1;
260 name = malloc(xcb_get_atom_name_name_length(r) + 1);
261 if (!name) {
262 free(r);
263 return NULL;
264 }
265
266 if (len)
267 *len = n;
268
269 memset(name, 0, xcb_get_atom_name_name_length(r) + 1);
270 strncpy(name, xcb_get_atom_name_name(r), xcb_get_atom_name_name_length(r));
271 free(r);
272
273 return name;
274 }
275
276
277 int
278 wm_get_cursor(int mode, uint32_t wid, int *x, int *y)
279 {
280 xcb_query_pointer_reply_t *r;
281 xcb_query_pointer_cookie_t c;
282
283 c = xcb_query_pointer(conn, wid);
284 r = xcb_query_pointer_reply(conn, c, NULL);
285
286 if (r == NULL)
287 return -1;
288
289 if (r->child != XCB_NONE) {
290 *x = r->win_x;
291 *y = r->win_y;
292 } else {
293 *x = r->root_x;
294 *y = r->root_y;
295 }
296
297 return 0;
298 }
299
300 int
301 wm_set_border(int width, int color, xcb_window_t wid)
302 {
303 uint32_t values[1];
304 int mask;
305
306 /* change width if >= 0 */
307 if (width > -1) {
308 values[0] = width;
309 mask = XCB_CONFIG_WINDOW_BORDER_WIDTH;
310 xcb_configure_window(conn, wid, mask, values);
311 }
312
313 /*
314 * color is an ARGB representation (eg. 0x80ff0000) for
315 * translucent red.
316 * Absolutely all values are valid color representations, so we
317 * will set it no matter what.
318 */
319 values[0] = color;
320 mask = XCB_CW_BORDER_PIXEL;
321 xcb_change_window_attributes(conn, wid, mask, values);
322
323 return 0;
324 }
325
326 int
327 wm_set_cursor(int x, int y, int mode)
328 {
329 xcb_warp_pointer(conn, XCB_NONE, mode ? XCB_NONE : scrn->root,
330 0, 0, 0, 0, x, y);
331 return 0;
332 }
333
334 int
335 wm_teleport(xcb_window_t wid, int x, int y, int w, int h)
336 {
337 uint32_t values[4];
338 uint32_t mask = XCB_CONFIG_WINDOW_X
339 | XCB_CONFIG_WINDOW_Y
340 | XCB_CONFIG_WINDOW_WIDTH
341 | XCB_CONFIG_WINDOW_HEIGHT;
342 values[0] = x;
343 values[1] = y;
344 values[2] = w;
345 values[3] = h;
346 xcb_configure_window(conn, wid, mask, values);
347
348 return 0;
349 }
350
351 int
352 wm_move(xcb_window_t wid, int mode, int x, int y)
353 {
354 int curx, cury, curw, curh, curb;
355
356 if (!wm_is_mapped(wid) || wid == scrn->root)
357 return -1;
358
359 curb = wm_get_attribute(wid, ATTR_B);
360 curx = wm_get_attribute(wid, ATTR_X);
361 cury = wm_get_attribute(wid, ATTR_Y);
362 curw = wm_get_attribute(wid, ATTR_W);
363 curh = wm_get_attribute(wid, ATTR_H);
364
365 if (mode == RELATIVE) {
366 x += curx;
367 y += cury;
368 }
369
370 /* the following prevent windows from moving off the screen */
371 if (x < 0)
372 x = 0;
373 else if (x > scrn->width_in_pixels - curw - 2*curb)
374 x = scrn->width_in_pixels - curw - 2*curb;
375
376 if (y < 0)
377 y = 0;
378 else if (y > scrn->height_in_pixels - curh - 2*curb)
379 y = scrn->height_in_pixels - curh - 2*curb;
380
381 wm_teleport(wid, x, y, curw, curh);
382 return 0;
383 }
384
385 int
386 wm_set_override(xcb_window_t wid, int or)
387 {
388 uint32_t mask = XCB_CW_OVERRIDE_REDIRECT;
389 uint32_t val[] = { or };
390
391 xcb_change_window_attributes(conn, wid, mask, val);
392
393 return 0;
394 }
395
396
397 int
398 wm_remap(xcb_window_t wid, int mode)
399 {
400 switch (mode) {
401 case MAP:
402 xcb_map_window(conn, wid);
403 break;
404 case UNMAP:
405 xcb_unmap_window(conn, wid);
406 break;
407 case TOGGLE:
408 if (wm_is_mapped(wid))
409 xcb_unmap_window(conn, wid);
410 else
411 xcb_map_window(conn, wid);
412 break;
413 }
414
415 return 0;
416 }
417
418 int
419 wm_resize(xcb_window_t wid, int mode, int w, int h)
420 {
421 int curx, cury, curw, curh, curb;
422
423 if (!wm_is_mapped(wid) || wid == scrn->root)
424 return -1;
425
426 curb = wm_get_attribute(wid, ATTR_B);
427 curx = wm_get_attribute(wid, ATTR_X);
428 cury = wm_get_attribute(wid, ATTR_Y);
429 curw = wm_get_attribute(wid, ATTR_W);
430 curh = wm_get_attribute(wid, ATTR_H);
431
432 if (mode == RELATIVE) {
433 w += curw;
434 h += curh;
435 } else {
436 w -= curx;
437 h -= cury;
438 }
439
440 /*
441 * The following prevent windows from growing out of the screen, or
442 * having a negative size
443 */
444 if (w < 0)
445 w = curw;
446 if (curx + w > scrn->width_in_pixels)
447 w = scrn->width_in_pixels - curx - 2*curb;
448
449 if (h < 0)
450 h = curh;
451 if (cury + h > scrn->height_in_pixels)
452 h = scrn->height_in_pixels - cury - 2*curb;
453
454 wm_teleport(wid, curx, cury, w, h);
455 return 0;
456 }
457
458 int
459 wm_restack(xcb_window_t wid, uint32_t mode)
460 {
461 uint32_t values[1] = { mode };
462 xcb_configure_window(conn, wid, XCB_CONFIG_WINDOW_STACK_MODE, values);
463 return 0;
464 }
465
466 int
467 wm_set_focus(xcb_window_t wid)
468 {
469 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, wid,
470 XCB_CURRENT_TIME);
471 return 0;
472 }
473
474 int
475 wm_reg_window_event(xcb_window_t wid, uint32_t mask)
476 {
477 uint32_t val[] = { mask };
478 xcb_void_cookie_t c;
479 xcb_generic_error_t *e;
480
481 c = xcb_change_window_attributes_checked(conn, wid, XCB_CW_EVENT_MASK, val);
482 e = xcb_request_check(conn, c);
483 if (!e)
484 return -1;
485
486 free(e);
487 return 0;
488 }
489
490
491 int
492 wm_reg_cursor_event(xcb_window_t wid, uint32_t mask, char *cursor)
493 {
494 xcb_cursor_t p;
495 xcb_cursor_context_t *cx;
496 xcb_grab_pointer_cookie_t c;
497 xcb_grab_pointer_reply_t *r;
498
499 p = XCB_NONE;
500 if (cursor) {
501 if (xcb_cursor_context_new(conn, scrn, &cx) < 0)
502 return -1;
503
504 p = xcb_cursor_load_cursor(cx, cursor);
505 }
506
507 c = xcb_grab_pointer(conn, 1, scrn->root, mask,
508 XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
509 XCB_NONE, p, XCB_CURRENT_TIME);
510
511 r = xcb_grab_pointer_reply(conn, c, NULL);
512 if (!r || r->status != XCB_GRAB_STATUS_SUCCESS)
513 return -1;
514
515 xcb_cursor_context_free(cx);
516 return 0;
517 }
518
519 int
520 wm_get_monitors(xcb_window_t wid, int *l)
521 {
522 int n;
523 xcb_randr_get_monitors_cookie_t c;
524 xcb_randr_get_monitors_reply_t *r;
525 xcb_randr_monitor_info_iterator_t i;
526
527 /* get_active: ignore inactive monitors */
528 c = xcb_randr_get_monitors(conn, wid, 0);
529 r = xcb_randr_get_monitors_reply(conn, c, NULL);
530 if (!r)
531 return -1;
532
533 i = xcb_randr_get_monitors_monitors_iterator(r);
534 if (!i.data)
535 return 0;
536
537 for (n = 0; l && i.rem > 0; xcb_randr_monitor_info_next(&i))
538 l[n++] = i.index;
539
540 n = r->nMonitors;
541 free(r);
542
543 return n;
544 }
545
546 xcb_randr_monitor_info_t *
547 wm_get_monitor(int index)
548 {
549 xcb_randr_monitor_info_t *monitor;
550 xcb_randr_get_monitors_cookie_t c;
551 xcb_randr_get_monitors_reply_t *r;
552 xcb_randr_monitor_info_iterator_t i;
553
554 /* get_active: ignore inactive monitors */
555 c = xcb_randr_get_monitors(conn, scrn->root, 0);
556 r = xcb_randr_get_monitors_reply(conn, c, NULL);
557 if (!r)
558 return NULL;
559
560 i = xcb_randr_get_monitors_monitors_iterator(r);
561 if (!i.data)
562 return NULL;
563
564 for (; i.rem > 0; xcb_randr_monitor_info_next(&i)) {
565 if (i.index != index)
566 continue;
567
568 monitor = calloc(1, sizeof(*monitor));
569 if (!monitor)
570 return NULL;
571
572 memcpy(monitor, i.data, sizeof(*monitor));
573 free(r);
574 return monitor;
575 }
576
577 free(r);
578 return NULL;
579 }
580
581 int
582 wm_find_monitor(int x, int y)
583 {
584 /* patch me if you use more than 64 monitors, and get a reward! */
585 int n, monitors[64];
586 xcb_randr_monitor_info_t *p;
587
588 n = wm_get_monitors(scrn->root, monitors);
589
590 /*
591 * When you have multiple monitors, like so:
592 * - 1920x1080+0+0
593 * - 1920x1080+1920+0
594 * the pixel located at 1920,500 would match both the first AND
595 * second monitor. By crawling monitors backward it ensures that
596 * the "farthest" monitor will match first.
597 * Also I love that backward loop notation.
598 */
599 while (n --> 0) {
600 p = wm_get_monitor(monitors[n]);
601 if (!p)
602 continue;
603
604 if (x >= p->x && x <= p->x + p->width
605 && y >= p->y && y <= p->y + p->height) {
606 free(p);
607 return monitors[n];
608 }
609 free(p);
610 }
611
612 return -1;
613 }