]> git.sur5r.net Git - i3/i3/blobdiff - src/manage.c
Make i3 compatible with the very latest xcb
[i3/i3] / src / manage.c
index 9ddcab42e51dbedad3d900cc96ca6b04e7ba2260..0b33034e5eafce7e0b34ad62c9b21691959ee29f 100644 (file)
@@ -3,7 +3,7 @@
  *
  * i3 - an improved dynamic tiling window manager
  *
- * © 2009 Michael Stapelberg and contributors
+ * © 2009-2010 Michael Stapelberg and contributors
  *
  * See file LICENSE for license information.
  *
 #include "manage.h"
 #include "floating.h"
 #include "client.h"
+#include "workspace.h"
+#include "log.h"
+#include "ewmh.h"
 
 /*
  * Go through all existing windows (if the window manager is restarted) and manage them
  *
  */
-void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *prophs, xcb_window_t root) {
+void manage_existing_windows(xcb_connection_t *conn, xcb_window_t root) {
         xcb_query_tree_reply_t *reply;
         int i, len;
         xcb_window_t *children;
@@ -49,25 +52,46 @@ void manage_existing_windows(xcb_connection_t *conn, xcb_property_handlers_t *pr
 
         /* Request the window attributes for every window */
         children = xcb_query_tree_children(reply);
-        for(i = 0; i < len; ++i)
+        for (i = 0; i < len; ++i)
                 cookies[i] = xcb_get_window_attributes(conn, children[i]);
 
         /* Call manage_window with the attributes for every window */
-        for(i = 0; i < len; ++i)
-                manage_window(prophs, conn, children[i], cookies[i], true);
+        for (i = 0; i < len; ++i)
+                manage_window(conn, children[i], cookies[i], true);
 
         free(reply);
         free(cookies);
 }
 
+/*
+ * Restores the geometry of each window by reparenting it to the root window
+ * at the position of its frame.
+ *
+ * This is to be called *only* before exiting/restarting i3 because of evil
+ * side-effects which are to be expected when continuing to run i3.
+ *
+ */
+void restore_geometry(xcb_connection_t *conn) {
+        Workspace *ws;
+        Client *client;
+        DLOG("Restoring geometry\n");
+
+        TAILQ_FOREACH(ws, workspaces, workspaces)
+                SLIST_FOREACH(client, &(ws->focus_stack), focus_clients)
+                        xcb_reparent_window(conn, client->child, root,
+                                            client->rect.x, client->rect.y);
+
+        /* Make sure our changes reach the X server, we restart/exit now */
+        xcb_flush(conn);
+}
+
 /*
  * Do some sanity checks and then reparent the window.
  *
  */
-void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
+void manage_window(xcb_connection_t *conn,
                    xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
                    bool needs_to_be_mapped) {
-        LOG("managing window.\n");
         xcb_drawable_t d = { window };
         xcb_get_geometry_cookie_t geomc;
         xcb_get_geometry_reply_t *geom;
@@ -78,20 +102,16 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
         /* Check if the window is mapped (it could be not mapped when intializing and
            calling manage_window() for every window) */
         if ((attr = xcb_get_window_attributes_reply(conn, cookie, 0)) == NULL) {
-                LOG("Could not get attributes\n");
+                ELOG("Could not get attributes\n");
                 return;
         }
 
-        if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) {
-                LOG("Window not mapped, not managing\n");
+        if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE)
                 goto out;
-        }
 
         /* Don’t manage clients with the override_redirect flag */
-        if (attr->override_redirect) {
-                LOG("override_redirect set, not managing\n");
+        if (attr->override_redirect)
                 goto out;
-        }
 
         /* Check if the window is already managed */
         if (table_get(&by_child, window))
@@ -103,14 +123,17 @@ void manage_window(xcb_property_handlers_t *prophs, xcb_connection_t *conn,
 
         /* Reparent the window and add it to our list of managed windows */
         reparent_window(conn, window, attr->visual, geom->root, geom->depth,
-                        geom->x, geom->y, geom->width, geom->height);
+                        geom->x, geom->y, geom->width, geom->height,
+                        geom->border_width);
 
         /* Generate callback events for every property we watch */
-        xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_CLASS);
-        xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NAME);
-        xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_NORMAL_HINTS);
-        xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, WM_TRANSIENT_FOR);
-        xcb_property_changed(prophs, XCB_PROPERTY_NEW_VALUE, window, atoms[_NET_WM_NAME]);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_CLASS);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_NAME);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_NORMAL_HINTS);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_HINTS);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_TRANSIENT_FOR);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A_WM_CLIENT_LEADER);
+        property_notify(XCB_PROPERTY_NEW_VALUE, window, A__NET_WM_NAME);
 
         free(geom);
 out:
