i3
src/manage.c
Go to the documentation of this file.
00001 /*
00002  * vim:ts=8:expandtab
00003  *
00004  * i3 - an improved dynamic tiling window manager
00005  *
00006  * © 2009-2010 Michael Stapelberg and contributors
00007  *
00008  * See file LICENSE for license information.
00009  *
00010  * src/manage.c: Contains all functions for initially managing new windows
00011  *               (or existing ones on restart).
00012  *
00013  */
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <assert.h>
00017 
00018 #include <xcb/xcb.h>
00019 #include <xcb/xcb_icccm.h>
00020 
00021 #include "xcb.h"
00022 #include "data.h"
00023 #include "util.h"
00024 #include "i3.h"
00025 #include "table.h"
00026 #include "config.h"
00027 #include "handlers.h"
00028 #include "layout.h"
00029 #include "manage.h"
00030 #include "floating.h"
00031 #include "client.h"
00032 #include "workspace.h"
00033 #include "log.h"
00034 #include "ewmh.h"
00035 
00036 /*
00037  * Go through all existing windows (if the window manager is restarted) and manage them
00038  *
00039  */
00040 void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *prophs, xcb_window_t root) {
00041         xcb_query_tree_reply_t *reply;
00042         int i, len;
00043         xcb_window_t *children;
00044         xcb_get_window_attributes_cookie_t *cookies;
00045 
00046         /* Get the tree of windows whose parent is the root window (= all) */
00047         if ((reply = xcb_query_tree_reply(conn, xcb_query_tree(conn, root), 0)) == NULL)
00048                 return;
00049 
00050         len = xcb_query_tree_children_length(reply);
00051         cookies = smalloc(len * sizeof(*cookies));
00052 
00053         /* Request the window attributes for every window */
00054         children = xcb_query_tree_children(reply);
00055         for (i = 0; i < len; ++i)
00056                 cookies[i] = xcb_get_window_attributes(conn, children[i]);
00057 
00058         /* Call manage_window with the attributes for every window */
00059         for (i = 0; i < len; ++i)
00060                 manage_window(prophs, conn, children[i], cookies[i], true);
00061 
00062         free(reply);
00063         free(cookies);
00064 }
00065 
00066 /*
00067  * Restores the geometry of each window by reparenting it to the root window
00068  * at the position of its frame.
00069  *
00070  * This is to be called *only* before exiting/restarting i3 because of evil
00071  * side-effects which are to be expected when continuing to run i3.
00072  *
00073  */
00074 void restore_geometry(xcb_connection_t *conn) {
00075         Workspace *ws;
00076         Client *client;
00077         DLOG("Restoring geometry\n");
00078 
00079         TAILQ_FOREACH(ws, workspaces, workspaces)
00080                 SLIST_FOREACH(client, &(ws->focus_stack), focus_clients)
00081                         xcb_reparent_window(conn, client->child, root,
00082                                             client->rect.x, client->rect.y);
00083 
00084         /* Make sure our changes reach the X server, we restart/exit now */
00085         xcb_flush(conn);
00086 }
00087 
00088 /*
00089  * Do some sanity checks and then reparent the window.
00090  *
00091  */
00092 void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
00093                    xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
00094                    bool needs_to_be_mapped) {
00095         xcb_drawable_t d = { window };
00096         xcb_get_geometry_cookie_t geomc;
00097         xcb_get_geometry_reply_t *geom;
00098         xcb_get_window_attributes_reply_t *attr = 0;
00099 
00100         geomc = xcb_get_geometry(conn, d);
00101 
00102         /* Check if the window is mapped (it could be not mapped when intializing and
00103            calling manage_window() for every window) */
00104         if ((attr = xcb_get_window_attributes_reply(conn, cookie, 0)) == NULL) {
00105                 ELOG("Could not get attributes\n");
00106                 return;
00107         }
00108 
00109         if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE)
00110                 goto out;
00111 
00112         /* Don’t manage clients with the override_redirect flag */
00113         if (attr->override_redirect)
00114                 goto out;
00115 
00116         /* Check if the window is already managed */
00117         if (table_get(&by_child, window))
00118                 goto out;
00119 
00120         /* Get the initial geometry (position, size, …) */
00121         if ((geom = xcb_get_geometry_reply(conn, geomc, 0)) == NULL)
00122                 goto out;
00123 
00124         /* Reparent the window and add it to our list of managed windows */
00125         reparent_window(conn, window, attr->visual, geom->root, geom->depth,
00126                         geom->x, geom->y, geom->width, geom->height,
00127                         geom->border_width);
00128 
00129         /* Generate callback events for every property we watch */
00130         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_CLASS);
00131         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
00132         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
00133         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_HINTS);
00134         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
00135         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[WM_CLIENT_LEADER]);
00136         xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
00137 
00138         free(geom);
00139 out:
00140         free(attr);
00141         return;
00142 }
00143 
00144 /*
00145  * reparent_window() gets called when a new window was opened and becomes a child of the root
00146  * window, or it gets called by us when we manage the already existing windows at startup.
00147  *
00148  * Essentially, this is the point where we take over control.
00149  *
00150  */
00151 void reparent_window(xcb_connection_t *conn, xcb_window_t child,
00152                      xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
00153                      int16_t x, int16_t y, uint16_t width, uint16_t height,
00154                      uint32_t border_width) {
00155 
00156         xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
00157                                   utf8_title_cookie, title_cookie,
00158                                   class_cookie, leader_cookie;
00159         uint32_t mask = 0;
00160         uint32_t values[3];
00161         uint16_t original_height = height;
00162         bool map_frame = true;
00163 
00164         /* We are interested in property changes */
00165         mask = XCB_CW_EVENT_MASK;
00166         values[0] = CHILD_EVENT_MASK;
00167         xcb_change_window_attributes(conn, child, mask, values);
00168 
00169         /* Place requests for properties ASAP */
00170         wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
00171         strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
00172         state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
00173         utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
00174         leader_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[WM_CLIENT_LEADER], UINT32_MAX);
00175         title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
00176         class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
00177 
00178         Client *new = table_get(&by_child, child);
00179 
00180         /* Events for already managed windows should already be filtered in manage_window() */
00181         assert(new == NULL);
00182 
00183         LOG("Managing window 0x%08x\n", child);
00184         DLOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
00185         new = scalloc(sizeof(Client));
00186         new->force_reconfigure = true;
00187 
00188         /* Update the data structures */
00189         Client *old_focused = CUR_CELL->currently_focused;
00190 
00191         new->container = CUR_CELL;
00192         new->workspace = new->container->workspace;
00193 
00194         /* Minimum useful size for managed windows is 75x50 (primarily affects floating) */
00195         width = max(width, 75);
00196         height = max(height, 50);
00197 
00198         new->frame = xcb_generate_id(conn);
00199         new->child = child;
00200         new->rect.width = width;
00201         new->rect.height = height;
00202         new->width_increment = 1;
00203         new->height_increment = 1;
00204         new->border_width = border_width;
00205         /* Pre-initialize the values for floating */
00206         new->floating_rect.x = -1;
00207         new->floating_rect.width = width;
00208         new->floating_rect.height = height;
00209 
00210         if (config.default_border != NULL)
00211                 client_init_border(conn, new, config.default_border[1]);
00212 
00213         mask = 0;
00214 
00215         /* Don’t generate events for our new window, it should *not* be managed */
00216         mask |= XCB_CW_OVERRIDE_REDIRECT;
00217         values[0] = 1;
00218 
00219         /* We want to know when… */
00220         mask |= XCB_CW_EVENT_MASK;
00221         values[1] = FRAME_EVENT_MASK;
00222 
00223         i3Font *font = load_font(conn, config.font);
00224         width = min(width, c_ws->rect.x + c_ws->rect.width);
00225         height = min(height, c_ws->rect.y + c_ws->rect.height);
00226 
00227         Rect framerect = {x, y,
00228                           width + 2 + 2,                  /* 2 px border at each side */
00229                           height + 2 + 2 + font->height}; /* 2 px border plus font’s height */
00230 
00231         /* Yo dawg, I heard you like windows, so I create a window around your window… */
00232         new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, false, mask, values);
00233 
00234         /* Put the client inside the save set. Upon termination (whether killed or normal exit
00235            does not matter) of the window manager, these clients will be correctly reparented
00236            to their most closest living ancestor (= cleanup) */
00237         xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
00238 
00239         /* Generate a graphics context for the titlebar */
00240         new->titlegc = xcb_generate_id(conn);
00241         xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
00242 
00243         /* Moves the original window into the new frame we've created for it */
00244         new->awaiting_useless_unmap = true;
00245         xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
00246         if (xcb_request_check(conn, cookie) != NULL) {
00247                 DLOG("Could not reparent the window, aborting\n");
00248                 xcb_destroy_window(conn, new->frame);
00249                 free(new);
00250                 return;
00251         }
00252 
00253         /* Put our data structure (Client) into the table */
00254         table_put(&by_parent, new->frame, new);
00255         table_put(&by_child, child, new);
00256 
00257         /* We need to grab the mouse buttons for click to focus */
00258         xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
00259                         XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
00260                         1 /* left mouse button */,
00261                         XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
00262 
00263         xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
00264                         XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
00265                         3 /* right mouse button */,
00266                         XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
00267 
00268         /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
00269         xcb_atom_t *atom;
00270         xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
00271         if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
00272                 for (int i = 0; i < xcb_get_property_value_length(preply); i++)
00273                         if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
00274                                 DLOG("Window is a dock.\n");
00275                                 Output *t_out = get_output_containing(x, y);
00276                                 if (t_out == NULL)
00277                                         t_out = c_ws->output;
00278                                 if (t_out != c_ws->output) {
00279                                         DLOG("Dock client requested to be on output %s by geometry (%d, %d)\n",
00280                                                         t_out->name, x, y);
00281                                         new->workspace = t_out->current_workspace;
00282                                 }
00283                                 new->dock = true;
00284                                 new->borderless = true;
00285                                 new->titlebar_position = TITLEBAR_OFF;
00286                                 new->force_reconfigure = true;
00287                                 new->container = NULL;
00288                                 SLIST_INSERT_HEAD(&(t_out->dock_clients), new, dock_clients);
00289                                 /* If it’s a dock we can’t make it float, so we break */
00290                                 new->floating = FLOATING_AUTO_OFF;
00291                                 break;
00292                         } else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
00293                                    atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
00294                                    atom[i] == atoms[_NET_WM_WINDOW_TYPE_TOOLBAR] ||
00295                                    atom[i] == atoms[_NET_WM_WINDOW_TYPE_SPLASH]) {
00296                                 /* Set the dialog window to automatically floating, will be used below */
00297                                 new->floating = FLOATING_AUTO_ON;
00298                                 DLOG("dialog/utility/toolbar/splash window, automatically floating\n");
00299                         }
00300         }
00301 
00302         /* All clients which have a leader should be floating */
00303         if (!new->dock && !client_is_floating(new) && new->leader != 0) {
00304                 DLOG("Client has WM_CLIENT_LEADER hint set, setting floating\n");
00305                 new->floating = FLOATING_AUTO_ON;
00306         }
00307 
00308         if (new->workspace->auto_float) {
00309                 new->floating = FLOATING_AUTO_ON;
00310                 DLOG("workspace is in autofloat mode, setting floating\n");
00311         }
00312 
00313         if (new->dock) {
00314                 /* Get _NET_WM_STRUT_PARTIAL to determine the client’s requested height */
00315                 uint32_t *strut;
00316                 preply = xcb_get_property_reply(conn, strut_cookie, NULL);
00317                 if (preply != NULL && preply->value_len > 0 && (strut = xcb_get_property_value(preply))) {
00318                         /* We only use a subset of the provided values, namely the reserved space at the top/bottom
00319                            of the screen. This is because the only possibility for bars is at to be at the top/bottom
00320                            with maximum horizontal size.
00321                            TODO: bars at the top */
00322                         new->desired_height = strut[3];
00323                         if (new->desired_height == 0) {
00324                                 DLOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", original_height);
00325                                 new->desired_height = original_height;
00326                         }
00327                         DLOG("the client wants to be %d pixels high\n", new->desired_height);
00328                 } else {
00329                         DLOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", original_height);
00330                         new->desired_height = original_height;
00331                 }
00332         } else {
00333                 /* If it’s not a dock, we can check on which workspace we should put it. */
00334 
00335                 /* Firstly, we need to get the window’s class / title. We asked for the properties at the
00336                  * top of this function, get them now and pass them to our callback function for window class / title
00337                  * changes. It is important that the client was already inserted into the by_child table,
00338                  * because the callbacks won’t work otherwise. */
00339                 preply = xcb_get_property_reply(conn, utf8_title_cookie, NULL);
00340                 handle_windowname_change(NULL, conn, 0, new->child, atoms[_NET_WM_NAME], preply);
00341 
00342                 preply = xcb_get_property_reply(conn, title_cookie, NULL);
00343                 handle_windowname_change_legacy(NULL, conn, 0, new->child, WM_NAME, preply);
00344 
00345                 preply = xcb_get_property_reply(conn, class_cookie, NULL);
00346                 handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
00347 
00348                 preply = xcb_get_property_reply(conn, leader_cookie, NULL);
00349                 handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
00350 
00351                 /* if WM_CLIENT_LEADER is set, we put the new window on the
00352                  * same window as its leader. This might be overwritten by
00353                  * assignments afterwards. */
00354                 if (new->leader != XCB_NONE) {
00355                         DLOG("client->leader is set (to 0x%08x)\n", new->leader);
00356                         Client *parent = table_get(&by_child, new->leader);
00357                         if (parent != NULL && parent->container != NULL) {
00358                                 Workspace *t_ws = parent->workspace;
00359                                 new->container = t_ws->table[parent->container->col][parent->container->row];
00360                                 new->workspace = t_ws;
00361                                 old_focused = new->container->currently_focused;
00362                                 map_frame = workspace_is_visible(t_ws);
00363                                 new->urgent = true;
00364                                 /* This is a little tricky: we cannot use
00365                                  * workspace_update_urgent_flag() because the
00366                                  * new window was not yet inserted into the
00367                                  * focus stack on t_ws. */
00368                                 t_ws->urgent = true;
00369                         } else {
00370                                 DLOG("parent is not usable\n");
00371                         }
00372                 }
00373 
00374                 struct Assignment *assign;
00375                 TAILQ_FOREACH(assign, &assignments, assignments) {
00376                         if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
00377                                 continue;
00378 
00379                         if (assign->floating == ASSIGN_FLOATING_ONLY ||
00380                             assign->floating == ASSIGN_FLOATING) {
00381                                 new->floating = FLOATING_AUTO_ON;
00382                                 LOG("Assignment matches, putting client into floating mode\n");
00383                                 if (assign->floating == ASSIGN_FLOATING_ONLY)
00384                                         break;
00385                         }
00386 
00387                         LOG("Assignment \"%s\" matches, so putting it on workspace %d\n",
00388                             assign->windowclass_title, assign->workspace);
00389 
00390                         if (c_ws->output->current_workspace->num == (assign->workspace-1)) {
00391                                 DLOG("We are already there, no need to do anything\n");
00392                                 break;
00393                         }
00394 
00395                         DLOG("Changing container/workspace and unmapping the client\n");
00396                         Workspace *t_ws = workspace_get(assign->workspace-1);
00397                         workspace_initialize(t_ws, c_ws->output, false);
00398 
00399                         new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
00400                         new->workspace = t_ws;
00401                         old_focused = new->container->currently_focused;
00402 
00403                         map_frame = workspace_is_visible(t_ws);
00404                         break;
00405                 }
00406         }
00407 
00408         if (new->workspace->fullscreen_client != NULL) {
00409                 DLOG("Setting below fullscreen window\n");
00410 
00411                 /* If we are in fullscreen, we should place the window below
00412                  * the fullscreen window to not be annoying */
00413                 uint32_t values[] = {
00414                         new->workspace->fullscreen_client->frame,
00415                         XCB_STACK_MODE_BELOW
00416                 };
00417                 xcb_configure_window(conn, new->frame,
00418                                      XCB_CONFIG_WINDOW_SIBLING |
00419                                      XCB_CONFIG_WINDOW_STACK_MODE, values);
00420         }
00421 
00422         /* Insert into the currently active container, if it’s not a dock window */
00423         if (!new->dock && !client_is_floating(new)) {
00424                 /* Insert after the old active client, if existing. If it does not exist, the
00425                    container is empty and it does not matter, where we insert it */
00426                 if (old_focused != NULL && !old_focused->dock)
00427                         CIRCLEQ_INSERT_AFTER(&(new->container->clients), old_focused, new, clients);
00428                 else CIRCLEQ_INSERT_TAIL(&(new->container->clients), new, clients);
00429 
00430                 if (new->container->workspace->fullscreen_client != NULL)
00431                         SLIST_INSERT_AFTER(new->container->workspace->fullscreen_client, new, focus_clients);
00432                 else SLIST_INSERT_HEAD(&(new->container->workspace->focus_stack), new, focus_clients);
00433 
00434                 client_set_below_floating(conn, new);
00435         }
00436 
00437         if (client_is_floating(new)) {
00438                 SLIST_INSERT_HEAD(&(new->workspace->focus_stack), new, focus_clients);
00439 
00440                 /* Add the client to the list of floating clients for its workspace */
00441                 TAILQ_INSERT_TAIL(&(new->workspace->floating_clients), new, floating_clients);
00442 
00443                 new->container = NULL;
00444 
00445                 new->rect.width = new->floating_rect.width + 2 + 2;
00446                 new->rect.height = new->floating_rect.height + (font->height + 2 + 2) + 2;
00447 
00448                 /* Some clients (like GIMP’s color picker window) get mapped
00449                  * to (0, 0), so we push them to a reasonable position
00450                  * (centered over their leader) */
00451                 if (new->leader != 0 && x == 0 && y == 0) {
00452                         DLOG("Floating client wants to (0x0), moving it over its leader instead\n");
00453                         Client *leader = table_get(&by_child, new->leader);
00454                         if (leader == NULL) {
00455                                 DLOG("leader is NULL, centering it over current workspace\n");
00456 
00457                                 x = c_ws->rect.x + (c_ws->rect.width / 2) - (new->rect.width / 2);
00458                                 y = c_ws->rect.y + (c_ws->rect.height / 2) - (new->rect.height / 2);
00459                         } else {
00460                                 x = leader->rect.x + (leader->rect.width / 2) - (new->rect.width / 2);
00461                                 y = leader->rect.y + (leader->rect.height / 2) - (new->rect.height / 2);
00462                         }
00463                 }
00464                 new->floating_rect.x = new->rect.x = x;
00465                 new->floating_rect.y = new->rect.y = y;
00466                 DLOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
00467                                 new->floating_rect.x, new->floating_rect.y,
00468                                 new->floating_rect.width, new->floating_rect.height);
00469                 DLOG("outer rect (%d, %d) size (%d, %d)\n",
00470                                 new->rect.x, new->rect.y, new->rect.width, new->rect.height);
00471 
00472                 /* Make sure it is on top of the other windows */
00473                 xcb_raise_window(conn, new->frame);
00474                 reposition_client(conn, new);
00475                 resize_client(conn, new);
00476                 /* redecorate_window flushes */
00477                 redecorate_window(conn, new);
00478         }
00479 
00480         new->initialized = true;
00481 
00482         /* Check if the window already got the fullscreen hint set */
00483         xcb_atom_t *state;
00484         if ((preply = xcb_get_property_reply(conn, state_cookie, NULL)) != NULL &&
00485             (state = xcb_get_property_value(preply)) != NULL)
00486                 /* Check all set _NET_WM_STATEs */
00487                 for (int i = 0; i < xcb_get_property_value_length(preply); i++) {
00488                         if (state[i] != atoms[_NET_WM_STATE_FULLSCREEN])
00489                                 continue;
00490                         /* If the window got the fullscreen state, we just toggle fullscreen
00491                            and don’t event bother to redraw the layout – that would not change
00492                            anything anyways */
00493                         client_toggle_fullscreen(conn, new);
00494                         goto map;
00495                 }
00496 
00497         render_layout(conn);
00498 
00499 map:
00500         /* Map the window first to avoid flickering */
00501         xcb_map_window(conn, child);
00502         if (map_frame)
00503                 client_map(conn, new);
00504 
00505         if ((CUR_CELL->workspace->fullscreen_client == NULL || new->fullscreen) && !new->dock) {
00506                 /* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
00507                 if ((new->workspace->fullscreen_client == NULL) || new->fullscreen) {
00508                         if (!client_is_floating(new)) {
00509                                 new->container->currently_focused = new;
00510                                 if (map_frame)
00511                                         render_container(conn, new->container);
00512                         }
00513                         if (new->container == CUR_CELL || client_is_floating(new)) {
00514                                 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
00515                                 ewmh_update_active_window(new->child);
00516                         }
00517                 }
00518         }
00519 
00520         xcb_flush(conn);
00521 }