]> git.lizzy.rs Git - bspwm.git/blobdiff - src/tree.c
Add automatic insertion scheme: alternate
[bspwm.git] / src / tree.c
index ac416d200c1534a1c66cf3676c2089438e8eea8d..bf5d3965f8e6ebe49f447d2dd496e769c10d79dc 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdbool.h>
+#include <limits.h>
 #include "bspwm.h"
 #include "desktop.h"
 #include "ewmh.h"
@@ -47,17 +48,22 @@ void arrange(monitor_t *m, desktop_t *d)
 
        layout_t l = d->layout;
 
-       if (single_monocle && tiled_count(d->root) <= 1) {
+       if (single_monocle && tiled_count(d->root, true) <= 1) {
                l = LAYOUT_MONOCLE;
        }
 
        xcb_rectangle_t rect = m->rectangle;
 
-       if (!paddingless_monocle || l != LAYOUT_MONOCLE) {
-               rect.x += m->padding.left + d->padding.left;
-               rect.y += m->padding.top + d->padding.top;
-               rect.width -= m->padding.left + d->padding.left + d->padding.right + m->padding.right;
-               rect.height -= m->padding.top + d->padding.top + d->padding.bottom + m->padding.bottom;
+       rect.x += m->padding.left + d->padding.left;
+       rect.y += m->padding.top + d->padding.top;
+       rect.width -= m->padding.left + d->padding.left + d->padding.right + m->padding.right;
+       rect.height -= m->padding.top + d->padding.top + d->padding.bottom + m->padding.bottom;
+
+       if (l == LAYOUT_MONOCLE) {
+               rect.x += monocle_padding.left;
+               rect.y += monocle_padding.top;
+               rect.width -= monocle_padding.left + monocle_padding.right;
+               rect.height -= monocle_padding.top + monocle_padding.bottom;
        }
 
        if (!gapless_monocle || l != LAYOUT_MONOCLE) {
@@ -78,13 +84,6 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, layout_t l, xcb_rectang
 
        n->rectangle = rect;
 
-       if (pointer_follows_focus && mon->desk->focus == n) {
-               xcb_rectangle_t r = rect;
-               r.width -= d->window_gap;
-               r.height -= d->window_gap;
-               center_pointer(r);
-       }
-
        if (n->presel != NULL) {
                draw_presel_feedback(m, d, n);
        }
@@ -328,14 +327,21 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
                                presel_dir(m, d, f, (rect.width >= rect.height ? DIR_EAST : DIR_SOUTH));
                        }
                }
-               if (f->presel == NULL && p != NULL && p->vacant) {
-                       f = p;
-                       p = f->parent;
-               }
                n->parent = c;
-               c->birth_rotation = f->birth_rotation;
                if (f->presel == NULL) {
-                       if (p == NULL) {
+                       bool single_tiled = f->client != NULL && IS_TILED(f->client) && tiled_count(d->root, true) == 1;
+                       if (p == NULL || automatic_scheme != SCHEME_SPIRAL || single_tiled) {
+                               if (p != NULL) {
+                                       if (is_first_child(f)) {
+                                               p->first_child = c;
+                                       } else {
+                                               p->second_child = c;
+                                       }
+                               } else {
+                                       d->root = c;
+                               }
+                               c->parent = p;
+                               f->parent = c;
                                if (initial_polarity == FIRST_CHILD) {
                                        c->first_child = n;
                                        c->second_child = f;
@@ -343,13 +349,19 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
                                        c->first_child = f;
                                        c->second_child = n;
                                }
-                               if (m->rectangle.width > m->rectangle.height) {
-                                       c->split_type = TYPE_VERTICAL;
+                               if (p == NULL || automatic_scheme == SCHEME_LONGEST_SIDE || single_tiled) {
+                                       if (f->rectangle.width > f->rectangle.height) {
+                                               c->split_type = TYPE_VERTICAL;
+                                       } else {
+                                               c->split_type = TYPE_HORIZONTAL;
+                                       }
                                } else {
-                                       c->split_type = TYPE_HORIZONTAL;
+                                       if (p->split_type == TYPE_HORIZONTAL) {
+                                               c->split_type = TYPE_VERTICAL;
+                                       } else {
+                                               c->split_type = TYPE_HORIZONTAL;
+                                       }
                                }
-                               f->parent = c;
-                               d->root = c;
                        } else {
                                node_t *g = p->parent;
                                c->parent = g;
@@ -375,7 +387,6 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
                                        c->second_child = n;
                                        rot = 270;
                                }
-                               n->birth_rotation = rot;
                                if (!n->vacant) {
                                        rotate_tree(p, rot);
                                }
@@ -391,7 +402,6 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
                        c->split_ratio = f->presel->split_ratio;
                        c->parent = p;
                        f->parent = c;
-                       f->birth_rotation = 0;
                        switch (f->presel->split_dir) {
                                case DIR_WEST:
                                        c->split_type = TYPE_VERTICAL;
@@ -418,6 +428,7 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
                                d->root = c;
                        }
                        cancel_presel(m, d, f);
+                       set_marked(m, d, n, false);
                }
        }
 
@@ -439,7 +450,10 @@ void insert_receptacle(monitor_t *m, desktop_t *d, node_t *n)
 bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
 {
        if (n == NULL && d->root != NULL) {
-               n = history_last_node(d, NULL);
+               n = d->focus;
+               if (n == NULL) {
+                       n = history_last_node(d, NULL);
+               }
                if (n == NULL) {
                        n = first_focusable_leaf(d->root);
                }
@@ -465,7 +479,7 @@ bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
        }
 
        d->focus = n;
-       history_add(m, d, n);
+       history_add(m, d, n, false);
 
        put_status(SBSC_MASK_REPORT);
 
@@ -478,26 +492,31 @@ bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
        return true;
 }
 
-void transfer_sticky_nodes(monitor_t *m, desktop_t *ds, desktop_t *dd, node_t *n)
+void transfer_sticky_nodes(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd, node_t *n)
 {
        if (n == NULL) {
                return;
        } else if (n->sticky) {
-               transfer_node(m, ds, n, m, dd, dd->focus, false);
+               sticky_still = false;
+               transfer_node(ms, ds, n, md, dd, dd->focus, false);
+               sticky_still = true;
        } else {
                /* we need references to the children because n might be freed after
                 * the first recursive call */
                node_t *first_child = n->first_child;
                node_t *second_child = n->second_child;
-               transfer_sticky_nodes(m, ds, dd, first_child);
-               transfer_sticky_nodes(m, ds, dd, second_child);
+               transfer_sticky_nodes(ms, ds, md, dd, first_child);
+               transfer_sticky_nodes(ms, ds, md, dd, second_child);
        }
 }
 
 bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
 {
        if (m == NULL) {
-               m = history_last_monitor(NULL);
+               m = mon;
+               if (m == NULL) {
+                       m = history_last_monitor(NULL);
+               }
                if (m == NULL) {
                        m = mon_head;
                }
@@ -508,7 +527,10 @@ bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
        }
 
        if (d == NULL) {
-               d = history_last_desktop(m, NULL);
+               d = m->desk;
+               if (d == NULL) {
+                       d = history_last_desktop(m, NULL);
+               }
                if (d == NULL) {
                        d = m->desk_head;
                }
@@ -518,8 +540,13 @@ bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
                return false;
        }
 
+       bool guess = (n == NULL);
+
        if (n == NULL && d->root != NULL) {
-               n = history_last_node(d, NULL);
+               n = d->focus;
+               if (n == NULL) {
+                       n = history_last_node(d, NULL);
+               }
                if (n == NULL) {
                        n = first_focusable_leaf(d->root);
                }
@@ -533,10 +560,13 @@ bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
                clear_input_focus();
        }
 
-       if (m->sticky_count > 0 && d != m->desk) {
-               sticky_still = false;
-               transfer_sticky_nodes(m, m->desk, d, m->desk->root);
-               sticky_still = true;
+       if (m->sticky_count > 0 && m->desk != NULL && d != m->desk) {
+               if (guess && m->desk->focus != NULL && m->desk->focus->sticky) {
+                       n = m->desk->focus;
+               }
+
+               transfer_sticky_nodes(m, m->desk, m, d, m->desk->root);
+
                if (n == NULL && d->focus != NULL) {
                        n = d->focus;
                }
@@ -578,7 +608,7 @@ bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
 
        d->focus = n;
        ewmh_update_active_window();
-       history_add(m, d, n);
+       history_add(m, d, n, true);
 
        put_status(SBSC_MASK_REPORT);
 
@@ -605,7 +635,7 @@ bool focus_node(monitor_t *m, desktop_t *d, node_t *n)
 
 void hide_node(desktop_t *d, node_t *n)
 {
-       if (n == NULL) {
+       if (n == NULL || (!hide_sticky && n->sticky)) {
                return;
        } else {
                if (!n->hidden) {
@@ -653,10 +683,9 @@ node_t *make_node(uint32_t id)
        node_t *n = calloc(1, sizeof(node_t));
        n->id = id;
        n->parent = n->first_child = n->second_child = NULL;
-       n->vacant = n->hidden = n->sticky = n->private = n->locked = false;
+       n->vacant = n->hidden = n->sticky = n->private = n->locked = n->marked = false;
        n->split_ratio = split_ratio;
        n->split_type = TYPE_VERTICAL;
-       n->birth_rotation = 0;
        n->constraints = (constraints_t) {MIN_WIDTH, MIN_HEIGHT};
        n->presel = NULL;
        n->client = NULL;
@@ -952,11 +981,41 @@ node_t *find_by_id_in(node_t *r, uint32_t id)
        }
 }
 
+void find_any_node(coordinates_t *ref, coordinates_t *dst, node_select_t *sel)
+{
+       for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+               for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+                       if (find_any_node_in(m, d, d->root, ref, dst, sel)) {
+                               return;
+                       }
+               }
+       }
+}
+
+bool find_any_node_in(monitor_t *m, desktop_t *d, node_t *n, coordinates_t *ref, coordinates_t *dst, node_select_t *sel)
+{
+       if (n == NULL) {
+               return false;
+       } else {
+               coordinates_t loc = {m, d, n};
+               if (node_matches(&loc, ref, sel)) {
+                       *dst = loc;
+                       return true;
+               } else {
+                       if (find_any_node_in(m, d, n->first_child, ref, dst, sel)) {
+                               return true;
+                       } else {
+                               return find_any_node_in(m, d, n->second_child, ref, dst, sel);
+                       }
+               }
+       }
+}
+
 /* Based on https://github.com/ntrrgc/right-window */
-void find_nearest_neighbor(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t sel)
+void find_nearest_neighbor(coordinates_t *ref, coordinates_t *dst, direction_t dir, node_select_t *sel)
 {
        xcb_rectangle_t rect = get_rectangle(ref->monitor, ref->desktop, ref->node);
-       double md = UINT32_MAX, mr = UINT32_MAX;
+       uint32_t md = UINT32_MAX, mr = UINT32_MAX;
 
        for (monitor_t *m = mon_head; m != NULL; m = m->next) {
                desktop_t *d = m->desk;
@@ -990,23 +1049,29 @@ unsigned int node_area(desktop_t *d, node_t *n)
        return area(get_rectangle(NULL, d, n));
 }
 
-int tiled_count(node_t *n)
+int tiled_count(node_t *n, bool include_receptacles)
 {
        if (n == NULL) {
                return 0;
        }
        int cnt = 0;
        for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
-               if (!f->hidden && f->client != NULL && IS_TILED(f->client)) {
+               if (!f->hidden && ((include_receptacles && f->client == NULL) ||
+                                  (f->client != NULL && IS_TILED(f->client)))) {
                        cnt++;
                }
        }
        return cnt;
 }
 
-void find_biggest(coordinates_t *ref, coordinates_t *dst, node_select_t sel)
+void find_by_area(area_peak_t ap, coordinates_t *ref, coordinates_t *dst, node_select_t *sel)
 {
-       unsigned int b_area = 0;
+       unsigned int p_area;
+       if (ap == AREA_BIGGEST) {
+               p_area = 0;
+       } else {
+               p_area = UINT_MAX;
+       }
 
        for (monitor_t *m = mon_head; m != NULL; m = m->next) {
                for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
@@ -1016,9 +1081,9 @@ void find_biggest(coordinates_t *ref, coordinates_t *dst, node_select_t sel)
                                        continue;
                                }
                                unsigned int f_area = node_area(d, f);
-                               if (f_area > b_area) {
+                               if ((ap == AREA_BIGGEST && f_area > p_area) || (ap == AREA_SMALLEST && f_area < p_area)) {
                                        *dst = loc;
-                                       b_area = f_area;
+                                       p_area = f_area;
                                }
                        }
                }
@@ -1060,24 +1125,6 @@ void rotate_tree_rec(node_t *n, int deg)
        rotate_tree_rec(n->second_child, deg);
 }
 
-void rotate_brother(node_t *n)
-{
-       rotate_tree(brother_tree(n), n->birth_rotation);
-}
-
-void unrotate_tree(node_t *n, int rot)
-{
-       if (rot == 0) {
-               return;
-       }
-       rotate_tree(n, 360 - rot);
-}
-
-void unrotate_brother(node_t *n)
-{
-       unrotate_tree(brother_tree(n), n->birth_rotation);
-}
-
 void flip_tree(node_t *n, flip_t flp)
 {
        if (n == NULL || is_leaf(n)) {
@@ -1151,10 +1198,6 @@ void unlink_node(monitor_t *m, desktop_t *d, node_t *n)
                node_t *b = brother_tree(n);
                node_t *g = p->parent;
 
-               if (!n->vacant) {
-                       unrotate_tree(b, n->birth_rotation);
-               }
-
                b->parent = g;
 
                if (g != NULL) {
@@ -1167,7 +1210,23 @@ void unlink_node(monitor_t *m, desktop_t *d, node_t *n)
                        d->root = b;
                }
 
-               b->birth_rotation = p->birth_rotation;
+               if (!n->vacant && removal_adjustment) {
+                       if (automatic_scheme == SCHEME_LONGEST_SIDE || g == NULL) {
+                               if (p != NULL) {
+                                       if (p->rectangle.width > p->rectangle.height) {
+                                               b->split_type = TYPE_VERTICAL;
+                                       } else {
+                                               b->split_type = TYPE_HORIZONTAL;
+                                       }
+                               }
+                       } else if (automatic_scheme == SCHEME_ALTERNATE) {
+                               if (g->split_type == TYPE_HORIZONTAL) {
+                                       b->split_type = TYPE_VERTICAL;
+                               } else {
+                                       b->split_type = TYPE_HORIZONTAL;
+                               }
+                       }
+               }
 
                free(p);
                n->parent = NULL;
@@ -1265,8 +1324,6 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
        node_t *pn2 = n2->parent;
        bool n1_first_child = is_first_child(n1);
        bool n2_first_child = is_first_child(n2);
-       int br1 = n1->birth_rotation;
-       int br2 = n2->birth_rotation;
        bool n1_held_focus = is_descendant(d1->focus, n1);
        bool n2_held_focus = is_descendant(d2->focus, n2);
        node_t *last_d1_focus = d1->focus;
@@ -1290,8 +1347,6 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
 
        n1->parent = pn2;
        n2->parent = pn1;
-       n1->birth_rotation = br2;
-       n2->birth_rotation = br1;
 
        propagate_flags_upward(m2, d2, n1);
        propagate_flags_upward(m1, d1, n2);
@@ -1321,7 +1376,8 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
                ewmh_set_wm_desktop(n1, d2);
                ewmh_set_wm_desktop(n2, d1);
 
-               history_swap_nodes(m1, d1, n1, m2, d2, n2);
+               history_remove(d1, n1, true);
+               history_remove(d2, n2, true);
 
                bool d1_was_focused = (d1 == mon->desk);
                bool d2_was_focused = (d2 == mon->desk);
@@ -1385,7 +1441,7 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
                return false;
        }
 
-       if (sticky_still && ds != dd && ms->sticky_count > 0 && sticky_count(ns) > 0) {
+       if (sticky_still && ms->sticky_count > 0 && sticky_count(ns) > 0 && dd != md->desk) {
                return false;
        }
 
@@ -1403,8 +1459,10 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
        unlink_node(ms, ds, ns);
        insert_node(md, dd, ns, nd);
 
-       if (md != ms && (ns->client == NULL || monitor_from_client(ns->client) != md)) {
-               adapt_geometry(&ms->rectangle, &md->rectangle, ns);
+       if (md != ms) {
+               if (ns->client == NULL || monitor_from_client(ns->client) != md) {
+                       adapt_geometry(&ms->rectangle, &md->rectangle, ns);
+               }
        }
 
        if (ds != dd) {
@@ -1418,7 +1476,7 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
                }
        }
 
-       history_transfer_node(md, dd, ns);
+       history_remove(ds, ns, true);
        stack(dd, ns, false);
 
        if (ds == dd) {
@@ -1468,7 +1526,7 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
        return true;
 }
 
-bool find_closest_node(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir, node_select_t sel)
+bool find_closest_node(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir, node_select_t *sel)
 {
        monitor_t *m = ref->monitor;
        desktop_t *d = ref->desktop;
@@ -1507,7 +1565,7 @@ bool find_closest_node(coordinates_t *ref, coordinates_t *dst, cycle_dir_t dir,
 
 void circulate_leaves(monitor_t *m, desktop_t *d, node_t *n, circulate_dir_t dir)
 {
-       if (tiled_count(n) < 2) {
+       if (tiled_count(n, false) < 2) {
                return;
        }
        node_t *p = d->focus->parent;
@@ -1560,10 +1618,7 @@ void set_vacant_local(monitor_t *m, desktop_t *d, node_t *n, bool value)
        n->vacant = value;
 
        if (value) {
-               unrotate_brother(n);
                cancel_presel(m, d, n);
-       } else {
-               rotate_brother(n);
        }
 }
 
@@ -1918,6 +1973,21 @@ void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
        }
 }
 
+void set_marked(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+       if (n == NULL || n->marked == value) {
+               return;
+       }
+
+       n->marked = value;
+
+       put_status(SBSC_MASK_NODE_FLAG, "node_flag 0x%08X 0x%08X 0x%08X marked %s\n", m->id, d->id, n->id, ON_OFF_STR(value));
+
+       if (n == m->desk->focus) {
+               put_status(SBSC_MASK_REPORT);
+       }
+}
+
 void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value)
 {
        if (value && mon->desk->focus == n) {
@@ -1938,13 +2008,6 @@ void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value)
        put_status(SBSC_MASK_REPORT);
 }
 
-/* Returns true if a contains b */
-bool contains(xcb_rectangle_t a, xcb_rectangle_t b)
-{
-       return (a.x <= b.x && (a.x + a.width) >= (b.x + b.width) &&
-               a.y <= b.y && (a.y + a.height) >= (b.y + b.height));
-}
-
 xcb_rectangle_t get_rectangle(monitor_t *m, desktop_t *d, node_t *n)
 {
        if (n == NULL) {