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