diff --git a/Sourcedeps b/Sourcedeps
index 5c93207..894f69e 100644
--- a/Sourcedeps
+++ b/Sourcedeps
@@ -1,18 +1,18 @@
bspc.o: bspc.c common.h helpers.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 subscribe.h types.h window.h
-desktop.o: desktop.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.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 settings.h subscribe.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 bspwm.h helpers.h query.h types.h
messages.o: messages.c bspwm.h common.h desktop.h ewmh.h helpers.h history.h messages.h monitor.h pointer.h query.h restore.h rule.h settings.h subscribe.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
+monitor.o: monitor.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h subscribe.h tree.h types.h window.h
pointer.o: pointer.c bspwm.h helpers.h monitor.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
+query.o: query.c bspwm.h desktop.h helpers.h history.h messages.h monitor.h query.h subscribe.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 messages.h rule.h settings.h types.h window.h
+rule.o: rule.c bspwm.h ewmh.h helpers.h messages.h rule.h settings.h subscribe.h types.h window.h
settings.o: settings.c bspwm.h helpers.h settings.h types.h
stack.o: stack.c bspwm.h helpers.h stack.h types.h window.h
subscribe.o: subscribe.c bspwm.h helpers.h settings.h subscribe.h tree.h types.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 messages.h monitor.h query.h rule.h settings.h stack.h tree.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 subscribe.h tree.h types.h window.h
+window.o: window.c bspwm.h ewmh.h helpers.h messages.h monitor.h query.h rule.h settings.h stack.h subscribe.h tree.h types.h window.h
diff --git a/desktop.c b/desktop.c
index 1e44bac..3e45340 100644
--- a/desktop.c
+++ b/desktop.c
@@ -76,8 +76,9 @@ void change_layout(monitor_t *m, desktop_t *d, layout_t l)
put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout %s %s %s\n", m->name, d->name, l==LAYOUT_TILED?"tiled":"monocle");
d->layout = l;
arrange(m, d);
- if (d == m->desk)
+ if (d == m->desk) {
put_status(SBSC_MASK_REPORT);
+ }
}
void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
@@ -92,19 +93,23 @@ void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
insert_desktop(md, d);
if (d == dd) {
- if (ms->desk != NULL)
+ if (ms->desk != NULL) {
show_desktop(ms->desk);
- if (md->desk != d)
+ }
+ if (md->desk != d) {
hide_desktop(d);
+ }
}
- for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
+ for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
translate_client(ms, 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);
@@ -139,7 +144,6 @@ void initialize_desktop(desktop_t *d)
d->top_padding = d->right_padding = d->bottom_padding = d->left_padding = 0;
d->window_gap = window_gap;
d->border_width = border_width;
- d->floating = false;
}
void insert_desktop(monitor_t *m, desktop_t *d)
diff --git a/doc/bspwm.1 b/doc/bspwm.1
index 38f9c0d..5ecfdd2 100644
--- a/doc/bspwm.1
+++ b/doc/bspwm.1
@@ -2,12 +2,12 @@
.\" Title: bspwm
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1
-.\" Date: 10/27/2015
+.\" Date: 11/05/2015
.\" Manual: Bspwm Manual
.\" Source: Bspwm 0.9
.\" Language: English
.\"
-.TH "BSPWM" "1" "10/27/2015" "Bspwm 0\&.9" "Bspwm Manual"
+.TH "BSPWM" "1" "11/05/2015" "Bspwm 0\&.9" "Bspwm Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@@ -167,7 +167,7 @@ Select a window\&.
.\}
.nf
WINDOW_SEL :=
- | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[\&.floating|\&.tiled][\&.like|\&.unlike][\&.manual|\&.automatic][\&.urgent|\&.nonurgent][\&.local|\&.foreign][\&.focused|\&.unfocused][\&.below|\&.normal|\&.above][\&.fullscreen|\&.nonfullscreen][\&.sticky|\&.nonsticky][\&.public|\&.private][\&.locked|\&.unlocked][\&.pseudotiled|\&.nonpseudotiled]
+ | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[\&.manual|\&.automatic][\&.tiled|nontiled][\&.pseudotiled|\&.nonpseudotiled][\&.floating|\&.nonfloating][\&.fullscreen|\&.nonfullscreen][\&.below|\&.normal|\&.above][\&.local|\&.foreign][\&.like|\&.unlike][\&.focused|\&.unfocused][\&.urgent|\&.nonurgent][\&.sticky|\&.nonsticky][\&.public|\&.private][\&.locked|\&.unlocked]
.fi
.if n \{\
.RE
@@ -225,24 +225,44 @@ Selects the window newer than the focused window in the history\&.
\fBModifiers\fR
.RS 4
.PP
-floating
-.RS 4
-Only consider floating windows\&.
-.RE
-.PP
tiled
.RS 4
Only consider tiled windows\&.
.RE
.PP
-like
+nontiled
.RS 4
-Only consider windows that have the same class as the current window\&.
+Only consider tiled windows\&.
.RE
.PP
-unlike
+pseudotiled
.RS 4
-Only consider windows that have a different class than the current window\&.
+Only consider pseudo\-tiled windows\&.
+.RE
+.PP
+nonpseudotiled
+.RS 4
+Only consider non pseudo\-tiled windows\&.
+.RE
+.PP
+floating
+.RS 4
+Only consider floating windows\&.
+.RE
+.PP
+nonfloating
+.RS 4
+Only consider non floating windows\&.
+.RE
+.PP
+fullscreen
+.RS 4
+Only consider fullscreen windows\&.
+.RE
+.PP
+nonfullscreen
+.RS 4
+Only consider non fullscreen windows\&.
.RE
.PP
manual
@@ -255,6 +275,41 @@ automatic
Only consider windows in automatic splitting mode\&.
.RE
.PP
+focused
+.RS 4
+Only consider focused windows\&.
+.RE
+.PP
+unfocused
+.RS 4
+Only consider unfocused windows\&.
+.RE
+.PP
+below
+.RS 4
+Only consider windows of the BELOW layer\&.
+.RE
+.PP
+normal
+.RS 4
+Only consider windows of the NORMAL layer\&.
+.RE
+.PP
+above
+.RS 4
+Only consider windows of the ABOVE layer\&.
+.RE
+.PP
+like
+.RS 4
+Only consider windows that have the same class as the current window\&.
+.RE
+.PP
+unlike
+.RS 4
+Only consider windows that have a different class than the current window\&.
+.RE
+.PP
local
.RS 4
Only consider windows of the current desktop\&.
@@ -285,16 +340,6 @@ nonurgent
Only consider non urgent windows\&.
.RE
.PP
-pseudotiled
-.RS 4
-Only consider pseudo\-tiled windows\&.
-.RE
-.PP
-nonpseudotiled
-.RS 4
-Only consider non pseudo\-tiled windows\&.
-.RE
-.PP
sticky
.RS 4
Only consider sticky windows\&.
@@ -314,46 +359,6 @@ unlocked
.RS 4
Only consider non locked windows\&.
.RE
-.PP
-nonfullscreen
-.RS 4
-Only consider non fullscreen windows\&.
-.RE
-.PP
-fullscreen
-.RS 4
-Only consider fullscreen windows\&.
-.RE
-.PP
-nonfullscreen
-.RS 4
-Only consider non fullscreen windows\&.
-.RE
-.PP
-focused
-.RS 4
-Only consider focused windows\&.
-.RE
-.PP
-unfocused
-.RS 4
-Only consider unfocused windows\&.
-.RE
-.PP
-below
-.RS 4
-Only consider windows of the BELOW layer\&.
-.RE
-.PP
-normal
-.RS 4
-Only consider windows of the NORMAL layer\&.
-.RE
-.PP
-above
-.RS 4
-Only consider windows of the ABOVE layer\&.
-.RE
.RE
.SS "Desktop"
.sp
@@ -543,9 +548,9 @@ Only consider monitors where the focused desktop is free\&.
.RE
.SH "WINDOW STATES"
.PP
-floating
+tiled
.RS 4
-Can be moved/resized freely\&. Although it doesn\(cqt occupy any tiling space, it is still part of the window tree\&.
+Its size and position are determined by the splitting type and ratio of each node of its path in the window tree\&.
.RE
.PP
pseudo_tiled
@@ -553,10 +558,16 @@ pseudo_tiled
Has an unrestricted size while being centered in its tiling space\&.
.RE
.PP
+floating
+.RS 4
+Can be moved/resized freely\&. Although it doesn\(cqt occupy any tiling space, it is still part of the window tree\&.
+.RE
+.PP
fullscreen
.RS 4
-Fills its monitor rectangle and has no borders\&.
+Fills its monitor rectangle and has no borders\&. It is send in the ABOVE layer by default\&.
.RE
+.SH "WINDOW FLAGS"
.PP
locked
.RS 4
@@ -577,13 +588,13 @@ Tries to keep the same tiling position/size\&.
.PP
urgent
.RS 4
-Has its urgency hint set\&.
+Has its urgency hint set\&. This flag is set externally\&.
.RE
.SH "STACKING LAYERS"
.sp
There\(cqs three stacking layers: BELOW, NORMAL and ABOVE\&.
.sp
-In each layer, floating windows are stacked above tiled windows\&.
+In each layer, the window are orderered as follow: tiled & pseudo\-tiled < fullscreen < floating\&.
.SH "COMMANDS"
.SS "Window"
.sp
@@ -653,9 +664,14 @@ Set or change the splitting ratio of the edge located in the given direction in
Rotate the tree holding the edge located in the given direction in relation to the selected window\&.
.RE
.PP
-\fB\-t\fR, \fB\-\-toggle\fR floating|fullscreen|pseudo_tiled|locked|sticky|private[=on|off]
+\fB\-t\fR, \fB\-\-state\fR tiled|pseudo_tiled|floating|fullscreen
.RS 4
-Set or toggle the given state for the selected window\&.
+Set the state of the selected window\&.
+.RE
+.PP
+\fB\-g\fR, \fB\-\-flag\fR locked|sticky|private[=on|off]
+.RS 4
+Set or toggle the given flag for the selected window\&.
.RE
.PP
\fB\-l\fR, \fB\-\-layer\fR below|normal|above
@@ -758,11 +774,6 @@ Adjust the split ratios of the tree of the selected desktop so that all windows
.RS 4
Circulate the leaves of the tree of the selected desktop\&.
.RE
-.PP
-\fB\-t\fR, \fB\-\-toggle\fR floating[=on|off]
-.RS 4
-Set or toggle the given state for the selected desktop\&.
-.RE
.RE
.SS "Monitor"
.sp
@@ -1015,7 +1026,7 @@ rule \fIOPTIONS\fR
\fBOptions\fR
.RS 4
.PP
-\fB\-a\fR, \fB\-\-add\fR ||* [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [(floating|fullscreen|pseudo_tiled|locked|sticky|private|center|follow|manage|focus|border)=(on|off)] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO]
+\fB\-a\fR, \fB\-\-add\fR ||* [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]
.RS 4
Create a new rule\&.
.RE
diff --git a/doc/bspwm.1.txt b/doc/bspwm.1.txt
index 21cfcca..e20bfa6 100644
--- a/doc/bspwm.1.txt
+++ b/doc/bspwm.1.txt
@@ -134,7 +134,7 @@ Select a window.
----
WINDOW_SEL :=
- | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[.floating|.tiled][.like|.unlike][.manual|.automatic][.urgent|.nonurgent][.local|.foreign][.focused|.unfocused][.below|.normal|.above][.fullscreen|.nonfullscreen][.sticky|.nonsticky][.public|.private][.locked|.unlocked][.pseudotiled|.nonpseudotiled]
+ | (DIR|CYCLE_DIR|biggest|last|focused|older|newer)[.manual|.automatic][.tiled|nontiled][.pseudotiled|.nonpseudotiled][.floating|.nonfloating][.fullscreen|.nonfullscreen][.below|.normal|.above][.local|.foreign][.like|.unlike][.focused|.unfocused][.urgent|.nonurgent][.sticky|.nonsticky][.public|.private][.locked|.unlocked]
----
Primary Selectors
@@ -164,17 +164,29 @@ newer::
Modifiers
^^^^^^^^^
-floating::
- Only consider floating windows.
-
tiled::
Only consider tiled windows.
-like::
- Only consider windows that have the same class as the current window.
+nontiled::
+ Only consider tiled windows.
-unlike::
- Only consider windows that have a different class than the current window.
+pseudotiled::
+ Only consider pseudo-tiled windows.
+
+nonpseudotiled::
+ Only consider non pseudo-tiled windows.
+
+floating::
+ Only consider floating windows.
+
+nonfloating::
+ Only consider non floating windows.
+
+fullscreen::
+ Only consider fullscreen windows.
+
+nonfullscreen::
+ Only consider non fullscreen windows.
manual::
Only consider windows in manual splitting mode.
@@ -182,6 +194,27 @@ manual::
automatic::
Only consider windows in automatic splitting mode.
+focused::
+ Only consider focused windows.
+
+unfocused::
+ Only consider unfocused windows.
+
+below::
+ Only consider windows of the BELOW layer.
+
+normal::
+ Only consider windows of the NORMAL layer.
+
+above::
+ Only consider windows of the ABOVE layer.
+
+like::
+ Only consider windows that have the same class as the current window.
+
+unlike::
+ Only consider windows that have a different class than the current window.
+
local::
Only consider windows of the current desktop.
@@ -200,12 +233,6 @@ urgent::
nonurgent::
Only consider non urgent windows.
-pseudotiled::
- Only consider pseudo-tiled windows.
-
-nonpseudotiled::
- Only consider non pseudo-tiled windows.
-
sticky::
Only consider sticky windows.
@@ -218,30 +245,6 @@ locked::
unlocked::
Only consider non locked windows.
-nonfullscreen::
- Only consider non fullscreen windows.
-
-fullscreen::
- Only consider fullscreen windows.
-
-nonfullscreen::
- Only consider non fullscreen windows.
-
-focused::
- Only consider focused windows.
-
-unfocused::
- Only consider unfocused windows.
-
-below::
- Only consider windows of the BELOW layer.
-
-normal::
- Only consider windows of the NORMAL layer.
-
-above::
- Only consider windows of the ABOVE layer.
-
Desktop
~~~~~~~
@@ -352,14 +355,21 @@ free::
Window States
-------------
-floating::
- Can be moved/resized freely. Although it doesn't occupy any tiling space, it is still part of the window tree.
+tiled::
+ Its size and position are determined by the splitting type and ratio of each node of its path in the window tree.
pseudo_tiled::
Has an unrestricted size while being centered in its tiling space.
+floating::
+ Can be moved/resized freely. Although it doesn't occupy any tiling space, it is still part of the window tree.
+
fullscreen::
- Fills its monitor rectangle and has no borders.
+ Fills its monitor rectangle and has no borders. It is send in the ABOVE layer by default.
+
+
+Window Flags
+-------------
locked::
Ignores the *close* message.
@@ -371,7 +381,7 @@ private::
Tries to keep the same tiling position/size.
urgent::
- Has its urgency hint set.
+ Has its urgency hint set. This flag is set externally.
Stacking Layers
@@ -379,7 +389,7 @@ Stacking Layers
There's three stacking layers: BELOW, NORMAL and ABOVE.
-In each layer, floating windows are stacked above tiled windows.
+In each layer, the window are orderered as follow: tiled & pseudo-tiled < fullscreen < floating.
Commands
@@ -422,8 +432,11 @@ Options
*-R*, *--rotate* 'DIR' '90|270|180'::
Rotate the tree holding the edge located in the given direction in relation to the selected window.
-*-t*, *--toggle* floating|fullscreen|pseudo_tiled|locked|sticky|private[=on|off]::
- Set or toggle the given state for the selected window.
+*-t*, *--state* tiled|pseudo_tiled|floating|fullscreen::
+ Set the state of the selected window.
+
+*-g*, *--flag* locked|sticky|private[=on|off]::
+ Set or toggle the given flag for the selected window.
*-l*, *--layer* below|normal|above::
Set the stacking layer of the selected window.
@@ -483,9 +496,6 @@ Options
*-C*, *--circulate* forward|backward::
Circulate the leaves of the tree of the selected desktop.
-*-t*, *--toggle* floating[=on|off]::
- Set or toggle the given state for the selected desktop.
-
Monitor
~~~~~~~
@@ -626,7 +636,7 @@ rule 'OPTIONS'
Options
^^^^^^^
-*-a*, *--add* ||* [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [(floating|fullscreen|pseudo_tiled|locked|sticky|private|center|follow|manage|focus|border)=(on|off)] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO]::
+*-a*, *--add* ||* [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]::
Create a new rule.
*-r*, *--remove* ^|head|tail|||*...::
diff --git a/events.c b/events.c
index 131f0a7..49dbedb 100644
--- a/events.c
+++ b/events.c
@@ -93,7 +93,7 @@ void configure_request(xcb_generic_event_t *evt)
client_t *c = (is_managed ? loc.node->client : NULL);
int w = 0, h = 0;
- if (is_managed && !c->floating) {
+ if (is_managed && !IS_FLOATING(c)) {
if (e->value_mask & XCB_CONFIG_WINDOW_X)
c->floating_rectangle.x = e->x;
if (e->value_mask & XCB_CONFIG_WINDOW_Y)
@@ -114,14 +114,10 @@ void configure_request(xcb_generic_event_t *evt)
}
xcb_configure_notify_event_t evt;
- xcb_rectangle_t rect;
xcb_window_t win = c->window;
unsigned int bw = c->border_width;
- if (c->fullscreen)
- rect = loc.monitor->rectangle;
- else
- rect = c->tiled_rectangle;
+ xcb_rectangle_t rect = get_rectangle(loc.monitor, c);
evt.response_type = XCB_CONFIGURE_NOTIFY;
evt.event = win;
@@ -136,8 +132,9 @@ void configure_request(xcb_generic_event_t *evt)
xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
- if (c->pseudo_tiled)
+ if (c->state == STATE_PSEUDO_TILED) {
arrange(loc.monitor, loc.desktop);
+ }
} else {
uint16_t mask = 0;
uint32_t values[7];
@@ -195,8 +192,9 @@ void configure_request(xcb_generic_event_t *evt)
xcb_configure_window(dpy, e->window, mask, values);
}
- if (is_managed)
+ if (is_managed) {
translate_client(monitor_from_client(c), loc.monitor, c);
+ }
}
void destroy_notify(xcb_generic_event_t *evt)
@@ -382,41 +380,46 @@ void motion_notify(xcb_generic_event_t *evt)
void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
{
if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
- if (action == XCB_EWMH_WM_STATE_ADD)
- set_fullscreen(n, true);
- else if (action == XCB_EWMH_WM_STATE_REMOVE)
- set_fullscreen(n, false);
- else if (action == XCB_EWMH_WM_STATE_TOGGLE)
- set_fullscreen(n, !n->client->fullscreen);
+ if (action == XCB_EWMH_WM_STATE_ADD) {
+ set_state(m, d, n, STATE_FULLSCREEN);
+ } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
+ set_state(m, d, n, n->client->last_state);
+ } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
+ set_state(m, d, n, IS_FULLSCREEN(n->client) ? n->client->last_state : STATE_FULLSCREEN);
+ }
arrange(m, d);
} else if (state == ewmh->_NET_WM_STATE_BELOW) {
- if (action == XCB_EWMH_WM_STATE_ADD)
- set_layer(n, LAYER_BELOW);
- else if (action == XCB_EWMH_WM_STATE_REMOVE)
- set_layer(n, LAYER_NORMAL);
- else if (action == XCB_EWMH_WM_STATE_TOGGLE)
- set_layer(n, n->client->layer == LAYER_BELOW ? LAYER_NORMAL : LAYER_BELOW);
+ if (action == XCB_EWMH_WM_STATE_ADD) {
+ set_layer(m, d, n, LAYER_BELOW);
+ } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
+ set_layer(m, d, n, LAYER_NORMAL);
+ } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
+ set_layer(m, d, n, n->client->layer == LAYER_BELOW ? n->client->last_layer : LAYER_BELOW);
+ }
} else if (state == ewmh->_NET_WM_STATE_ABOVE) {
- if (action == XCB_EWMH_WM_STATE_ADD)
- set_layer(n, LAYER_ABOVE);
- else if (action == XCB_EWMH_WM_STATE_REMOVE)
- set_layer(n, LAYER_NORMAL);
- else if (action == XCB_EWMH_WM_STATE_TOGGLE)
- set_layer(n, n->client->layer == LAYER_ABOVE ? LAYER_NORMAL : LAYER_ABOVE);
+ if (action == XCB_EWMH_WM_STATE_ADD) {
+ set_layer(m, d, n, LAYER_ABOVE);
+ } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
+ set_layer(m, d, n, n->client->last_layer);
+ } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
+ set_layer(m, d, n, n->client->layer == LAYER_ABOVE ? n->client->last_layer : LAYER_ABOVE);
+ }
} else if (state == ewmh->_NET_WM_STATE_STICKY) {
- if (action == XCB_EWMH_WM_STATE_ADD)
+ if (action == XCB_EWMH_WM_STATE_ADD) {
set_sticky(m, d, n, true);
- else if (action == XCB_EWMH_WM_STATE_REMOVE)
+ } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
set_sticky(m, d, n, false);
- else if (action == XCB_EWMH_WM_STATE_TOGGLE)
+ } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
set_sticky(m, d, n, !n->client->sticky);
+ }
} else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
- if (action == XCB_EWMH_WM_STATE_ADD)
+ if (action == XCB_EWMH_WM_STATE_ADD) {
set_urgency(m, d, n, true);
- else if (action == XCB_EWMH_WM_STATE_REMOVE)
+ } else if (action == XCB_EWMH_WM_STATE_REMOVE) {
set_urgency(m, d, n, false);
- else if (action == XCB_EWMH_WM_STATE_TOGGLE)
+ } else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
set_urgency(m, d, n, !n->client->urgent);
+ }
}
}
diff --git a/examples/bspwmrc b/examples/bspwmrc
index f54e04d..55bb964 100755
--- a/examples/bspwmrc
+++ b/examples/bspwmrc
@@ -10,8 +10,8 @@ bspc config focus_by_distance true
bspc monitor -d I II III IV V VI VII VIII IX X
-bspc rule -a Gimp desktop=^8 follow=on floating=on
+bspc rule -a Gimp desktop=^8 state=floating follow=on
bspc rule -a Chromium desktop=^2
-bspc rule -a mplayer2 floating=on
+bspc rule -a mplayer2 state=floating
bspc rule -a Kupfer.py focus=on
bspc rule -a Screenkey manage=off
diff --git a/examples/sxhkdrc b/examples/sxhkdrc
index b512c84..83dae47 100644
--- a/examples/sxhkdrc
+++ b/examples/sxhkdrc
@@ -8,14 +8,11 @@ super + alt + Escape
super + w
bspc window -c
-super + t
+super + n
bspc desktop -l next
-super + b
- bspc desktop -B
-
-super + {s,f}
- bspc window -t {floating,fullscreen}
+super + {t,p,s,f}
+ bspc window -t {tiled,pseudo_tiled,floating,fullscreen}
super + {grave,Tab}
bspc {window,desktop} -f last
@@ -61,8 +58,11 @@ super + alt + shift + {h,j,k,l}
super + ctrl + {1-9}
bspc window -r 0.{1-9}
+super + {Left,Down,Up,Right}
+ xdo move {-x -20,-y +20,-y -20,-x +20}
+
super + {_,shift + }{1-9,0}
- bspc {desktop -f,window -d} ^{1-9,10}
+ bspc {desktop -f,window -d} '^{1-9,10}'
~button1
bspc pointer -g focus
diff --git a/helpers.h b/helpers.h
index aac0527..f550ec9 100644
--- a/helpers.h
+++ b/helpers.h
@@ -37,6 +37,10 @@
#define BOOLSTR(A) ((A) ? "true" : "false")
#define ONOFFSTR(A) ((A) ? "on" : "off")
#define LAYERSTR(A) ((A) == LAYER_BELOW ? "below" : ((A) == LAYER_NORMAL ? "normal" : "above"))
+#define STATESTR(A) ((A) == STATE_TILED ? "tiled" : ((A) == STATE_FLOATING ? "floating" : ((A) == STATE_FULLSCREEN ? "fullscreen" : "pseudo_tiled")))
+#define IS_TILED(c) (c->state == STATE_TILED || c->state == STATE_PSEUDO_TILED)
+#define IS_FLOATING(c) (c->state == STATE_FLOATING)
+#define IS_FULLSCREEN(c) (c->state == STATE_FULLSCREEN)
#define XCB_CONFIG_WINDOW_X_Y XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
#define XCB_CONFIG_WINDOW_WIDTH_HEIGHT XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT
diff --git a/messages.c b/messages.c
index db00fa9..476b863 100644
--- a/messages.c
+++ b/messages.c
@@ -187,7 +187,21 @@ int cmd_window(char **args, int num)
} else {
return MSG_FAILURE;
}
- } else if (streq("-t", *args) || streq("--toggle", *args)) {
+ } else if (streq("-t", *args) || streq("--state", *args)) {
+ num--, args++;
+ if (num < 1)
+ return MSG_SYNTAX;
+ client_state_t cst;
+ if (parse_client_state(*args, &cst)) {
+ if (trg.node->client->state == cst) {
+ cst = trg.node->client->last_state;
+ }
+ set_state(trg.monitor, trg.desktop, trg.node, cst);
+ dirty = true;
+ } else {
+ return MSG_FAILURE;
+ }
+ } else if (streq("-g", *args) || streq("--flag", *args)) {
num--, args++;
if (num < 1)
return MSG_SYNTAX;
@@ -198,21 +212,13 @@ int cmd_window(char **args, int num)
if (val == NULL) {
a = ALTER_TOGGLE;
} else {
- if (parse_bool(val, &b))
+ if (parse_bool(val, &b)) {
a = ALTER_SET;
- else
+ } else {
return MSG_FAILURE;
+ }
}
- if (streq("fullscreen", key)) {
- set_fullscreen(trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen));
- dirty = true;
- } else if (streq("pseudo_tiled", key)) {
- set_pseudo_tiled(trg.node, (a == ALTER_SET ? b : !trg.node->client->pseudo_tiled));
- dirty = true;
- } else if (streq("floating", key)) {
- set_floating(trg.node, (a == ALTER_SET ? b : !trg.node->client->floating));
- dirty = true;
- } else if (streq("locked", key)) {
+ if (streq("locked", key)) {
set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->locked));
} else if (streq("sticky", key)) {
set_sticky(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->sticky));
@@ -225,7 +231,7 @@ int cmd_window(char **args, int num)
num--, args++;
if (num < 1)
return MSG_SYNTAX;
- if (trg.node->client->floating ||
+ if (IS_FLOATING(trg.node->client) ||
trg.desktop->layout != LAYOUT_TILED)
return MSG_FAILURE;
if (streq("cancel", *args)) {
@@ -257,7 +263,7 @@ int cmd_window(char **args, int num)
num--, args++;
if (num < 2)
return MSG_SYNTAX;
- if (trg.node->client->floating)
+ if (IS_FLOATING(trg.node->client))
return MSG_FAILURE;
direction_t dir;
if (!parse_direction(*args, &dir))
@@ -304,7 +310,7 @@ int cmd_window(char **args, int num)
}
stack_layer_t lyr;
if (parse_stack_layer(*args, &lyr)) {
- set_layer(trg.node, lyr);
+ set_layer(trg.monitor, trg.desktop, trg.node, lyr);
} else {
return MSG_FAILURE;
}
@@ -498,28 +504,6 @@ int cmd_desktop(char **args, int num)
} else {
return MSG_FAILURE;
}
- } else if (streq("-t", *args) || streq("--toggle", *args)) {
- num--, args++;
- if (num < 1)
- return MSG_SYNTAX;
- char *key = strtok(*args, EQL_TOK);
- char *val = strtok(NULL, EQL_TOK);
- alter_state_t a;
- bool b;
- if (val == NULL) {
- a = ALTER_TOGGLE;
- } else {
- if (parse_bool(val, &b))
- a = ALTER_SET;
- else
- return MSG_FAILURE;
- }
- if (streq("floating", key))
- trg.desktop->floating = (a == ALTER_SET ? b : !trg.desktop->floating);
- else
- return MSG_FAILURE;
- } else {
- return MSG_SYNTAX;
}
num--, args++;
}
@@ -1189,6 +1173,8 @@ bool parse_subscriber_mask(char *s, subscriber_mask_t *mask)
*mask = SBSC_MASK_WINDOW_MOVE;
} else if (streq("window_state", s)) {
*mask = SBSC_MASK_WINDOW_STATE;
+ } else if (streq("window_flag", s)) {
+ *mask = SBSC_MASK_WINDOW_FLAG;
} else if (streq("window_layer", s)) {
*mask = SBSC_MASK_WINDOW_LAYER;
} else if (streq("desktop_add", s)) {
@@ -1205,8 +1191,6 @@ bool parse_subscriber_mask(char *s, subscriber_mask_t *mask)
*mask = SBSC_MASK_DESKTOP_FOCUS;
} else if (streq("desktop_layout", s)) {
*mask = SBSC_MASK_DESKTOP_LAYOUT;
- } else if (streq("desktop_state", s)) {
- *mask = SBSC_MASK_DESKTOP_STATE;
} else if (streq("monitor_add", s)) {
*mask = SBSC_MASK_MONITOR_ADD;
} else if (streq("monitor_rename", s)) {
@@ -1249,6 +1233,24 @@ bool parse_layout(char *s, layout_t *l)
return false;
}
+bool parse_client_state(char *s, client_state_t *t)
+{
+ if (streq("tiled", s)) {
+ *t = STATE_TILED;
+ return true;
+ } else if (streq("pseudo_tiled", s)) {
+ *t = STATE_PSEUDO_TILED;
+ return true;
+ } else if (streq("floating", s)) {
+ *t = STATE_FLOATING;
+ return true;
+ } else if (streq("fullscreen", s)) {
+ *t = STATE_FULLSCREEN;
+ return true;
+ }
+ return false;
+}
+
bool parse_stack_layer(char *s, stack_layer_t *l)
{
if (streq("below", s)) {
diff --git a/messages.h b/messages.h
index 20de5a6..7c95fef 100644
--- a/messages.h
+++ b/messages.h
@@ -49,6 +49,7 @@ int get_setting(coordinates_t loc, char *name, FILE* rsp);
bool parse_subscriber_mask(char *s, subscriber_mask_t *mask);
bool parse_bool(char *value, bool *b);
bool parse_layout(char *s, layout_t *l);
+bool parse_client_state(char *s, client_state_t *t);
bool parse_stack_layer(char *s, stack_layer_t *l);
bool parse_direction(char *s, direction_t *d);
bool parse_cycle_direction(char *s, cycle_dir_t *d);
diff --git a/monitor.c b/monitor.c
index 85c0182..74dc57c 100644
--- a/monitor.c
+++ b/monitor.c
@@ -168,26 +168,41 @@ void remove_monitor(monitor_t *m)
PRINTF("remove monitor %s (0x%X)\n", m->name, m->id);
put_status(SBSC_MASK_MONITOR_REMOVE, "monitor_remove %s\n", m->name);
- while (m->desk_head != NULL)
+ while (m->desk_head != NULL) {
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)
+
+ if (prev != NULL) {
prev->next = next;
- if (next != NULL)
+ }
+
+ if (next != NULL) {
next->prev = prev;
- if (mon_head == m)
+ }
+
+ if (mon_head == m) {
mon_head = next;
- if (mon_tail == m)
+ }
+
+ if (mon_tail == m) {
mon_tail = prev;
- if (pri_mon == m)
+ }
+
+ if (pri_mon == m) {
pri_mon = NULL;
+ }
+
if (mon == m) {
mon = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon);
- if (mon != NULL && mon->desk != NULL)
+ if (mon != NULL && mon->desk != NULL) {
update_current();
+ }
}
+
xcb_destroy_window(dpy, m->root);
free(m);
num_monitors--;
diff --git a/pointer.c b/pointer.c
index 4a672e8..6e34615 100644
--- a/pointer.c
+++ b/pointer.c
@@ -69,12 +69,12 @@ void grab_pointer(pointer_action_t pac)
case ACTION_MOVE:
case ACTION_RESIZE_SIDE:
case ACTION_RESIZE_CORNER:
- if (c->floating) {
+ if (IS_FLOATING(c)) {
frozen_pointer->rectangle = c->floating_rectangle;
frozen_pointer->is_tiled = false;
- } else if (!c->floating) {
+ } else if (IS_TILED(c)) {
frozen_pointer->rectangle = c->tiled_rectangle;
- frozen_pointer->is_tiled = (pac == ACTION_MOVE || !c->pseudo_tiled);
+ frozen_pointer->is_tiled = (pac == ACTION_MOVE || c->state == STATE_PSEUDO_TILED);
} else {
frozen_pointer->action = ACTION_NONE;
return;
@@ -197,7 +197,7 @@ void track_pointer(int root_x, int root_y)
return;
coordinates_t loc;
bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
- if (is_managed && !loc.node->client->floating && loc.monitor == m) {
+ if (is_managed && !IS_FLOATING(loc.node->client) && loc.monitor == m) {
swap_nodes(m, d, n, m, d, loc.node);
arrange(m, d);
} else {
@@ -314,11 +314,7 @@ void track_pointer(int root_x, int root_y)
int oldw = w, oldh = h;
restrain_floating_size(c, &w, &h);
- if (c->pseudo_tiled) {
- c->floating_rectangle.width = w;
- c->floating_rectangle.height = h;
- arrange(m, d);
- } else {
+ if (c->state == STATE_FLOATING) {
if (oldw == w) {
c->floating_rectangle.x = x;
c->floating_rectangle.width = w;
@@ -331,6 +327,10 @@ void track_pointer(int root_x, int root_y)
c->floating_rectangle.y,
c->floating_rectangle.width,
c->floating_rectangle.height);
+ } else {
+ c->floating_rectangle.width = w;
+ c->floating_rectangle.height = h;
+ arrange(m, d);
}
}
break;
diff --git a/query.c b/query.c
index 64047a4..767d10d 100644
--- a/query.c
+++ b/query.c
@@ -65,10 +65,10 @@ void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int
fprintf(rsp, "%s\n", d->name);
continue;
} else {
- fprintf(rsp, "%s %u %i %i,%i,%i,%i %c %c%s\n", d->name, d->border_width,
+ fprintf(rsp, "%s %u %i %i,%i,%i,%i %c%s\n", d->name, d->border_width,
d->window_gap,
d->top_padding, d->right_padding, d->bottom_padding, d->left_padding,
- (d->layout == LAYOUT_TILED ? 'T' : 'M'), (d->floating ? 'f' : '-'),
+ (d->layout == LAYOUT_TILED ? 'T' : 'M'),
(d == m->desk ? " *" : ""));
}
query_tree(d, d->root, rsp, depth + 1);
@@ -85,16 +85,16 @@ void query_tree(desktop_t *d, node_t *n, FILE *rsp, unsigned int depth)
if (is_leaf(n)) {
client_t *c = n->client;
- fprintf(rsp, "%c %s %s 0x%X %u %ux%u%+i%+i %c %c%c%c%c%c%c%c%c%c%s\n",
+ fprintf(rsp, "%c %s %s 0x%X %u %ux%u%+i%+i %c%c %c%c %c%c%c%c%s\n",
(n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')),
c->class_name, c->instance_name, c->window, c->border_width,
c->floating_rectangle.width, c->floating_rectangle.height,
c->floating_rectangle.x, c->floating_rectangle.y,
(n->split_dir == DIR_UP ? 'U' : (n->split_dir == DIR_RIGHT ? 'R' : (n->split_dir == DIR_DOWN ? 'D' : 'L'))),
- (c->floating ? 'f' : '-'), (c->pseudo_tiled ? 'd' : '-'), (c->fullscreen ? 'F' : '-'),
- (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'),
- (c->private ? 'i' : '-'), (n->split_mode ? 'p' : '-'),
- (c->layer == LAYER_BELOW ? 'b' : (c->layer == LAYER_ABOVE ? 'a' : '-')),
+ (n->split_mode == MODE_AUTOMATIC ? '-' : 'p'),
+ (c->state == STATE_TILED ? '-' : (c->state == STATE_FLOATING ? 'f' : (c->state == STATE_FULLSCREEN ? 'F' : 'p'))),
+ (c->layer == LAYER_NORMAL ? '-' : (c->layer == LAYER_ABOVE ? 'a' : 'b')),
+ (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'), (c->private ? 'i' : '-'),
(n == d->focus ? " *" : ""));
} else {
fprintf(rsp, "%c %c %lf\n", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'),
@@ -155,6 +155,7 @@ client_select_t make_client_select(void)
OPTION_NONE,
OPTION_NONE,
OPTION_NONE,
+ OPTION_NONE,
NULL
};
return sel;
@@ -182,9 +183,17 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
tok[0] = '\0';
tok++;
- if (streq("floating", tok)) {
+ if (streq("tiled", tok)) {
+ sel.tiled = OPTION_TRUE;
+ } else if (streq("nontiled", tok)) {
+ sel.tiled = OPTION_FALSE;
+ } else if (streq("pseudotiled", tok)) {
+ sel.pseudo_tiled = OPTION_TRUE;
+ } else if (streq("nonpseudotiled", tok)) {
+ sel.pseudo_tiled = OPTION_FALSE;
+ } else if (streq("floating", tok)) {
sel.floating = OPTION_TRUE;
- } else if (streq("tiled", tok)) {
+ } else if (streq("nonfloating", tok)) {
sel.floating = OPTION_FALSE;
} else if (streq("like", tok)) {
sel.same_class = OPTION_TRUE;
@@ -198,10 +207,6 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
sel.fullscreen = OPTION_TRUE;
} else if (streq("nonfullscreen", tok)) {
sel.fullscreen = OPTION_FALSE;
- } else if (streq("pseudotiled", tok)) {
- sel.pseudo_tiled = OPTION_TRUE;
- } else if (streq("nonpseudotiled", tok)) {
- sel.pseudo_tiled = OPTION_FALSE;
} else if (streq("urgent", tok)) {
sel.urgent = OPTION_TRUE;
} else if (streq("nonurgent", tok)) {
@@ -466,15 +471,40 @@ bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
: sel.prop == OPTION_FALSE) { \
return false; \
}
- WSTATE(floating)
- WSTATE(fullscreen)
- WSTATE(pseudo_tiled)
WSTATE(locked)
WSTATE(sticky)
WSTATE(private)
WSTATE(urgent)
#undef MATCHSTATE
+ if (sel.tiled != OPTION_NONE &&
+ loc->node->client->state != STATE_TILED
+ ? sel.tiled == OPTION_TRUE
+ : sel.tiled == OPTION_FALSE) {
+ return false;
+ }
+
+ if (sel.pseudo_tiled != OPTION_NONE &&
+ loc->node->client->state != STATE_PSEUDO_TILED
+ ? sel.pseudo_tiled == OPTION_TRUE
+ : sel.pseudo_tiled == OPTION_FALSE) {
+ return false;
+ }
+
+ if (sel.floating != OPTION_NONE &&
+ loc->node->client->state != STATE_FLOATING
+ ? sel.floating == OPTION_TRUE
+ : sel.floating == OPTION_FALSE) {
+ return false;
+ }
+
+ if (sel.fullscreen != OPTION_NONE &&
+ loc->node->client->state != STATE_FULLSCREEN
+ ? sel.fullscreen == OPTION_TRUE
+ : sel.fullscreen == OPTION_FALSE) {
+ return false;
+ }
+
if (sel.same_class != OPTION_NONE && ref->node != NULL &&
streq(loc->node->client->class_name, ref->node->client->class_name)
? sel.same_class == OPTION_FALSE
@@ -489,7 +519,8 @@ bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
return false;
}
- if (sel.local != OPTION_NONE && loc->desktop != ref->desktop
+ if (sel.local != OPTION_NONE &&
+ loc->desktop != ref->desktop
? sel.local == OPTION_TRUE
: sel.local == OPTION_FALSE) {
return false;
diff --git a/restore.c b/restore.c
index 6ea6fad..5f6217f 100644
--- a/restore.c
+++ b/restore.c
@@ -92,21 +92,23 @@ void restore_tree(char *file_path)
&bw, &wg, &top, &right, &bottom, &left, &layout, &floating, &end);
locate_desktop(name, &loc);
d = loc.desktop;
- if (d == NULL)
+ if (d == NULL) {
continue;
+ }
d->border_width = bw;
d->window_gap = wg;
d->top_padding = top;
d->right_padding = right;
d->bottom_padding = bottom;
d->left_padding = left;
- if (layout == 'M')
+ if (layout == 'M') {
d->layout = LAYOUT_MONOCLE;
- else if (layout == 'T')
+ } else if (layout == 'T') {
d->layout = LAYOUT_TILED;
- d->floating = (floating == '-' ? false : true);
- if (end != 0)
+ }
+ if (end != 0) {
m->desk = d;
+ }
} else {
if (m == NULL || d == NULL)
continue;
@@ -128,76 +130,88 @@ void restore_tree(char *file_path)
birth->parent = n;
}
n = birth;
- char br;
+ char birth_rotation;
if (isupper(line[level])) {
- char st;
- sscanf(line + level, "%c %c %lf", &st, &br, &n->split_ratio);
- if (st == 'H')
+ char split_type;
+ sscanf(line + level, "%c %c %lf", &split_type, &birth_rotation, &n->split_ratio);
+ if (split_type == 'H') {
n->split_type = TYPE_HORIZONTAL;
- else if (st == 'V')
+ } else if (split_type == 'V') {
n->split_type = TYPE_VERTICAL;
+ }
} else {
client_t *c = make_client(XCB_NONE, d->border_width);
num_clients++;
- char floating, pseudo_tiled, fullscreen, urgent, locked, sticky, private, sd, sm, sl, end = 0;
- sscanf(line + level, "%c %s %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c%c%c %c", &br,
+ char urgent, locked, sticky, private, split_dir, split_mode, state, layer, end = 0;
+ sscanf(line + level, "%c %s %s %X %u %hux%hu%hi%hi %c%c %c%c %c%c%c%c %c", &birth_rotation,
c->class_name, c->instance_name, &c->window, &c->border_width,
&c->floating_rectangle.width, &c->floating_rectangle.height,
&c->floating_rectangle.x, &c->floating_rectangle.y,
- &sd, &floating, &pseudo_tiled, &fullscreen, &urgent,
- &locked, &sticky, &private, &sm, &sl, &end);
- c->floating = (floating == '-' ? false : true);
- c->pseudo_tiled = (pseudo_tiled == '-' ? false : true);
- c->fullscreen = (fullscreen == '-' ? false : true);
+ &split_dir, &split_mode, &state, &layer,
+ &urgent, &locked, &sticky, &private, &end);
+ n->split_mode = (split_mode == '-' ? MODE_AUTOMATIC : MODE_MANUAL);
+ if (split_dir == 'U') {
+ n->split_dir = DIR_UP;
+ } else if (split_dir == 'R') {
+ n->split_dir = DIR_RIGHT;
+ } else if (split_dir == 'D') {
+ n->split_dir = DIR_DOWN;
+ } else if (split_dir == 'L') {
+ n->split_dir = DIR_LEFT;
+ }
+ if (state == 'f') {
+ c->state = STATE_FLOATING;
+ } else if (state == 'F') {
+ c->state = STATE_FULLSCREEN;
+ } else if (state == 'p') {
+ c->state = STATE_PSEUDO_TILED;
+ }
+ if (layer == 'b') {
+ c->layer = LAYER_BELOW;
+ } else if (layer == 'a') {
+ c->layer = LAYER_ABOVE;
+ }
c->urgent = (urgent == '-' ? false : true);
c->locked = (locked == '-' ? false : true);
c->sticky = (sticky == '-' ? false : true);
c->private = (private == '-' ? false : true);
- n->split_mode = (sm == '-' ? MODE_AUTOMATIC : MODE_MANUAL);
- if (sd == 'U') {
- n->split_dir = DIR_UP;
- } else if (sd == 'R') {
- n->split_dir = DIR_RIGHT;
- } else if (sd == 'D') {
- n->split_dir = DIR_DOWN;
- } else if (sd == 'L') {
- n->split_dir = DIR_LEFT;
- }
- if (sl == 'b') {
- c->layer = LAYER_BELOW;
- } else if (sl == 'a') {
- c->layer = LAYER_ABOVE;
- }
n->client = c;
- if (end != 0)
+ if (end != 0) {
d->focus = n;
- if (c->sticky)
+ }
+ if (c->sticky) {
m->num_sticky++;
+ }
}
- if (br == 'a')
+ if (birth_rotation == 'a') {
n->birth_rotation = 90;
- else if (br == 'c')
+ } else if (birth_rotation == 'c') {
n->birth_rotation = 270;
- else if (br == 'm')
+ } else if (birth_rotation == 'm') {
n->birth_rotation = 0;
+ }
}
last_level = level;
}
fclose(snapshot);
- for (monitor_t *m = mon_head; m != NULL; m = m->next)
- for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
- if (n->client->floating) {
+ if (!IS_TILED(n->client)) {
n->vacant = true;
update_vacant_state(n->parent);
}
- if (n->client->private)
+ if (n->client->private) {
update_privacy_level(n, true);
+ }
}
+ }
+ }
+
ewmh_update_current_desktop();
}
diff --git a/rule.c b/rule.c
index 3a76a3f..9120eeb 100644
--- a/rule.c
+++ b/rule.c
@@ -95,6 +95,7 @@ rule_consequence_t *make_rule_conquence(void)
rule_consequence_t *rc = calloc(1, sizeof(rule_consequence_t));
rc->manage = rc->focus = rc->border = true;
rc->layer = NULL;
+ rc->state = NULL;
return rc;
}
@@ -153,14 +154,18 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
a == ewmh->_NET_WM_WINDOW_TYPE_UTILITY) {
csq->focus = false;
} else if (a == ewmh->_NET_WM_WINDOW_TYPE_DIALOG) {
- csq->floating = true;
+ if (csq->state == NULL) {
+ csq->state = malloc(sizeof(client_state_t));
+ }
+ *(csq->state) = STATE_FLOATING;
csq->center = true;
} else if (a == ewmh->_NET_WM_WINDOW_TYPE_DOCK ||
a == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP ||
a == ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION) {
csq->manage = false;
- if (a == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP)
+ if (a == ewmh->_NET_WM_WINDOW_TYPE_DESKTOP) {
window_lower(win);
+ }
}
}
xcb_ewmh_get_atoms_reply_wipe(&win_type);
@@ -172,7 +177,10 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
for (unsigned int i = 0; i < win_state.atoms_len; i++) {
xcb_atom_t a = win_state.atoms[i];
if (a == ewmh->_NET_WM_STATE_FULLSCREEN) {
- csq->fullscreen = true;
+ if (csq->state == NULL) {
+ csq->state = malloc(sizeof(client_state_t));
+ }
+ *(csq->state) = STATE_FULLSCREEN;
} else if (a == ewmh->_NET_WM_STATE_BELOW) {
if (csq->layer == NULL) {
csq->layer = malloc(sizeof(stack_layer_t));
@@ -194,8 +202,12 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
if (xcb_icccm_get_wm_normal_hints_reply(dpy, xcb_icccm_get_wm_normal_hints(dpy, win), &size_hints, NULL) == 1) {
if (size_hints.min_width > 0 && size_hints.min_height > 0 &&
size_hints.min_width == size_hints.max_width &&
- size_hints.min_height == size_hints.max_height)
- csq->floating = true;
+ size_hints.min_height == size_hints.max_height) {
+ if (csq->state == NULL) {
+ csq->state = malloc(sizeof(client_state_t));
+ }
+ *(csq->state) = STATE_FLOATING;
+ }
csq->min_width = size_hints.min_width;
csq->max_width = size_hints.max_width;
csq->min_height = size_hints.min_height;
@@ -204,8 +216,12 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
xcb_window_t transient_for = XCB_NONE;
xcb_icccm_get_wm_transient_for_reply(dpy, xcb_icccm_get_wm_transient_for(dpy, win), &transient_for, NULL);
- if (transient_for != XCB_NONE)
- csq->floating = true;
+ if (transient_for != XCB_NONE) {
+ if (csq->state == NULL) {
+ csq->state = malloc(sizeof(client_state_t));
+ }
+ *(csq->state) = STATE_FLOATING;
+ }
xcb_icccm_get_wm_class_reply_t reply;
if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &reply, NULL) == 1) {
@@ -229,8 +245,9 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
key = strtok(NULL, CSQ_BLK);
value = strtok(NULL, CSQ_BLK);
}
- if (rule->one_shot)
+ if (rule->one_shot) {
remove_rule(rule);
+ }
}
rule = next;
}
@@ -238,15 +255,18 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
bool schedule_rules(xcb_window_t win, rule_consequence_t *csq)
{
- if (external_rules_command[0] == '\0')
+ if (external_rules_command[0] == '\0') {
return false;
+ }
int fds[2];
- if (pipe(fds) == -1)
+ if (pipe(fds) == -1) {
return false;
+ }
pid_t pid = fork();
if (pid == 0) {
- if (dpy != NULL)
+ if (dpy != NULL) {
close(xcb_get_file_descriptor(dpy));
+ }
dup2(fds[1], 1);
close(fds[0]);
char wid[SMALEN];
@@ -292,6 +312,14 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
snprintf(csq->node_desc, sizeof(csq->node_desc), "%s", value);
} else if (streq("split_dir", key)) {
snprintf(csq->split_dir, sizeof(csq->split_dir), "%s", value);
+ } else if (streq("state", key)) {
+ client_state_t cst;
+ if (parse_client_state(value, &cst)) {
+ if (csq->state == NULL) {
+ csq->state = malloc(sizeof(client_state_t));
+ }
+ *(csq->state) = cst;
+ }
} else if (streq("layer", key)) {
stack_layer_t lyr;
if (parse_stack_layer(value, &lyr)) {
@@ -306,14 +334,11 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
csq->split_ratio = rat;
}
} else if (parse_bool(value, &v)) {
- if (streq("floating", key))
- csq->floating = v;
+ if (streq("locked", key))
+ csq->locked = true;
#define SETCSQ(name) \
else if (streq(#name, key)) \
csq->name = v;
- SETCSQ(pseudo_tiled)
- SETCSQ(fullscreen)
- SETCSQ(locked)
SETCSQ(sticky)
SETCSQ(private)
SETCSQ(center)
diff --git a/stack.c b/stack.c
index c5db6b1..eabcf46 100644
--- a/stack.c
+++ b/stack.c
@@ -102,31 +102,16 @@ void remove_stack_node(node_t *n)
}
}
+int stack_level(client_t *c)
+{
+ int layer_level = (c->layer == LAYER_NORMAL ? 1 : (c->layer == LAYER_BELOW ? 0 : 2));
+ int state_level = (IS_TILED(c) ? 0 : (IS_FLOATING(c) ? 2 : 1));
+ return 3 * layer_level + state_level;
+}
+
int stack_cmp(client_t *c1, client_t *c2)
{
- if (c1->layer == c2->layer) {
- if (!c1->floating && c2->floating) {
- return -1;
- } else if (c1->floating && !c2->floating) {
- return 1;
- } else {
- return 0;
- }
- } else {
- if (c1->layer == LAYER_BELOW) {
- return -1;
- } else if (c1->layer == LAYER_ABOVE) {
- return 1;
- /* c1->layer == LAYER_NORMAL */
- } else {
- if (c2->layer == LAYER_ABOVE) {
- return -1;
- /* c2->layer == LAYER_BELOW */
- } else {
- return 1;
- }
- }
- }
+ return stack_level(c1) - stack_level(c2);
}
void stack(node_t *n)
@@ -136,8 +121,9 @@ void stack(node_t *n)
if (stack_head == NULL) {
stack_insert_after(NULL, n);
} else {
- if (n->client->floating && !auto_raise)
+ if (IS_FLOATING(n->client) && !auto_raise) {
return;
+ }
stacking_list_t *s = stack_head;
while (s != NULL && stack_cmp(n->client, s->node->client) >= 0) {
s = s->next;
diff --git a/stack.h b/stack.h
index a641aef..069fc38 100644
--- a/stack.h
+++ b/stack.h
@@ -30,6 +30,7 @@ void stack_insert_after(stacking_list_t *a, node_t *n);
void stack_insert_before(stacking_list_t *a, node_t *n);
void remove_stack(stacking_list_t *s);
void remove_stack_node(node_t *n);
+int stack_level(client_t *c);
int stack_cmp(client_t *c1, client_t *c2);
void stack(node_t *n);
diff --git a/subscribe.h b/subscribe.h
index de07f6d..233e0f5 100644
--- a/subscribe.h
+++ b/subscribe.h
@@ -39,19 +39,19 @@ typedef enum {
SBSC_MASK_DESKTOP_TRANSFER = 1 << 10,
SBSC_MASK_DESKTOP_FOCUS = 1 << 11,
SBSC_MASK_DESKTOP_LAYOUT = 1 << 12,
- SBSC_MASK_DESKTOP_STATE = 1 << 13,
- SBSC_MASK_WINDOW_MANAGE = 1 << 14,
- SBSC_MASK_WINDOW_UNMANAGE = 1 << 15,
- SBSC_MASK_WINDOW_SWAP = 1 << 16,
- SBSC_MASK_WINDOW_TRANSFER = 1 << 17,
- SBSC_MASK_WINDOW_FOCUS = 1 << 18,
- SBSC_MASK_WINDOW_RESIZE = 1 << 19,
- SBSC_MASK_WINDOW_MOVE = 1 << 20,
- SBSC_MASK_WINDOW_STATE = 1 << 21,
+ SBSC_MASK_WINDOW_MANAGE = 1 << 13,
+ SBSC_MASK_WINDOW_UNMANAGE = 1 << 14,
+ SBSC_MASK_WINDOW_SWAP = 1 << 15,
+ SBSC_MASK_WINDOW_TRANSFER = 1 << 16,
+ SBSC_MASK_WINDOW_FOCUS = 1 << 17,
+ SBSC_MASK_WINDOW_RESIZE = 1 << 18,
+ SBSC_MASK_WINDOW_MOVE = 1 << 19,
+ SBSC_MASK_WINDOW_STATE = 1 << 20,
+ SBSC_MASK_WINDOW_FLAG = 1 << 21,
SBSC_MASK_WINDOW_LAYER = 1 << 22,
SBSC_MASK_MONITOR = (1 << 6) - (1 << 1),
- SBSC_MASK_DESKTOP = (1 << 14) - (1 << 6),
- SBSC_MASK_WINDOW = (1 << 23) - (1 << 14),
+ SBSC_MASK_DESKTOP = (1 << 13) - (1 << 6),
+ SBSC_MASK_WINDOW = (1 << 23) - (1 << 13),
SBSC_MASK_ALL = (1 << 23) - 1
} subscriber_mask_t;
diff --git a/tree.c b/tree.c
index f5d44a4..043122e 100644
--- a/tree.c
+++ b/tree.c
@@ -69,42 +69,39 @@ void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, x
if (is_leaf(n)) {
unsigned int bw;
- if ((borderless_monocle && !n->client->floating &&
- !n->client->pseudo_tiled &&
- d->layout == LAYOUT_MONOCLE) ||
- n->client->fullscreen)
+ if ((borderless_monocle && n->client->state == STATE_TILED && d->layout == LAYOUT_MONOCLE)
+ || n->client->state == STATE_FULLSCREEN) {
bw = 0;
- else
+ } else {
bw = n->client->border_width;
+ }
xcb_rectangle_t r;
- if (!n->client->fullscreen) {
- if (!n->client->floating) {
- int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
- if (n->client->pseudo_tiled) {
- /* pseudo-tiled clients */
- r = n->client->floating_rectangle;
- if (center_pseudo_tiled) {
- r.x = rect.x - bw + (rect.width - wg - r.width) / 2;
- r.y = rect.y - bw + (rect.height - wg - r.height) / 2;
- } else {
- r.x = rect.x;
- r.y = rect.y;
- }
- } else {
- /* tiled clients */
- r = rect;
- int bleed = wg + 2 * bw;
- r.width = (bleed < r.width ? r.width - bleed : 1);
- r.height = (bleed < r.height ? r.height - bleed : 1);
- }
- n->client->tiled_rectangle = r;
+ client_state_t s = n->client->state;
+ if (s == STATE_TILED || s == STATE_PSEUDO_TILED) {
+ int wg = (gapless_monocle && d->layout == LAYOUT_MONOCLE ? 0 : d->window_gap);
+ /* tiled clients */
+ if (s == STATE_TILED) {
+ r = rect;
+ int bleed = wg + 2 * bw;
+ r.width = (bleed < r.width ? r.width - bleed : 1);
+ r.height = (bleed < r.height ? r.height - bleed : 1);
+ /* pseudo-tiled clients */
} else {
- /* floating clients */
r = n->client->floating_rectangle;
+ if (center_pseudo_tiled) {
+ r.x = rect.x - bw + (rect.width - wg - r.width) / 2;
+ r.y = rect.y - bw + (rect.height - wg - r.height) / 2;
+ } else {
+ r.x = rect.x;
+ r.y = rect.y;
+ }
}
+ /* floating clients */
+ } else if (s == STATE_FLOATING) {
+ r = n->client->floating_rectangle;
+ /* fullscreen clients */
} else {
- /* fullscreen clients */
r = m->rectangle;
}
@@ -231,8 +228,9 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
c->second_child = n;
rot = 270;
}
- if (!n->client->floating)
+ if (IS_TILED(n->client)) {
rotate_tree(p, rot);
+ }
n->birth_rotation = rot;
}
break;
@@ -331,20 +329,23 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
n->client->urgent = false;
put_status(SBSC_MASK_REPORT);
}
- if (d->focus != NULL && n != d->focus && d->focus->client->fullscreen && stack_cmp(n->client, d->focus->client) <= 0) {
- set_fullscreen(d->focus, false);
- arrange(m, d);
+ if (d->focus != NULL && n != d->focus && stack_cmp(n->client, d->focus->client) < 0) {
+ neutralize_obscuring_windows(m, d, n);
}
}
if (mon != m) {
- for (desktop_t *cd = mon->desk_head; cd != NULL; cd = cd->next)
+ for (desktop_t *cd = mon->desk_head; cd != NULL; cd = cd->next) {
window_draw_border(cd->focus, true, false);
- for (desktop_t *cd = m->desk_head; cd != NULL; cd = cd->next)
- if (cd != d)
+ }
+ for (desktop_t *cd = m->desk_head; cd != NULL; cd = cd->next) {
+ if (cd != d) {
window_draw_border(cd->focus, true, true);
- if (d->focus == n)
+ }
+ }
+ if (d->focus == n) {
window_draw_border(n, true, true);
+ }
}
if (d->focus != n) {
@@ -381,7 +382,7 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
}
if (pointer_follows_focus) {
- center_pointer(get_rectangle(n->client));
+ center_pointer(get_rectangle(m, n->client));
}
ewmh_update_active_window();
@@ -410,11 +411,11 @@ client_t *make_client(xcb_window_t win, unsigned int border_width)
{
client_t *c = malloc(sizeof(client_t));
c->window = win;
+ c->state = c->last_state = STATE_TILED;
c->layer = c->last_layer = LAYER_NORMAL;
snprintf(c->class_name, sizeof(c->class_name), "%s", MISSING_VALUE);
snprintf(c->instance_name, sizeof(c->instance_name), "%s", MISSING_VALUE);
c->border_width = border_width;
- c->pseudo_tiled = c->floating = c->fullscreen = false;
c->locked = c->sticky = c->urgent = c->private = c->icccm_focus = false;
xcb_icccm_get_wm_protocols_reply_t protocols;
if (xcb_icccm_get_wm_protocols_reply(dpy, xcb_icccm_get_wm_protocols(dpy, win, ewmh->WM_PROTOCOLS), &protocols, NULL) == 1) {
@@ -479,7 +480,7 @@ void closest_public(desktop_t *d, node_t *n, node_t **closest, node_t **public)
while (prev != NULL || next != NULL) {
#define TESTLOOP(n) \
if (n != NULL) { \
- if (!n->client->floating) { \
+ if (IS_TILED(n->client)) { \
if (n->privacy_level == 0) { \
if (n->parent == NULL || n->parent->privacy_level == 0) { \
*public = n; \
@@ -544,7 +545,7 @@ node_t *prev_leaf(node_t *n, node_t *r)
node_t *next_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
{
node_t *next = next_leaf(n, r);
- if (next == NULL || !next->client->floating)
+ if (next == NULL || IS_TILED(next->client))
return next;
else
return next_tiled_leaf(d, next, r);
@@ -553,25 +554,12 @@ node_t *next_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
node_t *prev_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
{
node_t *prev = prev_leaf(n, r);
- if (prev == NULL || !prev->client->floating)
+ if (prev == NULL || IS_TILED(prev->client))
return prev;
else
return prev_tiled_leaf(d, prev, r);
}
-/* bool is_adjacent(node_t *a, node_t *r) */
-/* { */
-/* node_t *f = r->parent; */
-/* node_t *p = a; */
-/* bool first_child = is_first_child(r); */
-/* while (p != r) { */
-/* if (p->parent->split_type == f->split_type && is_first_child(p) == first_child) */
-/* return false; */
-/* p = p->parent; */
-/* } */
-/* return true; */
-/* } */
-
/* Returns true if *b* is adjacent to *a* in the direction *dir* */
bool is_adjacent(node_t *a, node_t *b, direction_t dir)
{
@@ -615,8 +603,8 @@ node_t *find_fence(node_t *n, direction_t dir)
node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
{
- if (n == NULL || n->client->fullscreen ||
- (d->layout == LAYOUT_MONOCLE && !n->client->floating))
+ if (n == NULL || IS_FULLSCREEN(n->client) ||
+ (d->layout == LAYOUT_MONOCLE && IS_TILED(n->client)))
return NULL;
node_t *nearest = NULL;
@@ -634,8 +622,9 @@ node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir,
node_t *nearest_from_tree(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
{
- if (n == NULL)
+ if (n == NULL) {
return NULL;
+ }
node_t *fence = find_fence(n, dir);
@@ -644,24 +633,27 @@ node_t *nearest_from_tree(monitor_t *m, desktop_t *d, node_t *n, direction_t dir
node_t *nearest = NULL;
- if (dir == DIR_UP || dir == DIR_LEFT)
+ if (dir == DIR_UP || dir == DIR_LEFT) {
nearest = second_extrema(fence->first_child);
- else if (dir == DIR_DOWN || dir == DIR_RIGHT)
+ } else if (dir == DIR_DOWN || dir == DIR_RIGHT) {
nearest = first_extrema(fence->second_child);
+ }
coordinates_t ref = {m, d, n};
coordinates_t loc = {m, d, nearest};
- if (node_matches(&loc, &ref, sel))
+ if (node_matches(&loc, &ref, sel)) {
return nearest;
- else
+ } else {
return NULL;
+ }
}
node_t *nearest_from_history(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
{
- if (n == NULL || n->client->floating)
+ if (n == NULL || !IS_TILED(n->client)) {
return NULL;
+ }
node_t *target = find_fence(n, dir);
if (target == NULL)
@@ -699,7 +691,7 @@ node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t
node_t *target = NULL;
- if (!n->client->floating) {
+ if (IS_TILED(n->client)) {
target = find_fence(n, dir);
if (target == NULL)
return NULL;
@@ -724,8 +716,8 @@ node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t
coordinates_t loc = {m, d, a};
if (a == n ||
!node_matches(&loc, &ref, sel) ||
- !a->client->floating != !n->client->floating ||
- (!a->client->floating && !is_adjacent(n, a, dir)))
+ IS_TILED(a->client) != IS_TILED(n->client) ||
+ (IS_TILED(a->client) && !is_adjacent(n, a, dir)))
continue;
get_side_handle(a->client, dir2, &pt2);
@@ -769,7 +761,7 @@ int tiled_count(desktop_t *d)
{
int cnt = 0;
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
- if (!f->client->floating) {
+ if (IS_TILED(f->client)) {
cnt++;
}
}
@@ -787,7 +779,7 @@ node_t *find_biggest(monitor_t *m, desktop_t *d, node_t *n, client_select_t sel)
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
coordinates_t loc = {m, d, f};
- if (f->client->floating || !node_matches(&loc, &ref, sel))
+ if (IS_FLOATING(f->client) || !node_matches(&loc, &ref, sel))
continue;
int f_area = tiled_area(f);
if (r == NULL) {
diff --git a/types.h b/types.h
index 0fbefa5..e99f9d1 100644
--- a/types.h
+++ b/types.h
@@ -43,6 +43,13 @@ typedef enum {
MODE_MANUAL
} split_mode_t;
+typedef enum {
+ STATE_TILED,
+ STATE_PSEUDO_TILED,
+ STATE_FLOATING,
+ STATE_FULLSCREEN
+} client_state_t;
+
typedef enum {
LAYER_BELOW,
LAYER_NORMAL,
@@ -120,8 +127,9 @@ typedef enum {
} child_polarity_t;
typedef struct {
- option_bool_t floating;
+ option_bool_t tiled;
option_bool_t pseudo_tiled;
+ option_bool_t floating;
option_bool_t fullscreen;
option_bool_t locked;
option_bool_t sticky;
@@ -145,14 +153,13 @@ typedef struct {
char class_name[3 * SMALEN / 2];
char instance_name[3 * SMALEN / 2];
unsigned int border_width;
- bool pseudo_tiled;
- bool floating;
- bool fullscreen;
bool locked; /* protects window from being closed */
bool sticky;
bool urgent;
bool private;
bool icccm_focus;
+ client_state_t state;
+ client_state_t last_state;
stack_layer_t layer;
stack_layer_t last_layer;
xcb_rectangle_t floating_rectangle;
@@ -195,7 +202,6 @@ struct desktop_t {
int left_padding;
int window_gap;
unsigned int border_width;
- bool floating;
};
typedef struct monitor_t monitor_t;
@@ -264,14 +270,12 @@ typedef struct {
char node_desc[MAXLEN];
char split_dir[SMALEN];
stack_layer_t *layer;
+ client_state_t *state;
double split_ratio;
uint16_t min_width;
uint16_t max_width;
uint16_t min_height;
uint16_t max_height;
- bool pseudo_tiled;
- bool floating;
- bool fullscreen;
bool locked;
bool sticky;
bool private;
diff --git a/window.c b/window.c
index 55acbed..5d0560d 100644
--- a/window.c
+++ b/window.c
@@ -72,6 +72,8 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
parse_rule_consequence(fd, csq);
if (!csq->manage) {
+ free(csq->layer);
+ free(csq->state);
disable_floating_atom(win);
window_show(win);
return;
@@ -142,41 +144,37 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
snprintf(c->class_name, sizeof(c->class_name), "%s", csq->class_name);
snprintf(c->instance_name, sizeof(c->instance_name), "%s", csq->instance_name);
- csq->floating = csq->floating || d->floating;
-
node_t *n = make_node();
n->client = c;
put_status(SBSC_MASK_WINDOW_MANAGE, "window_manage %s %s 0x%X 0x%X\n", m->name, d->name, f!=NULL?f->client->window:0, win);
insert_node(m, d, n, f);
- if (f != NULL && f->client != NULL && csq->floating) {
+ if (f != NULL && f->client != NULL && csq->state != NULL && *(csq->state) == STATE_FLOATING) {
c->layer = f->client->layer;
}
if (csq->layer != NULL) {
c->layer = *(csq->layer);
- free(csq->layer);
}
disable_floating_atom(c->window);
- set_pseudo_tiled(n, csq->pseudo_tiled);
- set_floating(n, csq->floating);
+ set_state(m, d, n, csq->state != NULL ? *(csq->state) : c->state);
set_locked(m, d, n, csq->locked);
set_sticky(m, d, n, csq->sticky);
set_private(m, d, n, csq->private);
- set_fullscreen(n, csq->fullscreen);
arrange(m, d);
bool give_focus = (csq->focus && (d == mon->desk || csq->follow));
- if (give_focus)
+ if (give_focus) {
focus_node(m, d, n);
- else if (csq->focus)
+ } else if (csq->focus) {
pseudo_focus(m, d, n);
- else
+ } else {
stack(n);
+ }
uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values);
@@ -189,12 +187,15 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
}
/* the same function is already called in `focus_node` but has no effects on unmapped windows */
- if (give_focus)
+ if (give_focus) {
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
+ }
num_clients++;
ewmh_set_wm_desktop(n, d);
ewmh_update_client_list();
+ free(csq->layer);
+ free(csq->state);
}
void unmanage_window(xcb_window_t win)
@@ -233,7 +234,7 @@ void window_draw_border(node_t *n, bool focused_window, bool focused_monitor)
uint32_t presel_border_color_pxl;
get_color(presel_border_color, win, &presel_border_color_pxl);
- xcb_rectangle_t actual_rectangle = get_rectangle(n->client);
+ xcb_rectangle_t actual_rectangle = get_rectangle(NULL, n->client);
uint16_t width = actual_rectangle.width;
uint16_t height = actual_rectangle.height;
@@ -312,17 +313,26 @@ bool contains(xcb_rectangle_t a, xcb_rectangle_t b)
a.y <= b.y && (a.y + a.height) >= (b.y + b.height));
}
-xcb_rectangle_t get_rectangle(client_t *c)
+xcb_rectangle_t get_rectangle(monitor_t *m, client_t *c)
{
- if (!c->floating)
- return c->tiled_rectangle;
- else
- return c->floating_rectangle;
+ switch (c->state) {
+ case STATE_TILED:
+ return c->tiled_rectangle;
+ break;
+ case STATE_PSEUDO_TILED:
+ case STATE_FLOATING:
+ return c->floating_rectangle;
+ break;
+ case STATE_FULLSCREEN:
+ return m->rectangle;
+ break;
+ }
}
void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt)
{
- xcb_rectangle_t rect = get_rectangle(c);
+ xcb_rectangle_t rect = get_rectangle(NULL, c);
+
switch (dir) {
case DIR_RIGHT:
pt->x = rect.x + rect.width;
@@ -385,68 +395,75 @@ void window_kill(monitor_t *m, desktop_t *d, node_t *n)
remove_node(m, d, n);
}
-void set_fullscreen(node_t *n, bool value)
+void set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l)
{
- if (n == NULL || n->client->fullscreen == value)
+ if (n == NULL || n->client->layer == l) {
return;
+ }
client_t *c = n->client;
- PRINTF("fullscreen %X: %s\n", c->window, BOOLSTR(value));
- put_status(SBSC_MASK_WINDOW_STATE, "window_state fullscreen %s 0x%X\n", ONOFFSTR(value), c->window);
+ c->layer = l;
- c->fullscreen = value;
- if (value) {
- ewmh_wm_state_add(c, ewmh->_NET_WM_STATE_FULLSCREEN);
- c->last_layer = c->layer;
- c->layer = LAYER_ABOVE;
- } else {
- ewmh_wm_state_remove(c, ewmh->_NET_WM_STATE_FULLSCREEN);
- c->layer = c->last_layer;
+ put_status(SBSC_MASK_WINDOW_LAYER, "window_layer %s 0x%X\n", LAYERSTR(l), c->window);
+
+ if (d->focus == n) {
+ neutralize_obscuring_windows(m, d, n);
}
stack(n);
}
-void set_layer(node_t *n, stack_layer_t layer)
+void set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s)
{
- if (n == NULL || n->client->layer == layer) {
+ if (n == NULL || n->client->state == s) {
return;
}
client_t *c = n->client;
- c->layer = layer;
- put_status(SBSC_MASK_WINDOW_LAYER, "window_layer %s 0x%X\n", LAYERSTR(layer), c->window);
+ c->last_state = c->state;
+ c->state = s;
- stack(n);
+ switch (c->last_state) {
+ case STATE_TILED:
+ case STATE_PSEUDO_TILED:
+ break;
+ case STATE_FLOATING:
+ set_floating(m, d, n, false);
+ break;
+ case STATE_FULLSCREEN:
+ set_fullscreen(m, d, n, false);
+ break;
+ }
+
+ put_status(SBSC_MASK_WINDOW_STATE, "window_state %s off 0x%X\n", STATESTR(c->last_state), c->window);
+
+ switch (c->state) {
+ case STATE_TILED:
+ case STATE_PSEUDO_TILED:
+ break;
+ case STATE_FLOATING:
+ set_floating(m, d, n, true);
+ break;
+ case STATE_FULLSCREEN:
+ set_fullscreen(m, d, n, true);
+ break;
+ }
+
+ put_status(SBSC_MASK_WINDOW_STATE, "window_state %s on 0x%X\n", STATESTR(c->state), c->window);
}
-void set_pseudo_tiled(node_t *n, bool value)
+void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value)
{
- if (n == NULL || n->client->pseudo_tiled == value)
+ if (n == NULL) {
return;
+ }
client_t *c = n->client;
- PRINTF("pseudo-tiled %X: %s\n", c->window, BOOLSTR(value));
- put_status(SBSC_MASK_WINDOW_STATE, "window_state pseudo_tiled %s 0x%X\n", ONOFFSTR(value), c->window);
-
- c->pseudo_tiled = value;
-}
-
-void set_floating(node_t *n, bool value)
-{
- if (n == NULL || n->client->fullscreen || n->client->floating == value)
- return;
-
- client_t *c = n->client;
-
- PRINTF("floating %X: %s\n", c->window, BOOLSTR(value));
- put_status(SBSC_MASK_WINDOW_STATE, "window_state floating %s 0x%X\n", ONOFFSTR(value), c->window);
-
n->split_mode = MODE_AUTOMATIC;
- c->floating = n->vacant = value;
+ n->vacant = value;
update_vacant_state(n->parent);
if (value) {
@@ -455,11 +472,57 @@ void set_floating(node_t *n, bool value)
} else {
disable_floating_atom(c->window);
rotate_brother(n);
+ if (d->focus == n) {
+ neutralize_obscuring_windows(m, d, n);
+ }
}
stack(n);
}
+void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value)
+{
+ if (n == NULL) {
+ return;
+ }
+
+ client_t *c = n->client;
+
+ n->split_mode = MODE_AUTOMATIC;
+ n->vacant = value;
+ update_vacant_state(n->parent);
+
+ if (value) {
+ ewmh_wm_state_add(c, ewmh->_NET_WM_STATE_FULLSCREEN);
+ c->last_layer = c->layer;
+ c->layer = LAYER_ABOVE;
+ } else {
+ ewmh_wm_state_remove(c, ewmh->_NET_WM_STATE_FULLSCREEN);
+ c->layer = c->last_layer;
+ if (d->focus == n) {
+ neutralize_obscuring_windows(m, d, n);
+ }
+ }
+
+ stack(n);
+}
+
+void neutralize_obscuring_windows(monitor_t *m, desktop_t *d, node_t *n)
+{
+ bool dirty = false;
+ for (node_t *a = first_extrema(d->root); a != NULL; a = next_leaf(a, d->root)) {
+ if (a != n) {
+ if (IS_FULLSCREEN(a->client) && stack_cmp(n->client, a->client) < 0) {
+ set_state(m, d, a, a->client->last_state);
+ dirty = true;
+ }
+ }
+ }
+ if (dirty) {
+ arrange(m, d);
+ }
+}
+
void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
{
if (n == NULL || n->client->locked == value)
@@ -467,8 +530,7 @@ void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
client_t *c = n->client;
- PRINTF("set locked %X: %s\n", c->window, BOOLSTR(value));
- put_status(SBSC_MASK_WINDOW_STATE, "window_state locked %s 0x%X\n", ONOFFSTR(value), c->window);
+ put_status(SBSC_MASK_WINDOW_FLAG, "window_flag locked %s 0x%X\n", ONOFFSTR(value), c->window);
c->locked = value;
window_draw_border(n, d->focus == n, m == mon);
@@ -481,8 +543,7 @@ void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
client_t *c = n->client;
- PRINTF("set sticky %X: %s\n", c->window, BOOLSTR(value));
- put_status(SBSC_MASK_WINDOW_STATE, "window_state sticky %s 0x%X\n", ONOFFSTR(value), c->window);
+ put_status(SBSC_MASK_WINDOW_FLAG, "window_flag sticky %s 0x%X\n", ONOFFSTR(value), c->window);
if (d != m->desk)
transfer_node(m, d, n, m, m->desk, m->desk->focus);
@@ -506,8 +567,7 @@ void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value)
client_t *c = n->client;
- PRINTF("set private %X: %s\n", c->window, BOOLSTR(value));
- put_status(SBSC_MASK_WINDOW_STATE, "window_state private %s 0x%X\n", ONOFFSTR(value), c->window);
+ put_status(SBSC_MASK_WINDOW_FLAG, "window_flag private %s 0x%X\n", ONOFFSTR(value), c->window);
c->private = value;
update_privacy_level(n, value);
@@ -521,7 +581,7 @@ void set_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value)
n->client->urgent = value;
window_draw_border(n, d->focus == n, m == mon);
- put_status(SBSC_MASK_WINDOW_STATE, "window_state urgent %s 0x%X\n", ONOFFSTR(value), n->client->window);
+ put_status(SBSC_MASK_WINDOW_FLAG, "window_flag urgent %s 0x%X\n", ONOFFSTR(value), n->client->window);
put_status(SBSC_MASK_REPORT);
}
diff --git a/window.h b/window.h
index b52fefd..1e55947 100644
--- a/window.h
+++ b/window.h
@@ -37,15 +37,16 @@ void unmanage_window(xcb_window_t win);
void window_draw_border(node_t *n, bool focused_window, bool focused_monitor);
pointer_state_t *make_pointer_state(void);
bool contains(xcb_rectangle_t a, xcb_rectangle_t b);
-xcb_rectangle_t get_rectangle(client_t *c);
+xcb_rectangle_t get_rectangle(monitor_t *m, client_t *c);
void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt);
void adopt_orphans(void);
void window_close(node_t *n);
void window_kill(monitor_t *m, desktop_t *d, node_t *n);
-void set_fullscreen(node_t *n, bool value);
-void set_layer(node_t *n, stack_layer_t layer);
-void set_pseudo_tiled(node_t *n, bool value);
-void set_floating(node_t *n, bool value);
+void set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l);
+void set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s);
+void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void neutralize_obscuring_windows(monitor_t *m, desktop_t *d, node_t *n);
void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value);
void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value);
void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value);