]> git.lizzy.rs Git - bspwm.git/blob - tree.c
120112650ee7cddc610be8dd0254e32e47408a57
[bspwm.git] / tree.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <xcb/xcb.h>
6 #include <xcb/xcb_event.h>
7 #include "settings.h"
8 #include "helpers.h"
9 #include "window.h"
10 #include "types.h"
11 #include "bspwm.h"
12 #include "ewmh.h"
13 #include "tree.h"
14
15 bool is_leaf(node_t *n)
16 {
17     return (n != NULL && n->first_child == NULL && n->second_child == NULL);
18 }
19
20 bool is_tiled(client_t *c)
21 {
22     if (c == NULL)
23         return false;
24     return (!c->floating && !c->transient && !c->fullscreen);
25 }
26
27 bool is_floating(client_t *c)
28 {
29     if (c == NULL)
30         return false;
31     return (c->floating && !c->fullscreen);
32 }
33
34 bool is_first_child(node_t *n)
35 {
36     return (n != NULL && n->parent != NULL && n->parent->first_child == n);
37 }
38
39 bool is_second_child(node_t *n)
40 {
41     return (n != NULL && n->parent != NULL && n->parent->second_child == n);
42 }
43
44 void change_split_ratio(node_t *n, value_change_t chg) {
45     n->split_ratio = pow(n->split_ratio, (chg == CHANGE_INCREASE ? INC_EXP : DEC_EXP));
46 }
47
48 node_t *first_extrema(node_t *n)
49 {
50     if (n == NULL)
51         return NULL;
52     else if (n->first_child == NULL)
53         return n;
54     else
55         return first_extrema(n->first_child);
56 }
57
58 node_t *second_extrema(node_t *n)
59 {
60     if (n == NULL)
61         return NULL;
62     else if (n->second_child == NULL)
63         return n;
64     else
65         return second_extrema(n->second_child);
66 }
67
68 node_t *next_leaf(node_t *n)
69 {
70     if (n == NULL)
71         return NULL;
72     node_t *p = n;
73     while (is_second_child(p))
74         p = p->parent;
75     if (p->parent == NULL)
76         return NULL;
77     return first_extrema(p->parent->second_child);
78 }
79
80 node_t *prev_leaf(node_t *n)
81 {
82     if (n == NULL)
83         return NULL;
84     node_t *p = n;
85     while (is_first_child(p))
86         p = p->parent;
87     if (p->parent == NULL)
88         return NULL;
89     return second_extrema(p->parent->first_child);
90 }
91
92 node_t *find_fence(node_t *n, direction_t dir)
93 {
94     node_t *p;
95
96     if (n == NULL)
97         return NULL;
98
99     p = n->parent;
100
101     while (p != NULL) {
102         if ((dir == DIR_UP && p->split_type == TYPE_HORIZONTAL && p->rectangle.y < n->rectangle.y)
103                 || (dir == DIR_LEFT && p->split_type == TYPE_VERTICAL && p->rectangle.x < n->rectangle.x)
104                 || (dir == DIR_DOWN && p->split_type == TYPE_HORIZONTAL && (p->rectangle.y + p->rectangle.height) > (n->rectangle.y + n->rectangle.height))
105                 || (dir == DIR_RIGHT && p->split_type == TYPE_VERTICAL && (p->rectangle.x + p->rectangle.width) > (n->rectangle.x + n->rectangle.width)))
106             return p;
107         p = p->parent;
108     }
109
110     return NULL;
111 }
112
113 node_t *find_neighbor(node_t *n, direction_t dir)
114 {
115     node_t *fence = find_fence(n, dir);
116
117     if (fence == NULL)
118         return NULL;
119
120     if (dir == DIR_UP || dir == DIR_LEFT)
121         return second_extrema(fence->first_child);
122     else if (dir == DIR_DOWN || dir == DIR_RIGHT)
123         return first_extrema(fence->second_child);
124
125     return NULL;
126 }
127
128 void move_fence(node_t *n, direction_t dir, fence_move_t mov)
129 {
130     node_t *fence = find_fence(n, dir);
131
132     if (fence == NULL)
133         return;
134
135     if ((mov == MOVE_PUSH && (dir == DIR_RIGHT || dir == DIR_DOWN))
136             || (mov == MOVE_PULL && (dir == DIR_LEFT || dir == DIR_UP)))
137         change_split_ratio(fence, CHANGE_INCREASE);
138     else
139         change_split_ratio(fence, CHANGE_DECREASE);
140 }
141
142 void rotate_tree(node_t *n, rotate_t rot)
143 {
144     if (n == NULL || is_leaf(n))
145         return;
146
147     node_t *tmp;
148
149     if ((rot == ROTATE_CLOCKWISE && n->split_type == TYPE_HORIZONTAL)
150             || (rot == ROTATE_COUNTER_CLOCKWISE && n->split_type == TYPE_VERTICAL)
151             || rot == ROTATE_FULL_CYCLE) {
152         tmp = n->first_child;
153         n->first_child = n->second_child;
154         n->second_child = tmp;
155         n->split_ratio = 1.0 - n->split_ratio;
156     }
157
158     if (rot != ROTATE_FULL_CYCLE) {
159         if (n->split_type == TYPE_HORIZONTAL)
160             n->split_type = TYPE_VERTICAL;
161         else if (n->split_type == TYPE_VERTICAL)
162             n->split_type = TYPE_HORIZONTAL;
163     }
164
165     rotate_tree(n->first_child, rot);
166     rotate_tree(n->second_child, rot);
167 }
168
169 void dump_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
170 {
171     if (n == NULL)
172         return;
173
174     char line[MAXLEN];
175
176     for (unsigned int i = 0; i < depth; i++)
177         strncat(rsp, "  ", REMLEN(rsp));
178
179     if (is_leaf(n))
180         snprintf(line, sizeof(line), "%s %X %s%s%s%s%s", n->client->class_name, n->client->window, (n->client->floating ? "f" : "-"), (n->client->transient ? "t" : "-"), (n->client->fullscreen ? "F" : "-"), (n->client->urgent ? "u" : "-"), (n->client->locked ? "l" : "-"));
181     else
182         snprintf(line, sizeof(line), "%s %.2f", (n->split_type == TYPE_HORIZONTAL ? "H" : "V"), n->split_ratio);
183
184     strncat(rsp, line, REMLEN(rsp));
185
186     if (n == d->focus)
187         strncat(rsp, " *\n", REMLEN(rsp));
188     else
189         strncat(rsp, "\n", REMLEN(rsp));
190
191     dump_tree(d, n->first_child, rsp, depth + 1);
192     dump_tree(d, n->second_child, rsp, depth + 1);
193 }
194
195 void list_monitors(list_option_t opt, char *rsp)
196 {
197     monitor_t *m = mon_head;
198
199     while (m != NULL) {
200         strncat(rsp, m->name, REMLEN(rsp));
201         if (mon == m)
202             strncat(rsp, " #\n", REMLEN(rsp));
203         else
204             strncat(rsp, "\n", REMLEN(rsp));
205         if (opt == LIST_OPTION_VERBOSE)
206             list_desktops(m, opt, 1, rsp);
207         m = m->next;
208     }
209 }
210
211 void list_desktops(monitor_t *m, list_option_t opt, unsigned int depth, char *rsp)
212 {
213     desktop_t *d = m->desk_head;
214
215     while (d != NULL) {
216         for (unsigned int i = 0; i < depth; i++)
217             strncat(rsp, "  ", REMLEN(rsp));
218         strncat(rsp, d->name, REMLEN(rsp));
219         if (m->desk == d)
220             strncat(rsp, " @\n", REMLEN(rsp));
221         else
222             strncat(rsp, "\n", REMLEN(rsp));
223         if (opt == LIST_OPTION_VERBOSE)
224             dump_tree(d, d->root, rsp, depth + 1);
225         d = d->next;
226     }
227 }
228
229 void put_status(void)
230 {
231     if (status_fifo == NULL)
232         return;
233     bool urgent = false;
234     for (monitor_t *m = mon_head; m != NULL; m = m->next) {
235         fprintf(status_fifo, "%c%s:", (mon == m ? 'M' : 'm'), m->name);
236         for (desktop_t *d = m->desk_head; d != NULL; d = d->next, urgent = false) {
237             for (node_t *n = first_extrema(d->root); n != NULL && !urgent; n = next_leaf(n))
238                 urgent |= n->client->urgent;
239             fprintf(status_fifo, "%c%c%s:", (m->desk == d ? 'D' : (d->root != NULL ? 'd' : '_')), (urgent ? '!' : '_'), d->name);
240         }
241     }
242     fprintf(status_fifo, "L%s:W%X\n", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"), (mon->desk->focus == NULL ? 0 : mon->desk->focus->client->window));
243     fflush(status_fifo);
244 }
245
246 void arrange(monitor_t *m, desktop_t *d)
247 {
248     PRINTF("arrange %s%s%s\n", (num_monitors > 1 ? m->name : ""), (num_monitors > 1 ? " " : ""), d->name);
249
250     xcb_rectangle_t rect = m->rectangle;
251     int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : window_gap);
252     rect.x += m->left_padding + wg;
253     rect.y += m->top_padding + wg;
254     rect.width -= m->left_padding + m->right_padding + wg;
255     rect.height -= m->top_padding + m->bottom_padding + wg;
256     if (focus_follows_mouse)
257         get_pointer_position(&pointer_position);
258     apply_layout(m, d, d->root, rect, rect);
259 }
260
261 void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect)
262 {
263     if (n == NULL)
264         return;
265
266     n->rectangle = rect;
267
268     if (is_leaf(n)) {
269         if (n->client->fullscreen)
270             return;
271
272         if (is_floating(n->client) && n->client->border_width != border_width) {
273             int ds = 2 * (border_width - n->client->border_width);
274             n->client->floating_rectangle.width += ds;
275             n->client->floating_rectangle.height += ds;
276         }
277
278         if (borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE)
279             n->client->border_width = 0;
280         else
281             n->client->border_width = border_width;
282
283         xcb_rectangle_t r;
284         if (is_tiled(n->client)) {
285             if (d->layout == LAYOUT_TILED)
286                 r = rect;
287             else if (d->layout == LAYOUT_MONOCLE)
288                 r = root_rect;
289             int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : window_gap);
290             int bleed = wg + 2 * n->client->border_width;
291             r.width = (bleed < r.width ? r.width - bleed : 1);
292             r.height = (bleed < r.height ? r.height - bleed : 1);
293             n->client->tiled_rectangle = r;
294         } else {
295             r = n->client->floating_rectangle;
296         }
297
298         window_move_resize(n->client->window, r.x, r.y, r.width, r.height);
299         window_border_width(n->client->window, n->client->border_width);
300         window_draw_border(n, n == d->focus, m == mon);
301
302     } else {
303         xcb_rectangle_t first_rect;
304         xcb_rectangle_t second_rect;
305
306         if (n->first_child->vacant || n->second_child->vacant) {
307             first_rect = second_rect = rect;
308         } else {
309             unsigned int fence;
310             if (n->split_type == TYPE_VERTICAL) {
311                 fence = rect.width * n->split_ratio;
312                 first_rect = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height};
313                 second_rect = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height};
314
315             } else if (n->split_type == TYPE_HORIZONTAL) {
316                 fence = rect.height * n->split_ratio;
317                 first_rect = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence};
318                 second_rect = (xcb_rectangle_t) {rect.x, rect.y + fence, rect.width, rect.height - fence};
319             }
320         }
321
322         apply_layout(m, d, n->first_child, first_rect, root_rect);
323         apply_layout(m, d, n->second_child, second_rect, root_rect);
324     }
325 }
326
327 void insert_node(monitor_t *m, desktop_t *d, node_t *n)
328 {
329     if (d == NULL || n == NULL)
330         return;
331
332     PRINTF("insert node %X\n", n->client->window);
333
334     node_t *focus = d->focus;
335
336     if (focus == NULL) {
337         d->root = n;
338     } else {
339         node_t *dad = make_node();
340         node_t *fopar = focus->parent;
341         n->parent = dad;
342         n->born_as = split_mode;
343         switch (split_mode) {
344             case MODE_AUTOMATIC:
345                 if (fopar == NULL) {
346                     dad->first_child = n;
347                     dad->second_child = focus;
348                     if (m->rectangle.width > m->rectangle.height)
349                         dad->split_type = TYPE_VERTICAL;
350                     else
351                         dad->split_type = TYPE_HORIZONTAL;
352                     focus->parent = dad;
353                     d->root = dad;
354                 } else {
355                     node_t *grandpa = fopar->parent;
356                     dad->parent = grandpa;
357                     if (grandpa != NULL) {
358                         if (is_first_child(fopar))
359                             grandpa->first_child = dad;
360                         else
361                             grandpa->second_child = dad;
362                     } else {
363                         d->root = dad;
364                     }
365                     dad->split_type = fopar->split_type;
366                     dad->split_ratio = fopar->split_ratio;
367                     fopar->parent = dad;
368                     if (is_first_child(focus)) {
369                         dad->first_child = n;
370                         dad->second_child = fopar;
371                         rotate_tree(fopar, ROTATE_CLOCKWISE);
372                     } else {
373                         dad->first_child = fopar;
374                         dad->second_child = n;
375                         rotate_tree(fopar, ROTATE_COUNTER_CLOCKWISE);
376                     }
377                 }
378                 break;
379             case MODE_MANUAL:
380                 if (fopar != NULL) {
381                     if (is_first_child(focus))
382                         fopar->first_child = dad;
383                     else
384                         fopar->second_child = dad;
385                 }
386                 dad->split_ratio = focus->split_ratio;
387                 dad->parent = fopar;
388                 focus->parent = dad;
389                 switch (split_dir) {
390                     case DIR_LEFT:
391                         dad->split_type = TYPE_VERTICAL;
392                         dad->first_child = n;
393                         dad->second_child = focus;
394                         break;
395                     case DIR_RIGHT:
396                         dad->split_type = TYPE_VERTICAL;
397                         dad->first_child = focus;
398                         dad->second_child = n;
399                         break;
400                     case DIR_UP:
401                         dad->split_type = TYPE_HORIZONTAL;
402                         dad->first_child = n;
403                         dad->second_child = focus;
404                         break;
405                     case DIR_DOWN:
406                         dad->split_type = TYPE_HORIZONTAL;
407                         dad->first_child = focus;
408                         dad->second_child = n;
409                         break;
410                 }
411                 if (d->root == focus)
412                     d->root = dad;
413                 split_mode = MODE_AUTOMATIC;
414                 break;
415         }
416         if (focus->vacant)
417             update_vacant_state(fopar);
418     }
419 }
420
421 void focus_node(monitor_t *m, desktop_t *d, node_t *n, bool is_mapped)
422 {
423     if (n == NULL)
424         return;
425
426     PRINTF("focus node %X\n", n->client->window);
427
428     split_mode = MODE_AUTOMATIC;
429     n->client->urgent = false;
430
431     if (is_mapped) {
432                 if (mon != m || d->focus != n) {
433                         /* Honour active_border_color setting. */
434                         window_draw_border(mon->desk->focus, true, false);
435                         window_draw_border(d->focus, m != mon, m == mon);
436                         window_draw_border(n, true, true);
437                 }
438
439                 if (focus_follows_mouse)
440             get_pointer_position(&pointer_position);
441                 xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
442         }
443
444     if (!is_tiled(n->client)) {
445         if (!adaptative_raise || !might_cover(d, n))
446             window_raise(n->client->window);
447     } else {
448         window_pseudo_raise(d, n->client->window);
449     }
450
451     if (d->focus != n) {
452         d->last_focus = d->focus;
453         d->focus = n;
454     }
455
456     ewmh_update_active_window();
457     put_status();
458 }
459
460 void update_current(void)
461 {
462     if (mon->desk->focus == NULL)
463         ewmh_update_active_window();
464     else
465         focus_node(mon, mon->desk, mon->desk->focus, true);
466     put_status();
467 }
468
469 void unlink_node(desktop_t *d, node_t *n)
470 {
471     if (d == NULL || n == NULL)
472         return;
473
474     PRINTF("unlink node %X\n", n->client->window);
475
476     node_t *p = n->parent;
477
478     if (p == NULL) {
479         d->root = NULL;
480         d->focus = NULL;
481         d->last_focus = NULL;
482     } else {
483         node_t *b;
484         node_t *g = p->parent;
485         bool n_first_child = is_first_child(n);
486         if (n_first_child) {
487             b = p->second_child;
488             if (n->born_as == MODE_AUTOMATIC)
489                 rotate_tree(b, ROTATE_COUNTER_CLOCKWISE);
490         } else {
491             b = p->first_child;
492             if (n->born_as == MODE_AUTOMATIC)
493                 rotate_tree(b, ROTATE_CLOCKWISE);
494         }
495         b->parent = g;
496         if (g != NULL) {
497             if (is_first_child(p))
498                 g->first_child = b;
499             else
500                 g->second_child = b;
501         } else {
502             d->root = b;
503         }
504
505         n->parent = NULL;
506         free(p);
507
508         if (n == d->last_focus) {
509             d->last_focus = NULL;
510         } else if (n == d->focus) {
511             if (d->last_focus != NULL)
512                 d->focus = d->last_focus;
513             else
514                 d->focus = (n_first_child ? first_extrema(b) : second_extrema(b));
515             d->last_focus = NULL;
516         }
517
518         update_vacant_state(b->parent);
519     }
520 }
521
522 void remove_node(desktop_t *d, node_t *n)
523 {
524     if (d == NULL || n == NULL)
525         return;
526
527     PRINTF("remove node %X\n", n->client->window);
528
529     unlink_node(d, n);
530     free(n->client);
531     free(n);
532
533     num_clients--;
534     ewmh_update_client_list();
535
536     if (mon->desk == d)
537         update_current();
538 }
539
540 void swap_nodes(node_t *n1, node_t *n2)
541 {
542     if (n1 == NULL || n2 == NULL || n1 == n2)
543         return;
544
545     PUTS("swap nodes");
546
547     /* (n1 and n2 are leaves) */
548     node_t *pn1 = n1->parent;
549     node_t *pn2 = n2->parent;
550     bool n1_first_child = is_first_child(n1);
551     bool n2_first_child = is_first_child(n2);
552
553     if (pn1 != NULL) {
554         if (n1_first_child)
555             pn1->first_child = n2;
556         else
557             pn1->second_child = n2;
558     }
559
560     if (pn2 != NULL) {
561         if (n2_first_child)
562             pn2->first_child = n1;
563         else
564             pn2->second_child = n1;
565     }
566
567     n1->parent = pn2;
568     n2->parent = pn1;
569
570     if (n1->vacant != n2->vacant) {
571         update_vacant_state(n1->parent);
572         update_vacant_state(n2->parent);
573     }
574 }
575
576 void fit_monitor(monitor_t *m, client_t *c)
577 {
578     xcb_rectangle_t crect = c->floating_rectangle;
579     xcb_rectangle_t mrect = m->rectangle;
580     while (crect.x < mrect.x)
581         crect.x += mrect.width;
582     while (crect.x > (mrect.x + mrect.width - 1))
583         crect.x -= mrect.width;
584     while (crect.y < mrect.y)
585         crect.y += mrect.height;
586     while (crect.y > (mrect.y + mrect.height - 1))
587         crect.y -= mrect.height;
588     c->floating_rectangle = crect;
589 }
590
591 void transfer_node(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd, node_t *n)
592 {
593     if (n == NULL || ds == NULL || dd == NULL || ms == NULL || md == NULL || (ms == md && dd == ds))
594         return;
595
596     PRINTF("transfer node %X\n", n->client->window);
597
598     unlink_node(ds, n);
599     insert_node(md, dd, n);
600     ewmh_set_wm_desktop(n, dd);
601
602     if (ds == ms->desk && dd != md->desk) {
603         window_hide(n->client->window);
604     }
605
606     fit_monitor(md, n->client);
607
608     if (n->client->fullscreen)
609         window_move_resize(n->client->window, md->rectangle.x, md->rectangle.y, md->rectangle.width, md->rectangle.height);
610
611     if (ds != ms->desk && dd == md->desk) {
612         window_show(n->client->window);
613         focus_node(md, dd, n, true);
614     } else {
615         focus_node(md, dd, n, false);
616     }
617
618     if (ds == ms->desk || dd == md->desk)
619         update_current();
620 }
621
622 void select_monitor(monitor_t *m)
623 {
624     if (m == NULL || mon == m)
625         return;
626
627     PRINTF("select monitor %s\n", m->name);
628
629     focus_node(m, m->desk, m->desk->focus, true);
630
631     last_mon = mon;
632     mon = m;
633
634     ewmh_update_current_desktop();
635     put_status();
636 }
637
638 void select_desktop(desktop_t *d)
639 {
640     if (d == NULL || d == mon->desk)
641         return;
642
643     PRINTF("select desktop %s\n", d->name);
644
645     if (visible) {
646         node_t *n = first_extrema(d->root);
647
648         while (n != NULL) {
649             window_show(n->client->window);
650             n = next_leaf(n);
651         }
652
653         n = first_extrema(mon->desk->root);
654
655         while (n != NULL) {
656             window_hide(n->client->window);
657             n = next_leaf(n);
658         }
659     }
660
661     mon->last_desk = mon->desk;
662     mon->desk = d;
663
664     update_current();
665     ewmh_update_current_desktop();
666     put_status();
667 }
668
669 void cycle_monitor(cycle_dir_t dir)
670 {
671     if (dir == CYCLE_NEXT)
672         select_monitor((mon->next == NULL ? mon_head : mon->next));
673     else if (dir == CYCLE_PREV)
674         select_monitor((mon->prev == NULL ? mon_tail : mon->prev));
675 }
676
677 void cycle_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, skip_desktop_t skip)
678 {
679     desktop_t *f = (dir == CYCLE_PREV ? d->prev : d->next);
680     if (f == NULL)
681         f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
682
683     while (f != d) {
684         if (skip == DESKTOP_SKIP_NONE 
685                 || (skip == DESKTOP_SKIP_FREE && f->root != NULL)
686                 || (skip == DESKTOP_SKIP_OCCUPIED && f->root == NULL)) {
687             select_desktop(f);
688             return;
689         }
690         f = (dir == CYCLE_PREV ? f->prev : f->next);
691         if (f == NULL)
692             f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
693     }
694 }
695
696 void cycle_leaf(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, skip_client_t skip)
697 {
698     if (n == NULL)
699         return;
700
701     PUTS("cycle leaf");
702
703     node_t *f = (dir == CYCLE_PREV ? prev_leaf(n) : next_leaf(n));
704     if (f == NULL)
705         f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
706
707     while (f != n) {
708         bool tiled = is_tiled(f->client);
709         if (skip == CLIENT_SKIP_NONE || (skip == CLIENT_SKIP_TILED && !tiled) || (skip == CLIENT_SKIP_FLOATING && tiled)
710                 || (skip == CLIENT_SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0)
711                 || (skip == CLIENT_SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0)) {
712             focus_node(m, d, f, true);
713             return;
714         }
715         f = (dir == CYCLE_PREV ? prev_leaf(f) : next_leaf(f));
716         if (f == NULL)
717             f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
718     }
719 }
720
721 void nearest_leaf(monitor_t *m, desktop_t *d, node_t *n, nearest_arg_t dir, skip_client_t skip)
722 {
723     if (n == NULL)
724         return;
725
726     PUTS("nearest leaf");
727
728     node_t *x = NULL;
729
730     for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f))
731         if (skip == CLIENT_SKIP_NONE || (skip == CLIENT_SKIP_TILED && !is_tiled(f->client)) || (skip == CLIENT_SKIP_FLOATING && is_tiled(f->client))
732                 || (skip == CLIENT_SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0)
733                 || (skip == CLIENT_SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0))
734             if ((dir == NEAREST_OLDER
735                         && (f->client->uid < n->client->uid)
736                         && (x == NULL || f->client->uid > x->client->uid))
737                     || (dir == NEAREST_NEWER
738                         && (f->client->uid > n->client->uid)
739                         && (x == NULL || f->client->uid < x->client->uid)))
740                 x = f;
741
742     focus_node(m, d, x, true);
743 }
744
745 void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir) {
746     if (d == NULL || d->root == NULL || is_leaf(d->root))
747         return;
748     node_t *par = d->focus->parent;
749     bool focus_first_child = is_first_child(d->focus);
750     if (dir == CIRCULATE_FORWARD)
751         for (node_t *s = second_extrema(d->root), *f = prev_leaf(s); f != NULL; s = prev_leaf(f), f = prev_leaf(s))
752             swap_nodes(f, s);
753     else
754         for (node_t *f = first_extrema(d->root), *s = next_leaf(f); s != NULL; f = next_leaf(s), s = next_leaf(f))
755             swap_nodes(f, s);
756     if (focus_first_child)
757         focus_node(m, d, par->first_child, true);
758     else
759         focus_node(m, d, par->second_child, true);
760 }
761
762 void update_vacant_state(node_t *n)
763 {
764     if (n == NULL)
765         return;
766
767     PUTS("update vacant state");
768
769     /* n is not a leaf */
770     node_t *p = n;
771
772     while (p != NULL) {
773         p->vacant = (p->first_child->vacant && p->second_child->vacant);
774         p = p->parent;
775     }
776 }
777
778 monitor_t *find_monitor(char *name)
779 {
780     for (monitor_t *m = mon_head; m != NULL; m = m->next)
781         if (strcmp(m->name, name) == 0)
782             return m;
783     return NULL;
784 }
785
786 void add_desktop(monitor_t *m, char *name)
787 {
788     desktop_t *d = make_desktop(name);
789     if (m->desk == NULL) {
790         m->desk = d;
791         m->desk_head = d;
792         m->desk_tail = d;
793     } else {
794         m->desk_tail->next = d;
795         d->prev = m->desk_tail;
796         m->desk_tail = d;
797     }
798     num_desktops++;
799     ewmh_update_number_of_desktops();
800     ewmh_update_desktop_names();
801     put_status();
802 }
803
804 void add_monitor(xcb_rectangle_t *rect)
805 {
806     monitor_t *m = make_monitor(rect);
807     if (mon == NULL) {
808         mon = m;
809         mon_head = m;
810         mon_tail = m;
811     } else {
812         mon_tail->next = m;
813         m->prev = mon_tail;
814         mon_tail = m;
815     }
816     num_monitors++;
817 }