#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <limits.h>
#include <math.h>
#include <float.h>
#include <xcb/xcb.h>
{
if (c == NULL)
return false;
- return (!c->floating && !c->transient && !c->fullscreen);
+ return (!c->floating && !c->fullscreen);
}
bool is_floating(client_t *c)
n->split_ratio = pow(n->split_ratio, (chg == CHANGE_INCREASE ? INC_EXP : DEC_EXP));
}
+void change_layout(monitor_t *m, desktop_t *d, layout_t l)
+{
+ d->layout = l;
+ arrange(m, d);
+ if (d == mon->desk)
+ put_status();
+}
+
node_t *first_extrema(node_t *n)
{
if (n == NULL)
return second_extrema(p->parent->first_child);
}
+bool is_adjacent(node_t *a, node_t *r)
+{
+ node_t *f = r->parent;
+ node_t *p = a;
+ bool first_child = is_first_child(r);
+ while (p != r) {
+ if (p->parent->split_type == f->split_type && is_first_child(p) == first_child)
+ return false;
+ p = p->parent;
+ }
+ return true;
+}
+
node_t *find_fence(node_t *n, direction_t dir)
{
node_t *p;
node_t *find_neighbor(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)
- return second_extrema(fence->first_child);
+ nearest = second_extrema(fence->first_child);
else if (dir == DIR_DOWN || dir == DIR_RIGHT)
- return first_extrema(fence->second_child);
+ nearest = first_extrema(fence->second_child);
- return NULL;
+ return nearest;
}
-void get_opposite(direction_t src, direction_t* dst)
+node_t *nearest_from_history(focus_history_t *f, node_t *n, direction_t dir)
{
- switch (src) {
- case DIR_RIGHT:
- *dst = DIR_LEFT;
- break;
- case DIR_DOWN:
- *dst = DIR_UP;
- break;
- case DIR_LEFT:
- *dst = DIR_RIGHT;
- break;
- case DIR_UP:
- *dst = DIR_DOWN;
- break;
+ if (n == NULL || !is_tiled(n->client))
+ return NULL;
+
+ node_t *target = find_fence(n, dir);
+ if (target == NULL)
+ return NULL;
+ if (dir == DIR_UP || dir == DIR_LEFT)
+ target = target->first_child;
+ else if (dir == DIR_DOWN || dir == DIR_RIGHT)
+ target = target->second_child;
+
+ node_t *nearest = NULL;
+ int min_rank = INT_MAX;
+
+ for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
+ if (!is_tiled(a->client) || !is_adjacent(a, target) || a == n)
+ continue;
+ int rank = history_rank(f, a);
+ if (rank >= 0 && rank < min_rank) {
+ nearest = a;
+ min_rank = rank;
+ }
}
+
+ return nearest;
}
node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir)
return NULL;
node_t *target = NULL;
+
if (is_tiled(n->client)) {
target = find_fence(n, dir);
if (target == NULL)
} else {
target = d->root;
}
+
node_t *nearest = NULL;
direction_t dir2;
xcb_point_t pt;
get_side_handle(n->client, dir, &pt);
get_opposite(dir, &dir2);
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) || a == n)
+ if (is_tiled(a->client) != is_tiled(n->client)
+ || (is_tiled(a->client) && !is_adjacent(a, target))
+ || a == n)
continue;
get_side_handle(a->client, dir2, &pt2);
double ds2 = distance(pt, pt2);
- PRINTF("distance %X %g\n", a->client->window, ds2);
if (ds2 < ds) {
ds = ds2;
nearest = a;
}
}
+
return nearest;
}
+void get_opposite(direction_t src, direction_t *dst)
+{
+ switch (src) {
+ case DIR_RIGHT:
+ *dst = DIR_LEFT;
+ break;
+ case DIR_DOWN:
+ *dst = DIR_UP;
+ break;
+ case DIR_LEFT:
+ *dst = DIR_RIGHT;
+ break;
+ case DIR_UP:
+ *dst = DIR_DOWN;
+ break;
+ }
+}
+
int tiled_area(node_t *n)
{
if (n == NULL)
void rotate_tree(node_t *n, rotate_t rot)
{
- if (n == NULL || is_leaf(n))
+ if (n == NULL || is_leaf(n) || rot == ROTATE_IDENTITY)
return;
node_t *tmp;
n->rectangle = rect;
if (is_leaf(n)) {
- if (n->client->fullscreen)
- return;
if (is_floating(n->client) && n->client->border_width != border_width) {
int ds = 2 * (border_width - n->client->border_width);
n->client->floating_rectangle.height += ds;
}
- if (borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE)
+ if ((borderless_monocle && is_tiled(n->client) && d->layout == LAYOUT_MONOCLE) ||
+ n->client->fullscreen)
n->client->border_width = 0;
else
n->client->border_width = border_width;
xcb_rectangle_t r;
- if (is_tiled(n->client)) {
- if (d->layout == LAYOUT_TILED)
- r = rect;
- else if (d->layout == LAYOUT_MONOCLE)
- r = root_rect;
- 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);
- r.height = (bleed < r.height ? r.height - bleed : 1);
- n->client->tiled_rectangle = r;
+ if (!n->client->fullscreen) {
+ if (!n->client->floating) {
+ /* tiled clients */
+ if (d->layout == LAYOUT_TILED)
+ r = rect;
+ else if (d->layout == LAYOUT_MONOCLE)
+ r = root_rect;
+ 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);
+ r.height = (bleed < r.height ? r.height - bleed : 1);
+ n->client->tiled_rectangle = r;
+ } else {
+ /* floating clients */
+ r = n->client->floating_rectangle;
+ }
} else {
- r = n->client->floating_rectangle;
+ /* fullscreen clients */
+ r = m->rectangle;
}
window_move_resize(n->client->window, r.x, r.y, r.width, r.height);
dad->second_child = n;
rot = ROTATE_COUNTER_CLOCKWISE;
}
- rotate_tree(fopar, rot);
+ if (!is_floating(n->client))
+ rotate_tree(fopar, rot);
n->birth_rotation = rot;
}
break;
if (n == NULL && d->root != NULL)
return;
+ split_mode = MODE_AUTOMATIC;
+
if (mon->desk != d)
clear_input_focus();
PRINTF("focus node %X\n", n->client->window);
- split_mode = MODE_AUTOMATIC;
n->client->urgent = false;
pseudo_focus(d, n);
- xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
+ stack(d, n);
- if (!is_tiled(n->client)) {
- if (!adaptative_raise || !might_cover(d, n))
- window_raise(n->client->window);
- } else {
- stack_tiled(d);
- }
+ xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, n->client->window, XCB_CURRENT_TIME);
if (focus_follows_pointer) {
xcb_window_t win = XCB_NONE;
void remove_node(desktop_t *d, node_t *n)
{
- if (d == NULL || n == NULL)
+ if (n == NULL)
return;
PRINTF("remove node %X\n", n->client->window);
void transfer_node(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd, node_t *n)
{
- if (n == NULL || (ms == md && dd == ds))
+ if (n == NULL || dd == ds)
return;
PRINTF("transfer node %X\n", n->client->window);
fit_monitor(md, n->client);
- if (n->client->fullscreen)
- window_move_resize(n->client->window, md->rectangle.x, md->rectangle.y, md->rectangle.width, md->rectangle.height);
-
if (ds != ms->desk && dd == md->desk)
window_show(n->client->window);
pseudo_focus(dd, n);
+ if (md->desk == dd)
+ stack(dd, n);
+
+ arrange(ms, ds);
+ arrange(md, dd);
+
if (ds == ms->desk || dd == md->desk)
update_current();
}
last_mon = mon;
mon = m;
+ if (pointer_follows_monitor)
+ center_pointer(m);
+
ewmh_update_current_desktop();
put_status();
}
PRINTF("select desktop %s\n", d->name);
- if (visible) {
- desktop_show(d);
- desktop_hide(mon->desk);
- }
+ desktop_show(d);
+ desktop_hide(mon->desk);
mon->last_desk = mon->desk;
mon->desk = d;
}
}
if (mon != NULL && mon->desk != NULL)
- fprintf(status_fifo, "L%s\n", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
+ fprintf(status_fifo, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
+ fprintf(status_fifo, "\n");
fflush(status_fifo);
}