i3
src/xcb.c
Go to the documentation of this file.
00001 /*
00002  * vim:ts=4:sw=4:expandtab
00003  *
00004  * i3 - an improved dynamic tiling window manager
00005  * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
00006  *
00007  * xcb.c: Helper functions for easier usage of XCB
00008  *
00009  */
00010 #include "all.h"
00011 
00012 unsigned int xcb_numlock_mask;
00013 
00014 /*
00015  * Convenience wrapper around xcb_create_window which takes care of depth, generating an ID and checking
00016  * for errors.
00017  *
00018  */
00019 xcb_window_t create_window(xcb_connection_t *conn, Rect dims,
00020         uint16_t depth, xcb_visualid_t visual, uint16_t window_class,
00021         enum xcursor_cursor_t cursor, bool map, uint32_t mask, uint32_t *values) {
00022     xcb_window_t result = xcb_generate_id(conn);
00023 
00024     /* If the window class is XCB_WINDOW_CLASS_INPUT_ONLY, we copy depth and
00025      * visual id from the parent window. */
00026     if (window_class == XCB_WINDOW_CLASS_INPUT_ONLY) {
00027         depth = XCB_COPY_FROM_PARENT;
00028         visual = XCB_COPY_FROM_PARENT;
00029     }
00030 
00031     xcb_create_window(conn,
00032             depth,
00033             result, /* the window id */
00034             root, /* parent == root */
00035             dims.x, dims.y, dims.width, dims.height, /* dimensions */
00036             0, /* border = 0, we draw our own */
00037             window_class,
00038             visual,
00039             mask,
00040             values);
00041 
00042     /* Set the cursor */
00043     if (xcursor_supported) {
00044         mask = XCB_CW_CURSOR;
00045         values[0] = xcursor_get_cursor(cursor);
00046         xcb_change_window_attributes(conn, result, mask, values);
00047     } else {
00048         xcb_cursor_t cursor_id = xcb_generate_id(conn);
00049         i3Font cursor_font = load_font("cursor", false);
00050         int xcb_cursor = xcursor_get_xcb_cursor(cursor);
00051         xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
00052                 xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
00053         xcb_change_window_attributes(conn, result, XCB_CW_CURSOR, &cursor_id);
00054         xcb_free_cursor(conn, cursor_id);
00055     }
00056 
00057     /* Map the window (= make it visible) */
00058     if (map)
00059         xcb_map_window(conn, result);
00060 
00061     return result;
00062 }
00063 
00064 /*
00065  * Draws a line from x,y to to_x,to_y using the given color
00066  *
00067  */
00068 void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc,
00069                    uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t to_x, uint32_t to_y) {
00070     xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, (uint32_t[]){ colorpixel });
00071     xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, drawable, gc, 2,
00072                   (xcb_point_t[]) { {x, y}, {to_x, to_y} });
00073 }
00074 
00075 /*
00076  * Draws a rectangle from x,y with width,height using the given color
00077  *
00078  */
00079 void xcb_draw_rect(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc,
00080                    uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t width, uint32_t height) {
00081     xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, (uint32_t[]){ colorpixel });
00082     xcb_rectangle_t rect = {x, y, width, height};
00083     xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect);
00084 }
00085 
00086 /*
00087  * Generates a configure_notify_event with absolute coordinates (relative to the X root
00088  * window, not to the client’s frame) for the given client.
00089  *
00090  */
00091 void fake_absolute_configure_notify(Con *con) {
00092     xcb_rectangle_t absolute;
00093     if (con->window == NULL)
00094         return;
00095 
00096     absolute.x = con->rect.x + con->window_rect.x;
00097     absolute.y = con->rect.y + con->window_rect.y;
00098     absolute.width = con->window_rect.width;
00099     absolute.height = con->window_rect.height;
00100 
00101     DLOG("fake rect = (%d, %d, %d, %d)\n", absolute.x, absolute.y, absolute.width, absolute.height);
00102 
00103     fake_configure_notify(conn, absolute, con->window->id, con->border_width);
00104 }
00105 
00106 /*
00107  * Sends the WM_TAKE_FOCUS ClientMessage to the given window
00108  *
00109  */
00110 void send_take_focus(xcb_window_t window) {
00111     /* Every X11 event is 32 bytes long. Therefore, XCB will copy 32 bytes.
00112      * In order to properly initialize these bytes, we allocate 32 bytes even
00113      * though we only need less for an xcb_configure_notify_event_t */
00114     void *event = scalloc(32);
00115     xcb_client_message_event_t *ev = event;
00116 
00117     ev->response_type = XCB_CLIENT_MESSAGE;
00118     ev->window = window;
00119     ev->type = A_WM_PROTOCOLS;
00120     ev->format = 32;
00121     ev->data.data32[0] = A_WM_TAKE_FOCUS;
00122     ev->data.data32[1] = XCB_CURRENT_TIME;
00123 
00124     DLOG("Sending WM_TAKE_FOCUS to the client\n");
00125     xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char*)ev);
00126     free(event);
00127 }
00128 
00129 /*
00130  * Raises the given window (typically client->frame) above all other windows
00131  *
00132  */
00133 void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window) {
00134     uint32_t values[] = { XCB_STACK_MODE_ABOVE };
00135     xcb_configure_window(conn, window, XCB_CONFIG_WINDOW_STACK_MODE, values);
00136 }
00137 
00138 /*
00139  * Configures the given window to have the size/position specified by given rect
00140  *
00141  */
00142 void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r) {
00143     xcb_void_cookie_t cookie;
00144     cookie = xcb_configure_window(conn, window,
00145                          XCB_CONFIG_WINDOW_X |
00146                          XCB_CONFIG_WINDOW_Y |
00147                          XCB_CONFIG_WINDOW_WIDTH |
00148                          XCB_CONFIG_WINDOW_HEIGHT,
00149                          &(r.x));
00150     /* ignore events which are generated because we configured a window */
00151     add_ignore_event(cookie.sequence, -1);
00152 }
00153 
00154 /*
00155  * Returns true if the given reply contains the given atom.
00156  *
00157  */
00158 bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom) {
00159     if (prop == NULL || xcb_get_property_value_length(prop) == 0)
00160         return false;
00161 
00162     xcb_atom_t *atoms;
00163     if ((atoms = xcb_get_property_value(prop)) == NULL)
00164         return false;
00165 
00166     for (int i = 0; i < xcb_get_property_value_length(prop) / (prop->format / 8); i++)
00167         if (atoms[i] == atom)
00168             return true;
00169 
00170     return false;
00171 
00172 }
00173 
00178 void xcb_warp_pointer_rect(xcb_connection_t *conn, Rect *rect) {
00179     int mid_x = rect->x + (rect->width / 2);
00180     int mid_y = rect->y + (rect->height / 2);
00181 
00182     LOG("warp pointer to: %d %d\n", mid_x, mid_y);
00183     xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, mid_x, mid_y);
00184 }
00185 
00186 /*
00187  * Set the cursor of the root window to the given cursor id.
00188  * This function should only be used if xcursor_supported == false.
00189  * Otherwise, use xcursor_set_root_cursor().
00190  *
00191  */
00192 void xcb_set_root_cursor(int cursor) {
00193     xcb_cursor_t cursor_id = xcb_generate_id(conn);
00194     i3Font cursor_font = load_font("cursor", false);
00195     int xcb_cursor = xcursor_get_xcb_cursor(cursor);
00196     xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id,
00197             xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535);
00198     xcb_change_window_attributes(conn, root, XCB_CW_CURSOR, &cursor_id);
00199     xcb_free_cursor(conn, cursor_id);
00200     xcb_flush(conn);
00201 }
00202 
00203 /*
00204  * Get depth of visual specified by visualid
00205  *
00206  */
00207 uint16_t get_visual_depth(xcb_visualid_t visual_id){
00208     xcb_depth_iterator_t depth_iter;
00209 
00210     depth_iter = xcb_screen_allowed_depths_iterator(root_screen);
00211     for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
00212         xcb_visualtype_iterator_t visual_iter;
00213 
00214         visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
00215         for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) {
00216             if (visual_id == visual_iter.data->visual_id) {
00217                 return depth_iter.data->depth;
00218             }
00219         }
00220     }
00221     return 0;
00222 }
00223 
00224 /*
00225  * Get visualid with specified depth
00226  *
00227  */
00228 xcb_visualid_t get_visualid_by_depth(uint16_t depth){
00229     xcb_depth_iterator_t depth_iter;
00230 
00231     depth_iter = xcb_screen_allowed_depths_iterator(root_screen);
00232     for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
00233         if (depth_iter.data->depth != depth)
00234             continue;
00235 
00236         xcb_visualtype_iterator_t visual_iter;
00237 
00238         visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
00239         if (!visual_iter.rem)
00240             continue;
00241         return visual_iter.data->visual_id;
00242     }
00243     return 0;
00244 }