i3
tree.c
Go to the documentation of this file.
1 /*
2  * vim:ts=4:sw=4:expandtab
3  *
4  * i3 - an improved dynamic tiling window manager
5  * © 2009 Michael Stapelberg and contributors (see also: LICENSE)
6  *
7  * tree.c: Everything that primarily modifies the layout tree data structure.
8  *
9  */
10 #include "all.h"
11 
12 struct Con *croot;
13 struct Con *focused;
14 
15 struct all_cons_head all_cons = TAILQ_HEAD_INITIALIZER(all_cons);
16 
17 /*
18  * Create the pseudo-output __i3. Output-independent workspaces such as
19  * __i3_scratch will live there.
20  *
21  */
22 static Con *_create___i3(void) {
23  Con *__i3 = con_new(croot, NULL);
24  FREE(__i3->name);
25  __i3->name = sstrdup("__i3");
26  __i3->type = CT_OUTPUT;
27  __i3->layout = L_OUTPUT;
29  x_set_name(__i3, "[i3 con] pseudo-output __i3");
30  /* For retaining the correct position/size of a scratchpad window, the
31  * dimensions of the real outputs should be multiples of the __i3
32  * pseudo-output. Ensuring that is the job of scratchpad_fix_resolution()
33  * which gets called after this function and after detecting all the
34  * outputs (or whenever an output changes). */
35  __i3->rect.width = 1280;
36  __i3->rect.height = 1024;
37 
38  /* Add a content container. */
39  DLOG("adding main content container\n");
40  Con *content = con_new(NULL, NULL);
41  content->type = CT_CON;
42  FREE(content->name);
43  content->name = sstrdup("content");
44  content->layout = L_SPLITH;
45 
46  x_set_name(content, "[i3 con] content __i3");
47  con_attach(content, __i3, false);
48 
49  /* Attach the __i3_scratch workspace. */
50  Con *ws = con_new(NULL, NULL);
51  ws->type = CT_WORKSPACE;
52  ws->num = -1;
53  ws->name = sstrdup("__i3_scratch");
54  ws->layout = L_SPLITH;
55  con_attach(ws, content, false);
56  x_set_name(ws, "[i3 con] workspace __i3_scratch");
58 
59  return __i3;
60 }
61 
62 /*
63  * Loads tree from 'path' (used for in-place restarts).
64  *
65  */
66 bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry) {
67  bool result = false;
68  char *globbed = resolve_tilde(path);
69  char *buf = NULL;
70 
71  if (!path_exists(globbed)) {
72  LOG("%s does not exist, not restoring tree\n", globbed);
73  goto out;
74  }
75 
76  ssize_t len;
77  if ((len = slurp(globbed, &buf)) < 0) {
78  /* slurp already logged an error. */
79  goto out;
80  }
81 
82  /* TODO: refactor the following */
83  croot = con_new(NULL, NULL);
84  croot->rect = (Rect){
85  geometry->x,
86  geometry->y,
87  geometry->width,
88  geometry->height};
89  focused = croot;
90 
91  tree_append_json(focused, buf, len, NULL);
92 
93  DLOG("appended tree, using new root\n");
95  if (!croot) {
96  /* tree_append_json failed. Continuing here would segfault. */
97  goto out;
98  }
99  DLOG("new root = %p\n", croot);
100  Con *out = TAILQ_FIRST(&(croot->nodes_head));
101  DLOG("out = %p\n", out);
102  Con *ws = TAILQ_FIRST(&(out->nodes_head));
103  DLOG("ws = %p\n", ws);
104 
105  /* For in-place restarting into v4.2, we need to make sure the new
106  * pseudo-output __i3 is present. */
107  if (strcmp(out->name, "__i3") != 0) {
108  DLOG("Adding pseudo-output __i3 during inplace restart\n");
109  Con *__i3 = _create___i3();
110  /* Ensure that it is the first output, other places in the code make
111  * that assumption. */
112  TAILQ_REMOVE(&(croot->nodes_head), __i3, nodes);
113  TAILQ_INSERT_HEAD(&(croot->nodes_head), __i3, nodes);
114  }
115 
117  result = true;
118 
119 out:
120  free(globbed);
121  free(buf);
122  return result;
123 }
124 
125 /*
126  * Initializes the tree by creating the root node. The CT_OUTPUT Cons below the
127  * root node are created in randr.c for each Output.
128  *
129  */
130 void tree_init(xcb_get_geometry_reply_t *geometry) {
131  croot = con_new(NULL, NULL);
132  FREE(croot->name);
133  croot->name = "root";
134  croot->type = CT_ROOT;
135  croot->layout = L_SPLITH;
136  croot->rect = (Rect){
137  geometry->x,
138  geometry->y,
139  geometry->width,
140  geometry->height};
141 
142  _create___i3();
143 }
144 
145 /*
146  * Opens an empty container in the current container
147  *
148  */
149 Con *tree_open_con(Con *con, i3Window *window) {
150  if (con == NULL) {
151  /* every focusable Con has a parent (outputs have parent root) */
152  con = focused->parent;
153  /* If the parent is an output, we are on a workspace. In this case,
154  * the new container needs to be opened as a leaf of the workspace. */
155  if (con->parent->type == CT_OUTPUT && con->type != CT_DOCKAREA) {
156  con = focused;
157  }
158 
159  /* If the currently focused container is a floating container, we
160  * attach the new container to the currently focused spot in its
161  * workspace. */
162  if (con->type == CT_FLOATING_CON) {
164  if (con->type != CT_WORKSPACE)
165  con = con->parent;
166  }
167  DLOG("con = %p\n", con);
168  }
169 
170  assert(con != NULL);
171 
172  /* 3. create the container and attach it to its parent */
173  Con *new = con_new(con, window);
174  new->layout = L_SPLITH;
175 
176  /* 4: re-calculate child->percent for each child */
177  con_fix_percent(con);
178 
179  return new;
180 }
181 
182 /*
183  * Closes the given container including all children.
184  * Returns true if the container was killed or false if just WM_DELETE was sent
185  * and the window is expected to kill itself.
186  *
187  * The dont_kill_parent flag is specified when the function calls itself
188  * recursively while deleting a containers children.
189  *
190  */
191 bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent) {
192  Con *parent = con->parent;
193 
194  /* remove the urgency hint of the workspace (if set) */
195  if (con->urgent) {
196  con_set_urgency(con, false);
199  }
200 
201  DLOG("closing %p, kill_window = %d\n", con, kill_window);
202  Con *child, *nextchild;
203  bool abort_kill = false;
204  /* We cannot use TAILQ_FOREACH because the children get deleted
205  * in their parent’s nodes_head */
206  for (child = TAILQ_FIRST(&(con->nodes_head)); child;) {
207  nextchild = TAILQ_NEXT(child, nodes);
208  DLOG("killing child=%p\n", child);
209  if (!tree_close_internal(child, kill_window, true)) {
210  abort_kill = true;
211  }
212  child = nextchild;
213  }
214 
215  if (abort_kill) {
216  DLOG("One of the children could not be killed immediately (WM_DELETE sent), aborting.\n");
217  return false;
218  }
219 
220  if (con->window != NULL) {
221  if (kill_window != DONT_KILL_WINDOW) {
222  x_window_kill(con->window->id, kill_window);
223  return false;
224  } else {
225  xcb_void_cookie_t cookie;
226  /* Ignore any further events by clearing the event mask,
227  * unmap the window,
228  * then reparent it to the root window. */
229  xcb_change_window_attributes(conn, con->window->id,
230  XCB_CW_EVENT_MASK, (uint32_t[]){XCB_NONE});
231  xcb_unmap_window(conn, con->window->id);
232  cookie = xcb_reparent_window(conn, con->window->id, root, con->rect.x, con->rect.y);
233 
234  /* Ignore X11 errors for the ReparentWindow request.
235  * X11 Errors are returned when the window was already destroyed */
236  add_ignore_event(cookie.sequence, 0);
237 
238  /* We are no longer handling this window, thus set WM_STATE to
239  * WM_STATE_WITHDRAWN (see ICCCM 4.1.3.1) */
240  long data[] = {XCB_ICCCM_WM_STATE_WITHDRAWN, XCB_NONE};
241  cookie = xcb_change_property(conn, XCB_PROP_MODE_REPLACE,
242  con->window->id, A_WM_STATE, A_WM_STATE, 32, 2, data);
243 
244  /* Remove the window from the save set. All windows in the save set
245  * will be mapped when i3 closes its connection (e.g. when
246  * restarting). This is not what we want, since some apps keep
247  * unmapped windows around and don’t expect them to suddenly be
248  * mapped. See https://bugs.i3wm.org/1617 */
249  xcb_change_save_set(conn, XCB_SET_MODE_DELETE, con->window->id);
250 
251  /* Stop receiving ShapeNotify events. */
252  if (shape_supported) {
253  xcb_shape_select_input(conn, con->window->id, false);
254  }
255 
256  /* Ignore X11 errors for the ReparentWindow request.
257  * X11 Errors are returned when the window was already destroyed */
258  add_ignore_event(cookie.sequence, 0);
259  }
260  ipc_send_window_event("close", con);
261  window_free(con->window);
262  con->window = NULL;
263  }
264 
265  Con *ws = con_get_workspace(con);
266 
267  /* Figure out which container to focus next before detaching 'con'. */
268  Con *next = (con == focused) ? con_next_focused(con) : NULL;
269  DLOG("next = %p, focused = %p\n", next, focused);
270 
271  /* Detach the container so that it will not be rendered anymore. */
272  con_detach(con);
273 
274  /* disable urgency timer, if needed */
275  if (con->urgency_timer != NULL) {
276  DLOG("Removing urgency timer of con %p\n", con);
278  ev_timer_stop(main_loop, con->urgency_timer);
279  FREE(con->urgency_timer);
280  }
281 
282  if (con->type != CT_FLOATING_CON) {
283  /* If the container is *not* floating, we might need to re-distribute
284  * percentage values for the resized containers. */
285  con_fix_percent(parent);
286  }
287 
288  /* Render the tree so that the surrounding containers take up the space
289  * which 'con' does no longer occupy. If we don’t render here, there will
290  * be a gap in our containers and that could trigger an EnterNotify for an
291  * underlying container, see ticket #660.
292  *
293  * Rendering has to be avoided when dont_kill_parent is set (when
294  * tree_close_internal calls itself recursively) because the tree is in a
295  * non-renderable state during that time. */
296  if (!dont_kill_parent)
297  tree_render();
298 
299  /* kill the X11 part of this container */
300  x_con_kill(con);
301 
302  if (ws == con) {
303  DLOG("Closing workspace container %s, updating EWMH atoms\n", ws->name);
305  }
306 
307  con_free(con);
308 
309  if (next) {
310  con_activate(next);
311  } else {
312  DLOG("not changing focus, the container was not focused before\n");
313  }
314 
315  /* check if the parent container is empty now and close it */
316  if (!dont_kill_parent)
317  CALL(parent, on_remove_child);
318 
319  return true;
320 }
321 
322 /*
323  * Splits (horizontally or vertically) the given container by creating a new
324  * container which contains the old one and the future ones.
325  *
326  */
327 void tree_split(Con *con, orientation_t orientation) {
328  if (con_is_floating(con)) {
329  DLOG("Floating containers can't be split.\n");
330  return;
331  }
332 
333  if (con->type == CT_WORKSPACE) {
334  if (con_num_children(con) < 2) {
335  if (con_num_children(con) == 0) {
336  DLOG("Changing workspace_layout to L_DEFAULT\n");
338  }
339  DLOG("Changing orientation of workspace\n");
340  con->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV;
341  return;
342  } else {
343  /* if there is more than one container on the workspace
344  * move them into a new container and handle this instead */
345  con = workspace_encapsulate(con);
346  }
347  }
348 
349  Con *parent = con->parent;
350 
351  /* Force re-rendering to make the indicator border visible. */
353 
354  /* if we are in a container whose parent contains only one
355  * child (its split functionality is unused so far), we just change the
356  * orientation (more intuitive than splitting again) */
357  if (con_num_children(parent) == 1 &&
358  (parent->layout == L_SPLITH ||
359  parent->layout == L_SPLITV)) {
360  parent->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV;
361  DLOG("Just changing orientation of existing container\n");
362  return;
363  }
364 
365  DLOG("Splitting in orientation %d\n", orientation);
366 
367  /* 2: replace it with a new Con */
368  Con *new = con_new(NULL, NULL);
369  TAILQ_REPLACE(&(parent->nodes_head), con, new, nodes);
370  TAILQ_REPLACE(&(parent->focus_head), con, new, focused);
371  new->parent = parent;
372  new->layout = (orientation == HORIZ) ? L_SPLITH : L_SPLITV;
373 
374  /* 3: swap 'percent' (resize factor) */
375  new->percent = con->percent;
376  con->percent = 0.0;
377 
378  /* 4: add it as a child to the new Con */
379  con_attach(con, new, false);
380 }
381 
382 /*
383  * Moves focus one level up. Returns true if focus changed.
384  *
385  */
386 bool level_up(void) {
387  /* Skip over floating containers and go directly to the grandparent
388  * (which should always be a workspace) */
389  if (focused->parent->type == CT_FLOATING_CON) {
391  return true;
392  }
393 
394  /* We can focus up to the workspace, but not any higher in the tree */
395  if ((focused->parent->type != CT_CON &&
396  focused->parent->type != CT_WORKSPACE) ||
397  focused->type == CT_WORKSPACE) {
398  ELOG("'focus parent': Focus is already on the workspace, cannot go higher than that.\n");
399  return false;
400  }
402  return true;
403 }
404 
405 /*
406  * Moves focus one level down. Returns true if focus changed.
407  *
408  */
409 bool level_down(void) {
410  /* Go down the focus stack of the current node */
411  Con *next = TAILQ_FIRST(&(focused->focus_head));
412  if (next == TAILQ_END(&(focused->focus_head))) {
413  DLOG("cannot go down\n");
414  return false;
415  } else if (next->type == CT_FLOATING_CON) {
416  /* Floating cons shouldn't be directly focused; try immediately
417  * going to the grandchild of the focused con. */
418  Con *child = TAILQ_FIRST(&(next->focus_head));
419  if (child == TAILQ_END(&(next->focus_head))) {
420  DLOG("cannot go down\n");
421  return false;
422  } else
423  next = TAILQ_FIRST(&(next->focus_head));
424  }
425 
426  con_activate(next);
427  return true;
428 }
429 
430 static void mark_unmapped(Con *con) {
431  Con *current;
432 
433  con->mapped = false;
434  TAILQ_FOREACH(current, &(con->nodes_head), nodes)
435  mark_unmapped(current);
436  if (con->type == CT_WORKSPACE) {
437  /* We need to call mark_unmapped on floating nodes as well since we can
438  * make containers floating. */
439  TAILQ_FOREACH(current, &(con->floating_head), floating_windows)
440  mark_unmapped(current);
441  }
442 }
443 
444 /*
445  * Renders the tree, that is rendering all outputs using render_con() and
446  * pushing the changes to X11 using x_push_changes().
447  *
448  */
449 void tree_render(void) {
450  if (croot == NULL)
451  return;
452 
453  DLOG("-- BEGIN RENDERING --\n");
454  /* Reset map state for all nodes in tree */
455  /* TODO: a nicer method to walk all nodes would be good, maybe? */
457  croot->mapped = true;
458 
459  render_con(croot, false);
460 
462  DLOG("-- END RENDERING --\n");
463 }
464 
465 static Con *get_tree_next_workspace(Con *con, direction_t direction) {
466  if (con_get_fullscreen_con(con, CF_GLOBAL)) {
467  DLOG("Cannot change workspace while in global fullscreen mode.\n");
468  return NULL;
469  }
470 
471  Output *current_output = get_output_containing(con->rect.x, con->rect.y);
472  if (!current_output) {
473  return NULL;
474  }
475  DLOG("Current output is %s\n", output_primary_name(current_output));
476 
477  Output *next_output = get_output_next(direction, current_output, CLOSEST_OUTPUT);
478  if (!next_output) {
479  return NULL;
480  }
481  DLOG("Next output is %s\n", output_primary_name(next_output));
482 
483  /* Find visible workspace on next output */
484  Con *workspace = NULL;
485  GREP_FIRST(workspace, output_get_content(next_output->con), workspace_is_visible(child));
486  return workspace;
487 }
488 
489 /*
490  * Returns the next / previous container to focus in the given direction. Does
491  * not modify focus and ensures focus restrictions for fullscreen containers
492  * are respected.
493  *
494  */
495 static Con *get_tree_next(Con *con, direction_t direction) {
496  const bool previous = position_from_direction(direction) == BEFORE;
497  const orientation_t orientation = orientation_from_direction(direction);
498 
499  Con *first_wrap = NULL;
500 
501  if (con->type == CT_WORKSPACE) {
502  /* Special case for FOCUS_WRAPPING_WORKSPACE: allow the focus to leave
503  * the workspace only when a workspace is selected. */
504  goto handle_workspace;
505  }
506 
507  while (con->type != CT_WORKSPACE) {
508  if (con->fullscreen_mode == CF_OUTPUT) {
509  /* We've reached a fullscreen container. Directional focus should
510  * now operate on the workspace level. */
511  con = con_get_workspace(con);
512  break;
513  } else if (con->fullscreen_mode == CF_GLOBAL) {
514  /* Focus changes should happen only inside the children of a global
515  * fullscreen container. */
516  return first_wrap;
517  }
518 
519  Con *const parent = con->parent;
520  if (con->type == CT_FLOATING_CON) {
521  if (orientation != HORIZ) {
522  /* up/down does not change floating containers */
523  return NULL;
524  }
525 
526  /* left/right focuses the previous/next floating container */
527  Con *next = previous ? TAILQ_PREV(con, floating_head, floating_windows)
528  : TAILQ_NEXT(con, floating_windows);
529  /* If there is no next/previous container, wrap */
530  if (!next) {
531  next = previous ? TAILQ_LAST(&(parent->floating_head), floating_head)
532  : TAILQ_FIRST(&(parent->floating_head));
533  }
534  /* Our parent does not list us in floating heads? */
535  assert(next);
536 
537  return next;
538  }
539 
540  if (con_num_children(parent) > 1 && con_orientation(parent) == orientation) {
541  Con *const next = previous ? TAILQ_PREV(con, nodes_head, nodes)
542  : TAILQ_NEXT(con, nodes);
543  if (next && con_fullscreen_permits_focusing(next)) {
544  return next;
545  }
546 
547  Con *const wrap = previous ? TAILQ_LAST(&(parent->nodes_head), nodes_head)
548  : TAILQ_FIRST(&(parent->nodes_head));
549  switch (config.focus_wrapping) {
550  case FOCUS_WRAPPING_OFF:
551  break;
553  case FOCUS_WRAPPING_ON:
554  if (!first_wrap && con_fullscreen_permits_focusing(wrap)) {
555  first_wrap = wrap;
556  }
557  break;
559  /* 'force' should always return to ensure focus doesn't
560  * leave the parent. */
561  if (next) {
562  return NULL; /* blocked by fullscreen */
563  }
564  return con_fullscreen_permits_focusing(wrap) ? wrap : NULL;
565  }
566  }
567 
568  con = parent;
569  }
570 
571  assert(con->type == CT_WORKSPACE);
573  return first_wrap;
574  }
575 
576 handle_workspace:;
577  Con *workspace = get_tree_next_workspace(con, direction);
578  return workspace ? workspace : first_wrap;
579 }
580 
581 /*
582  * Changes focus in the given direction
583  *
584  */
585 void tree_next(Con *con, direction_t direction) {
586  Con *next = get_tree_next(con, direction);
587  if (!next) {
588  return;
589  }
590  if (next->type == CT_WORKSPACE) {
591  /* Show next workspace and focus appropriate container if possible. */
592  /* Use descend_focused first to give higher priority to floating or
593  * tiling fullscreen containers. */
594  Con *focus = con_descend_focused(next);
595  if (focus->fullscreen_mode == CF_NONE) {
596  Con *focus_tiling = con_descend_tiling_focused(next);
597  /* If descend_tiling returned a workspace then focus is either a
598  * floating container or the same workspace. */
599  if (focus_tiling != next) {
600  focus = focus_tiling;
601  }
602  }
603 
604  workspace_show(next);
605  con_activate(focus);
606  x_set_warp_to(&(focus->rect));
607  return;
608  } else if (next->type == CT_FLOATING_CON) {
609  /* Raise the floating window on top of other windows preserving relative
610  * stack order */
611  Con *parent = next->parent;
612  while (TAILQ_LAST(&(parent->floating_head), floating_head) != next) {
613  Con *last = TAILQ_LAST(&(parent->floating_head), floating_head);
614  TAILQ_REMOVE(&(parent->floating_head), last, floating_windows);
615  TAILQ_INSERT_HEAD(&(parent->floating_head), last, floating_windows);
616  }
617  }
618 
621 }
622 
623 /*
624  * Get the previous / next sibling
625  *
626  */
628  Con *to_focus = (direction == BEFORE ? TAILQ_PREV(con, nodes_head, nodes)
629  : TAILQ_NEXT(con, nodes));
631  return to_focus;
632  }
633  return NULL;
634 }
635 
636 /*
637  * tree_flatten() removes pairs of redundant split containers, e.g.:
638  * [workspace, horizontal]
639  * [v-split] [child3]
640  * [h-split]
641  * [child1] [child2]
642  * In this example, the v-split and h-split container are redundant.
643  * Such a situation can be created by moving containers in a direction which is
644  * not the orientation of their parent container. i3 needs to create a new
645  * split container then and if you move containers this way multiple times,
646  * redundant chains of split-containers can be the result.
647  *
648  */
649 void tree_flatten(Con *con) {
650  Con *current, *child, *parent = con->parent;
651  DLOG("Checking if I can flatten con = %p / %s\n", con, con->name);
652 
653  /* We only consider normal containers without windows */
654  if (con->type != CT_CON ||
655  parent->layout == L_OUTPUT || /* con == "content" */
656  con->window != NULL)
657  goto recurse;
658 
659  /* Ensure it got only one child */
660  child = TAILQ_FIRST(&(con->nodes_head));
661  if (child == NULL || TAILQ_NEXT(child, nodes) != NULL)
662  goto recurse;
663 
664  DLOG("child = %p, con = %p, parent = %p\n", child, con, parent);
665 
666  /* The child must have a different orientation than the con but the same as
667  * the con’s parent to be redundant */
668  if (!con_is_split(con) ||
669  !con_is_split(child) ||
670  (con->layout != L_SPLITH && con->layout != L_SPLITV) ||
671  (child->layout != L_SPLITH && child->layout != L_SPLITV) ||
672  con_orientation(con) == con_orientation(child) ||
673  con_orientation(child) != con_orientation(parent))
674  goto recurse;
675 
676  DLOG("Alright, I have to flatten this situation now. Stay calm.\n");
677  /* 1: save focus */
678  Con *focus_next = TAILQ_FIRST(&(child->focus_head));
679 
680  DLOG("detaching...\n");
681  /* 2: re-attach the children to the parent before con */
682  while (!TAILQ_EMPTY(&(child->nodes_head))) {
683  current = TAILQ_FIRST(&(child->nodes_head));
684  DLOG("detaching current=%p / %s\n", current, current->name);
685  con_detach(current);
686  DLOG("re-attaching\n");
687  /* We don’t use con_attach() here because for a CT_CON, the special
688  * case handling of con_attach() does not trigger. So all it would do
689  * is calling TAILQ_INSERT_AFTER, but with the wrong container. So we
690  * directly use the TAILQ macros. */
691  current->parent = parent;
692  TAILQ_INSERT_BEFORE(con, current, nodes);
693  DLOG("attaching to focus list\n");
694  TAILQ_INSERT_TAIL(&(parent->focus_head), current, focused);
695  current->percent = con->percent;
696  }
697  DLOG("re-attached all\n");
698 
699  /* 3: restore focus, if con was focused */
700  if (focus_next != NULL &&
701  TAILQ_FIRST(&(parent->focus_head)) == con) {
702  DLOG("restoring focus to focus_next=%p\n", focus_next);
703  TAILQ_REMOVE(&(parent->focus_head), focus_next, focused);
704  TAILQ_INSERT_HEAD(&(parent->focus_head), focus_next, focused);
705  DLOG("restored focus.\n");
706  }
707 
708  /* 4: close the redundant cons */
709  DLOG("closing redundant cons\n");
711 
712  /* Well, we got to abort the recursion here because we destroyed the
713  * container. However, if tree_flatten() is called sufficiently often,
714  * there can’t be the situation of having two pairs of redundant containers
715  * at once. Therefore, we can safely abort the recursion on this level
716  * after flattening. */
717  return;
718 
719 recurse:
720  /* We cannot use normal foreach here because tree_flatten might close the
721  * current container. */
722  current = TAILQ_FIRST(&(con->nodes_head));
723  while (current != NULL) {
724  Con *next = TAILQ_NEXT(current, nodes);
725  tree_flatten(current);
726  current = next;
727  }
728 
729  current = TAILQ_FIRST(&(con->floating_head));
730  while (current != NULL) {
731  Con *next = TAILQ_NEXT(current, floating_windows);
732  tree_flatten(current);
733  current = next;
734  }
735 }
void con_free(Con *con)
Frees the specified container.
Definition: con.c:79
void window_free(i3Window *win)
Frees an i3Window and all its members.
Definition: window.c:16
Con * con
Pointer to the Con which represents this output.
Definition: data.h:433
void con_fix_percent(Con *con)
Updates the percent attribute of the children of the given container.
Definition: con.c:985
bool tree_restore(const char *path, xcb_get_geometry_reply_t *geometry)
Loads tree from ~/.i3/_restart.json (used for in-place restarts).
Definition: tree.c:66
void con_detach(Con *con)
Detaches the given container from its current parent.
Definition: con.c:206
void tree_append_json(Con *con, const char *buf, const size_t len, char **errormsg)
Definition: load_layout.c:640
Definition: data.h:110
struct ev_timer * urgency_timer
Definition: data.h:734
#define TAILQ_HEAD_INITIALIZER(head)
Definition: queue.h:324
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:347
void x_con_kill(Con *con)
Kills the window decoration associated with the given container.
Definition: x.c:289
static Con * get_tree_next(Con *con, direction_t direction)
Definition: tree.c:495
#define LOG(fmt,...)
Definition: libi3.h:94
char * name
Definition: data.h:709
void x_set_warp_to(Rect *rect)
Set warp_to coordinates.
Definition: x.c:1445
Definition: data.h:109
void ipc_send_window_event(const char *property, Con *con)
For the window events we send, along the usual "change" field, also the window container,...
Definition: ipc.c:1643
void add_ignore_event(const int sequence, const int response_type)
Adds the given sequence to the list of events which are ignored.
double percent
Definition: data.h:725
xcb_window_t id
Definition: data.h:448
An Output is a physical output on your graphics driver.
Definition: data.h:412
uint32_t y
Definition: data.h:195
position_t
Definition: data.h:63
Definition: data.h:108
focus_head
Definition: data.h:747
struct Con * croot
Definition: tree.c:12
void x_set_name(Con *con, const char *name)
Sets the WM_NAME property (so, no UTF8, but used only for debugging anyways) of the given name.
Definition: x.c:1399
uint32_t width
Definition: data.h:196
xcb_window_t root
Definition: main.c:57
void restore_open_placeholder_windows(Con *parent)
Open placeholder windows for all children of parent.
void tree_init(xcb_get_geometry_reply_t *geometry)
Initializes the tree by creating the root node, adding all RandR outputs to the tree (that means rand...
Definition: tree.c:130
bool mapped
Definition: data.h:661
Definition: data.h:645
Con * output_get_content(Con *output)
Returns the output container below the given output container.
Definition: output.c:16
#define ELOG(fmt,...)
Definition: libi3.h:99
#define CALL(obj, member,...)
Definition: util.h:53
static Con * get_tree_next_workspace(Con *con, direction_t direction)
Definition: tree.c:465
layout_t workspace_layout
Definition: data.h:773
#define GREP_FIRST(dest, head, condition)
Definition: util.h:38
char * resolve_tilde(const char *path)
This function resolves ~ in pathnames.
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
Definition: tree.c:449
orientation_t orientation_from_direction(direction_t direction)
Convert a direction to its corresponding orientation.
Definition: util.c:482
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
bool level_up(void)
Moves focus one level up.
Definition: tree.c:386
uint32_t height
Definition: data.h:197
ssize_t slurp(const char *path, char **buf)
Slurp reads path in its entirety into buf, returning the length of the file or -1 if the file could n...
Definition: util.c:453
void tree_flatten(Con *con)
tree_flatten() removes pairs of redundant split containers, e.g.
Definition: tree.c:649
kill_window_t
parameter to specify whether tree_close_internal() and x_window_kill() should kill only this specific...
Definition: data.h:71
xcb_connection_t * conn
XCB connection and root screen.
Definition: main.c:44
Con * con_get_workspace(Con *con)
Gets the workspace container this node is on.
Definition: con.c:453
int con_num_children(Con *con)
Returns the number of children of this container.
Definition: con.c:922
bool con_is_floating(Con *con)
Returns true if the node is floating.
Definition: con.c:575
#define TAILQ_EMPTY(head)
Definition: queue.h:344
struct Rect Rect
Definition: data.h:44
bool level_down(void)
Moves focus one level down.
Definition: tree.c:409
Con * con_next_focused(Con *con)
Returns the container which will be focused next when the given container is not available anymore.
Definition: con.c:1474
orientation_t con_orientation(Con *con)
Returns the orientation of the given container (for stacked containers, vertical orientation is used ...
Definition: con.c:1443
struct Con * focused
Definition: tree.c:13
#define TAILQ_LAST(head, headname)
Definition: queue.h:339
A 'Con' represents everything from the X11 root window down to a single X11 window.
Definition: data.h:660
static void mark_unmapped(Con *con)
Definition: tree.c:430
Output * get_output_next(direction_t direction, Output *current, output_close_far_t close_far)
Gets the output which is the next one in the given direction.
Definition: randr.c:239
#define TAILQ_INSERT_HEAD(head, elm, field)
Definition: queue.h:366
void con_set_urgency(Con *con, bool urgent)
Set urgency flag to the container, all the parent containers and the workspace.
Definition: con.c:2173
bool con_is_split(Con *con)
Returns true if a container should be considered split.
Definition: con.c:361
#define FREE(pointer)
Definition: util.h:47
#define TAILQ_NEXT(elm, field)
Definition: queue.h:338
bool con_fullscreen_permits_focusing(Con *con)
Returns true if changing the focus to con would be allowed considering the fullscreen focus constrain...
Definition: con.c:2084
#define TAILQ_PREV(elm, headname, field)
Definition: queue.h:342
Con * workspace_encapsulate(Con *ws)
Creates a new container and re-parents all of children from the given workspace into it.
Definition: workspace.c:961
void x_window_kill(xcb_window_t window, kill_window_t kill_window)
Kills the given X11 window using WM_DELETE_WINDOW (if supported).
Definition: x.c:330
void x_push_changes(Con *con)
Pushes all changes (state of each node, see x_push_node() and the window stack) to X11.
Definition: x.c:1173
floating_head
Definition: data.h:741
void tree_next(Con *con, direction_t direction)
Changes focus in the given direction.
Definition: tree.c:585
#define TAILQ_INSERT_BEFORE(listelm, elm, field)
Definition: queue.h:394
char * output_primary_name(Output *output)
Retrieves the primary name of an output.
Definition: output.c:51
enum Con::@20 type
bool tree_close_internal(Con *con, kill_window_t kill_window, bool dont_kill_parent)
Closes the given container including all children.
Definition: tree.c:191
struct Con * parent
Definition: data.h:695
void workspace_show(Con *workspace)
Switches to the given workspace.
Definition: workspace.c:446
Con * con_descend_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
Definition: con.c:1516
nodes_head
Definition: data.h:744
uint32_t x
Definition: data.h:194
#define TAILQ_REPLACE(head, elm, elm2, field)
Definition: queue.h:413
Con * con_new(Con *parent, i3Window *window)
A wrapper for con_new_skeleton, to retain the old con_new behaviour.
Definition: con.c:69
struct Rect rect
Definition: data.h:699
direction_t
Definition: data.h:56
#define TAILQ_END(head)
Definition: queue.h:337
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:376
Definition: data.h:63
fullscreen_mode_t fullscreen_mode
Definition: data.h:752
void ewmh_update_desktop_properties(void)
Updates all the EWMH desktop properties.
Definition: ewmh.c:116
layout_t layout
Definition: data.h:773
Con * con_get_fullscreen_con(Con *con, fullscreen_mode_t fullscreen_mode)
Returns the first fullscreen node below this node.
Definition: con.c:502
void render_con(Con *con, bool already_inset)
"Renders" the given container (and its children), meaning that all rects are updated correctly.
Definition: render.c:42
Definition: data.h:61
Output * get_output_containing(unsigned int x, unsigned int y)
Returns the active (!) output which contains the coordinates x, y or NULL if there is no output which...
Definition: randr.c:113
void tree_split(Con *con, orientation_t orientation)
Splits (horizontally or vertically) the given container by creating a new container which contains th...
Definition: tree.c:327
struct Window * window
Definition: data.h:731
bool workspace_is_visible(Con *ws)
Returns true if the workspace is currently visible.
Definition: workspace.c:333
struct all_cons_head all_cons
Definition: tree.c:15
orientation_t
Definition: data.h:60
#define DLOG(fmt,...)
Definition: libi3.h:104
void con_attach(Con *con, Con *parent, bool ignore_focus)
Attaches the given container to the given parent.
Definition: con.c:198
Con * con_descend_tiling_focused(Con *con)
Returns the focused con inside this client, descending the tree as far as possible.
Definition: con.c:1531
void con_activate(Con *con)
Sets input focus to the given container and raises it to the top.
Definition: con.c:263
Con * get_tree_next_sibling(Con *con, position_t direction)
Get the previous / next sibling.
Definition: tree.c:627
Config config
Definition: config.c:17
focus_wrapping_t focus_wrapping
When focus wrapping is enabled (the default), attempting to move focus past the edge of the screen (i...
int num
the workspace number, if this Con is of type CT_WORKSPACE and the workspace is not a named workspace ...
Definition: data.h:690
A 'Window' is a type which contains an xcb_window_t and all the related information (hints like _NET_...
Definition: data.h:447
void workspace_update_urgent_flag(Con *ws)
Goes through all clients on the given workspace and updates the workspace’s urgent flag accordingly.
Definition: workspace.c:872
#define TAILQ_FIRST(head)
Definition: queue.h:336
void con_force_split_parents_redraw(Con *con)
force parent split containers to be redrawn
Definition: con.c:22
static Con * _create___i3(void)
Definition: tree.c:22
bool urgent
Definition: data.h:665
bool shape_supported
Definition: main.c:92
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:402
struct ev_loop * main_loop
Definition: main.c:66
bool path_exists(const char *path)
Checks if the given path exists by calling stat().
Definition: util.c:182
void con_update_parents_urgency(Con *con)
Make all parent containers urgent if con is urgent or clear the urgent flag of all parent containers ...
Definition: con.c:2145
Con * tree_open_con(Con *con, i3Window *window)
Opens an empty container in the current container.
Definition: tree.c:149
position_t position_from_direction(direction_t direction)
Convert a direction to its corresponding position.
Definition: util.c:490
static Con * to_focus
Definition: load_layout.c:23