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, uint16_t window_class, 00020 enum xcursor_cursor_t cursor, bool map, uint32_t mask, uint32_t *values) { 00021 xcb_window_t result = xcb_generate_id(conn); 00022 00023 /* If the window class is XCB_WINDOW_CLASS_INPUT_ONLY, depth has to be 0 */ 00024 uint16_t depth = (window_class == XCB_WINDOW_CLASS_INPUT_ONLY ? 0 : XCB_COPY_FROM_PARENT); 00025 00026 xcb_create_window(conn, 00027 depth, 00028 result, /* the window id */ 00029 root, /* parent == root */ 00030 dims.x, dims.y, dims.width, dims.height, /* dimensions */ 00031 0, /* border = 0, we draw our own */ 00032 window_class, 00033 XCB_WINDOW_CLASS_COPY_FROM_PARENT, /* copy visual from parent */ 00034 mask, 00035 values); 00036 00037 /* Set the cursor */ 00038 if (xcursor_supported) { 00039 mask = XCB_CW_CURSOR; 00040 values[0] = xcursor_get_cursor(cursor); 00041 xcb_change_window_attributes(conn, result, mask, values); 00042 } else { 00043 xcb_cursor_t cursor_id = xcb_generate_id(conn); 00044 i3Font cursor_font = load_font("cursor", false); 00045 int xcb_cursor = xcursor_get_xcb_cursor(cursor); 00046 xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id, 00047 xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535); 00048 xcb_change_window_attributes(conn, result, XCB_CW_CURSOR, &cursor_id); 00049 xcb_free_cursor(conn, cursor_id); 00050 } 00051 00052 /* Map the window (= make it visible) */ 00053 if (map) 00054 xcb_map_window(conn, result); 00055 00056 return result; 00057 } 00058 00059 /* 00060 * Draws a line from x,y to to_x,to_y using the given color 00061 * 00062 */ 00063 void xcb_draw_line(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc, 00064 uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t to_x, uint32_t to_y) { 00065 xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, (uint32_t[]){ colorpixel }); 00066 xcb_poly_line(conn, XCB_COORD_MODE_ORIGIN, drawable, gc, 2, 00067 (xcb_point_t[]) { {x, y}, {to_x, to_y} }); 00068 } 00069 00070 /* 00071 * Draws a rectangle from x,y with width,height using the given color 00072 * 00073 */ 00074 void xcb_draw_rect(xcb_connection_t *conn, xcb_drawable_t drawable, xcb_gcontext_t gc, 00075 uint32_t colorpixel, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { 00076 xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, (uint32_t[]){ colorpixel }); 00077 xcb_rectangle_t rect = {x, y, width, height}; 00078 xcb_poly_fill_rectangle(conn, drawable, gc, 1, &rect); 00079 } 00080 00081 /* 00082 * Generates a configure_notify_event with absolute coordinates (relative to the X root 00083 * window, not to the client’s frame) for the given client. 00084 * 00085 */ 00086 void fake_absolute_configure_notify(Con *con) { 00087 xcb_rectangle_t absolute; 00088 if (con->window == NULL) 00089 return; 00090 00091 absolute.x = con->rect.x + con->window_rect.x; 00092 absolute.y = con->rect.y + con->window_rect.y; 00093 absolute.width = con->window_rect.width; 00094 absolute.height = con->window_rect.height; 00095 00096 DLOG("fake rect = (%d, %d, %d, %d)\n", absolute.x, absolute.y, absolute.width, absolute.height); 00097 00098 fake_configure_notify(conn, absolute, con->window->id, con->border_width); 00099 } 00100 00101 /* 00102 * Sends the WM_TAKE_FOCUS ClientMessage to the given window 00103 * 00104 */ 00105 void send_take_focus(xcb_window_t window) { 00106 /* Every X11 event is 32 bytes long. Therefore, XCB will copy 32 bytes. 00107 * In order to properly initialize these bytes, we allocate 32 bytes even 00108 * though we only need less for an xcb_configure_notify_event_t */ 00109 void *event = scalloc(32); 00110 xcb_client_message_event_t *ev = event; 00111 00112 ev->response_type = XCB_CLIENT_MESSAGE; 00113 ev->window = window; 00114 ev->type = A_WM_PROTOCOLS; 00115 ev->format = 32; 00116 ev->data.data32[0] = A_WM_TAKE_FOCUS; 00117 ev->data.data32[1] = XCB_CURRENT_TIME; 00118 00119 DLOG("Sending WM_TAKE_FOCUS to the client\n"); 00120 xcb_send_event(conn, false, window, XCB_EVENT_MASK_NO_EVENT, (char*)ev); 00121 free(event); 00122 } 00123 00124 /* 00125 * Raises the given window (typically client->frame) above all other windows 00126 * 00127 */ 00128 void xcb_raise_window(xcb_connection_t *conn, xcb_window_t window) { 00129 uint32_t values[] = { XCB_STACK_MODE_ABOVE }; 00130 xcb_configure_window(conn, window, XCB_CONFIG_WINDOW_STACK_MODE, values); 00131 } 00132 00133 /* 00134 * Query the width of the given text (16-bit characters, UCS) with given real 00135 * length (amount of glyphs) using the given font. 00136 * 00137 */ 00138 int predict_text_width(char *text, int length) { 00139 xcb_query_text_extents_cookie_t cookie; 00140 xcb_query_text_extents_reply_t *reply; 00141 xcb_generic_error_t *error; 00142 int width; 00143 00144 cookie = xcb_query_text_extents(conn, config.font.id, length, (xcb_char2b_t*)text); 00145 if ((reply = xcb_query_text_extents_reply(conn, cookie, &error)) == NULL) { 00146 ELOG("Could not get text extents (X error code %d)\n", 00147 error->error_code); 00148 /* We return the rather safe guess of 7 pixels, because a 00149 * rendering error is better than a crash. Plus, the user will 00150 * see the error in his log. */ 00151 return 7; 00152 } 00153 00154 width = reply->overall_width; 00155 free(reply); 00156 return width; 00157 } 00158 00159 /* 00160 * Configures the given window to have the size/position specified by given rect 00161 * 00162 */ 00163 void xcb_set_window_rect(xcb_connection_t *conn, xcb_window_t window, Rect r) { 00164 xcb_void_cookie_t cookie; 00165 cookie = xcb_configure_window(conn, window, 00166 XCB_CONFIG_WINDOW_X | 00167 XCB_CONFIG_WINDOW_Y | 00168 XCB_CONFIG_WINDOW_WIDTH | 00169 XCB_CONFIG_WINDOW_HEIGHT, 00170 &(r.x)); 00171 /* ignore events which are generated because we configured a window */ 00172 add_ignore_event(cookie.sequence, -1); 00173 } 00174 00175 /* 00176 * Returns true if the given reply contains the given atom. 00177 * 00178 */ 00179 bool xcb_reply_contains_atom(xcb_get_property_reply_t *prop, xcb_atom_t atom) { 00180 if (prop == NULL || xcb_get_property_value_length(prop) == 0) 00181 return false; 00182 00183 xcb_atom_t *atoms; 00184 if ((atoms = xcb_get_property_value(prop)) == NULL) 00185 return false; 00186 00187 for (int i = 0; i < xcb_get_property_value_length(prop) / (prop->format / 8); i++) 00188 if (atoms[i] == atom) 00189 return true; 00190 00191 return false; 00192 00193 } 00194 00199 void xcb_warp_pointer_rect(xcb_connection_t *conn, Rect *rect) { 00200 int mid_x = rect->x + (rect->width / 2); 00201 int mid_y = rect->y + (rect->height / 2); 00202 00203 LOG("warp pointer to: %d %d\n", mid_x, mid_y); 00204 xcb_warp_pointer(conn, XCB_NONE, root, 0, 0, 0, 0, mid_x, mid_y); 00205 } 00206 00207 /* 00208 * Set the cursor of the root window to the given cursor id. 00209 * This function should only be used if xcursor_supported == false. 00210 * Otherwise, use xcursor_set_root_cursor(). 00211 * 00212 */ 00213 void xcb_set_root_cursor(int cursor) { 00214 xcb_cursor_t cursor_id = xcb_generate_id(conn); 00215 i3Font cursor_font = load_font("cursor", false); 00216 int xcb_cursor = xcursor_get_xcb_cursor(cursor); 00217 xcb_create_glyph_cursor(conn, cursor_id, cursor_font.id, cursor_font.id, 00218 xcb_cursor, xcb_cursor + 1, 0, 0, 0, 65535, 65535, 65535); 00219 xcb_change_window_attributes(conn, root, XCB_CW_CURSOR, &cursor_id); 00220 xcb_free_cursor(conn, cursor_id); 00221 xcb_flush(conn); 00222 }