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 }