]> git.sur5r.net Git - i3/i3/blob - src/manage.c
e15e802ad2759630cac0cb2e32fe3fa42be5a12b
[i3/i3] / src / manage.c
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009-2010 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * manage.c: Contains all functions for initially managing new windows
8  *           (or existing ones on restart).
9  *
10  */
11
12 #include "all.h"
13
14 /*
15  * Go through all existing windows (if the window manager is restarted) and manage them
16  *
17  */
18 void manage_existing_windows(xcb_window_t root) {
19     xcb_query_tree_reply_t *reply;
20     int i, len;
21     xcb_window_t *children;
22     xcb_get_window_attributes_cookie_t *cookies;
23
24     /* Get the tree of windows whose parent is the root window (= all) */
25     if ((reply = xcb_query_tree_reply(conn, xcb_query_tree(conn, root), 0)) == NULL)
26         return;
27
28     len = xcb_query_tree_children_length(reply);
29     cookies = smalloc(len * sizeof(*cookies));
30
31     /* Request the window attributes for every window */
32     children = xcb_query_tree_children(reply);
33     for (i = 0; i < len; ++i)
34         cookies[i] = xcb_get_window_attributes(conn, children[i]);
35
36     /* Call manage_window with the attributes for every window */
37     for (i = 0; i < len; ++i)
38         manage_window(children[i], cookies[i], true);
39
40
41     free(reply);
42     free(cookies);
43 }
44
45 /*
46  * Restores the geometry of each window by reparenting it to the root window
47  * at the position of its frame.
48  *
49  * This is to be called *only* before exiting/restarting i3 because of evil
50  * side-effects which are to be expected when continuing to run i3.
51  *
52  */
53 void restore_geometry() {
54     LOG("Restoring geometry\n");
55
56     Con *con;
57     TAILQ_FOREACH(con, &all_cons, all_cons)
58         if (con->window) {
59             printf("placing window at %d %d\n", con->rect.x, con->rect.y);
60             xcb_reparent_window(conn, con->window->id, root,
61                                 con->rect.x, con->rect.y);
62         }
63
64     /* Make sure our changes reach the X server, we restart/exit now */
65     xcb_flush(conn);
66 }
67
68 /*
69  * Do some sanity checks and then reparent the window.
70  *
71  */
72 void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
73                    bool needs_to_be_mapped) {
74     xcb_drawable_t d = { window };
75     xcb_get_geometry_cookie_t geomc;
76     xcb_get_geometry_reply_t *geom;
77     xcb_get_window_attributes_reply_t *attr = 0;
78
79     printf("---> looking at window 0x%08x\n", window);
80
81     xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
82                               utf8_title_cookie, title_cookie,
83                               class_cookie, leader_cookie;
84
85     wm_type_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
86     strut_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
87     state_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_STATE], UINT32_MAX);
88     utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[_NET_WM_NAME], 128);
89     leader_cookie = xcb_get_any_property_unchecked(conn, false, window, atoms[WM_CLIENT_LEADER], UINT32_MAX);
90     title_cookie = xcb_get_any_property_unchecked(conn, false, window, WM_NAME, 128);
91     class_cookie = xcb_get_any_property_unchecked(conn, false, window, WM_CLASS, 128);
92
93
94     geomc = xcb_get_geometry(conn, d);
95
96     /* Check if the window is mapped (it could be not mapped when intializing and
97        calling manage_window() for every window) */
98     if ((attr = xcb_get_window_attributes_reply(conn, cookie, 0)) == NULL) {
99         LOG("Could not get attributes\n");
100         return;
101     }
102
103     if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) {
104         LOG("map_state unviewable\n");
105         goto out;
106     }
107
108     /* Don’t manage clients with the override_redirect flag */
109     LOG("override_redirect is %d\n", attr->override_redirect);
110     if (attr->override_redirect)
111         goto out;
112
113     /* Check if the window is already managed */
114     if (con_by_window_id(window) != NULL)
115         goto out;
116
117     /* Get the initial geometry (position, size, …) */
118     if ((geom = xcb_get_geometry_reply(conn, geomc, 0)) == NULL)
119         goto out;
120
121     LOG("reparenting!\n");
122
123     i3Window *cwindow = scalloc(sizeof(i3Window));
124     cwindow->id = window;
125
126     class_cookie = xcb_get_any_property_unchecked(conn, false, window, WM_CLASS, 128);
127     xcb_get_property_reply_t *preply;
128     preply = xcb_get_property_reply(conn, class_cookie, NULL);
129     if (preply == NULL || xcb_get_property_value_length(preply) == 0) {
130         LOG("cannot get wm_class\n");
131     } else cwindow->class = strdup(xcb_get_property_value(preply));
132
133     Con *nc;
134     Match *match;
135
136     /* TODO: assignments */
137     /* TODO: two matches for one container */
138     /* See if any container swallows this new window */
139     nc = con_for_window(cwindow, &match);
140     if (nc == NULL) {
141         if (focused->type == CT_CON && con_accepts_window(focused)) {
142             LOG("using current container, focused = %p, focused->name = %s\n",
143                             focused, focused->name);
144             nc = focused;
145         } else nc = tree_open_con(NULL);
146     } else {
147         if (match != NULL && match->insert_where == M_ACTIVE) {
148             /* We need to go down the focus stack starting from nc */
149             while (TAILQ_FIRST(&(nc->focus_head)) != TAILQ_END(&(nc->focus_head))) {
150                 printf("walking down one step...\n");
151                 nc = TAILQ_FIRST(&(nc->focus_head));
152             }
153             /* We need to open a new con */
154             /* TODO: make a difference between match-once containers (directly assign
155              * cwindow) and match-multiple (tree_open_con first) */
156             nc = tree_open_con(nc->parent);
157         }
158     }
159     nc->window = cwindow;
160
161     xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame, 0, 0);
162     if (xcb_request_check(conn, rcookie) != NULL) {
163         LOG("Could not reparent the window, aborting\n");
164         goto out;
165         //xcb_destroy_window(conn, nc->frame);
166     }
167
168     xcb_change_save_set(conn, XCB_SET_MODE_INSERT, window);
169
170     tree_render();
171
172 #if 0
173     /* Reparent the window and add it to our list of managed windows */
174     reparent_window(conn, window, attr->visual, geom->root, geom->depth,
175                     geom->x, geom->y, geom->width, geom->height,
176                     geom->border_width);
177 #endif
178
179     /* Generate callback events for every property we watch */
180     free(geom);
181 out:
182     free(attr);
183     return;
184 }
185
186 #if 0
187 /*
188  * reparent_window() gets called when a new window was opened and becomes a child of the root
189  * window, or it gets called by us when we manage the already existing windows at startup.
190  *
191  * Essentially, this is the point where we take over control.
192  *
193  */
194 void reparent_window(xcb_connection_t *conn, xcb_window_t child,
195                      xcb_visualid_t visual, xcb_window_t root, uint8_t depth,
196                      int16_t x, int16_t y, uint16_t width, uint16_t height,
197                      uint32_t border_width) {
198
199         xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
200                                   utf8_title_cookie, title_cookie,
201                                   class_cookie, leader_cookie;
202         uint32_t mask = 0;
203         uint32_t values[3];
204         uint16_t original_height = height;
205         bool map_frame = true;
206
207         /* We are interested in property changes */
208         mask = XCB_CW_EVENT_MASK;
209         values[0] = CHILD_EVENT_MASK;
210         xcb_change_window_attributes(conn, child, mask, values);
211
212         /* Place requests for properties ASAP */
213         wm_type_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_WINDOW_TYPE], UINT32_MAX);
214         strut_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STRUT_PARTIAL], UINT32_MAX);
215         state_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_STATE], UINT32_MAX);
216         utf8_title_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[_NET_WM_NAME], 128);
217         leader_cookie = xcb_get_any_property_unchecked(conn, false, child, atoms[WM_CLIENT_LEADER], UINT32_MAX);
218         title_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_NAME, 128);
219         class_cookie = xcb_get_any_property_unchecked(conn, false, child, WM_CLASS, 128);
220
221         Client *new = table_get(&by_child, child);
222
223         /* Events for already managed windows should already be filtered in manage_window() */
224         assert(new == NULL);
225
226         LOG("Managing window 0x%08x\n", child);
227         DLOG("x = %d, y = %d, width = %d, height = %d\n", x, y, width, height);
228         new = scalloc(sizeof(Client));
229         new->force_reconfigure = true;
230
231         /* Update the data structures */
232         Client *old_focused = CUR_CELL->currently_focused;
233
234         new->container = CUR_CELL;
235         new->workspace = new->container->workspace;
236
237         /* Minimum useful size for managed windows is 75x50 (primarily affects floating) */
238         width = max(width, 75);
239         height = max(height, 50);
240
241         new->frame = xcb_generate_id(conn);
242         new->child = child;
243         new->rect.width = width;
244         new->rect.height = height;
245         new->width_increment = 1;
246         new->height_increment = 1;
247         new->border_width = border_width;
248         /* Pre-initialize the values for floating */
249         new->floating_rect.x = -1;
250         new->floating_rect.width = width;
251         new->floating_rect.height = height;
252
253         if (config.default_border != NULL)
254                 client_init_border(conn, new, config.default_border[1]);
255
256         mask = 0;
257
258         /* Don’t generate events for our new window, it should *not* be managed */
259         mask |= XCB_CW_OVERRIDE_REDIRECT;
260         values[0] = 1;
261
262         /* We want to know when… */
263         mask |= XCB_CW_EVENT_MASK;
264         values[1] = FRAME_EVENT_MASK;
265
266         i3Font *font = load_font(conn, config.font);
267         width = min(width, c_ws->rect.x + c_ws->rect.width);
268         height = min(height, c_ws->rect.y + c_ws->rect.height);
269
270         Rect framerect = {x, y,
271                           width + 2 + 2,                  /* 2 px border at each side */
272                           height + 2 + 2 + font->height}; /* 2 px border plus font’s height */
273
274         /* Yo dawg, I heard you like windows, so I create a window around your window… */
275         new->frame = create_window(conn, framerect, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_CURSOR_LEFT_PTR, false, mask, values);
276
277         /* Put the client inside the save set. Upon termination (whether killed or normal exit
278            does not matter) of the window manager, these clients will be correctly reparented
279            to their most closest living ancestor (= cleanup) */
280         xcb_change_save_set(conn, XCB_SET_MODE_INSERT, child);
281
282         /* Generate a graphics context for the titlebar */
283         new->titlegc = xcb_generate_id(conn);
284         xcb_create_gc(conn, new->titlegc, new->frame, 0, 0);
285
286         /* Moves the original window into the new frame we've created for it */
287         new->awaiting_useless_unmap = true;
288         xcb_void_cookie_t cookie = xcb_reparent_window_checked(conn, child, new->frame, 0, font->height);
289         if (xcb_request_check(conn, cookie) != NULL) {
290                 DLOG("Could not reparent the window, aborting\n");
291                 xcb_destroy_window(conn, new->frame);
292                 free(new);
293                 return;
294         }
295
296         /* Put our data structure (Client) into the table */
297         table_put(&by_parent, new->frame, new);
298         table_put(&by_child, child, new);
299
300         /* We need to grab the mouse buttons for click to focus */
301         xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
302                         XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
303                         1 /* left mouse button */,
304                         XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
305
306         xcb_grab_button(conn, false, child, XCB_EVENT_MASK_BUTTON_PRESS,
307                         XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
308                         3 /* right mouse button */,
309                         XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);
310
311         /* Get _NET_WM_WINDOW_TYPE (to see if it’s a dock) */
312         xcb_atom_t *atom;
313         xcb_get_property_reply_t *preply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
314         if (preply != NULL && preply->value_len > 0 && (atom = xcb_get_property_value(preply))) {
315                 for (int i = 0; i < xcb_get_property_value_length(preply); i++)
316                         if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DOCK]) {
317                                 DLOG("Window is a dock.\n");
318                                 Output *t_out = get_output_containing(x, y);
319                                 if (t_out != c_ws->output) {
320                                         DLOG("Dock client requested to be on output %s by geometry (%d, %d)\n",
321                                                         t_out->name, x, y);
322                                         new->workspace = t_out->current_workspace;
323                                 }
324                                 new->dock = true;
325                                 new->borderless = true;
326                                 new->titlebar_position = TITLEBAR_OFF;
327                                 new->force_reconfigure = true;
328                                 new->container = NULL;
329                                 SLIST_INSERT_HEAD(&(t_out->dock_clients), new, dock_clients);
330                                 /* If it’s a dock we can’t make it float, so we break */
331                                 new->floating = FLOATING_AUTO_OFF;
332                                 break;
333                         } else if (atom[i] == atoms[_NET_WM_WINDOW_TYPE_DIALOG] ||
334                                    atom[i] == atoms[_NET_WM_WINDOW_TYPE_UTILITY] ||
335                                    atom[i] == atoms[_NET_WM_WINDOW_TYPE_TOOLBAR] ||
336                                    atom[i] == atoms[_NET_WM_WINDOW_TYPE_SPLASH]) {
337                                 /* Set the dialog window to automatically floating, will be used below */
338                                 new->floating = FLOATING_AUTO_ON;
339                                 DLOG("dialog/utility/toolbar/splash window, automatically floating\n");
340                         }
341         }
342
343         /* All clients which have a leader should be floating */
344         if (!new->dock && !client_is_floating(new) && new->leader != 0) {
345                 DLOG("Client has WM_CLIENT_LEADER hint set, setting floating\n");
346                 new->floating = FLOATING_AUTO_ON;
347         }
348
349         if (new->workspace->auto_float) {
350                 new->floating = FLOATING_AUTO_ON;
351                 DLOG("workspace is in autofloat mode, setting floating\n");
352         }
353
354         if (new->dock) {
355                 /* Get _NET_WM_STRUT_PARTIAL to determine the client’s requested height */
356                 uint32_t *strut;
357                 preply = xcb_get_property_reply(conn, strut_cookie, NULL);
358                 if (preply != NULL && preply->value_len > 0 && (strut = xcb_get_property_value(preply))) {
359                         /* We only use a subset of the provided values, namely the reserved space at the top/bottom
360                            of the screen. This is because the only possibility for bars is at to be at the top/bottom
361                            with maximum horizontal size.
362                            TODO: bars at the top */
363                         new->desired_height = strut[3];
364                         if (new->desired_height == 0) {
365                                 DLOG("Client wanted to be 0 pixels high, using the window's height (%d)\n", original_height);
366                                 new->desired_height = original_height;
367                         }
368                         DLOG("the client wants to be %d pixels high\n", new->desired_height);
369                 } else {
370                         DLOG("The client didn't specify space to reserve at the screen edge, using its height (%d)\n", original_height);
371                         new->desired_height = original_height;
372                 }
373         } else {
374                 /* If it’s not a dock, we can check on which workspace we should put it. */
375
376                 /* Firstly, we need to get the window’s class / title. We asked for the properties at the
377                  * top of this function, get them now and pass them to our callback function for window class / title
378                  * changes. It is important that the client was already inserted into the by_child table,
379                  * because the callbacks won’t work otherwise. */
380                 preply = xcb_get_property_reply(conn, utf8_title_cookie, NULL);
381                 handle_windowname_change(NULL, conn, 0, new->child, atoms[_NET_WM_NAME], preply);
382
383                 preply = xcb_get_property_reply(conn, title_cookie, NULL);
384                 handle_windowname_change_legacy(NULL, conn, 0, new->child, WM_NAME, preply);
385
386                 preply = xcb_get_property_reply(conn, class_cookie, NULL);
387                 handle_windowclass_change(NULL, conn, 0, new->child, WM_CLASS, preply);
388
389                 preply = xcb_get_property_reply(conn, leader_cookie, NULL);
390                 handle_clientleader_change(NULL, conn, 0, new->child, atoms[WM_CLIENT_LEADER], preply);
391
392                 /* if WM_CLIENT_LEADER is set, we put the new window on the
393                  * same window as its leader. This might be overwritten by
394                  * assignments afterwards. */
395                 if (new->leader != XCB_NONE) {
396                         DLOG("client->leader is set (to 0x%08x)\n", new->leader);
397                         Client *parent = table_get(&by_child, new->leader);
398                         if (parent != NULL && parent->container != NULL) {
399                                 Workspace *t_ws = parent->workspace;
400                                 new->container = t_ws->table[parent->container->col][parent->container->row];
401                                 new->workspace = t_ws;
402                                 old_focused = new->container->currently_focused;
403                                 map_frame = workspace_is_visible(t_ws);
404                                 new->urgent = true;
405                                 /* This is a little tricky: we cannot use
406                                  * workspace_update_urgent_flag() because the
407                                  * new window was not yet inserted into the
408                                  * focus stack on t_ws. */
409                                 t_ws->urgent = true;
410                         } else {
411                                 DLOG("parent is not usable\n");
412                         }
413                 }
414
415                 struct Assignment *assign;
416                 TAILQ_FOREACH(assign, &assignments, assignments) {
417                         if (get_matching_client(conn, assign->windowclass_title, new) == NULL)
418                                 continue;
419
420                         if (assign->floating == ASSIGN_FLOATING_ONLY ||
421                             assign->floating == ASSIGN_FLOATING) {
422                                 new->floating = FLOATING_AUTO_ON;
423                                 LOG("Assignment matches, putting client into floating mode\n");
424                                 if (assign->floating == ASSIGN_FLOATING_ONLY)
425                                         break;
426                         }
427
428                         LOG("Assignment \"%s\" matches, so putting it on workspace %d\n",
429                             assign->windowclass_title, assign->workspace);
430
431                         if (c_ws->output->current_workspace->num == (assign->workspace-1)) {
432                                 DLOG("We are already there, no need to do anything\n");
433                                 break;
434                         }
435
436                         DLOG("Changing container/workspace and unmapping the client\n");
437                         Workspace *t_ws = workspace_get(assign->workspace-1);
438                         workspace_initialize(t_ws, c_ws->output, false);
439
440                         new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
441                         new->workspace = t_ws;
442                         old_focused = new->container->currently_focused;
443
444                         map_frame = workspace_is_visible(t_ws);
445                         break;
446                 }
447         }
448
449         if (new->workspace->fullscreen_client != NULL) {
450                 DLOG("Setting below fullscreen window\n");
451
452                 /* If we are in fullscreen, we should place the window below
453                  * the fullscreen window to not be annoying */
454                 uint32_t values[] = {
455                         new->workspace->fullscreen_client->frame,
456                         XCB_STACK_MODE_BELOW
457                 };
458                 xcb_configure_window(conn, new->frame,
459                                      XCB_CONFIG_WINDOW_SIBLING |
460                                      XCB_CONFIG_WINDOW_STACK_MODE, values);
461         }
462
463         /* Insert into the currently active container, if it’s not a dock window */
464         if (!new->dock && !client_is_floating(new)) {
465                 /* Insert after the old active client, if existing. If it does not exist, the
466                    container is empty and it does not matter, where we insert it */
467                 if (old_focused != NULL && !old_focused->dock)
468                         CIRCLEQ_INSERT_AFTER(&(new->container->clients), old_focused, new, clients);
469                 else CIRCLEQ_INSERT_TAIL(&(new->container->clients), new, clients);
470
471                 if (new->container->workspace->fullscreen_client != NULL)
472                         SLIST_INSERT_AFTER(new->container->workspace->fullscreen_client, new, focus_clients);
473                 else SLIST_INSERT_HEAD(&(new->container->workspace->focus_stack), new, focus_clients);
474
475                 client_set_below_floating(conn, new);
476         }
477
478         if (client_is_floating(new)) {
479                 SLIST_INSERT_HEAD(&(new->workspace->focus_stack), new, focus_clients);
480
481                 /* Add the client to the list of floating clients for its workspace */
482                 TAILQ_INSERT_TAIL(&(new->workspace->floating_clients), new, floating_clients);
483
484                 new->container = NULL;
485
486                 new->rect.width = new->floating_rect.width + 2 + 2;
487                 new->rect.height = new->floating_rect.height + (font->height + 2 + 2) + 2;
488
489                 /* Some clients (like GIMP’s color picker window) get mapped
490                  * to (0, 0), so we push them to a reasonable position
491                  * (centered over their leader) */
492                 if (new->leader != 0 && x == 0 && y == 0) {
493                         DLOG("Floating client wants to (0x0), moving it over its leader instead\n");
494                         Client *leader = table_get(&by_child, new->leader);
495                         if (leader == NULL) {
496                                 DLOG("leader is NULL, centering it over current workspace\n");
497
498                                 x = c_ws->rect.x + (c_ws->rect.width / 2) - (new->rect.width / 2);
499                                 y = c_ws->rect.y + (c_ws->rect.height / 2) - (new->rect.height / 2);
500                         } else {
501                                 x = leader->rect.x + (leader->rect.width / 2) - (new->rect.width / 2);
502                                 y = leader->rect.y + (leader->rect.height / 2) - (new->rect.height / 2);
503                         }
504                 }
505                 new->floating_rect.x = new->rect.x = x;
506                 new->floating_rect.y = new->rect.y = y;
507                 DLOG("copying floating_rect from tiling (%d, %d) size (%d, %d)\n",
508                                 new->floating_rect.x, new->floating_rect.y,
509                                 new->floating_rect.width, new->floating_rect.height);
510                 DLOG("outer rect (%d, %d) size (%d, %d)\n",
511                                 new->rect.x, new->rect.y, new->rect.width, new->rect.height);
512
513                 /* Make sure it is on top of the other windows */
514                 xcb_raise_window(conn, new->frame);
515                 reposition_client(conn, new);
516                 resize_client(conn, new);
517                 /* redecorate_window flushes */
518                 redecorate_window(conn, new);
519         }
520
521         new->initialized = true;
522
523         /* Check if the window already got the fullscreen hint set */
524         xcb_atom_t *state;
525         if ((preply = xcb_get_property_reply(conn, state_cookie, NULL)) != NULL &&
526             (state = xcb_get_property_value(preply)) != NULL)
527                 /* Check all set _NET_WM_STATEs */
528                 for (int i = 0; i < xcb_get_property_value_length(preply); i++) {
529                         if (state[i] != atoms[_NET_WM_STATE_FULLSCREEN])
530                                 continue;
531                         /* If the window got the fullscreen state, we just toggle fullscreen
532                            and don’t event bother to redraw the layout – that would not change
533                            anything anyways */
534                         client_toggle_fullscreen(conn, new);
535                         goto map;
536                 }
537
538         render_layout(conn);
539
540 map:
541         /* Map the window first to avoid flickering */
542         xcb_map_window(conn, child);
543         if (map_frame)
544                 client_map(conn, new);
545
546         if ((CUR_CELL->workspace->fullscreen_client == NULL || new->fullscreen) && !new->dock) {
547                 /* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
548                 if ((new->workspace->fullscreen_client == NULL) || new->fullscreen) {
549                         if (!client_is_floating(new)) {
550                                 new->container->currently_focused = new;
551                                 if (map_frame)
552                                         render_container(conn, new->container);
553                         }
554                         if (new->container == CUR_CELL || client_is_floating(new)) {
555                                 xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
556                                 ewmh_update_active_window(new->child);
557                         }
558                 }
559         }
560
561         xcb_flush(conn);
562 }
563 #endif