@@ -127,13 +150,16 @@ out:
  */
 void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                      xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
-                     int16_t x, int16_t y, uint16_t width, uint16_t height) {
+                     int16_t x, int16_t y, uint16_t width, uint16_t height,
+                     uint32_t border_width) {
 
         xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
-                                  utf8_title_cookie, title_cookie, class_cookie;
+                                  utf8_title_cookie, title_cookie,
+                                  class_cookie, leader_cookie;
         uint32_t mask = 0;
         uint32_t values[3];
         uint16_t original_height = height;
+        bool map_frame = true;
 
         /* We are interested in property changes */
         mask = XCB_CW_EVENT_MASK;
@@ -141,21 +167,22 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         xcb_change_window_attributes(conn, child, mask, values);
 
         /* Place requests for properties ASAP */
-        wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
-        strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
-        state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
-        utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
-        title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
-        class_cookie  = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
+        wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_WINDOW_TYPE, UINT32_MAX);
+        strut_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_STRUT_PARTIAL, UINT32_MAX);
+        state_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_STATE, UINT32_MAX);
+        utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, A__NET_WM_NAME, 128);
+        leader_cookie = xcb_get_any_property_unchecked(conn, false, child, A_WM_CLIENT_LEADER, UINT32_MAX);
+        title_cookie = xcb_get_any_property_unchecked(conn, false, child, A_WM_NAME, 128);
+        class_cookie = xcb_get_any_property_unchecked(conn, false, child, A_WM_CLASS, 128);
 
         Client *new = table_get(&by_child, child);
 
         /* Events for already managed windows should already be filtered in manage_window() */
         assert(new == NULL);
 
-        LOG("reparenting new client\n");
-        LOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
-        new = calloc(sizeof(Client), 1);
+        LOG("Managing window 0x%08x\n", child);
+        DLOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
+        new = scalloc(sizeof(Client));
         new->force_reconfigure = true;
 
         /* Update the data structures */
@@ -172,11 +199,17 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         new->child = child;
         new->rect.width = width;
         new->rect.height = height;
+        new->width_increment = 1;
+        new->height_increment = 1;
+        new->border_width = border_width;
         /* Pre-initialize the values for floating */
         new->floating_rect.x = -1;
         new->floating_rect.width = width;
         new->floating_rect.height = height;
 
+        if (config.default_border != NULL)
+                client_init_border(conn, new, config.default_border[1]);
+
         mask = 0;
 
         /* Don’t generate events for our new window, it should *not* be managed */
@@ -187,8 +220,6 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         mask |= XCB_CW_EVENT_MASK;
         values[1] = FRAME_EVENT_MASK;
 
-        LOG("Reparenting 0x%08x under 0x%08x.\n", child, new->frame);
-
         i3Font *font = load_font(conn, config.font);
         width = min(width, c_ws->rect.x + c_ws->rect.width);
         height = min(height, c_ws->rect.y + c_ws->rect.height);
@@ -200,11 +231,6 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         /* Yo dawg, I heard you like windows, so I create a window around your window… */
         new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, false, mask, values);
 
-        /* Set WM_STATE_NORMAL because GTK applications don’t want to drag & drop if we don’t.
-         * Also, xprop(1) needs that to work. */
-        long data[] = { XCB_WM_STATE_NORMAL, XCB_NONE };
-        xcb_change_property(conn, XCB_PROP_MODE_REPLACE, new->child, atoms[WM_STATE], atoms[WM_STATE], 32, 2, data);
-
         /* Put the client inside the save set. Upon termination (whether killed or normal exit
            does not matter) of the window manager, these clients will be correctly reparented
            to their most closest living ancestor (= cleanup) */
