From bfded1effccbed8f76fe5fbbe11c3aca665fd9c4 Mon Sep 17 00:00:00 2001 From: Bastien Dejean Date: Tue, 1 Oct 2013 10:48:03 +0200 Subject: [PATCH 1/1] History is global and stacking is independent The last desktop and monitor are now deduced from the history. The stacking order is now independent from the history of the focused nodes: this prevents hacks on both sides. All windows are now considered in the stacking algorithm: it prevents tiled windows from one monitor to appear above the floating windows of another monitor. Transfered windows are stacked below the windows of the same kind. --- Makefile | 2 +- Sourcedeps | 17 +-- bspwm.c | 9 +- bspwm.h | 5 +- desktop.c | 80 +++++++++---- desktop.h | 2 +- doc/bspwm.1 | 14 ++- doc/bspwm.1.txt | 6 + events.c | 18 +-- ewmh.c | 3 - examples/loop/bspwmrc | 11 +- examples/loop/profile | 1 + history.c | 204 +++++++++++++++++++++----------- history.h | 24 ++-- messages.c | 58 ++++++--- monitor.c | 27 ++--- pointer.c | 13 +- query.c | 57 +++++---- query.h | 6 +- restore.c | 94 ++++++++++----- restore.h | 1 + stack.c | 151 ++++++++++++++++++++++++ stack.h | 12 ++ tree.c | 166 +++++++++++++++----------- tree.h | 7 +- types.h | 30 ++--- window.c | 267 ++++++++++++++++++------------------------ window.h | 8 +- 28 files changed, 812 insertions(+), 481 deletions(-) create mode 100644 stack.c create mode 100644 stack.h diff --git a/Makefile b/Makefile index e19ba8d..01881f7 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ MANPREFIX = $(PREFIX)/share/man BASHCPL = $(PREFIX)/share/bash-completion/completions ZSHCPL = $(PREFIX)/share/zsh/site-functions -WM_SRC = bspwm.c helpers.c settings.c monitor.c desktop.c tree.c history.c \ +WM_SRC = bspwm.c helpers.c settings.c monitor.c desktop.c tree.c stack.c history.c \ events.c pointer.c window.c messages.c query.c restore.c rule.c ewmh.c WM_OBJ = $(WM_SRC:.c=.o) CL_SRC = bspc.c helpers.c diff --git a/Sourcedeps b/Sourcedeps index a3551bb..aa67aaf 100644 --- a/Sourcedeps +++ b/Sourcedeps @@ -1,16 +1,17 @@ bspc.o: bspc.c common.h helpers.h -bspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h messages.h monitor.h rule.h settings.h tree.h types.h window.h +bspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h history.h messages.h monitor.h rule.h settings.h stack.h tree.h types.h window.h desktop.o: desktop.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h tree.h types.h window.h events.o: events.c bspwm.h events.h ewmh.h helpers.h monitor.h query.h settings.h tree.h types.h window.h ewmh.o: ewmh.c bspwm.h ewmh.h helpers.h settings.h tree.h types.h helpers.o: helpers.c bspwm.h helpers.h types.h -history.o: history.c helpers.h query.h types.h -messages.o: messages.c bspwm.h desktop.h ewmh.h helpers.h messages.h monitor.h pointer.h query.h restore.h rule.h settings.h tree.h types.h window.h -monitor.o: monitor.c bspwm.h desktop.h ewmh.h helpers.h monitor.h query.h settings.h tree.h types.h window.h -pointer.o: pointer.c bspwm.h helpers.h pointer.h query.h settings.h tree.h types.h window.h +history.o: history.c bspwm.h helpers.h query.h types.h +messages.o: messages.c bspwm.h desktop.h ewmh.h helpers.h history.h messages.h monitor.h pointer.h query.h restore.h rule.h settings.h tree.h types.h window.h +monitor.o: monitor.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h tree.h types.h window.h +pointer.o: pointer.c bspwm.h helpers.h pointer.h query.h settings.h stack.h tree.h types.h window.h query.o: query.c bspwm.h desktop.h helpers.h history.h messages.h monitor.h query.h tree.h types.h -restore.o: restore.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h restore.h settings.h tree.h types.h +restore.o: restore.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h restore.h settings.h stack.h tree.h types.h rule.o: rule.c bspwm.h ewmh.h helpers.h query.h rule.h types.h window.h settings.o: settings.c bspwm.h helpers.h settings.h types.h -tree.o: tree.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h tree.h types.h window.h -window.o: window.c bspwm.h ewmh.h helpers.h monitor.h query.h rule.h settings.h tree.h types.h window.h +stack.o: stack.c bspwm.h helpers.h stack.h types.h window.h +tree.o: tree.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h stack.h tree.h types.h window.h +window.o: window.c bspwm.h ewmh.h helpers.h monitor.h query.h rule.h settings.h stack.h tree.h types.h window.h diff --git a/bspwm.c b/bspwm.c index d2b0b02..af9637b 100644 --- a/bspwm.c +++ b/bspwm.c @@ -17,6 +17,8 @@ #include "bspwm.h" #include "tree.h" #include "window.h" +#include "history.h" +#include "stack.h" #include "rule.h" #include "ewmh.h" @@ -163,8 +165,10 @@ void init(void) { num_monitors = num_desktops = num_clients = 0; monitor_uid = desktop_uid = rule_uid = 0; - mon = last_mon = mon_head = mon_tail = pri_mon = NULL; + mon = mon_head = mon_tail = pri_mon = NULL; rule_head = rule_tail = NULL; + history_head = history_tail = NULL; + stack_head = stack_tail = NULL; status_fifo = NULL; last_motion_time = last_motion_x = last_motion_y = 0; randr_base = 0; @@ -264,6 +268,9 @@ void cleanup(void) remove_monitor(mon_head); while (rule_head != NULL) remove_rule(rule_head); + while (stack_head != NULL) + remove_stack(stack_head); + empty_history(); free(frozen_pointer); } diff --git a/bspwm.h b/bspwm.h index 414a78c..be4c3bd 100644 --- a/bspwm.h +++ b/bspwm.h @@ -23,10 +23,13 @@ char *status_prefix; char config_path[MAXLEN]; monitor_t *mon; -monitor_t *last_mon; monitor_t *mon_head; monitor_t *mon_tail; monitor_t *pri_mon; +history_t *history_head; +history_t *history_tail; +stack_t *stack_head; +stack_t *stack_tail; rule_t *rule_head; rule_t *rule_tail; diff --git a/desktop.c b/desktop.c index e3ce391..f9aba4a 100644 --- a/desktop.c +++ b/desktop.c @@ -1,12 +1,12 @@ #include #include "bspwm.h" -#include "desktop.h" +#include "ewmh.h" +#include "history.h" #include "monitor.h" +#include "query.h" #include "tree.h" -#include "history.h" #include "window.h" -#include "query.h" -#include "ewmh.h" +#include "desktop.h" void select_desktop(monitor_t *m, desktop_t *d) { @@ -20,7 +20,6 @@ void select_desktop(monitor_t *m, desktop_t *d) show_desktop(d); hide_desktop(mon->desk); - mon->last_desk = mon->desk; mon->desk = d; ewmh_update_current_desktop(); @@ -70,10 +69,13 @@ void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) fit_monitor(md, n->client); + arrange(md, d); - if (d != dd && md->desk == d) { + + if (d != dd && md->desk == d) show_desktop(d); - } + + history_transfer_desktop(md, d); ewmh_update_wm_desktops(); ewmh_update_desktop_names(); @@ -91,7 +93,6 @@ desktop_t *make_desktop(const char *name) d->layout = LAYOUT_TILED; d->prev = d->next = NULL; d->root = d->focus = NULL; - d->history = make_focus_history(); d->window_gap = WINDOW_GAP; return d; } @@ -124,13 +125,13 @@ void empty_desktop(desktop_t *d) { destroy_tree(d->root); d->root = d->focus = NULL; - empty_history(d->history); } void unlink_desktop(monitor_t *m, desktop_t *d) { desktop_t *prev = d->prev; desktop_t *next = d->next; + desktop_t *last_desk = history_get_desktop(m, d); if (prev != NULL) prev->next = next; if (next != NULL) @@ -139,10 +140,8 @@ void unlink_desktop(monitor_t *m, desktop_t *d) m->desk_head = next; if (m->desk_tail == d) m->desk_tail = prev; - if (m->last_desk == d) - m->last_desk = NULL; if (m->desk == d) - m->desk = (m->last_desk == NULL ? (prev == NULL ? next : prev) : m->last_desk); + m->desk = (last_desk == NULL ? (prev == NULL ? next : prev) : last_desk); d->prev = d->next = NULL; } @@ -151,6 +150,7 @@ void remove_desktop(monitor_t *m, desktop_t *d) PRINTF("remove desktop %s\n", d->name); unlink_desktop(m, d); + history_remove(d, NULL); empty_desktop(d); free(d); num_desktops--; @@ -159,19 +159,39 @@ void remove_desktop(monitor_t *m, desktop_t *d) put_status(); } -void swap_desktops(monitor_t *m, desktop_t *d1, desktop_t *d2) +void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2) { if (d1 == NULL || d2 == NULL || d1 == d2) return; - if (m->desk_head == d1) - m->desk_head = d2; - else if (m->desk_head == d2) - m->desk_head = d1; - if (m->desk_tail == d1) - m->desk_tail = d2; - else if (m->desk_tail == d2) - m->desk_tail = d1; + PRINTF("swap desktops %s %s\n", d1->name, d2->name); + + bool d1_focused = (m1->desk == d1); + bool d2_focused = (m2->desk == d2); + + if (m1 != m2) { + if (m1->desk == d1) + m1->desk = d2; + if (m1->desk_head == d1) + m1->desk_head = d2; + if (m1->desk_tail == d1) + m1->desk_tail = d2; + if (m2->desk == d2) + m2->desk = d1; + if (m2->desk_head == d2) + m2->desk_head = d1; + if (m2->desk_tail == d2) + m2->desk_tail = d1; + } else { + if (m1->desk_head == d1) + m1->desk_head = d2; + else if (m1->desk_head == d2) + m1->desk_head = d1; + if (m1->desk_tail == d1) + m1->desk_tail = d2; + else if (m1->desk_tail == d2) + m1->desk_tail = d1; + } desktop_t *p1 = d1->prev; desktop_t *n1 = d1->next; @@ -192,6 +212,24 @@ void swap_desktops(monitor_t *m, desktop_t *d1, desktop_t *d2) d2->prev = p1 == d2 ? d1 : p1; d2->next = n1 == d2 ? d1 : n1; + if (m1 != m2) { + for (node_t *n = first_extrema(d1->root); n != NULL; n = next_leaf(n, d1->root)) + fit_monitor(m2, n->client); + for (node_t *n = first_extrema(d2->root); n != NULL; n = next_leaf(n, d2->root)) + fit_monitor(m1, n->client); + history_swap_desktops(m1, d1, m2, d2); + arrange(m1, d2); + arrange(m2, d1); + if (d1_focused && !d2_focused) { + hide_desktop(d1); + show_desktop(d2); + } else if (!d1_focused && d2_focused) { + show_desktop(d1); + hide_desktop(d2); + } + } + + update_input_focus(); ewmh_update_wm_desktops(); ewmh_update_desktop_names(); ewmh_update_current_desktop(); diff --git a/desktop.h b/desktop.h index 792d80e..990d44a 100644 --- a/desktop.h +++ b/desktop.h @@ -13,7 +13,7 @@ void add_desktop(monitor_t *, desktop_t *); void empty_desktop(desktop_t *); void unlink_desktop(monitor_t *, desktop_t *); void remove_desktop(monitor_t *, desktop_t *); -void swap_desktops(monitor_t *, desktop_t *, desktop_t *); +void swap_desktops(monitor_t *, desktop_t *, monitor_t *, desktop_t *); void transfer_desktop(monitor_t *, monitor_t *, desktop_t *); void show_desktop(desktop_t *); void hide_desktop(desktop_t *); diff --git a/doc/bspwm.1 b/doc/bspwm.1 index fd08054..00535ae 100644 --- a/doc/bspwm.1 +++ b/doc/bspwm.1 @@ -2,12 +2,12 @@ .\" Title: bspwm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.78.1 -.\" Date: 09/23/2013 +.\" Date: 10/01/2013 .\" Manual: Bspwm Manual .\" Source: Bspwm 0.8 .\" Language: English .\" -.TH "BSPWM" "1" "09/23/2013" "Bspwm 0\&.8" "Bspwm Manual" +.TH "BSPWM" "1" "10/01/2013" "Bspwm 0\&.8" "Bspwm Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -676,6 +676,11 @@ Print tree rooted at query\&. Print the history as it relates to the query\&. .RE .PP +\fB\-S\fR, \fB\-\-stack\fR +.RS 4 +Print the window stacking order\&. +.RE +.PP [\fB\-m\fR,\fB\-\-monitor\fR [\fIMONITOR_SEL\fR]] | [\fB\-d\fR,\fB\-\-desktop\fR [\fIDESKTOP_SEL\fR]] | [\fB\-w\fR, \fB\-\-window\fR [\fIWINDOW_SEL\fR]] .RS 4 Constrain matches to the selected monitor, desktop or window\&. @@ -711,6 +716,11 @@ Load the desktop trees from the given file\&. .RS 4 Load the focus history from the given file\&. .RE +.PP +\fB\-S\fR, \fB\-\-stack\fR +.RS 4 +Load the window stacking order from the given file\&. +.RE .RE .SS "Control" .sp diff --git a/doc/bspwm.1.txt b/doc/bspwm.1.txt index 8c283e3..ced5237 100644 --- a/doc/bspwm.1.txt +++ b/doc/bspwm.1.txt @@ -421,6 +421,9 @@ Options *-H*, *--history*:: Print the history as it relates to the query. +*-S*, *--stack*:: + Print the window stacking order. + [*-m*,*--monitor* ['MONITOR_SEL']] | [*-d*,*--desktop* ['DESKTOP_SEL']] | [*-w*, *--window* ['WINDOW_SEL']]:: Constrain matches to the selected monitor, desktop or window. @@ -441,6 +444,9 @@ Options *-H*, *--history* :: Load the focus history from the given file. +*-S*, *--stack* :: + Load the window stacking order from the given file. + Control ~~~~~~~ diff --git a/events.c b/events.c index 46e1b74..d1dba53 100644 --- a/events.c +++ b/events.c @@ -1,12 +1,12 @@ #include #include "bspwm.h" -#include "settings.h" -#include "events.h" +#include "ewmh.h" #include "monitor.h" -#include "window.h" #include "query.h" +#include "settings.h" #include "tree.h" -#include "ewmh.h" +#include "window.h" +#include "events.h" void handle_event(xcb_generic_event_t *evt) { @@ -210,14 +210,14 @@ void client_message(xcb_generic_event_t *evt) if (!honor_ewmh_focus || loc.node == mon->desk->focus) return; if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node) { - set_fullscreen(loc.desktop, loc.desktop->focus, false); + set_fullscreen(loc.desktop->focus, false); arrange(loc.monitor, loc.desktop); } focus_node(loc.monitor, loc.desktop, loc.node); } else if (e->type == ewmh->_NET_WM_DESKTOP) { coordinates_t dloc; if (ewmh_locate_desktop(e->data.data32[0], &dloc)) - transfer_node(loc.monitor, loc.desktop, dloc.monitor, dloc.desktop, loc.node); + transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus); } } @@ -294,11 +294,11 @@ void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsig { if (state == ewmh->_NET_WM_STATE_FULLSCREEN) { if (action == XCB_EWMH_WM_STATE_ADD) - set_fullscreen(d, n, true); + set_fullscreen(n, true); else if (action == XCB_EWMH_WM_STATE_REMOVE) - set_fullscreen(d, n, false); + set_fullscreen(n, false); else if (action == XCB_EWMH_WM_STATE_TOGGLE) - set_fullscreen(d, n, !n->client->fullscreen); + set_fullscreen(n, !n->client->fullscreen); arrange(m, d); } else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) { if (action == XCB_EWMH_WM_STATE_ADD) diff --git a/ewmh.c b/ewmh.c index ae1bfe0..c37d03c 100644 --- a/ewmh.c +++ b/ewmh.c @@ -107,9 +107,6 @@ void ewmh_update_client_list(void) for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) wins[i++] = n->client->window; - if (i != num_clients) - return; - xcb_ewmh_set_client_list(ewmh, default_screen, num_clients, wins); xcb_ewmh_set_client_list_stacking(ewmh, default_screen, num_clients, wins); } diff --git a/examples/loop/bspwmrc b/examples/loop/bspwmrc index 02e1d4b..5238e43 100755 --- a/examples/loop/bspwmrc +++ b/examples/loop/bspwmrc @@ -1,13 +1,6 @@ #! /bin/sh if [ -e "$BSPWM_TREE" ] ; then - bspc restore -T "$BSPWM_TREE" - rm "$BSPWM_TREE" -else - bspc control --adopt-orphans -fi - -if [ -e "$BSPWM_HISTORY" ] ; then - bspc restore -H "$BSPWM_HISTORY" - rm "$BSPWM_HISTORY" + bspc restore -T "$BSPWM_TREE" -H "$BSPWM_HISTORY" -S "$BSPWM_STACK" + rm "$BSPWM_TREE" "$BSPWM_HISTORY" "$BSPWM_STACK" fi diff --git a/examples/loop/profile b/examples/loop/profile index 00cb550..e82cdbe 100644 --- a/examples/loop/profile +++ b/examples/loop/profile @@ -1,2 +1,3 @@ export BSPWM_TREE=/tmp/bspwm.tree export BSPWM_HISTORY=/tmp/bspwm.history +export BSPWM_STACK=/tmp/bspwm.stack diff --git a/history.c b/history.c index 3035535..c99aa8c 100644 --- a/history.c +++ b/history.c @@ -1,118 +1,182 @@ #include -#include "types.h" +#include "bspwm.h" #include "query.h" -focus_history_t *make_focus_history(void) +history_t *make_history(monitor_t *m, desktop_t *d, node_t *n) { - focus_history_t *f = malloc(sizeof(focus_history_t)); - f->head = f->tail = NULL; - return f; + history_t *h = malloc(sizeof(history_t)); + h->loc = (coordinates_t) {m, d, n}; + h->prev = h->next = NULL; + h->latest = true; + return h; } -node_list_t *make_node_list(void) +void history_add(monitor_t *m, desktop_t *d, node_t *n) { - node_list_t *n = malloc(sizeof(node_list_t)); - n->node = NULL; - n->prev = n->next = NULL; - n->latest = true; - return n; + history_t *h = make_history(m, d, n); + if (history_head == NULL) { + history_head = history_tail = h; + } else if ((n != NULL && history_tail->loc.node != n) || (n == NULL && d != history_tail->loc.desktop)) { + for (history_t *hh = history_tail; hh != NULL; hh = hh->prev) + if ((n != NULL && hh->loc.node == n) || (n == NULL && d == hh->loc.desktop)) + hh->latest = false; + history_tail->next = h; + h->prev = history_tail; + history_tail = h; + } else { + free(h); + } } -void history_add(focus_history_t *f, node_t *n) +void history_transfer_node(monitor_t *m, desktop_t *d, node_t *n) { - node_list_t *a = make_node_list(); - a->node = n; - if (f->head == NULL) { - f->head = f->tail = a; - } else if (f->head->node != n) { - for (node_list_t *b = f->head; b != NULL; b = b->next) - if (b->node == n) - b->latest = false; - f->head->prev = a; - a->next = f->head; - f->head = a; - } else { - free(a); - } + for (history_t *h = history_head; h != NULL; h = h->next) + if (h->loc.node == n) { + h->loc.monitor = m; + h->loc.desktop = d; + } +} + +void history_transfer_desktop(monitor_t *m, desktop_t *d) +{ + for (history_t *h = history_head; h != NULL; h = h->next) + if (h->loc.desktop == d) + h->loc.monitor = m; +} + +void history_swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2) +{ + for (history_t *h = history_head; h != NULL; h = h->next) + if (h->loc.node == n1) { + h->loc.monitor = m2; + h->loc.desktop = d2; + } else if (h->loc.node == n2) { + h->loc.monitor = m1; + h->loc.desktop = d1; + } } -void history_remove(focus_history_t *f, node_t *n) +void history_swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2) { - /* in order to maintain the `latest` node list state, - we remove node lists from head to tail */ - node_list_t *b = f->head; + for (history_t *h = history_head; h != NULL; h = h->next) + if (h->loc.desktop == d1) + h->loc.monitor = m2; + else if (h->loc.desktop == d2) + h->loc.monitor = m1; +} + +void history_remove(desktop_t *d, node_t *n) +{ + /* removing from the newest to the oldest is required */ + /* for maintaining the *latest* attribute */ + history_t *b = history_tail; while (b != NULL) { - if (b->node == n) { - node_list_t *a = b->prev; - node_list_t *c = b->next; + if ((n != NULL && n == b->loc.node) || (n == NULL && d == b->loc.desktop)) { + history_t *a = b->next; + history_t *c = b->prev; if (a != NULL) { /* remove duplicate entries */ - while (c != NULL && c->node == a->node) { - node_list_t *d = c->next; - if (f->tail == c) - f->tail = f->head; + while (c != NULL && ((a->loc.node != NULL && a->loc.node == c->loc.node) + || (a->loc.node == NULL && a->loc.desktop == c->loc.desktop))) { + history_t *d = c->prev; + if (history_head == c) + history_head = history_tail; free(c); c = d; } - a->next = c; + a->prev = c; } if (c != NULL) - c->prev = a; - if (f->head == b) - f->head = c; - if (f->tail == b) - f->tail = a; + c->next = a; + if (history_tail == b) + history_tail = c; + if (history_head == b) + history_head = a; free(b); b = c; } else { - b = b->next; + b = b->prev; } } } -void empty_history(focus_history_t *f) +void empty_history(void) { - node_list_t *a = f->head; - while (a != NULL) { - node_list_t *b = a->next; - free(a); - a = b; + history_t *h = history_head; + while (h != NULL) { + history_t *next = h->next; + free(h); + h = next; } - f->head = f->tail = NULL; + history_head = history_tail = NULL; } -node_t *history_get(focus_history_t *f, int i) +node_t *history_get_node(desktop_t *d, node_t *n) { - node_list_t *a = f->head; - while (a != NULL && i > 0) { - a = a->next; - i--; + for (history_t *h = history_tail; h != NULL; h = h->prev) + if (h->latest && h->loc.node != NULL && h->loc.node != n && h->loc.desktop == d) + return h->loc.node; + return NULL; +} + +desktop_t *history_get_desktop(monitor_t *m, desktop_t *d) +{ + for (history_t *h = history_tail; h != NULL; h = h->prev) + if (h->latest && h->loc.desktop != d && h->loc.monitor == m) + return h->loc.desktop; + return NULL; +} + +monitor_t *history_get_monitor(monitor_t *m) +{ + for (history_t *h = history_tail; h != NULL; h = h->prev) + if (h->latest && h->loc.monitor != m) + return h->loc.monitor; + return NULL; +} + +bool history_last_node(node_t *n, client_select_t sel, coordinates_t *loc) +{ + for (history_t *h = history_tail; h != NULL; h = h->prev) { + if (!h->latest || h->loc.node == NULL || h->loc.node == n || !node_matches(n, h->loc.node, sel)) + continue; + *loc = h->loc; + return true; } - if (a == NULL) - return NULL; - else - return a->node; + return false; } -node_t *history_last(focus_history_t *f, node_t *n, client_select_t sel) +bool history_last_desktop(desktop_t *d, desktop_select_t sel, coordinates_t *loc) { - for (node_list_t *a = f->head; a != NULL; a = a->next) { - if (!a->latest || a->node == n || !node_matches(n, a->node, sel)) + for (history_t *h = history_tail; h != NULL; h = h->prev) { + if (!h->latest || h->loc.desktop == d || !desktop_matches(h->loc.desktop, sel)) continue; - return a->node; + *loc = h->loc; + return true; } - return NULL; + return false; +} + +bool history_last_monitor(monitor_t *m, desktop_select_t sel, coordinates_t *loc) +{ + for (history_t *h = history_tail; h != NULL; h = h->prev) { + if (!h->latest || h->loc.monitor == m || !desktop_matches(h->loc.monitor->desk, sel)) + continue; + *loc = h->loc; + return true; + } + return false; } -int history_rank(focus_history_t *f, node_t *n) +int history_rank(desktop_t *d, node_t *n) { int i = 0; - node_list_t *a = f->head; - while (a != NULL && (!a->latest || a->node != n)) { - a = a->next; + history_t *h = history_tail; + while (h != NULL && (!h->latest || h->loc.node != n || h->loc.desktop != d)) { + h = h->prev; i++; } - if (a == NULL) + if (h == NULL) return -1; else return i; diff --git a/history.h b/history.h index 00da5b1..441b9c9 100644 --- a/history.h +++ b/history.h @@ -3,13 +3,21 @@ #include "types.h" -focus_history_t *make_focus_history(void); -node_list_t *make_node_list(void); -void history_add(focus_history_t *, node_t *); -void history_remove(focus_history_t *, node_t *); -void empty_history(focus_history_t *); -node_t *history_get(focus_history_t *, int); -node_t *history_last(focus_history_t *, node_t *, client_select_t); -int history_rank(focus_history_t *, node_t *); +history_t *make_history(monitor_t *, desktop_t *, node_t *); +void history_add(monitor_t *, desktop_t *, node_t *); +void history_insert(monitor_t *, desktop_t *, node_t *); +void history_remove(desktop_t *, node_t *); +void history_transfer_node(monitor_t *, desktop_t *, node_t *); +void history_transfer_desktop(monitor_t *, desktop_t *); +void history_swap_nodes(monitor_t *, desktop_t *, node_t *, monitor_t *, desktop_t *, node_t *); +void history_swap_desktops(monitor_t *, desktop_t *, monitor_t *, desktop_t *); +node_t *history_get_node(desktop_t *, node_t *); +desktop_t *history_get_desktop(monitor_t *, desktop_t *); +monitor_t *history_get_monitor(monitor_t *); +bool *history_last_node(node_t *, client_select_t, coordinates_t *); +bool *history_last_desktop(desktop_t *, desktop_select_t, coordinates_t *); +bool *history_last_monitor(monitor_t *, desktop_select_t, coordinates_t *); +int history_rank(desktop_t *, node_t *); +void empty_history(void); #endif diff --git a/messages.c b/messages.c index 8bda537..d7018bb 100644 --- a/messages.c +++ b/messages.c @@ -1,18 +1,19 @@ +#include #include -#include #include -#include -#include "settings.h" -#include "query.h" +#include #include "bspwm.h" -#include "tree.h" #include "desktop.h" +#include "ewmh.h" +#include "history.h" #include "monitor.h" #include "pointer.h" -#include "window.h" -#include "rule.h" +#include "query.h" #include "restore.h" -#include "ewmh.h" +#include "rule.h" +#include "settings.h" +#include "tree.h" +#include "window.h" #include "messages.h" bool handle_message(char *msg, int msg_len, char *rsp) @@ -111,7 +112,7 @@ bool cmd_window(char **args, int num) num--, args++; coordinates_t dst; if (desktop_from_desc(*args, &trg, &dst)) { - transfer_node(trg.monitor, trg.desktop, dst.monitor, dst.desktop, trg.node); + transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.desktop->focus); trg.monitor = dst.monitor; trg.desktop = dst.desktop; } else { @@ -123,7 +124,7 @@ bool cmd_window(char **args, int num) return false; coordinates_t dst; if (monitor_from_desc(*args, &trg, &dst)) { - transfer_node(trg.monitor, trg.desktop, dst.monitor, dst.monitor->desk, trg.node); + transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.monitor->desk, dst.monitor->desk->focus); trg.monitor = dst.monitor; trg.desktop = dst.monitor->desk; } else { @@ -135,7 +136,7 @@ bool cmd_window(char **args, int num) return false; coordinates_t dst; if (node_from_desc(*args, &trg, &dst)) - transplant_node(trg.monitor, trg.desktop, trg.node, dst.node); + transfer_node(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.node); else return false; dirty = true; @@ -145,9 +146,11 @@ bool cmd_window(char **args, int num) return false; coordinates_t dst; if (node_from_desc(*args, &trg, &dst)) - swap_nodes(trg.node, dst.node); + swap_nodes(trg.monitor, trg.desktop, trg.node, dst.monitor, dst.desktop, dst.node); else return false; + if (trg.desktop != dst.desktop) + arrange(dst.monitor, dst.desktop); dirty = true; } else if (streq("-t", *args) || streq("--toggle", *args)) { num--, args++; @@ -166,10 +169,10 @@ bool cmd_window(char **args, int num) return false; } if (streq("fullscreen", key)) { - set_fullscreen(trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen)); + set_fullscreen(trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen)); dirty = true; } else if (streq("floating", key)) { - set_floating(trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->floating)); + set_floating(trg.node, (a == ALTER_SET ? b : !trg.node->client->floating)); dirty = true; } else if (streq("locked", key)) { set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->locked)); @@ -301,8 +304,12 @@ bool cmd_desktop(char **args, int num) if (!desktop_from_desc(*args, &trg, &dst)) return false; } - if (auto_alternate && dst.desktop == dst.monitor->desk && dst.monitor->last_desk != NULL) - dst.desktop = dst.monitor->last_desk; + if (auto_alternate && dst.desktop == dst.monitor->desk) { + desktop_select_t sel; + sel.status = DESKTOP_STATUS_ALL; + sel.urgency = DESKTOP_URGENCY_ALL; + history_last_desktop(dst.desktop, sel, &dst); + } focus_node(dst.monitor, dst.desktop, dst.desktop->focus); } else if (streq("-m", *args) || streq("--to-monitor", *args)) { num--, args++; @@ -322,7 +329,7 @@ bool cmd_desktop(char **args, int num) return false; coordinates_t dst; if (desktop_from_desc(*args, &trg, &dst) && trg.monitor == dst.monitor) - swap_desktops(dst.monitor, trg.desktop, dst.desktop); + swap_desktops(trg.monitor, trg.desktop, dst.monitor, dst.desktop); else return false; } else if (streq("-l", *args) || streq("--layout", *args)) { @@ -427,8 +434,12 @@ bool cmd_monitor(char **args, int num) if (!monitor_from_desc(*args, &trg, &dst)) return false; } - if (auto_alternate && dst.monitor == mon && last_mon != NULL) - dst.monitor = last_mon; + if (auto_alternate && dst.monitor == mon) { + desktop_select_t sel; + sel.status = DESKTOP_STATUS_ALL; + sel.urgency = DESKTOP_URGENCY_ALL; + history_last_monitor(dst.monitor, sel, &dst); + } focus_node(dst.monitor, dst.monitor->desk, dst.monitor->desk->focus); } else if (streq("-a", *args) || streq("--add-desktops", *args)) { num--, args++; @@ -491,6 +502,8 @@ bool cmd_query(char **args, int num, char *rsp) { dom = DOMAIN_WINDOW, d++; } else if (streq("-H", *args) || streq("--history", *args)) { dom = DOMAIN_HISTORY, d++; + } else if (streq("-S", *args) || streq("--stack", *args)) { + dom = DOMAIN_STACK, d++; } else if (streq("-m", *args) || streq("--monitor", *args)) { trg.monitor = ref.monitor; if (num > 1 && *(args + 1)[0] != OPT_CHR) { @@ -527,6 +540,8 @@ bool cmd_query(char **args, int num, char *rsp) { if (dom == DOMAIN_HISTORY) query_history(trg, rsp); + else if (dom == DOMAIN_STACK) + query_stack(rsp); else if (dom == DOMAIN_WINDOW) query_windows(trg, rsp); else @@ -650,6 +665,11 @@ bool cmd_restore(char **args, int num) { if (num < 1) return false; restore_history(*args); + } else if (streq("-S", *args) || streq("--stack", *args)) { + num--, args++; + if (num < 1) + return false; + restore_stack(*args); } else { return false; } diff --git a/monitor.c b/monitor.c index 7874926..2a36437 100644 --- a/monitor.c +++ b/monitor.c @@ -1,13 +1,14 @@ +#include #include #include -#include -#include "settings.h" #include "bspwm.h" -#include "tree.h" #include "desktop.h" -#include "window.h" -#include "query.h" #include "ewmh.h" +#include "history.h" +#include "query.h" +#include "settings.h" +#include "tree.h" +#include "window.h" #include "monitor.h" monitor_t *make_monitor(xcb_rectangle_t rect) @@ -15,7 +16,7 @@ monitor_t *make_monitor(xcb_rectangle_t rect) monitor_t *m = malloc(sizeof(monitor_t)); snprintf(m->name, sizeof(m->name), "%s%02d", DEFAULT_MON_NAME, ++monitor_uid); m->prev = m->next = NULL; - m->desk = m->last_desk = m->desk_head = m->desk_tail = NULL; + m->desk = m->desk_head = m->desk_tail = NULL; m->rectangle = rect; m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0; m->wired = true; @@ -73,7 +74,6 @@ void select_monitor(monitor_t *m) PRINTF("select monitor %s\n", m->name); - last_mon = mon; mon = m; if (pointer_follows_monitor) @@ -107,6 +107,7 @@ void remove_monitor(monitor_t *m) remove_desktop(m, m->desk_head); monitor_t *prev = m->prev; monitor_t *next = m->next; + monitor_t *last_mon = history_get_monitor(m); if (prev != NULL) prev->next = next; if (next != NULL) @@ -115,18 +116,12 @@ void remove_monitor(monitor_t *m) mon_head = next; if (mon_tail == m) mon_tail = prev; - if (last_mon == m) - last_mon = NULL; if (pri_mon == m) pri_mon = NULL; if (mon == m) { - monitor_t *mm = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon); - if (mm != NULL) { - focus_node(mm, mm->desk, mm->desk->focus); - last_mon = NULL; - } else { - mon = NULL; - } + mon = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon); + if (mon != NULL && mon->desk != NULL) + update_current(); } xcb_destroy_window(dpy, m->root); free(m); diff --git a/pointer.c b/pointer.c index 2b3f3d4..8ae8576 100644 --- a/pointer.c +++ b/pointer.c @@ -1,8 +1,9 @@ #include "bspwm.h" +#include "query.h" #include "settings.h" +#include "stack.h" #include "tree.h" #include "window.h" -#include "query.h" #include "pointer.h" void grab_pointer(pointer_action_t pac) @@ -35,8 +36,8 @@ void grab_pointer(pointer_action_t pac) pointer_follows_monitor = false; focus_node(loc.monitor, loc.desktop, loc.node); pointer_follows_monitor = backup; - } else if (focus_follows_pointer && is_floating(loc.node->client)) { - stack(loc.desktop, loc.node); + } else if (focus_follows_pointer) { + stack(loc.node); } break; case ACTION_MOVE: @@ -172,7 +173,7 @@ void track_pointer(int root_x, int root_y) coordinates_t loc; bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc)); if (is_managed && is_tiled(loc.node->client) && loc.monitor == m) { - swap_nodes(n, loc.node); + swap_nodes(m, d, n, m, d, loc.node); arrange(m, d); } else { if (is_managed && loc.monitor == m) { @@ -188,7 +189,7 @@ void track_pointer(int root_x, int root_y) } } bool focused = (n == mon->desk->focus); - transfer_node(m, d, loc.monitor, loc.desktop, n); + transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus); if (focused) focus_node(loc.monitor, loc.desktop, n); frozen_pointer->monitor = loc.monitor; @@ -205,7 +206,7 @@ void track_pointer(int root_x, int root_y) if (pmon == NULL || pmon == m) return; bool focused = (n == mon->desk->focus); - transfer_node(m, d, pmon, pmon->desk, n); + transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus); if (focused) focus_node(pmon, pmon->desk, n); frozen_pointer->monitor = pmon; diff --git a/query.c b/query.c index 63cf288..5ad484b 100644 --- a/query.c +++ b/query.c @@ -1,11 +1,11 @@ -#include #include +#include #include "bspwm.h" -#include "tree.h" -#include "monitor.h" #include "desktop.h" -#include "messages.h" #include "history.h" +#include "messages.h" +#include "monitor.h" +#include "tree.h" #include "query.h" void query_monitors(coordinates_t loc, domain_t dom, char *rsp) @@ -23,9 +23,7 @@ void query_monitors(coordinates_t loc, domain_t dom, char *rsp) snprintf(line, sizeof(line), "%s %ux%u%+i%+i %i,%i,%i,%i", m->name, m->rectangle.width, m->rectangle.height, m->rectangle.x, m->rectangle.y, m->top_padding, m->right_padding, m->bottom_padding, m->left_padding); strncat(rsp, line, REMLEN(rsp)); if (m == mon) - strncat(rsp, " #", REMLEN(rsp)); - else if (m == last_mon) - strncat(rsp, " ~", REMLEN(rsp)); + strncat(rsp, " *", REMLEN(rsp)); strncat(rsp, "\n", REMLEN(rsp)); } } @@ -49,9 +47,7 @@ void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int snprintf(line, sizeof(line), "%s %i %c", d->name, d->window_gap, (d->layout == LAYOUT_TILED ? 'T' : 'M')); strncat(rsp, line, REMLEN(rsp)); if (d == m->desk) - strncat(rsp, " @", REMLEN(rsp)); - else if (d == m->last_desk) - strncat(rsp, " ~", REMLEN(rsp)); + strncat(rsp, " *", REMLEN(rsp)); strncat(rsp, "\n", REMLEN(rsp)); } query_tree(d, d->root, rsp, depth + 1); @@ -88,19 +84,26 @@ void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth) void query_history(coordinates_t loc, char *rsp) { char line[MAXLEN]; - for (monitor_t *m = mon_head; m != NULL; m = m->next) { - if (loc.monitor != NULL && m != loc.monitor) + for (history_t *h = history_head; h != NULL; h = h->next) { + if ((loc.monitor != NULL && h->loc.monitor != loc.monitor) + || (loc.desktop != NULL && h->loc.desktop != loc.desktop)) continue; - for (desktop_t *d = m->desk_head; d != NULL; d = d->next) { - if (loc.desktop != NULL && d != loc.desktop) - continue; - snprintf(line, sizeof(line), "%s\n", d->name); - strncat(rsp, line, REMLEN(rsp)); - for (node_list_t *a = d->history->tail; a != NULL; a = a->prev) { - snprintf(line, sizeof(line), " %X\n", a->node->client->window); - strncat(rsp, line, REMLEN(rsp)); - } - } + xcb_window_t win = XCB_NONE; + if (h->loc.node != NULL) + win = h->loc.node->client->window; + snprintf(line, sizeof(line), "%s %s 0x%X", h->loc.monitor->name, h->loc.desktop->name, win); + strncat(rsp, line, REMLEN(rsp)); + strncat(rsp, "\n", REMLEN(rsp)); + } +} + +void query_stack(char *rsp) +{ + char line[MAXLEN]; + for (stack_t *s = stack_head; s != NULL; s = s->next) { + snprintf(line, sizeof(line), "0x%X", s->node->client->window); + strncat(rsp, line, REMLEN(rsp)); + strncat(rsp, "\n", REMLEN(rsp)); } } @@ -165,7 +168,7 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst) } else if (parse_cycle_direction(desc, &cyc)) { dst->node = closest_node(ref->desktop, ref->node, cyc, sel); } else if (streq("last", desc)) { - dst->node = history_last(ref->desktop->history, ref->node, sel); + history_last_node(ref->node, sel, dst); } else if (streq("biggest", desc)) { dst->node = find_biggest(ref->desktop, ref->node, sel); } else if (streq("focused", desc)) { @@ -213,10 +216,7 @@ bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst) } else if (parse_index(desc, &idx)) { desktop_from_index(idx, dst); } else if (streq("last", desc)) { - if (mon->last_desk != NULL && desktop_matches(mon->last_desk, sel)) { - dst->monitor = mon; - dst->desktop = mon->last_desk; - } + history_last_desktop(ref->desktop, sel, dst); } else if (streq("focused", desc)) { if (desktop_matches(mon->desk, sel)) { dst->monitor = mon; @@ -257,8 +257,7 @@ bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst) } else if (parse_index(desc, &idx)) { monitor_from_index(idx, dst); } else if (streq("last", desc)) { - if (last_mon != NULL && desktop_matches(last_mon->desk, sel)) - dst->monitor = last_mon; + history_last_monitor(ref->monitor, sel, dst); } else if (streq("primary", desc)) { if (pri_mon != NULL && desktop_matches(pri_mon->desk, sel)) dst->monitor = pri_mon; diff --git a/query.h b/query.h index 7ad2afe..113cfc3 100644 --- a/query.h +++ b/query.h @@ -6,14 +6,16 @@ typedef enum { DOMAIN_DESKTOP, DOMAIN_WINDOW, DOMAIN_TREE, - DOMAIN_HISTORY + DOMAIN_HISTORY, + DOMAIN_STACK } domain_t; void query_monitors(coordinates_t, domain_t, char *); void query_desktops(monitor_t *, domain_t, coordinates_t, unsigned int, char *); +void query_windows(coordinates_t, char *); void query_tree(desktop_t *, node_t *, char *, unsigned int); void query_history(coordinates_t, char *); -void query_windows(coordinates_t, char *); +void query_stack(char *); bool locate_window(xcb_window_t, coordinates_t *); bool locate_desktop(char *, coordinates_t *); bool locate_monitor(char *, coordinates_t *); diff --git a/restore.c b/restore.c index afb8f6a..0b3f334 100644 --- a/restore.c +++ b/restore.c @@ -1,13 +1,14 @@ #include #include #include "bspwm.h" -#include "monitor.h" #include "desktop.h" -#include "tree.h" -#include "settings.h" -#include "query.h" -#include "history.h" #include "ewmh.h" +#include "history.h" +#include "monitor.h" +#include "query.h" +#include "settings.h" +#include "stack.h" +#include "tree.h" #include "restore.h" void restore_tree(char *file_path) @@ -53,11 +54,8 @@ void restore_tree(char *file_path) m->right_padding = right; m->bottom_padding = bottom; m->left_padding = left; - if (end == '#') + if (end != 0) mon = m; - else if (end == '~') - last_mon = m; - } else if (level == 2) { if (m == NULL) continue; @@ -75,10 +73,8 @@ void restore_tree(char *file_path) d->layout = LAYOUT_MONOCLE; else if (layout == 'T') d->layout = LAYOUT_TILED; - if (end == '@') + if (end != 0) m->desk = d; - else if (end == '~') - m->last_desk = d; } else { if (m == NULL || d == NULL) @@ -130,7 +126,7 @@ void restore_tree(char *file_path) else if (sd == 'L') n->split_dir = DIR_LEFT; n->client = c; - if (end == '*') + if (end != 0) d->focus = n; } if (br == 'a') @@ -165,34 +161,70 @@ void restore_history(char *file_path) FILE *snapshot = fopen(file_path, "r"); if (snapshot == NULL) { - warn("Restore history: can't open file\n"); + warn("Restore history: can't open '%s'.\n", file_path); return; } PUTS("restore history"); char line[MAXLEN]; - desktop_t *d = NULL; - unsigned int level; + char mnm[SMALEN]; + char dnm[SMALEN]; + xcb_window_t win; while (fgets(line, sizeof(line), snapshot) != NULL) { - unsigned int i = strlen(line) - 1; - while (i > 0 && isspace(line[i])) - line[i--] = '\0'; - level = 0; - while (level < strlen(line) && isspace(line[level])) - level++; - if (level == 0) { + if (sscanf(line, "%s %s %X", mnm, dnm, &win) == 3) { + coordinates_t loc; + if (win != XCB_NONE && !locate_window(win, &loc)) { + warn("Can't locate window 0x%X.\n", win); + continue; + } + node_t *n = (win == XCB_NONE ? NULL : loc.node); + if (!locate_desktop(dnm, &loc)) { + warn("Can't locate desktop '%s'.\n", dnm); + continue; + } + desktop_t *d = loc.desktop; + if (!locate_monitor(mnm, &loc)) { + warn("Can't locate monitor '%s'.\n", mnm); + continue; + } + monitor_t *m = loc.monitor; + history_add(m, d, n); + } else { + warn("Can't parse history entry: '%s'\n", line); + } + } + + fclose(snapshot); +} + +void restore_stack(char *file_path) +{ + if (file_path == NULL) + return; + + FILE *snapshot = fopen(file_path, "r"); + if (snapshot == NULL) { + warn("Restore stack: can't open '%s'.\n", file_path); + return; + } + + PUTS("restore stack"); + + char line[MAXLEN]; + xcb_window_t win; + + while (fgets(line, sizeof(line), snapshot) != NULL) { + if (sscanf(line, "%X", &win) == 1) { coordinates_t loc; - if (locate_desktop(line + level, &loc)) - d = loc.desktop; - } else if (d != NULL) { - xcb_window_t win; - if (sscanf(line + level, "%X", &win) == 1) { - coordinates_t loc; - if (locate_window(win, &loc)) - history_add(d->history, loc.node); + if (win != XCB_NONE && !locate_window(win, &loc)) { + warn("Can't locate window 0x%X.\n", win); + continue; } + stack_insert_after(stack_tail, loc.node); + } else { + warn("Can't parse stack entry: '%s'\n", line); } } diff --git a/restore.h b/restore.h index d95559f..466f0bb 100644 --- a/restore.h +++ b/restore.h @@ -3,5 +3,6 @@ void restore_tree(char *); void restore_history(char *); +void restore_stack(char *); #endif diff --git a/stack.c b/stack.c new file mode 100644 index 0000000..b6f3f97 --- /dev/null +++ b/stack.c @@ -0,0 +1,151 @@ +#include +#include "bspwm.h" +#include "window.h" +#include "stack.h" + +stack_t *make_stack(node_t *n) +{ + stack_t *s = malloc(sizeof(stack_t)); + s->node = n; + s->prev = s->next = NULL; + return s; +} + +void stack_insert_after(stack_t *a, node_t *n) +{ + stack_t *s = make_stack(n); + if (a == NULL) { + stack_head = stack_tail = s; + } else { + remove_stack_node(n); + stack_t *b = a->next; + if (b != NULL) + b->prev = s; + s->next = b; + s->prev = a; + a->next = s; + if (stack_tail == a) + stack_tail = s; + } +} + +void stack_insert_before(stack_t *a, node_t *n) +{ + stack_t *s = make_stack(n); + if (a == NULL) { + stack_head = stack_tail = s; + } else { + remove_stack_node(n); + stack_t *b = a->prev; + if (b != NULL) + b->next = s; + s->prev = b; + s->next = a; + a->prev = s; + if (stack_head == a) + stack_head = s; + } +} + +void remove_stack(stack_t *s) +{ + if (s == NULL) + return; + stack_t *a = s->prev; + stack_t *b = s->next; + if (a != NULL) + a->next = b; + if (b != NULL) + b->prev = a; + if (s == stack_head) + stack_head = b; + if (s == stack_tail) + stack_tail = a; + free(s); +} + +void remove_stack_node(node_t *n) +{ + for (stack_t *s = stack_head; s != NULL; s = s->next) + if (s->node == n) { + remove_stack(s); + return; + } +} + +void stack(node_t *n) +{ + PRINTF("stack %X\n", n->client->window); + + if (stack_head == NULL) { + stack_insert_after(NULL, n); + } else if (n->client->fullscreen) { + stack_insert_after(stack_tail, n); + window_raise(n->client->window); + } else { + if (n->client->floating && !auto_raise) + return; + stack_t *latest_tiled = NULL; + stack_t *oldest_floating = NULL; + for (stack_t *s = stack_tail; s != NULL; s = s->prev) { + if (s->node != n) { + if (s->node->client->floating == n->client->floating) { + stack_insert_after(s, n); + window_above(n->client->window, s->node->client->window); + return; + } else if (latest_tiled == NULL && !s->node->client->floating) { + latest_tiled = s; + } else if (s->node->client->floating) { + oldest_floating = s; + } + } + } + if (latest_tiled == NULL && oldest_floating == NULL) + return; + if (n->client->floating) { + window_above(n->client->window, latest_tiled->node->client->window); + stack_insert_after(latest_tiled, n); + } else { + window_below(n->client->window, oldest_floating->node->client->window); + stack_insert_before(oldest_floating, n); + } + } +} + +void stack_under(node_t *n) +{ + PRINTF("stack under %X\n", n->client->window); + + if (stack_head == NULL) { + stack_insert_after(NULL, n); + } else if (n->client->fullscreen) { + ; + } else { + if (n->client->floating && !auto_raise) + return; + stack_t *latest_tiled = NULL; + stack_t *oldest_floating = NULL; + for (stack_t *s = stack_head; s != NULL; s = s->next) { + if (s->node != n) { + if (s->node->client->floating == n->client->floating) { + stack_insert_before(s, n); + window_below(n->client->window, s->node->client->window); + return; + } else if (!s->node->client->floating) { + latest_tiled = s; + } else if (oldest_floating == NULL && s->node->client->floating) { + oldest_floating = s; + } + } + } + if (latest_tiled == NULL && oldest_floating == NULL) + return; + if (n->client->floating) { + window_above(n->client->window, latest_tiled->node->client->window); + stack_insert_after(latest_tiled, n); + } else { + window_below(n->client->window, oldest_floating->node->client->window); + stack_insert_before(oldest_floating, n); + } + } +} diff --git a/stack.h b/stack.h new file mode 100644 index 0000000..ecac932 --- /dev/null +++ b/stack.h @@ -0,0 +1,12 @@ +#ifndef _STACK_H +#define _STACK_H + +stack_t *make_stack(node_t *); +void stack_insert_after(stack_t *, node_t *); +void stack_insert_before(stack_t *, node_t *); +void remove_stack(stack_t *); +void remove_stack_node(node_t *); +void stack(node_t *); +void stack_under(node_t *); + +#endif diff --git a/tree.c b/tree.c index fcb8250..5c57995 100644 --- a/tree.c +++ b/tree.c @@ -1,22 +1,23 @@ -#include -#include #include -#include "settings.h" -#include "window.h" +#include #include "bspwm.h" -#include "ewmh.h" -#include "tree.h" #include "desktop.h" -#include "monitor.h" +#include "ewmh.h" #include "history.h" +#include "monitor.h" #include "query.h" +#include "settings.h" +#include "stack.h" +#include "window.h" +#include +#include "tree.h" void arrange(monitor_t *m, desktop_t *d) { if (d->root == NULL) return; - PRINTF("arrange %s%s%s\n", (num_monitors > 1 ? m->name : ""), (num_monitors > 1 ? " " : ""), d->name); + PRINTF("arrange %s %s\n", m->name, d->name); xcb_rectangle_t rect = m->rectangle; int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap); @@ -115,6 +116,7 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f) if (f == NULL) { d->root = n; + d->focus = n; } else { node_t *c = make_node(); node_t *p = f->parent; @@ -206,11 +208,10 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f) void pseudo_focus(desktop_t *d, node_t *n) { - if (n == NULL || d->focus == n) + if (n == NULL) return; d->focus = n; - history_add(d->history, n); - stack(d, n); + stack(n); } void focus_node(monitor_t *m, desktop_t *d, node_t *n) @@ -221,6 +222,11 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n) if (mon->desk != d || n == NULL) clear_input_focus(); + if (n != NULL && d->focus != NULL && d->focus->client->fullscreen) { + set_fullscreen(d->focus, false); + arrange(m, d); + } + if (mon != m) { for (desktop_t *cd = mon->desk_head; cd != NULL; cd = cd->next) window_draw_border(cd->focus, true, false); @@ -239,6 +245,7 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n) select_desktop(m, d); if (n == NULL) { + history_add(m, d, NULL); ewmh_update_active_window(); return; } @@ -248,6 +255,7 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n) n->client->urgent = false; pseudo_focus(d, n); + history_add(m, d, n); set_input_focus(n); if (focus_follows_pointer) { @@ -462,13 +470,13 @@ node_t *nearest_neighbor(desktop_t *d, node_t *n, direction_t dir, client_select node_t *nearest = NULL; if (history_aware_focus) - nearest = nearest_from_history(d->history, n, dir, sel); + nearest = nearest_from_history(d, n, dir, sel); if (nearest == NULL) nearest = nearest_from_distance(d, n, dir, sel); return nearest; } -node_t *nearest_from_history(focus_history_t *f, node_t *n, direction_t dir, client_select_t sel) +node_t *nearest_from_history(desktop_t *d, node_t *n, direction_t dir, client_select_t sel) { if (n == NULL || !is_tiled(n->client)) return NULL; @@ -490,7 +498,7 @@ node_t *nearest_from_history(focus_history_t *f, node_t *n, direction_t dir, cli if (!node_matches(n, a, sel)) continue; - int rank = history_rank(f, a); + int rank = history_rank(d, a); if (rank >= 0 && rank < min_rank) { nearest = a; min_rank = rank; @@ -723,8 +731,11 @@ void unlink_node(desktop_t *d, node_t *n) n->parent = NULL; free(p); - if (n == d->focus) - d->focus = history_get(d->history, 1); + if (n == d->focus) { + d->focus = history_get_node(d, n); + if (d->focus == NULL && d->root != NULL) + d->focus = first_extrema(d->root); + } update_vacant_state(b->parent); } @@ -739,7 +750,8 @@ void remove_node(desktop_t *d, node_t *n) PRINTF("remove node %X\n", n->client->window); unlink_node(d, n); - history_remove(d->history, n); + history_remove(d, n); + remove_stack_node(n); free(n->client); free(n); @@ -763,14 +775,13 @@ void destroy_tree(node_t *n) destroy_tree(second_tree); } -void swap_nodes(node_t *n1, node_t *n2) +void swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2) { if (n1 == NULL || n2 == NULL || n1 == n2) return; - PUTS("swap nodes"); + PRINTF("swap nodes %X %X", n1->client->window, n2->client->window); - /* (n1 and n2 are leaves) */ node_t *pn1 = n1->parent; node_t *pn2 = n2->parent; bool n1_first_child = is_first_child(n1); @@ -802,64 +813,79 @@ void swap_nodes(node_t *n1, node_t *n2) update_vacant_state(n2->parent); } - /* If we ever need to generalize: */ - /* if (d1 != d2) { */ - /* if (d1->root == n1) */ - /* d1->root = n2; */ - /* if (d1->focus == n1) */ - /* d1->focus = n2; */ - /* if (d1->last_focus == n1) */ - /* d1->last_focus = n2; */ - /* if (d2->root == n2) */ - /* d2->root = n1; */ - /* if (d2->focus == n2) */ - /* d2->focus = n1; */ - /* if (d2->last_focus == n2) */ - /* d2->last_focus = n1; */ - /* } */ -} - -void transfer_node(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd, node_t *n) -{ - if (n == NULL || dd == ds) - return; + if (d1 != d2) { + if (d1->root == n1) + d1->root = n2; + if (d1->focus == n1) + d1->focus = n2; + if (d2->root == n2) + d2->root = n1; + if (d2->focus == n2) + d2->focus = n1; + + if (m1 != m2) { + fit_monitor(m1, n2->client); + fit_monitor(m2, n1->client); + } - PRINTF("transfer node %X\n", n->client->window); + ewmh_set_wm_desktop(n1, d2); + ewmh_set_wm_desktop(n2, d1); + history_swap_nodes(m1, d1, n1, m2, d2, n2); - unlink_node(ds, n); - history_remove(ds->history, n); - insert_node(md, dd, n, dd->focus); - ewmh_set_wm_desktop(n, dd); + if (m1->desk != d1 && m2->desk == d2) { + window_show(n1->client->window); + window_hide(n2->client->window); + } else if (m1->desk == d1 && m2->desk != d2) { + window_hide(n1->client->window); + window_show(n2->client->window); + } - if (ds == ms->desk && dd != md->desk) { - if (n == ds->focus) - clear_input_focus(); - window_hide(n->client->window); + update_input_focus(); } +} - fit_monitor(md, n->client); +void transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd) +{ + if (ns == NULL || ns == nd) + return; - if (ds != ms->desk && dd == md->desk) - window_show(n->client->window); + PRINTF("transfer node %X\n", ns->client->window); - pseudo_focus(dd, n); + bool focused = (ns == mon->desk->focus); + bool active = (ns == ds->focus); - arrange(ms, ds); - arrange(md, dd); + if (focused) + clear_input_focus(); - if (ds == ms->desk || dd == md->desk) - update_current(); -} + unlink_node(ds, ns); + insert_node(md, dd, ns, nd); -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); + if (md != ms) + fit_monitor(md, ns->client); + + if (ds != dd) { + ewmh_set_wm_desktop(ns, dd); + if (ds == ms->desk && dd != md->desk) + window_hide(ns->client->window); + else if (ds != ms->desk && dd == md->desk) + window_show(ns->client->window); + } + + history_transfer_node(md, dd, ns); + stack_under(ns); + + if (ds == dd) { + if (focused) + focus_node(md, dd, ns); + else if (active) + pseudo_focus(dd, ns); + } else { + if (focused) + update_current(); + } + + arrange(ms, ds); + arrange(md, dd); } node_t *closest_node(desktop_t *d, node_t *n, cycle_dir_t dir, client_select_t sel) @@ -889,10 +915,10 @@ void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir) 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); + swap_nodes(m, d, f, m, d, 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); + swap_nodes(m, d, f, m, d, s); if (focus_first_child) focus_node(m, d, p->first_child); else diff --git a/tree.h b/tree.h index e338934..e42e886 100644 --- a/tree.h +++ b/tree.h @@ -9,13 +9,14 @@ void focus_node(monitor_t *, desktop_t *, node_t *); void insert_node(monitor_t *, desktop_t *, node_t *, node_t *); void unlink_node(desktop_t *, node_t *); void remove_node(desktop_t *, node_t *); -void swap_nodes(node_t *, node_t *); +void transfer_node(monitor_t *, desktop_t *, node_t *, monitor_t *, desktop_t *, node_t *); +void swap_nodes(monitor_t *, desktop_t *, node_t *, monitor_t *, desktop_t *, node_t *); void pseudo_focus(desktop_t *, node_t *); void update_current(void); node_t *find_fence(node_t *, direction_t); node_t *nearest_neighbor(desktop_t *, node_t *, direction_t, client_select_t); node_t *nearest_from_distance(desktop_t *, node_t *, direction_t, client_select_t); -node_t *nearest_from_history(focus_history_t *, node_t *, direction_t, client_select_t); +node_t *nearest_from_history(desktop_t *, node_t *, direction_t, client_select_t); node_t *find_biggest(desktop_t *, node_t *, client_select_t); bool is_leaf(node_t *); bool is_tiled(client_t *); @@ -40,8 +41,6 @@ void unrotate_brother(node_t *); void flip_tree(node_t *, flip_t); int balance_tree(node_t *); void destroy_tree(node_t *); -void transfer_node(monitor_t *, desktop_t *, monitor_t *, desktop_t *, node_t *); -void transplant_node(monitor_t *, desktop_t *, node_t *, node_t *); node_t *closest_node(desktop_t *, node_t *, cycle_dir_t, client_select_t); void circulate_leaves(monitor_t *, desktop_t *, circulate_dir_t); void update_vacant_state(node_t *); diff --git a/types.h b/types.h index 6527230..ef86326 100644 --- a/types.h +++ b/types.h @@ -161,26 +161,12 @@ struct node_t { client_t *client; /* NULL except for leaves */ }; -typedef struct node_list_t node_list_t; -struct node_list_t { - node_t *node; - bool latest; - node_list_t *prev; - node_list_t *next; -}; - -typedef struct { - node_list_t *head; - node_list_t *tail; -} focus_history_t; - typedef struct desktop_t desktop_t; struct desktop_t { char name[SMALEN]; layout_t layout; node_t *root; node_t *focus; - focus_history_t *history; desktop_t *prev; desktop_t *next; int window_gap; @@ -198,7 +184,6 @@ struct monitor_t { int bottom_padding; int left_padding; desktop_t *desk; - desktop_t *last_desk; desktop_t *desk_head; desktop_t *desk_tail; monitor_t *prev; @@ -211,6 +196,21 @@ typedef struct { node_t *node; } coordinates_t; +typedef struct history_t history_t; +struct history_t { + coordinates_t loc; + bool latest; + history_t *prev; + history_t *next; +}; + +typedef struct stack_t stack_t; +struct stack_t { + node_t *node; + stack_t *prev; + stack_t *next; +}; + typedef struct { char name[SMALEN]; } rule_cause_t; diff --git a/window.c b/window.c index f553802..2352939 100644 --- a/window.c +++ b/window.c @@ -1,92 +1,15 @@ #include #include -#include "types.h" -#include "monitor.h" -#include "tree.h" #include "bspwm.h" -#include "settings.h" #include "ewmh.h" +#include "monitor.h" #include "query.h" #include "rule.h" +#include "settings.h" +#include "stack.h" +#include "tree.h" #include "window.h" -pointer_state_t *make_pointer_state(void) -{ - pointer_state_t *p = malloc(sizeof(pointer_state_t)); - p->monitor = NULL; - p->desktop = NULL; - p->node = p->vertical_fence = p->horizontal_fence = NULL; - p->client = NULL; - p->window = XCB_NONE; - return p; -} - -void center(xcb_rectangle_t a, xcb_rectangle_t *b) -{ - if (b->width < a.width) - b->x = a.x + (a.width - b->width) / 2; - if (b->height < a.height) - b->y = a.y + (a.height - b->height) / 2; -} - -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)); -} - -bool is_inside(monitor_t *m, xcb_point_t pt) -{ - xcb_rectangle_t r = m->rectangle; - return (r.x <= pt.x && pt.x < (r.x + r.width) - && r.y <= pt.y && pt.y < (r.y + r.height)); -} - -xcb_rectangle_t get_rectangle(client_t *c) -{ - if (is_tiled(c)) - return c->tiled_rectangle; - else - return c->floating_rectangle; -} - -void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt) -{ - xcb_rectangle_t rect = get_rectangle(c); - switch (dir) { - case DIR_RIGHT: - pt->x = rect.x + rect.width; - pt->y = rect.y + (rect.height / 2); - break; - case DIR_DOWN: - pt->x = rect.x + (rect.width / 2); - pt->y = rect.y + rect.height; - break; - case DIR_LEFT: - pt->x = rect.x; - pt->y = rect.y + (rect.height / 2); - break; - case DIR_UP: - pt->x = rect.x + (rect.width / 2); - pt->y = rect.y; - break; - } -} - -monitor_t *monitor_from_point(xcb_point_t pt) -{ - for (monitor_t *m = mon_head; m != NULL; m = m->next) - if (is_inside(m, pt)) - return m; - return NULL; -} - -monitor_t *underlying_monitor(client_t *c) -{ - xcb_point_t pt = (xcb_point_t) {c->floating_rectangle.x, c->floating_rectangle.y}; - return monitor_from_point(pt); -} - void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win) { coordinates_t loc; @@ -130,27 +53,24 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win) insert_node(m, d, n, d->focus); disable_floating_atom(c->window); - set_floating(d, n, floating); + set_floating(n, floating); set_locked(m, d, n, locked); if (d->focus != NULL && d->focus->client->fullscreen) - set_fullscreen(d, d->focus, false); + set_fullscreen(d->focus, false); - set_fullscreen(d, n, fullscreen); + set_fullscreen(n, fullscreen); c->transient = transient; bool give_focus = (takes_focus && (d == mon->desk || follow)); - if (give_focus) { + + if (give_focus) focus_node(m, d, n); - } else if (takes_focus) { - pseudo_focus(d, n); - } else { - node_t *f = d->focus; + else if (takes_focus) pseudo_focus(d, n); - if (f != NULL) - pseudo_focus(d, f); - } + else + stack(n); xcb_rectangle_t *frect = &n->client->floating_rectangle; if (frect->x == 0 && frect->y == 0) @@ -177,30 +97,6 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win) ewmh_update_client_list(); } -void adopt_orphans(void) -{ - xcb_query_tree_reply_t *qtr = xcb_query_tree_reply(dpy, xcb_query_tree(dpy, root), NULL); - if (qtr == NULL) - return; - - PUTS("adopt orphans"); - - int len = xcb_query_tree_children_length(qtr); - xcb_window_t *wins = xcb_query_tree_children(qtr); - for (int i = 0; i < len; i++) { - uint32_t idx; - xcb_window_t win = wins[i]; - if (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), &idx, NULL) == 1) { - coordinates_t loc; - if (ewmh_locate_desktop(idx, &loc)) - manage_window(loc.monitor, loc.desktop, win); - else - manage_window(mon, mon->desk, win); - } - } - free(qtr); -} - void window_draw_border(node_t *n, bool focused_window, bool focused_monitor) { if (n == NULL || border_width < 1 || n->client->border_width < 1) @@ -275,6 +171,107 @@ void window_draw_border(node_t *n, bool focused_window, bool focused_monitor) } } +pointer_state_t *make_pointer_state(void) +{ + pointer_state_t *p = malloc(sizeof(pointer_state_t)); + p->monitor = NULL; + p->desktop = NULL; + p->node = p->vertical_fence = p->horizontal_fence = NULL; + p->client = NULL; + p->window = XCB_NONE; + return p; +} + +void center(xcb_rectangle_t a, xcb_rectangle_t *b) +{ + if (b->width < a.width) + b->x = a.x + (a.width - b->width) / 2; + if (b->height < a.height) + b->y = a.y + (a.height - b->height) / 2; +} + +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)); +} + +bool is_inside(monitor_t *m, xcb_point_t pt) +{ + xcb_rectangle_t r = m->rectangle; + return (r.x <= pt.x && pt.x < (r.x + r.width) + && r.y <= pt.y && pt.y < (r.y + r.height)); +} + +xcb_rectangle_t get_rectangle(client_t *c) +{ + if (is_tiled(c)) + return c->tiled_rectangle; + else + return c->floating_rectangle; +} + +void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt) +{ + xcb_rectangle_t rect = get_rectangle(c); + switch (dir) { + case DIR_RIGHT: + pt->x = rect.x + rect.width; + pt->y = rect.y + (rect.height / 2); + break; + case DIR_DOWN: + pt->x = rect.x + (rect.width / 2); + pt->y = rect.y + rect.height; + break; + case DIR_LEFT: + pt->x = rect.x; + pt->y = rect.y + (rect.height / 2); + break; + case DIR_UP: + pt->x = rect.x + (rect.width / 2); + pt->y = rect.y; + break; + } +} + +monitor_t *monitor_from_point(xcb_point_t pt) +{ + for (monitor_t *m = mon_head; m != NULL; m = m->next) + if (is_inside(m, pt)) + return m; + return NULL; +} + +monitor_t *underlying_monitor(client_t *c) +{ + xcb_point_t pt = (xcb_point_t) {c->floating_rectangle.x, c->floating_rectangle.y}; + return monitor_from_point(pt); +} + +void adopt_orphans(void) +{ + xcb_query_tree_reply_t *qtr = xcb_query_tree_reply(dpy, xcb_query_tree(dpy, root), NULL); + if (qtr == NULL) + return; + + PUTS("adopt orphans"); + + int len = xcb_query_tree_children_length(qtr); + xcb_window_t *wins = xcb_query_tree_children(qtr); + for (int i = 0; i < len; i++) { + uint32_t idx; + xcb_window_t win = wins[i]; + if (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), &idx, NULL) == 1) { + coordinates_t loc; + if (ewmh_locate_desktop(idx, &loc)) + manage_window(loc.monitor, loc.desktop, win); + else + manage_window(mon, mon->desk, win); + } + } + free(qtr); +} + void window_close(node_t *n) { if (n == NULL || n->client->locked) @@ -297,7 +294,7 @@ void window_kill(desktop_t *d, node_t *n) remove_node(d, n); } -void set_fullscreen(desktop_t *d, node_t *n, bool value) +void set_fullscreen(node_t *n, bool value) { if (n == NULL || n->client->fullscreen == value) return; @@ -316,10 +313,10 @@ void set_fullscreen(desktop_t *d, node_t *n, bool value) xcb_ewmh_set_wm_state(ewmh, c->window, LENGTH(values), values); } - stack(d, n); + stack(n); } -void set_floating(desktop_t *d, node_t *n, bool value) +void set_floating(node_t *n, bool value) { if (n == NULL || n->client->transient || n->client->fullscreen || n->client->floating == value) return; @@ -339,7 +336,7 @@ void set_floating(desktop_t *d, node_t *n, bool value) rotate_brother(n); } - stack(d, n); + stack(n); } void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value) @@ -502,36 +499,6 @@ void window_below(xcb_window_t w1, xcb_window_t w2) window_stack(w1, w2, XCB_STACK_MODE_BELOW); } -void stack(desktop_t *d, node_t *n) -{ - if (is_leaf(d->root)) - return; - if (n->client->fullscreen) { - window_raise(n->client->window); - } else { - if (n->client->floating && !auto_raise) - return; - xcb_window_t latest_tiled = XCB_NONE; - xcb_window_t oldest_floating = XCB_NONE; - for (node_list_t *a = d->history->head; a != NULL; a = a->next) { - if (a->latest && a->node != n) { - if (a->node->client->floating == n->client->floating) { - window_above(n->client->window, a->node->client->window); - return; - } else if (latest_tiled == XCB_NONE && !a->node->client->floating) { - latest_tiled = a->node->client->window; - } else if (a->node->client->floating) { - oldest_floating = a->node->client->window; - } - } - } - if (n->client->floating) - window_above(n->client->window, latest_tiled); - else - window_below(n->client->window, oldest_floating); - } -} - void window_lower(xcb_window_t win) { uint32_t values[] = {XCB_STACK_MODE_BELOW}; diff --git a/window.h b/window.h index 164b1f9..9a527c3 100644 --- a/window.h +++ b/window.h @@ -3,8 +3,8 @@ #include #include -#include #include +#include #include "types.h" pointer_state_t *make_pointer_state(void); @@ -23,8 +23,8 @@ void update_floating_rectangle(client_t *); void query_pointer(xcb_window_t *, xcb_point_t *); void window_close(node_t *); void window_kill(desktop_t *, node_t *); -void set_fullscreen(desktop_t *, node_t *, bool); -void set_floating(desktop_t *, node_t *, bool); +void set_fullscreen(node_t *, bool); +void set_floating(node_t *, bool); void set_locked(monitor_t *, desktop_t *, node_t *, bool); void set_urgency(monitor_t *, desktop_t *, node_t *, bool); void set_floating_atom(xcb_window_t, uint32_t); @@ -39,8 +39,6 @@ void window_raise(xcb_window_t); void window_stack(xcb_window_t, xcb_window_t, uint32_t); void window_above(xcb_window_t, xcb_window_t); void window_below(xcb_window_t, xcb_window_t); -void stack_tiled(desktop_t *); -void stack(desktop_t *, node_t *); void window_lower(xcb_window_t); void window_set_visibility(xcb_window_t, bool); void window_hide(xcb_window_t); -- 2.44.0