#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
+#include <limits.h>
#include "bspwm.h"
#include "desktop.h"
#include "ewmh.h"
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) {
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);
}
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;
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;
c->second_child = n;
rot = 270;
}
- n->birth_rotation = rot;
if (!n->vacant) {
rotate_tree(p, rot);
}
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;
d->root = c;
}
cancel_presel(m, d, f);
+ set_marked(m, d, n, false);
}
}
bool activate_node(monitor_t *m, desktop_t *d, node_t *n)
{
- if (d == NULL) {
- d = history_last_desktop(m, NULL);
- if (d == NULL) {
- d = m->desk_head;
- }
- }
-
- if (d == NULL) {
- return false;
- }
-
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);
}
draw_border(n, true, (m == mon));
}
- activate_desktop(m, d);
-
d->focus = n;
- history_add(m, d, n);
+ history_add(m, d, n, false);
put_status(SBSC_MASK_REPORT);
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);
+ 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;
}
}
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;
}
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);
}
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;
}
d->focus = n;
ewmh_update_active_window();
- history_add(m, d, n);
+ history_add(m, d, n, true);
put_status(SBSC_MASK_REPORT);
void hide_node(desktop_t *d, node_t *n)
{
- if (n == NULL) {
+ if (n == NULL || (!hide_sticky && n->sticky)) {
return;
} else {
if (!n->hidden) {
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;
}
}
+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;
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) {
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;
}
}
}
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)) {
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) {
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;
free_node(second_child);
}
-bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
+bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2, bool follow)
{
if (n1 == NULL || n2 == NULL || n1 == n2 || is_descendant(n1, n2) || is_descendant(n2, n1) ||
(d1 != d2 && ((m1->sticky_count > 0 && sticky_count(n1) > 0) ||
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;
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);
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);
if (m1->desk != d1 && m2->desk == d2) {
show_node(d2, n1);
- hide_node(d2, n2);
+ if (!follow || !d2_was_focused || !n2_held_focus) {
+ hide_node(d2, n2);
+ }
} else if (m1->desk == d1 && m2->desk != d2) {
- hide_node(d1, n1);
+ if (!follow || !d1_was_focused || !n1_held_focus) {
+ hide_node(d1, n1);
+ }
show_node(d1, n2);
}
if (n1_held_focus) {
- if (d1 == mon->desk) {
- focus_node(m1, d1, d1->focus);
+ if (d1_was_focused) {
+ if (follow) {
+ focus_node(m2, d2, last_d1_focus);
+ } else {
+ focus_node(m1, d1, d1->focus);
+ }
} else {
activate_node(m1, d1, d1->focus);
}
}
if (n2_held_focus) {
- if (d2 == mon->desk) {
- focus_node(m2, d2, d2->focus);
+ if (d2_was_focused) {
+ if (follow) {
+ focus_node(m1, d1, last_d2_focus);
+ } else {
+ focus_node(m2, d2, d2->focus);
+ }
} else {
activate_node(m2, d2, d2->focus);
}
return true;
}
-bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd)
+bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd, bool follow)
{
if (ns == NULL || ns == nd || is_child(ns, nd) || is_descendant(nd, ns)) {
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;
}
bool held_focus = is_descendant(ds->focus, ns);
/* avoid ending up with a dangling pointer (because of unlink_node) */
node_t *last_ds_focus = is_child(ns, ds->focus) ? NULL : ds->focus;
+ bool ds_was_focused = (ds == mon->desk);
- if (held_focus && ds == mon->desk) {
+ if (held_focus && ds_was_focused) {
clear_input_focus();
}
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) {
}
}
- history_transfer_node(md, dd, ns);
+ history_remove(ds, ns, true);
stack(dd, ns, false);
if (ds == dd) {
if (held_focus) {
- if (ds == mon->desk) {
+ if (ds_was_focused) {
focus_node(ms, ds, last_ds_focus);
} else {
activate_node(ms, ds, last_ds_focus);
}
} else {
if (held_focus) {
- if (ds == mon->desk) {
- focus_node(ms, ds, ds->focus);
- } else {
+ if (follow) {
+ if (ds_was_focused) {
+ focus_node(md, dd, last_ds_focus);
+ }
activate_node(ms, ds, ds->focus);
+ } else {
+ if (ds_was_focused) {
+ focus_node(ms, ds, ds->focus);
+ } else {
+ activate_node(ms, ds, ds->focus);
+ }
}
}
- if (dd->focus == ns) {
- if (dd == mon->desk) {
- focus_node(md, dd, held_focus ? last_ds_focus : dd->focus);
+ if (!held_focus || !follow || !ds_was_focused) {
+ if (dd->focus == ns) {
+ if (dd == mon->desk) {
+ focus_node(md, dd, held_focus ? last_ds_focus : ns);
+ } else {
+ activate_node(md, dd, held_focus ? last_ds_focus : ns);
+ }
} else {
- activate_node(md, dd, held_focus ? last_ds_focus : dd->focus);
+ draw_border(ns, is_descendant(ns, dd->focus), (md == mon));
}
- } else {
- draw_border(ns, is_descendant(ns, dd->focus), (md == mon));
}
}
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;
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;
e = prev_leaf(e, n);
}
for (node_t *s = e, *f = prev_tiled_leaf(s, n); f != NULL; s = prev_tiled_leaf(f, n), f = prev_tiled_leaf(s, n)) {
- swap_nodes(m, d, f, m, d, s);
+ swap_nodes(m, d, f, m, d, s, false);
}
} else {
node_t *e = first_extrema(n);
e = next_leaf(e, n);
}
for (node_t *f = e, *s = next_tiled_leaf(f, n); s != NULL; f = next_tiled_leaf(s, n), s = next_tiled_leaf(f, n)) {
- swap_nodes(m, d, f, m, d, s);
+ swap_nodes(m, d, f, m, d, s, false);
}
}
if (p != NULL) {
n->vacant = value;
if (value) {
- unrotate_brother(n);
cancel_presel(m, d, n);
- } else {
- rotate_brother(n);
}
}
bool set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l)
{
- if (n == NULL || n->client->layer == l) {
+ if (n == NULL || n->client == NULL || n->client->layer == l) {
return false;
}
}
if (d != m->desk) {
- transfer_node(m, d, n, m, m->desk, m->desk->focus);
+ transfer_node(m, d, n, m, m->desk, m->desk->focus, false);
}
n->sticky = 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) {
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) {
}
}
+void regenerate_ids_in(node_t *n)
+{
+ if (n == NULL || n->client != NULL) {
+ return;
+ }
+ n->id = xcb_generate_id(dpy);
+ regenerate_ids_in(n->first_child);
+ regenerate_ids_in(n->second_child);
+}
+
#define DEF_FLAG_COUNT(flag) \
unsigned int flag##_count(node_t *n) \
{ \