@@ -218,7 +244,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         new->awaiting_useless_unmap = true;
         xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
         if (xcb_request_check(conn, cookie) != NULL) {
-                LOG("Could not reparent the window, aborting\n");
+                DLOG("Could not reparent the window, aborting\n");
                 xcb_destroy_window(conn, new->frame);
                 free(new);
                 return;
@@ -236,35 +262,52 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
         xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
                         XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
-                        1 /* left mouse button */, XCB_MOD_MASK_1);
+                        3 /* right mouse button */,
+                        XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
 
         /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
         xcb_atom_t *atom;
         xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
         if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
                 for (int i = 0; i < xcb_get_property_value_length(preply); i++)
-                        if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
-                                LOG("Window is a dock.\n");
+                        if (atom[i] == A__NET_WM_WINDOW_TYPE_DOCK) {
+                                DLOG("Window is a dock.\n");
+                                Output *t_out = get_output_containing(x, y);
+                                if (t_out == NULL)
+                                        t_out = c_ws->output;
+                                if (t_out != c_ws->output) {
+                                        DLOG("Dock client requested to be on output %s by geometry (%d, %d)\n",
+                                                        t_out->name, x, y);
+                                        new->workspace = t_out->current_workspace;
+                                }
                                 new->dock = true;
+                                new->borderless = true;
                                 new->titlebar_position = TITLEBAR_OFF;
                                 new->force_reconfigure = true;
                                 new->container = NULL;
-                                SLIST_INSERT_HEAD(&(c_ws->screen->dock_clients), new, dock_clients);
+                                SLIST_INSERT_HEAD(&(t_out->dock_clients), new, dock_clients);
                                 /* If it’s a dock we can’t make it float, so we break */
+                                new->floating = FLOATING_AUTO_OFF;
                                 break;
-                        } else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
-                                   atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
-                                   atom[i] == atoms[_NET_WM_WINDOW_TYPE_TOOLBAR] ||
-                                   atom[i] == atoms[_NET_WM_WINDOW_TYPE_SPLASH]) {
+                        } else if (atom[i] == A__NET_WM_WINDOW_TYPE_DIALOG ||
+                                   atom[i] == A__NET_WM_WINDOW_TYPE_UTILITY ||
+                                   atom[i] == A__NET_WM_WINDOW_TYPE_TOOLBAR ||
+                                   atom[i] == A__NET_WM_WINDOW_TYPE_SPLASH) {
                                 /* Set the dialog window to automatically floating, will be used below */
                                 new->floating = FLOATING_AUTO_ON;
-                                LOG("dialog/utility/toolbar/splash window, automatically floating\n");
+                                DLOG("dialog/utility/toolbar/splash window, automatically floating\n");
                         }
         }
 
