]> git.lizzy.rs Git - bspwm.git/commitdiff
History is global and stacking is independent
authorBastien Dejean <nihilhill@gmail.com>
Tue, 1 Oct 2013 08:48:03 +0000 (10:48 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Tue, 1 Oct 2013 08:48:03 +0000 (10:48 +0200)
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.

28 files changed:
Makefile
Sourcedeps
bspwm.c
bspwm.h
desktop.c
desktop.h
doc/bspwm.1
doc/bspwm.1.txt
events.c
ewmh.c
examples/loop/bspwmrc
examples/loop/profile
history.c
history.h
messages.c
monitor.c
pointer.c
query.c
query.h
restore.c
restore.h
stack.c [new file with mode: 0644]
stack.h [new file with mode: 0644]
tree.c
tree.h
types.h
window.c
window.h

index e19ba8d4203faf90e1727af785f8b44718b1f51f..01881f7c0c9c8983a165b31921625bc84fcd7b13 100644 (file)
--- 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
index a3551bb113bfb3a933244ca30cb55d4ed4ee34d3..aa67aaf843b169e48540f5985389381bf8cdbcfd 100644 (file)
@@ -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 d2b0b029cdcd081d29b1ec4f39255cdb9daf1d83..af9637bf924bcc8528b416bccb712c75cd32a766 100644 (file)
--- 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 414a78c5909a627c1c3c0addea3b2872cf96f9c9..be4c3bd312ca6c0ec9acad29fdadee82eed08fd3 100644 (file)
--- 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;
 
index e3ce391783e6be37d6ed54a40494e5f35ffb55c6..f9aba4a3cd729dc8abcada4282dd2bb8934deb83 100644 (file)
--- a/desktop.c
+++ b/desktop.c
@@ -1,12 +1,12 @@
 #include <stdlib.h>
 #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();
index 792d80e85ad9dcc6f4ef0991a5480a7a13b7933e..990d44a486061cf377a33cad607a8a8a49f1404e 100644 (file)
--- 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 *);
index fd080542c776a7692fd9dad441656da96b07b8fd..00535ae36c3b8c9f20b1a28270af0afdd3e9d742 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: bspwm
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      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 <file_path>
+.RS 4
+Load the window stacking order from the given file\&.
+.RE
 .RE
 .SS "Control"
 .sp
index 8c283e30841601c5458ab98d532dae17d0975f67..ced52372d22241b3a9f3b13c346c4635efe0cfff 100644 (file)
@@ -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* <file_path>::
     Load the focus history from the given file.
 
+*-S*, *--stack* <file_path>::
+    Load the window stacking order from the given file.
+
 Control
 ~~~~~~~
 
index 46e1b74d1ff861e00d07cef83378e0f4479cb195..d1dba5355b582dc1d2f64486abe7b68f4d8b5c9e 100644 (file)
--- a/events.c
+++ b/events.c
@@ -1,12 +1,12 @@
 #include <stdlib.h>
 #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 ae1bfe062523824fa82cb74429afb8610531cb7f..c37d03cd6d551a9a624bb4162e600f39f3cbdccd 100644 (file)
--- 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);
 }
index 02e1d4b94cfe26e88970884d28e01637ecc93bde..5238e43438d61fda50bff325767c1e739acfd978 100755 (executable)
@@ -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
index 00cb550bb5b38a4396f841ff07804d3291752365..e82cdbe2424e050e7c8dd8e78665dc4de66fa8b5 100644 (file)
@@ -1,2 +1,3 @@
 export BSPWM_TREE=/tmp/bspwm.tree
 export BSPWM_HISTORY=/tmp/bspwm.history
+export BSPWM_STACK=/tmp/bspwm.stack
index 30355358a0bb1242d5d1444804367f08d1265883..c99aa8ca486a256bc421b272c7f5d537f20aa45d 100644 (file)
--- a/history.c
+++ b/history.c
 #include <stdlib.h>
-#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;
index 00da5b1079d66dcd0833108f916f292be2cc2d80..441b9c90228e7c3064b9d2d12487c6e7722c76a3 100644 (file)
--- 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
index 8bda5374e6a7e03fec5788d255138e6e959c1ae1..d7018bb32af3932dfef6628453d2e4be63bfb115 100644 (file)
@@ -1,18 +1,19 @@
+#include <errno.h>
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
-#include <errno.h>
-#include "settings.h"
-#include "query.h"
+#include <string.h>
 #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;
         }
index 787492692818351ed558dc4975e50b06b24d5a3d..2a3643784ef4042e0c377941bdbbe672d81c8f13 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -1,13 +1,14 @@
+#include <limits.h>
 #include <stdlib.h>
 #include <string.h>
-#include <limits.h>
-#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);
index 2b3f3d4a2de13cbeb49255dd7eb2d65e72736352..8ae857678e50b6c5a3a038e2424e079273ebe096 100644 (file)
--- 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 63cf2882f264f9bd46457611efd048328933389a..5ad484bdb4e42ff9f2468e4a700b270b44056c19 100644 (file)
--- a/query.c
+++ b/query.c
@@ -1,11 +1,11 @@
-#include <string.h>
 #include <stdio.h>
+#include <string.h>
 #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 7ad2afe601c51c467582f487aae37f56d3ede102..113cfc3bd3900399159ca05ec9de588df43a3d5e 100644 (file)
--- 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 *);
index afb8f6a7e910dd36bf298c5cbd7eb9362a49e376..0b3f3349b9f96d590e2c9fe9c67b2433e3151b40 100644 (file)
--- a/restore.c
+++ b/restore.c
@@ -1,13 +1,14 @@
 #include <ctype.h>
 #include <string.h>
 #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);
         }
     }
 
index d95559f6cca08b75baf61ac82f52314c7217abe7..466f0bbcae4933a05a9a990880a554d92a946893 100644 (file)
--- 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 (file)
index 0000000..b6f3f97
--- /dev/null
+++ b/stack.c
@@ -0,0 +1,151 @@
+#include <stdlib.h>
+#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 (file)
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 fcb8250b54901fe22c4be755bcd79d894b43339d..5c57995db9bf954d3b9aec5603c1365e4d67c0fc 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -1,22 +1,23 @@
-#include <math.h>
-#include <limits.h>
 #include <float.h>
-#include "settings.h"
-#include "window.h"
+#include <limits.h>
 #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 <math.h>
+#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 e3389346f6197d859500f193d2e9fee9fb9d541e..e42e886e3d8b2898c0c558c66e959e1b9038a6b3 100644 (file)
--- 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 6527230e5680119543836116dd0541875d581ab4..ef86326d2992fdb8bb8675777ff6d244c33acfed 100644 (file)
--- 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;
index f55380264d40b678dd0536ad246093ef3d87009f..23529399c5aedaa4bb28e1525b574ba5145907a8 100644 (file)
--- a/window.c
+++ b/window.c
@@ -1,92 +1,15 @@
 #include <stdlib.h>
 #include <string.h>
-#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};
index 164b1f9f4119ee81ed989cf6cbffe3b6d5661e09..9a527c34d4a93686c78d97076b3673b01f087d69 100644 (file)
--- a/window.h
+++ b/window.h
@@ -3,8 +3,8 @@
 
 #include <stdarg.h>
 #include <xcb/xcb.h>
-#include <xcb/xcb_icccm.h>
 #include <xcb/xcb_event.h>
+#include <xcb/xcb_icccm.h>
 #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);