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.
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
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
#include "bspwm.h"
#include "tree.h"
#include "window.h"
+#include "history.h"
+#include "stack.h"
#include "rule.h"
#include "ewmh.h"
{
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;
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);
}
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;
#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)
{
show_desktop(d);
hide_desktop(mon->desk);
- mon->last_desk = mon->desk;
mon->desk = d;
ewmh_update_current_desktop();
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();
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;
}
{
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)
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;
}
PRINTF("remove desktop %s\n", d->name);
unlink_desktop(m, d);
+ history_remove(d, NULL);
empty_desktop(d);
free(d);
num_desktops--;
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;
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();
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 *);
.\" 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
.\" -----------------------------------------------------------------
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\&.
.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
*-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.
*-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
~~~~~~~
#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)
{
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);
}
}
{
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)
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);
}
#! /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
export BSPWM_TREE=/tmp/bspwm.tree
export BSPWM_HISTORY=/tmp/bspwm.history
+export BSPWM_STACK=/tmp/bspwm.stack
#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;
#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
+#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)
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 {
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 {
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;
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++;
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));
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++;
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)) {
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++;
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) {
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
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;
}
+#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)
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;
PRINTF("select monitor %s\n", m->name);
- last_mon = mon;
mon = m;
if (pointer_follows_monitor)
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)
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);
#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)
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:
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) {
}
}
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;
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;
-#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)
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));
}
}
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);
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));
}
}
} 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)) {
} 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;
} 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;
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 *);
#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)
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;
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)
else if (sd == 'L')
n->split_dir = DIR_LEFT;
n->client = c;
- if (end == '*')
+ if (end != 0)
d->focus = n;
}
if (br == 'a')
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);
}
}
void restore_tree(char *);
void restore_history(char *);
+void restore_stack(char *);
#endif
--- /dev/null
+#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);
+ }
+ }
+}
--- /dev/null
+#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
-#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);
if (f == NULL) {
d->root = n;
+ d->focus = n;
} else {
node_t *c = make_node();
node_t *p = f->parent;
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)
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);
select_desktop(m, d);
if (n == NULL) {
+ history_add(m, d, NULL);
ewmh_update_active_window();
return;
}
n->client->urgent = false;
pseudo_focus(d, n);
+ history_add(m, d, n);
set_input_focus(n);
if (focus_follows_pointer) {
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;
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;
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);
}
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);
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);
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)
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
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 *);
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 *);
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;
int bottom_padding;
int left_padding;
desktop_t *desk;
- desktop_t *last_desk;
desktop_t *desk_head;
desktop_t *desk_tail;
monitor_t *prev;
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;
#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;
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)
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)
}
}
+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)
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;
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;
rotate_brother(n);
}
- stack(d, n);
+ stack(n);
}
void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
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};
#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);
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);
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);