1 /* Copyright (c) 2012, Bastien Dejean
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
17 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "subscribe.h"
39 void arrange(monitor_t *m, desktop_t *d)
44 layout_t set_layout = d->layout;
45 if (leaf_monocle && tiled_count(d) == 1) {
46 d->layout = LAYOUT_MONOCLE;
49 xcb_rectangle_t rect = m->rectangle;
50 int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
51 rect.x += m->left_padding + d->left_padding + wg;
52 rect.y += m->top_padding + d->top_padding + wg;
53 rect.width -= m->left_padding + d->left_padding + d->right_padding + m->right_padding + wg;
54 rect.height -= m->top_padding + d->top_padding + d->bottom_padding + m->bottom_padding + wg;
55 apply_layout(m, d, d->root, rect, rect);
57 d->layout = set_layout;
60 void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect)
70 if ((borderless_monocle && n->client->state == STATE_TILED && d->layout == LAYOUT_MONOCLE)
71 || n->client->state == STATE_FULLSCREEN) {
74 bw = n->client->border_width;
78 client_state_t s = n->client->state;
79 if (s == STATE_TILED || s == STATE_PSEUDO_TILED) {
80 int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
82 if (s == STATE_TILED) {
84 int bleed = wg + 2 * bw;
85 r.width = (bleed < r.width ? r.width - bleed : 1);
86 r.height = (bleed < r.height ? r.height - bleed : 1);
87 /* pseudo-tiled clients */
89 r = n->client->floating_rectangle;
90 if (center_pseudo_tiled) {
91 r.x = rect.x - bw + (rect.width - wg - r.width) / 2;
92 r.y = rect.y - bw + (rect.height - wg - r.height) / 2;
98 n->client->tiled_rectangle = r;
99 /* floating clients */
100 } else if (s == STATE_FLOATING) {
101 r = n->client->floating_rectangle;
102 /* fullscreen clients */
107 window_move_resize(n->client->window, r.x, r.y, r.width, r.height);
108 window_border_width(n->client->window, bw);
109 window_draw_border(n, d->focus == n, m == mon);
111 if (frozen_pointer->action == ACTION_NONE) {
112 put_status(SBSC_MASK_WINDOW_GEOMETRY, "window_geometry %s %s 0x%X %ux%u+%i+%i\n", m->name, d->name, n->client->window, r.width, r.height, r.x, r.y);
115 if (pointer_follows_focus && mon->desk->focus == n && frozen_pointer->action == ACTION_NONE) {
120 xcb_rectangle_t first_rect;
121 xcb_rectangle_t second_rect;
123 if (d->layout == LAYOUT_MONOCLE || n->first_child->vacant || n->second_child->vacant) {
124 first_rect = second_rect = rect;
127 if (n->split_type == TYPE_VERTICAL) {
128 fence = rect.width * n->split_ratio;
129 first_rect = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height};
130 second_rect = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height};
132 fence = rect.height * n->split_ratio;
133 first_rect = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence};
134 second_rect = (xcb_rectangle_t) {rect.x, rect.y + fence, rect.width, rect.height - fence};
138 apply_layout(m, d, n->first_child, first_rect, root_rect);
139 apply_layout(m, d, n->second_child, second_rect, root_rect);
143 void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
145 if (d == NULL || n == NULL)
148 /* n: new leaf node */
149 /* c: new container node */
150 /* f: focus or insertion anchor */
151 /* p: parent of focus */
152 /* g: grand parent of focus */
160 node_t *c = make_node();
161 node_t *p = f->parent;
162 if ((f->client->private ||
163 (p != NULL && p->privacy_level > 0)) &&
164 f->split_mode == MODE_AUTOMATIC) {
165 node_t *closest = NULL;
166 node_t *public = NULL;
167 closest_public(d, f, &closest, &public);
168 if (public != NULL) {
172 if (closest != NULL) {
176 f->split_mode = MODE_MANUAL;
177 xcb_rectangle_t rect = f->client->tiled_rectangle;
178 f->split_dir = (rect.width >= rect.height ? DIR_LEFT : DIR_UP);
179 if (f->client->private) {
180 get_opposite(f->split_dir, &f->split_dir);
181 update_privacy_level(f, false);
185 if (p != NULL && f->split_mode == MODE_AUTOMATIC &&
186 (p->first_child->vacant || p->second_child->vacant)) {
191 c->birth_rotation = f->birth_rotation;
192 switch (f->split_mode) {
195 if (initial_polarity == FIRST_CHILD) {
202 if (m->rectangle.width > m->rectangle.height)
203 c->split_type = TYPE_VERTICAL;
205 c->split_type = TYPE_HORIZONTAL;
209 node_t *g = p->parent;
212 if (is_first_child(p))
219 c->split_type = p->split_type;
220 c->split_ratio = p->split_ratio;
223 if (is_first_child(f)) {
232 if (IS_TILED(n->client)) {
235 n->birth_rotation = rot;
240 if (is_first_child(f))
245 c->split_ratio = f->split_ratio;
248 f->birth_rotation = 0;
249 switch (f->split_dir) {
251 c->split_type = TYPE_VERTICAL;
256 c->split_type = TYPE_VERTICAL;
261 c->split_type = TYPE_HORIZONTAL;
266 c->split_type = TYPE_HORIZONTAL;
273 f->split_mode = MODE_AUTOMATIC;
277 update_vacant_state(f->parent);
279 if (f->client != NULL) {
280 if (f->client->private) {
281 update_privacy_level(f, true);
285 if (n->client->private) {
286 update_privacy_level(n, true);
288 if (d->focus == NULL) {
291 if (n->client->sticky) {
294 put_status(SBSC_MASK_REPORT);
297 void activate_node(monitor_t *m, desktop_t *d, node_t *n)
300 if (d->focus != NULL && n != d->focus && stack_cmp(n->client, d->focus->client) < 0) {
301 neutralize_obscuring_windows(m, d, n);
305 window_draw_border(d->focus, false, m == mon);
306 window_draw_border(n, true, m == mon);
310 put_status(SBSC_MASK_WINDOW_ACTIVATE, "window_activate %s %s 0x%X\n", m->name, d->name, n->client->window);
313 void focus_node(monitor_t *m, desktop_t *d, node_t *n)
315 if (mon->desk != d || n == NULL)
318 if (m->num_sticky > 0 && d != m->desk) {
319 node_t *a = first_extrema(m->desk->root);
320 sticky_still = false;
322 node_t *b = next_leaf(a, m->desk->root);
323 if (a->client->sticky)
324 transfer_node(m, m->desk, a, m, d, d->focus);
328 if (n == NULL && d->focus != NULL)
333 if (n->client->urgent) {
334 n->client->urgent = false;
335 put_status(SBSC_MASK_REPORT);
337 if (d->focus != NULL && n != d->focus && stack_cmp(n->client, d->focus->client) < 0) {
338 neutralize_obscuring_windows(m, d, n);
343 for (desktop_t *cd = mon->desk_head; cd != NULL; cd = cd->next) {
344 window_draw_border(cd->focus, true, false);
346 for (desktop_t *cd = m->desk_head; cd != NULL; cd = cd->next) {
348 window_draw_border(cd->focus, true, true);
352 window_draw_border(n, true, true);
357 window_draw_border(d->focus, false, true);
358 window_draw_border(n, true, true);
366 history_add(m, d, NULL);
367 ewmh_update_active_window();
373 put_status(SBSC_MASK_WINDOW_FOCUS, "window_focus %s %s 0x%X\n", m->name, d->name, n->client->window);
375 history_add(m, d, n);
378 if (focus_follows_pointer) {
379 xcb_window_t win = XCB_NONE;
380 query_pointer(&win, NULL);
381 if (win != n->client->window) {
382 enable_motion_recorder();
384 disable_motion_recorder();
388 if (pointer_follows_focus) {
389 center_pointer(get_rectangle(m, n->client));
392 ewmh_update_active_window();
395 void update_current(void)
397 focus_node(mon, mon->desk, mon->desk->focus);
400 node_t *make_node(void)
402 node_t *n = malloc(sizeof(node_t));
403 n->parent = n->first_child = n->second_child = NULL;
404 n->split_ratio = split_ratio;
405 n->split_mode = MODE_AUTOMATIC;
406 n->split_type = TYPE_VERTICAL;
407 n->split_dir = DIR_RIGHT;
408 n->birth_rotation = 0;
409 n->privacy_level = 0;
415 client_t *make_client(xcb_window_t win, unsigned int border_width)
417 client_t *c = malloc(sizeof(client_t));
419 c->state = c->last_state = STATE_TILED;
420 c->layer = c->last_layer = LAYER_NORMAL;
421 snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
422 snprintf(c->instance_name, sizeof(c->instance_name), "%s", MISSING_VALUE);
423 c->border_width = border_width;
424 c->locked = c->sticky = c->urgent = c->private = c->icccm_focus = false;
425 c->icccm_input = true;
426 xcb_icccm_get_wm_protocols_reply_t protocols;
427 if (xcb_icccm_get_wm_protocols_reply(dpy, xcb_icccm_get_wm_protocols(dpy, win, ewmh->WM_PROTOCOLS), &protocols, NULL) == 1) {
428 if (has_proto(WM_TAKE_FOCUS, &protocols)) {
429 c->icccm_focus = true;
431 xcb_icccm_get_wm_protocols_reply_wipe(&protocols);
434 xcb_ewmh_get_atoms_reply_t wm_state;
435 if (xcb_ewmh_get_wm_state_reply(ewmh, xcb_ewmh_get_wm_state(ewmh, win), &wm_state, NULL) == 1) {
436 for (unsigned int i = 0; i < wm_state.atoms_len && i < MAX_STATE; i++) {
437 ewmh_wm_state_add(c, wm_state.atoms[i]);
439 xcb_ewmh_get_atoms_reply_wipe(&wm_state);
441 xcb_icccm_wm_hints_t hints;
442 if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, win), &hints, NULL) == 1
443 && (hints.flags & XCB_ICCCM_WM_HINT_INPUT)) {
444 c->icccm_input = hints.input;
449 bool is_leaf(node_t *n)
451 return (n != NULL && n->first_child == NULL && n->second_child == NULL);
454 bool is_first_child(node_t *n)
456 return (n != NULL && n->parent != NULL && n->parent->first_child == n);
459 bool is_second_child(node_t *n)
461 return (n != NULL && n->parent != NULL && n->parent->second_child == n);
464 void reset_mode(coordinates_t *loc)
466 if (loc->node != NULL) {
467 loc->node->split_mode = MODE_AUTOMATIC;
468 window_draw_border(loc->node, loc->desktop->focus == loc->node, mon == loc->monitor);
469 } else if (loc->desktop != NULL) {
470 for (node_t *a = first_extrema(loc->desktop->root); a != NULL; a = next_leaf(a, loc->desktop->root)) {
471 a->split_mode = MODE_AUTOMATIC;
472 window_draw_border(a, loc->desktop->focus == a, mon == loc->monitor);
477 node_t *brother_tree(node_t *n)
479 if (n == NULL || n->parent == NULL)
481 if (is_first_child(n))
482 return n->parent->second_child;
484 return n->parent->first_child;
487 void closest_public(desktop_t *d, node_t *n, node_t **closest, node_t **public)
491 node_t *prev = prev_leaf(n, d->root);
492 node_t *next = next_leaf(n, d->root);
493 while (prev != NULL || next != NULL) {
494 #define TESTLOOP(n) \
496 if (IS_TILED(n->client)) { \
497 if (n->privacy_level == 0) { \
498 if (n->parent == NULL || n->parent->privacy_level == 0) { \
501 } else if (*closest == NULL) { \
506 n = n##_leaf(n, d->root); \
514 node_t *first_extrema(node_t *n)
518 else if (n->first_child == NULL)
521 return first_extrema(n->first_child);
524 node_t *second_extrema(node_t *n)
528 else if (n->second_child == NULL)
531 return second_extrema(n->second_child);
534 node_t *next_leaf(node_t *n, node_t *r)
539 while (is_second_child(p) && p != r)
543 return first_extrema(p->parent->second_child);
546 node_t *prev_leaf(node_t *n, node_t *r)
551 while (is_first_child(p) && p != r)
555 return second_extrema(p->parent->first_child);
558 node_t *next_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
560 node_t *next = next_leaf(n, r);
561 if (next == NULL || IS_TILED(next->client))
564 return next_tiled_leaf(d, next, r);
567 node_t *prev_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
569 node_t *prev = prev_leaf(n, r);
570 if (prev == NULL || IS_TILED(prev->client))
573 return prev_tiled_leaf(d, prev, r);
576 /* Returns true if *b* is adjacent to *a* in the direction *dir* */
577 bool is_adjacent(node_t *a, node_t *b, direction_t dir)
581 return (a->rectangle.x + a->rectangle.width) == b->rectangle.x;
584 return (a->rectangle.y + a->rectangle.height) == b->rectangle.y;
587 return (b->rectangle.x + b->rectangle.width) == a->rectangle.x;
590 return (b->rectangle.y + b->rectangle.height) == a->rectangle.y;
596 node_t *find_fence(node_t *n, direction_t dir)
606 if ((dir == DIR_UP && p->split_type == TYPE_HORIZONTAL && p->rectangle.y < n->rectangle.y) ||
607 (dir == DIR_LEFT && p->split_type == TYPE_VERTICAL && p->rectangle.x < n->rectangle.x) ||
608 (dir == DIR_DOWN && p->split_type == TYPE_HORIZONTAL && (p->rectangle.y + p->rectangle.height) > (n->rectangle.y + n->rectangle.height)) ||
609 (dir == DIR_RIGHT && p->split_type == TYPE_VERTICAL && (p->rectangle.x + p->rectangle.width) > (n->rectangle.x + n->rectangle.width)))
617 node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
619 if (n == NULL || IS_FULLSCREEN(n->client) ||
620 (d->layout == LAYOUT_MONOCLE && IS_TILED(n->client)))
623 node_t *nearest = NULL;
624 if (history_aware_focus)
625 nearest = nearest_from_history(m, d, n, dir, sel);
626 if (nearest == NULL) {
627 if (focus_by_distance) {
628 nearest = nearest_from_distance(m, d, n, dir, sel);
630 nearest = nearest_from_tree(m, d, n, dir, sel);
636 node_t *nearest_from_tree(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
642 node_t *fence = find_fence(n, dir);
647 node_t *nearest = NULL;
649 if (dir == DIR_UP || dir == DIR_LEFT) {
650 nearest = second_extrema(fence->first_child);
651 } else if (dir == DIR_DOWN || dir == DIR_RIGHT) {
652 nearest = first_extrema(fence->second_child);
655 coordinates_t ref = {m, d, n};
656 coordinates_t loc = {m, d, nearest};
658 if (node_matches(&loc, &ref, sel)) {
665 node_t *nearest_from_history(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
667 if (n == NULL || !IS_TILED(n->client)) {
671 node_t *target = find_fence(n, dir);
674 if (dir == DIR_UP || dir == DIR_LEFT)
675 target = target->first_child;
676 else if (dir == DIR_DOWN || dir == DIR_RIGHT)
677 target = target->second_child;
679 node_t *nearest = NULL;
680 int min_rank = INT_MAX;
681 coordinates_t ref = {m, d, n};
683 for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
684 if (a->vacant || !is_adjacent(n, a, dir) || a == n)
686 coordinates_t loc = {m, d, a};
687 if (!node_matches(&loc, &ref, sel))
690 int rank = history_rank(d, a);
691 if (rank >= 0 && rank < min_rank) {
700 node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
705 node_t *target = NULL;
707 if (IS_TILED(n->client)) {
708 target = find_fence(n, dir);
711 if (dir == DIR_UP || dir == DIR_LEFT)
712 target = target->first_child;
713 else if (dir == DIR_DOWN || dir == DIR_RIGHT)
714 target = target->second_child;
719 node_t *nearest = NULL;
723 get_side_handle(n->client, dir, &pt);
724 get_opposite(dir, &dir2);
726 coordinates_t ref = {m, d, n};
728 for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
729 coordinates_t loc = {m, d, a};
731 !node_matches(&loc, &ref, sel) ||
732 IS_TILED(a->client) != IS_TILED(n->client) ||
733 (IS_TILED(a->client) && !is_adjacent(n, a, dir)))
736 get_side_handle(a->client, dir2, &pt2);
737 double ds2 = distance(pt, pt2);
747 void get_opposite(direction_t src, direction_t *dst)
765 int tiled_area(node_t *n)
769 xcb_rectangle_t rect = n->client->tiled_rectangle;
770 return rect.width * rect.height;
773 int tiled_count(desktop_t *d)
776 for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
777 if (IS_TILED(f->client)) {
784 node_t *find_biggest(monitor_t *m, desktop_t *d, node_t *n, client_select_t sel)
790 int r_area = tiled_area(r);
791 coordinates_t ref = {m, d, n};
793 for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
794 coordinates_t loc = {m, d, f};
795 if (IS_FLOATING(f->client) || !node_matches(&loc, &ref, sel))
797 int f_area = tiled_area(f);
801 } else if (f_area > r_area) {
810 void rotate_tree(node_t *n, int deg)
812 if (n == NULL || is_leaf(n) || deg == 0)
817 if ((deg == 90 && n->split_type == TYPE_HORIZONTAL) ||
818 (deg == 270 && n->split_type == TYPE_VERTICAL) ||
820 tmp = n->first_child;
821 n->first_child = n->second_child;
822 n->second_child = tmp;
823 n->split_ratio = 1.0 - n->split_ratio;
827 if (n->split_type == TYPE_HORIZONTAL)
828 n->split_type = TYPE_VERTICAL;
829 else if (n->split_type == TYPE_VERTICAL)
830 n->split_type = TYPE_HORIZONTAL;
833 rotate_tree(n->first_child, deg);
834 rotate_tree(n->second_child, deg);
837 void rotate_brother(node_t *n)
839 rotate_tree(brother_tree(n), n->birth_rotation);
842 void unrotate_tree(node_t *n, int rot)
846 rotate_tree(n, 360 - rot);
849 void unrotate_brother(node_t *n)
851 unrotate_tree(brother_tree(n), n->birth_rotation);
854 void flip_tree(node_t *n, flip_t flp)
856 if (n == NULL || is_leaf(n))
861 if ((flp == FLIP_HORIZONTAL && n->split_type == TYPE_HORIZONTAL) ||
862 (flp == FLIP_VERTICAL && n->split_type == TYPE_VERTICAL)) {
863 tmp = n->first_child;
864 n->first_child = n->second_child;
865 n->second_child = tmp;
866 n->split_ratio = 1.0 - n->split_ratio;
869 flip_tree(n->first_child, flp);
870 flip_tree(n->second_child, flp);
873 void equalize_tree(node_t *n)
875 if (n == NULL || n->vacant) {
878 n->split_ratio = split_ratio;
879 equalize_tree(n->first_child);
880 equalize_tree(n->second_child);
884 int balance_tree(node_t *n)
886 if (n == NULL || n->vacant) {
888 } else if (is_leaf(n)) {
891 int b1 = balance_tree(n->first_child);
892 int b2 = balance_tree(n->second_child);
894 if (b1 > 0 && b2 > 0)
895 n->split_ratio = (double) b1 / b;
900 void unlink_node(monitor_t *m, desktop_t *d, node_t *n)
902 if (d == NULL || n == NULL)
905 node_t *p = n->parent;
911 if (n->client->private)
912 update_privacy_level(n, false);
915 node_t *g = p->parent;
917 if (is_first_child(n)) {
920 unrotate_tree(b, n->birth_rotation);
924 unrotate_tree(b, n->birth_rotation);
930 if (is_first_child(p))
938 b->birth_rotation = p->birth_rotation;
941 update_vacant_state(b->parent);
944 d->focus = history_get_node(d, n);
945 // fallback to the first extrema (`n` is not reachable)
946 if (d->focus == NULL)
947 d->focus = first_extrema(d->root);
950 if (n->client->sticky)
952 put_status(SBSC_MASK_REPORT);
955 void remove_node(monitor_t *m, desktop_t *d, node_t *n)
960 bool focused = (n == mon->desk->focus);
962 unlink_node(m, d, n);
963 history_remove(d, n);
964 remove_stack_node(n);
969 ewmh_update_client_list();
975 void destroy_tree(node_t *n)
979 node_t *first_tree = n->first_child;
980 node_t *second_tree = n->second_child;
981 if (n->client != NULL) {
986 destroy_tree(first_tree);
987 destroy_tree(second_tree);
990 bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
992 if (n1 == NULL || n2 == NULL || n1 == n2
993 || (d1 != d2 && (n1->client->sticky || n2->client->sticky))) {
997 put_status(SBSC_MASK_WINDOW_SWAP, "window_swap %s %s 0x%X %s %s 0x%X\n", m1->name, d1->name, n1->client->window, m2->name, d2->name, n2->client->window);
999 node_t *pn1 = n1->parent;
1000 node_t *pn2 = n2->parent;
1001 bool n1_first_child = is_first_child(n1);
1002 bool n2_first_child = is_first_child(n2);
1003 int br1 = n1->birth_rotation;
1004 int br2 = n2->birth_rotation;
1005 int pl1 = n1->privacy_level;
1006 int pl2 = n2->privacy_level;
1010 pn1->first_child = n2;
1012 pn1->second_child = n2;
1017 pn2->first_child = n1;
1019 pn2->second_child = n1;
1024 n1->birth_rotation = br2;
1025 n2->birth_rotation = br1;
1026 n1->privacy_level = pl2;
1027 n2->privacy_level = pl1;
1029 if (n1->vacant != n2->vacant) {
1030 update_vacant_state(n1->parent);
1031 update_vacant_state(n2->parent);
1034 if (n1->client->private != n2->client->private) {
1035 n1->client->private = !n1->client->private;
1036 n2->client->private = !n2->client->private;
1042 if (d1->focus == n1)
1046 if (d2->focus == n2)
1050 translate_client(m2, m1, n2->client);
1051 translate_client(m1, m2, n1->client);
1054 ewmh_set_wm_desktop(n1, d2);
1055 ewmh_set_wm_desktop(n2, d1);
1056 history_swap_nodes(m1, d1, n1, m2, d2, n2);
1058 if (m1->desk != d1 && m2->desk == d2) {
1059 window_show(n1->client->window);
1060 window_hide(n2->client->window);
1061 } else if (m1->desk == d1 && m2->desk != d2) {
1062 window_hide(n1->client->window);
1063 window_show(n2->client->window);
1066 update_input_focus();
1072 bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd)
1074 if (ns == NULL || ns == nd || (sticky_still && ns->client->sticky)) {
1078 put_status(SBSC_MASK_WINDOW_TRANSFER, "window_transfer %s %s 0x%X %s %s 0x%X\n", ms->name, ds->name, ns->client->window, md->name, dd->name, nd!=NULL?nd->client->window:0);
1080 bool focused = (ns == mon->desk->focus);
1081 bool active = (ns == ds->focus);
1084 clear_input_focus();
1087 unlink_node(ms, ds, ns);
1088 insert_node(md, dd, ns, nd);
1091 translate_client(ms, md, ns->client);
1095 ewmh_set_wm_desktop(ns, dd);
1096 if (!ns->client->sticky) {
1097 if (ds == ms->desk && dd != md->desk) {
1098 window_hide(ns->client->window);
1099 } else if (ds != ms->desk && dd == md->desk) {
1100 window_show(ns->client->window);
1105 history_transfer_node(md, dd, ns);
1110 focus_node(md, dd, ns);
1111 } else if (active) {
1112 activate_node(md, dd, ns);
1117 } else if (ns == mon->desk->focus) {
1118 update_input_focus();
1131 node_t *closest_node(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, client_select_t sel)
1136 node_t *f = (dir == CYCLE_PREV ? prev_leaf(n, d->root) : next_leaf(n, d->root));
1138 f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
1140 coordinates_t ref = {m, d, n};
1142 coordinates_t loc = {m, d, f};
1143 if (node_matches(&loc, &ref, sel))
1145 f = (dir == CYCLE_PREV ? prev_leaf(f, d->root) : next_leaf(f, d->root));
1147 f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
1152 void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir)
1154 if (d == NULL || d->root == NULL || d->focus == NULL || is_leaf(d->root))
1156 node_t *p = d->focus->parent;
1157 bool focus_first_child = is_first_child(d->focus);
1158 if (dir == CIRCULATE_FORWARD)
1159 for (node_t *s = second_extrema(d->root), *f = prev_tiled_leaf(d, s, d->root); f != NULL; s = prev_tiled_leaf(d, f, d->root), f = prev_tiled_leaf(d, s, d->root))
1160 swap_nodes(m, d, f, m, d, s);
1162 for (node_t *f = first_extrema(d->root), *s = next_tiled_leaf(d, f, d->root); s != NULL; f = next_tiled_leaf(d, s, d->root), s = next_tiled_leaf(d, f, d->root))
1163 swap_nodes(m, d, f, m, d, s);
1164 if (focus_first_child)
1165 focus_node(m, d, p->first_child);
1167 focus_node(m, d, p->second_child);
1170 void update_vacant_state(node_t *n)
1175 /* n is not a leaf */
1179 p->vacant = (p->first_child->vacant && p->second_child->vacant);
1184 void update_privacy_level(node_t *n, bool value)
1186 int v = (value ? 1 : -1);
1187 for (node_t *p = n; p != NULL; p = p->parent)
1188 p->privacy_level += v;