+        /* All clients which have a leader should be floating */
+        if (!new->dock && !client_is_floating(new) && new->leader != 0) {
+                DLOG("Client has WM_CLIENT_LEADER hint set, setting floating\n");
+                new->floating = FLOATING_AUTO_ON;
+        }
+
         if (new->workspace->auto_float) {
                 new->floating = FLOATING_AUTO_ON;
-                LOG("workspace is in autofloat mode, setting floating\n");
+                DLOG("workspace is in autofloat mode, setting floating\n");
         }
 
         if (new->dock) {
@@ -278,12 +321,12 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                            TODO: bars at the top */
                         new->desired_height = strut[3];
                         if (new->desired_height == 0) {
-                                LOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", original_height);
+                                DLOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", original_height);
                                 new->desired_height = original_height;
                         }
-                        LOG("the client wants to be %d pixels high\n", new->desired_height);
+                        DLOG("the client wants to be %d pixels high\n", new->desired_height);
                 } else {
-                        LOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", original_height);
+                        DLOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", original_height);
                         new->desired_height = original_height;
                 }
         } else {
@@ -294,15 +337,40 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                  * changes. It is important that the client was already inserted into the by_child table,
                  * because the callbacks won’t work otherwise. */
                 preply = xcb_get_property_reply(conn, utf8_title_cookie, NULL);
-                handle_windowname_change(NULL, conn, 0, new->child, atoms[_NET_WM_NAME], preply);
+                handle_windowname_change(NULL, conn, 0, new->child, A__NET_WM_NAME, preply);
 
                 preply = xcb_get_property_reply(conn, title_cookie, NULL);
-                handle_windowname_change_legacy(NULL, conn, 0, new->child, WM_NAME, preply);
+                handle_windowname_change_legacy(NULL, conn, 0, new->child, A_WM_NAME, preply);
 
                 preply = xcb_get_property_reply(conn, class_cookie, NULL);
-                handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
+                handle_windowclass_change(NULL, conn, 0, new->child, A_WM_CLASS, preply);
+
+                preply = xcb_get_property_reply(conn, leader_cookie, NULL);
+                handle_clientleader_change(NULL, conn, 0, new->child, A_WM_CLIENT_LEADER, preply);
+
+                /* if WM_CLIENT_LEADER is set, we put the new window on the
+                 * same window as its leader. This might be overwritten by
+                 * assignments afterwards. */
+                if (new->leader != XCB_NONE) {
+                        DLOG("client->leader is set (to 0x%08x)\n", new->leader);
+                        Client *parent = table_get(&by_child, new->leader);
+                        if (parent != NULL && parent->container != NULL) {
+                                Workspace *t_ws = parent->workspace;
+                                new->container = t_ws->table[parent->container->col][parent->container->row];
+                                new->workspace = t_ws;
+                                old_focused = new->container->currently_focused;
+                                map_frame = workspace_is_visible(t_ws);
+                                new->urgent = true;
+                                /* This is a little tricky: we cannot use
+                                 * workspace_update_urgent_flag() because the
+                                 * new window was not yet inserted into the
+                                 * focus stack on t_ws. */
+                                t_ws->urgent = true;
+                        } else {
+                                DLOG("parent is not usable\n");
+                        }
+                }
 
-                LOG("DEBUG: should have all infos now\n");
                 struct Assignment *assign;
                 TAILQ_FOREACH(assign, &assignments, assignments) {
                         if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
@@ -319,35 +387,36 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                         LOG("Assignment \"%s\" matches, so putting it on workspace %d\n",
                             assign->windowclass_title, assign->workspace);
 
-                        if (c_ws->screen->current_workspace == (assign->workspace-1)) {
-                                LOG("We are already there, no need to do anything\n");
+                        if (c_ws->output->current_workspace->num == (assign->workspace-1)) {
+                                DLOG("We are already there, no need to do anything\n");
                                 break;
                         }
 
-                        LOG("Changin container/workspace and unmapping the client\n");
-                        Workspace *t_ws = &(workspaces[assign->workspace-1]);
-                        if (t_ws->screen == NULL) {
-                                LOG("initializing new workspace, setting num to %d\n", assign->workspace);
-                                t_ws->screen = c_ws->screen;
-                                /* Copy the dimensions from the virtual screen */
-                                memcpy(&(t_ws->rect), &(t_ws->screen->rect), sizeof(Rect));
-                        }
+                        DLOG("Changing container/workspace and unmapping the client\n");
+                        Workspace *t_ws = workspace_get(assign->workspace-1);
+                        workspace_initialize(t_ws, c_ws->output, false);
 
                         new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
                         new->workspace = t_ws;
                         old_focused = new->container->currently_focused;
 
-                        xcb_unmap_window(conn, new->frame);
+                        map_frame = workspace_is_visible(t_ws);
                         break;
                 }
         }
 
-        if (CUR_CELL->workspace->fullscreen_client != NULL) {
-                if (new->container == CUR_CELL) {
-                        /* If we are in fullscreen, we should lower the window to not be annoying */
-                        uint32_t values[] = { XCB_STACK_MODE_BELOW };
-                        xcb_configure_window(conn, new->frame, XCB_CONFIG_WINDOW_STACK_MODE, values);
-                }
+        if (new->workspace->fullscreen_client != NULL) {
+                DLOG("Setting below fullscreen window\n");
+
+                /* If we are in fullscreen, we should place the window below
+                 * the fullscreen window to not be annoying */
+                uint32_t values[] = {
+                        new->workspace->fullscreen_client->frame,
+                        XCB_STACK_MODE_BELOW
+                };
+                xcb_configure_window(conn, new->frame,
+                                     XCB_CONFIG_WINDOW_SIBLING |
+                                     XCB_CONFIG_WINDOW_STACK_MODE, values);
         }
 
         /* Insert into the currently active container, if it’s not a dock window */
@@ -373,14 +442,31 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
 
                 new->container = NULL;
 
-                new->floating_rect.x = new->rect.x = x;
-                new->floating_rect.y = new->rect.y = y;
                 new->rect.width = new->floating_rect.width + 2 + 2;
                 new->rect.height = new->floating_rect.height + (font->height + 2 + 2) + 2;
-                LOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
+
+                /* Some clients (like GIMP’s color picker window) get mapped
+                 * to (0, 0), so we push them to a reasonable position
+                 * (centered over their leader) */
+                if (new->leader != 0 && x == 0 && y == 0) {
+                        DLOG("Floating client wants to (0x0), moving it over its leader instead\n");
+                        Client *leader = table_get(&by_child, new->leader);
+                        if (leader == NULL) {
+                                DLOG("leader is NULL, centering it over current workspace\n");
+
+                                x = c_ws->rect.x + (c_ws->rect.width / 2) - (new->rect.width / 2);
+                                y = c_ws->rect.y + (c_ws->rect.height / 2) - (new->rect.height / 2);
+                        } else {
+                                x = leader->rect.x + (leader->rect.width / 2) - (new->rect.width / 2);
+                                y = leader->rect.y + (leader->rect.height / 2) - (new->rect.height / 2);
+                        }
+                }
+                new->floating_rect.x = new->rect.x = x;
+                new->floating_rect.y = new->rect.y = y;
+                DLOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
                                 new->floating_rect.x, new->floating_rect.y,
                                 new->floating_rect.width, new->floating_rect.height);
-                LOG("outer rect (%d, %d) size (%d, %d)\n",
+                DLOG("outer rect (%d, %d) size (%d, %d)\n",
                                 new->rect.x, new->rect.y, new->rect.width, new->rect.height);
 
                 /* Make sure it is on top of the other windows */
@@ -399,27 +485,36 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
             (state = xcb_get_property_value(preply)) != NULL)
                 /* Check all set _NET_WM_STATEs */
                 for (int i = 0; i < xcb_get_property_value_length(preply); i++) {
-                        if (state[i] != atoms[_NET_WM_STATE_FULLSCREEN])
+                        if (state[i] != A__NET_WM_STATE_FULLSCREEN)
                                 continue;
                         /* If the window got the fullscreen state, we just toggle fullscreen
                            and don’t event bother to redraw the layout – that would not change
                            anything anyways */
                         client_toggle_fullscreen(conn, new);
-                        return;
+                        goto map;
                 }
 
         render_layout(conn);
 
+map:
         /* Map the window first to avoid flickering */
-        xcb_map_window(conn, new->frame);
         xcb_map_window(conn, child);
-        if (CUR_CELL->workspace->fullscreen_client == NULL && !new->dock) {
+        if (map_frame)
+                client_map(conn, new);
+
+        if ((CUR_CELL->workspace->fullscreen_client == NULL || new->fullscreen) && !new->dock) {
                 /* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
-                if (new->container->workspace->fullscreen_client == NULL) {
-                        if (!client_is_floating(new))
+                if ((new->workspace->fullscreen_client == NULL) || new->fullscreen) {
+                        if (!client_is_floating(new)) {
                                 new->container->currently_focused = new;
-                        if (new->container == CUR_CELL)
+                                if (map_frame)
+                                        render_container(conn, new->container);
+                        }
+                        if (new->container == CUR_CELL || client_is_floating(new)) {
                                 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
+                                take_focus(conn, new);
+                                ewmh_update_active_window(new->child);
+                        }
                 }
         }