i3
|
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 }