return (n != NULL && n->parent != NULL && n->parent->second_child == n);
}
+/**
+ * Check if the specified node matches the selection criteria.
+ *
+ * Arguments:
+ * node_t *c - the active node
+ * node_t *t - the node to test
+ * client_sel_t sel - the selection criteria
+ *
+ * Returns true if the node matches.
+ **/
+bool node_matches(node_t *c, node_t *t, client_select_t sel)
+{
+ if (sel.type != CLIENT_TYPE_ALL &&
+ is_tiled(t->client)
+ ? sel.type == CLIENT_TYPE_FLOATING
+ : sel.type == CLIENT_TYPE_TILED
+ ) return false;
+
+ if (sel.class != CLIENT_CLASS_ALL &&
+ streq(c->client->class_name, t->client->class_name)
+ ? sel.class == CLIENT_CLASS_DIFFER
+ : sel.class == CLIENT_CLASS_EQUAL
+ ) return false;
+
+ if (sel.mode != CLIENT_MODE_ALL &&
+ t->split_mode == MODE_MANUAL
+ ? sel.mode == CLIENT_MODE_AUTOMATIC
+ : sel.mode == CLIENT_MODE_MANUAL)
+ return false;
+
+ if (sel.urgency != CLIENT_URGENCY_ALL &&
+ t->client->urgent
+ ? sel.urgency == CLIENT_URGENCY_OFF
+ : sel.urgency == CLIENT_URGENCY_ON
+ ) return false;
+
+ return true;
+}
+
+bool desktop_matches(desktop_t *t, desktop_select_t sel) {
+ if (sel.status != DESKTOP_STATUS_ALL &&
+ t->root == NULL
+ ? sel.status == DESKTOP_STATUS_OCCUPIED
+ : sel.status == DESKTOP_STATUS_FREE
+ ) return false;
+
+ if (sel.urgency != DESKTOP_URGENCY_ALL &&
+ is_urgent(t)
+ ? sel.urgency == DESKTOP_URGENCY_OFF
+ : sel.urgency == DESKTOP_URGENCY_ON
+ ) return false;
+
+ return true;
+}
+
+bool is_urgent(desktop_t *d)
+{
+ for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
+ if (n->client->urgent)
+ return true;
+ return false;
+}
+
void change_split_ratio(node_t *n, value_change_t chg)
{
n->split_ratio = pow(n->split_ratio,
}
}
+node_t *brother_tree(node_t *n)
+{
+ if (n == NULL || n->parent == NULL)
+ return NULL;
+ if (is_first_child(n))
+ return n->parent->second_child;
+ else
+ return n->parent->first_child;
+}
+
node_t *first_extrema(node_t *n)
{
if (n == NULL)
}
-node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
+node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
{
if (n == NULL || n->client->fullscreen
|| (d->layout == LAYOUT_MONOCLE && is_tiled(n->client)))
node_t *nearest = NULL;
if (history_aware_focus)
- nearest = nearest_from_history(d->history, n, dir);
- if (nearest == NULL) {
- if (focus_by_distance) {
- nearest = nearest_from_distance(d, n, dir);
- } else {
- nearest = nearest_from_tree(n, dir);
- }
- }
+ nearest = nearest_from_history(d->history, n, dir, sel);
+ if (nearest == NULL)
+ nearest = nearest_from_distance(d, n, dir, sel);
return nearest;
}
-node_t *nearest_from_tree(node_t *n, direction_t dir)
-{
- if (n == NULL)
- return NULL;
-
- node_t *fence = find_fence(n, dir);
-
- if (fence == NULL)
- return NULL;
-
- node_t *nearest = NULL;
-
- if (dir == DIR_UP || dir == DIR_LEFT)
- nearest = second_extrema(fence->first_child);
- else if (dir == DIR_DOWN || dir == DIR_RIGHT)
- nearest = first_extrema(fence->second_child);
-
- return nearest;
-}
-
-node_t *nearest_from_history(focus_history_t *f, node_t *n, direction_t dir)
+node_t *nearest_from_history(focus_history_t *f, node_t *n, direction_t dir, client_select_t sel)
{
if (n == NULL || !is_tiled(n->client))
return NULL;
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
if (a->vacant || !is_adjacent(n, a, dir) || a == n)
continue;
+ if (!node_matches(n, a, sel))
+ continue;
+
int rank = history_rank(f, a);
if (rank >= 0 && rank < min_rank) {
nearest = a;
return nearest;
}
-node_t *nearest_from_distance(desktop_t *d, node_t *n, direction_t dir)
+node_t *nearest_from_distance(desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
{
if (n == NULL)
return NULL;
double ds = DBL_MAX;
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
- if (is_tiled(a->client) != is_tiled(n->client)
- || (is_tiled(a->client) && !is_adjacent(n, a, dir))
- || a == n)
- continue;
+ if (a == n) continue;
+ if (!node_matches(n, a, sel)) continue;
+ if (is_tiled(a->client) != is_tiled(n->client)) continue;
+ if (is_tiled(a->client) && !is_adjacent(n, a, dir)) continue;
+
get_side_handle(a->client, dir2, &pt2);
double ds2 = distance(pt, pt2);
if (ds2 < ds) {
return rect.width * rect.height;
}
-node_t *find_biggest(desktop_t *d)
+node_t *find_biggest(desktop_t *d, node_t *c, client_select_t sel)
{
if (d == NULL)
return NULL;
int r_area = tiled_area(r);
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
- if (!is_tiled(f->client))
+ if (!is_tiled(f->client) || !node_matches(c, f, sel))
continue;
int f_area = tiled_area(f);
if (r == NULL) {
void move_fence(node_t *n, direction_t dir, fence_move_t mov)
{
- node_t *fence = find_fence(n, dir);
-
- if (fence == NULL)
+ if (n == NULL)
return;
if ((mov == MOVE_PUSH && (dir == DIR_RIGHT || dir == DIR_DOWN))
|| (mov == MOVE_PULL && (dir == DIR_LEFT || dir == DIR_UP)))
- change_split_ratio(fence, CHANGE_INCREASE);
+ change_split_ratio(n, CHANGE_INCREASE);
else
- change_split_ratio(fence, CHANGE_DECREASE);
+ change_split_ratio(n, CHANGE_DECREASE);
}
-void rotate_tree(node_t *n, int rot)
+void rotate_tree(node_t *n, int deg)
{
- if (n == NULL || is_leaf(n) || rot == 0)
+ if (n == NULL || is_leaf(n) || deg == 0)
return;
node_t *tmp;
- if ((rot == 90 && n->split_type == TYPE_HORIZONTAL)
- || (rot == 270 && n->split_type == TYPE_VERTICAL)
- || rot == 180) {
+ if ((deg == 90 && n->split_type == TYPE_HORIZONTAL)
+ || (deg == 270 && n->split_type == TYPE_VERTICAL)
+ || deg == 180) {
tmp = n->first_child;
n->first_child = n->second_child;
n->second_child = tmp;
n->split_ratio = 1.0 - n->split_ratio;
}
- if (rot != 180) {
+ if (deg != 180) {
if (n->split_type == TYPE_HORIZONTAL)
n->split_type = TYPE_VERTICAL;
else if (n->split_type == TYPE_VERTICAL)
n->split_type = TYPE_HORIZONTAL;
}
- rotate_tree(n->first_child, rot);
- rotate_tree(n->second_child, rot);
+ rotate_tree(n->first_child, deg);
+ rotate_tree(n->second_child, deg);
}
void rotate_brother(node_t *n)
{
- if (n == NULL || n->parent == NULL)
- return;
- if (is_first_child(n))
- rotate_tree(n->parent->second_child, n->birth_rotation);
- else
- rotate_tree(n->parent->first_child, n->birth_rotation);
+ rotate_tree(brother_tree(n), n->birth_rotation);
}
void unrotate_tree(node_t *n, int rot)
void unrotate_brother(node_t *n)
{
- if (n == NULL || n->parent == NULL)
- return;
- if (is_first_child(n))
- unrotate_tree(n->parent->second_child, n->birth_rotation);
- else
- unrotate_tree(n->parent->first_child, n->birth_rotation);
+ unrotate_tree(brother_tree(n), n->birth_rotation);
}
void flip_tree(node_t *n, flip_t flp)
r = rect;
else if (d->layout == LAYOUT_MONOCLE)
r = root_rect;
+ else
+ return;
int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : window_gap);
int bleed = wg + 2 * n->client->border_width;
r.width = (bleed < r.width ? r.width - bleed : 1);
destroy_tree(second_tree);
}
-void swap_nodes(node_t *n1, node_t *n2, bool interpret)
+void swap_nodes(node_t *n1, node_t *n2)
{
if (n1 == NULL || n2 == NULL || n1 == n2)
return;
PUTS("swap nodes");
- if (interpret && n2->split_mode == MODE_MANUAL) {
- transplant_node(mon, mon->desk, n1, n2);
- return;
- }
-
/* (n1 and n2 are leaves) */
node_t *pn1 = n1->parent;
node_t *pn2 = n2->parent;
void transplant_node(monitor_t *m, desktop_t *d, node_t *n1, node_t *n2)
{
+ if (n1 == n2)
+ return;
+ bool was_focused = (d->focus == n1);
unlink_node(d, n1);
insert_node(m, d, n1, n2);
+ if (was_focused)
+ pseudo_focus(d, n1);
}
void select_monitor(monitor_t *m)
put_status();
}
-monitor_t *nearest_monitor(monitor_t *m, direction_t dir)
+monitor_t *nearest_monitor(monitor_t *m, direction_t dir, desktop_select_t sel)
{
int dmin = INT_MAX;
monitor_t *nearest = NULL;
for (monitor_t *f = mon_head; f != NULL; f = f->next) {
if (f == m)
continue;
+ if (!desktop_matches(f->desk, sel))
+ continue;
xcb_rectangle_t r = f->rectangle;
if ((dir == DIR_LEFT && r.x < rect.x) ||
(dir == DIR_RIGHT && r.x >= (rect.x + rect.width)) ||
f = (dir == CYCLE_PREV ? mon_tail : mon_head);
while (f != m) {
- if (sel == DESKTOP_ALL
- || (sel == DESKTOP_FREE && f->desk->root == NULL)
- || (sel == DESKTOP_OCCUPIED && f->desk->root != NULL)) {
+ if (desktop_matches(f->desk, sel))
return f;
- }
f = (dir == CYCLE_PREV ? m->prev : m->next);
if (f == NULL)
f = (dir == CYCLE_PREV ? mon_tail : mon_head);
f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
while (f != d) {
- if (sel == DESKTOP_ALL
- || (sel == DESKTOP_FREE && f->root == NULL)
- || (sel == DESKTOP_OCCUPIED && f->root != NULL)) {
+ if (desktop_matches(f, sel))
return f;
- }
f = (dir == CYCLE_PREV ? f->prev : f->next);
if (f == NULL)
f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
while (f != n) {
- bool tiled = is_tiled(f->client);
- if ((sel.type == CLIENT_TYPE_ALL
- || (tiled && sel.type == CLIENT_TYPE_TILED)
- || (!tiled && sel.type == CLIENT_TYPE_FLOATING)) &&
- (sel.class == CLIENT_CLASS_ALL
- || (sel.class == CLIENT_CLASS_EQUAL
- && streq(f->client->class_name, n->client->class_name))
- || (sel.class == CLIENT_CLASS_DIFFER
- && !streq(f->client->class_name, n->client->class_name)))) {
+ if (node_matches(n, f, sel))
return f;
- }
f = (dir == CYCLE_PREV ? prev_leaf(f, d->root) : next_leaf(f, d->root));
if (f == NULL)
f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
bool focus_first_child = is_first_child(d->focus);
if (dir == CIRCULATE_FORWARD)
for (node_t *s = second_extrema(d->root), *f = prev_leaf(s, d->root); f != NULL; s = prev_leaf(f, d->root), f = prev_leaf(s, d->root))
- swap_nodes(f, s, false);
+ swap_nodes(f, s);
else
for (node_t *f = first_extrema(d->root), *s = next_leaf(f, d->root); s != NULL; f = next_leaf(s, d->root), s = next_leaf(f, d->root))
- swap_nodes(f, s, false);
+ swap_nodes(f, s);
if (focus_first_child)
focus_node(m, d, p->first_child);
else