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 * ewmh.c: Get/set certain EWMH properties easily. 00008 * 00009 */ 00010 #include "all.h" 00011 00012 /* 00013 * Updates _NET_CURRENT_DESKTOP with the current desktop number. 00014 * 00015 * EWMH: The index of the current desktop. This is always an integer between 0 00016 * and _NET_NUMBER_OF_DESKTOPS - 1. 00017 * 00018 */ 00019 void ewmh_update_current_desktop() { 00020 Con *focused_ws = con_get_workspace(focused); 00021 Con *output; 00022 uint32_t idx = 0; 00023 /* We count to get the index of this workspace because named workspaces 00024 * don’t have the ->num property */ 00025 TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { 00026 Con *ws; 00027 TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) { 00028 if (ws == focused_ws) { 00029 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, 00030 A__NET_CURRENT_DESKTOP, XCB_ATOM_CARDINAL, 32, 1, &idx); 00031 return; 00032 } 00033 ++idx; 00034 } 00035 } 00036 } 00037 00038 /* 00039 * Updates _NET_ACTIVE_WINDOW with the currently focused window. 00040 * 00041 * EWMH: The window ID of the currently active window or None if no window has 00042 * the focus. 00043 * 00044 */ 00045 void ewmh_update_active_window(xcb_window_t window) { 00046 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, 00047 A__NET_ACTIVE_WINDOW, XCB_ATOM_WINDOW, 32, 1, &window); 00048 } 00049 00050 /* 00051 * Updates the workarea for each desktop. 00052 * 00053 * This function is not called at the moment due to: 00054 * http://bugs.i3wm.org/539 00055 * http://bugs.i3wm.org/301 00056 * 00057 * EWMH: Contains a geometry for each desktop. These geometries specify an area 00058 * that is completely contained within the viewport. Work area SHOULD be used by 00059 * desktop applications to place desktop icons appropriately. 00060 * 00061 */ 00062 void ewmh_update_workarea() { 00063 int num_workspaces = 0, count = 0; 00064 Rect last_rect = {0, 0, 0, 0}; 00065 Con *output; 00066 00067 TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { 00068 Con *ws; 00069 TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) { 00070 /* Check if we need to initialize last_rect. The case that the 00071 * first workspace is all-zero may happen when the user 00072 * assigned workspace 2 for his first screen, for example. Thus 00073 * we need an initialized last_rect in the very first run of 00074 * the following loop. */ 00075 if (last_rect.width == 0 && last_rect.height == 0 && 00076 ws->rect.width != 0 && ws->rect.height != 0) { 00077 memcpy(&last_rect, &(ws->rect), sizeof(Rect)); 00078 } 00079 num_workspaces++; 00080 } 00081 } 00082 00083 DLOG("Got %d workspaces\n", num_workspaces); 00084 uint8_t *workarea = smalloc(sizeof(Rect) * num_workspaces); 00085 TAILQ_FOREACH(output, &(croot->nodes_head), nodes) { 00086 Con *ws; 00087 TAILQ_FOREACH(ws, &(output_get_content(output)->nodes_head), nodes) { 00088 DLOG("storing %d: %dx%d with %d x %d\n", count, ws->rect.x, 00089 ws->rect.y, ws->rect.width, ws->rect.height); 00090 /* If a workspace is not yet initialized and thus its 00091 * dimensions are zero, we will instead put the dimensions 00092 * of the last workspace in the list. For example firefox 00093 * intersects all workspaces and does not cope so well with 00094 * an all-zero workspace. */ 00095 if (ws->rect.width == 0 || ws->rect.height == 0) { 00096 DLOG("re-using last_rect (%dx%d, %d, %d)\n", 00097 last_rect.x, last_rect.y, last_rect.width, 00098 last_rect.height); 00099 memcpy(workarea + (sizeof(Rect) * count++), &last_rect, sizeof(Rect)); 00100 continue; 00101 } 00102 memcpy(workarea + (sizeof(Rect) * count++), &(ws->rect), sizeof(Rect)); 00103 memcpy(&last_rect, &(ws->rect), sizeof(Rect)); 00104 } 00105 } 00106 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, 00107 A__NET_WORKAREA, XCB_ATOM_CARDINAL, 32, 00108 num_workspaces * (sizeof(Rect) / sizeof(uint32_t)), 00109 workarea); 00110 free(workarea); 00111 xcb_flush(conn); 00112 } 00113 00114 /* 00115 * Updates the _NET_CLIENT_LIST_STACKING hint. 00116 * 00117 */ 00118 void ewmh_update_client_list_stacking(xcb_window_t *stack, int num_windows) { 00119 xcb_change_property( 00120 conn, 00121 XCB_PROP_MODE_REPLACE, 00122 root, 00123 A__NET_CLIENT_LIST_STACKING, 00124 XCB_ATOM_WINDOW, 00125 32, 00126 num_windows, 00127 stack); 00128 } 00129 00130 /* 00131 * Set up the EWMH hints on the root window. 00132 * 00133 */ 00134 void ewmh_setup_hints() { 00135 xcb_atom_t supported_atoms[] = { 00136 #define xmacro(atom) A_ ## atom, 00137 #include "atoms.xmacro" 00138 #undef xmacro 00139 }; 00140 00141 /* Set up the window manager’s name. According to EWMH, section "Root Window 00142 * Properties", to indicate that an EWMH-compliant window manager is 00143 * present, a child window has to be created (and kept alive as long as the 00144 * window manager is running) which has the _NET_SUPPORTING_WM_CHECK and 00145 * _NET_WM_ATOMS. */ 00146 xcb_window_t child_window = xcb_generate_id(conn); 00147 xcb_create_window( 00148 conn, 00149 XCB_COPY_FROM_PARENT, /* depth */ 00150 child_window, /* window id */ 00151 root, /* parent */ 00152 0, 0, 1, 1, /* dimensions (x, y, w, h) */ 00153 0, /* border */ 00154 XCB_WINDOW_CLASS_INPUT_ONLY, /* window class */ 00155 XCB_COPY_FROM_PARENT, /* visual */ 00156 0, 00157 NULL); 00158 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, child_window, A__NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32, 1, &child_window); 00159 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, child_window, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3"); 00160 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTING_WM_CHECK, XCB_ATOM_WINDOW, 32, 1, &child_window); 00161 00162 /* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */ 00163 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3"); 00164 00165 xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 16, supported_atoms); 00166 }