]> git.lizzy.rs Git - bspwm.git/commitdiff
Implement tags
authorBastien Dejean <nihilhill@gmail.com>
Sat, 5 Oct 2013 20:32:40 +0000 (22:32 +0200)
committerBastien Dejean <nihilhill@gmail.com>
Sat, 5 Oct 2013 20:32:40 +0000 (22:32 +0200)
33 files changed:
Makefile
Sourcedeps
bspwm.c
bspwm.h
desktop.c
desktop.h
doc/bspwm.1
doc/bspwm.1.txt
events.h
ewmh.h
helpers.h
history.c
history.h
messages.c
messages.h
monitor.c
monitor.h
pointer.h
query.c
query.h
restore.c
restore.h
rule.c
rule.h
settings.h
stack.h
tag.c [new file with mode: 0644]
tag.h [new file with mode: 0644]
tree.c
tree.h
types.h
window.c
window.h

index 058812d3b868d3fbae47f7e9ecbfe92677a7eee3..7065745b44976bc9c405fc44a4da4dd9970c8f12 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ 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 stack.c history.c \
-        events.c pointer.c window.c messages.c query.c restore.c rule.c ewmh.c
+        events.c pointer.c window.c messages.c query.c restore.c rule.c tag.c ewmh.c
 WM_OBJ = $(WM_SRC:.c=.o)
 CL_SRC = bspc.c helpers.c
 CL_OBJ = $(CL_SRC:.c=.o)
index aa67aaf843b169e48540f5985389381bf8cdbcfd..6c7baa15844304091f1c4d7e658c8e431e86e789 100644 (file)
@@ -1,11 +1,11 @@
 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 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 tag.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 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
+history.o: history.c bspwm.h helpers.h query.h tree.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 tag.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
@@ -13,5 +13,6 @@ restore.o: restore.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h quer
 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
 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
+tag.o: tag.c bspwm.h helpers.h history.h tag.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 tag.h tree.h types.h window.h
 window.o: window.c bspwm.h ewmh.h helpers.h monitor.h query.h rule.h settings.h stack.h tree.h types.h window.h
diff --git a/bspwm.c b/bspwm.c
index 64404f5b895043c55fa7d57f01fd07025639c6f2..9a6969f9193cfe4664d9e8683a9f76a2939b92cc 100644 (file)
--- a/bspwm.c
+++ b/bspwm.c
@@ -1,12 +1,12 @@
-#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
+#include <sys/select.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/select.h>
+#include <unistd.h>
 #include "types.h"
 #include "desktop.h"
 #include "monitor.h"
 #include "messages.h"
 #include "events.h"
 #include "common.h"
-#include "bspwm.h"
 #include "tree.h"
 #include "window.h"
 #include "history.h"
 #include "stack.h"
+#include "tag.h"
 #include "rule.h"
 #include "ewmh.h"
+#include "bspwm.h"
 
 int main(int argc, char *argv[])
 {
@@ -169,11 +170,12 @@ void init(void)
     rule_head = rule_tail = NULL;
     history_head = history_tail = NULL;
     stack_head = stack_tail = NULL;
+    init_tags();
     status_fifo = NULL;
     last_motion_time = last_motion_x = last_motion_y = 0;
-    randr_base = 0;
     visible = auto_raise = sticky_still = true;
     num_sticky = 0;
+    randr_base = 0;
     exit_status = 0;
 }
 
@@ -272,6 +274,8 @@ void cleanup(void)
         remove_rule(rule_head);
     while (stack_head != NULL)
         remove_stack(stack_head);
+    while (num_tags > 0)
+        remove_tag_by_index(num_tags - 1);
     empty_history();
     free(frozen_pointer);
 }
@@ -294,8 +298,11 @@ void put_status(void)
             fprintf(status_fifo, "%c%s:", c, d->name);
         }
     }
-    if (mon != NULL && mon->desk != NULL)
+    if (mon != NULL && mon->desk != NULL) {
+        for (int i = 0; i < num_tags; i++)
+            fprintf(status_fifo, "%c%s:", (tags[i]->mask & mon->desk->tags_field) != 0 ? 'T' : 't', tags[i]->name);
         fprintf(status_fifo, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
+    }
     fprintf(status_fifo, "\n");
     fflush(status_fifo);
 }
diff --git a/bspwm.h b/bspwm.h
index dd0f7c071bb0c3a80d5d57616a17d8bdf7dd62e1..57368ced53ddca08a71712df2eed171e5e39f13b 100644 (file)
--- a/bspwm.h
+++ b/bspwm.h
@@ -50,8 +50,8 @@ bool randr;
 void init(void);
 void setup(void);
 void register_events(void);
-void put_status(void);
-void cleanup(void);
 void quit(void);
+void cleanup(void);
+void put_status(void);
 
 #endif
index 5f1d53b0e4eeabb827988257fb07c5a50496c95f..01f231ee46b05e0c6bd6eb1df2f095ea42592c66 100644 (file)
--- a/desktop.c
+++ b/desktop.c
@@ -15,7 +15,7 @@ void focus_desktop(monitor_t *m, desktop_t *d)
     if (d == mon->desk)
         return;
 
-    PRINTF("select desktop %s\n", d->name);
+    PRINTF("focus desktop %s\n", d->name);
 
     show_desktop(d);
     hide_desktop(mon->desk);
@@ -95,6 +95,7 @@ desktop_t *make_desktop(const char *name)
     d->root = d->focus = NULL;
     d->window_gap = WINDOW_GAP;
     d->border_width = BORDER_WIDTH;
+    d->tags_field = 1;
     return d;
 }
 
@@ -254,7 +255,8 @@ void show_desktop(desktop_t *d)
     if (!visible)
         return;
     for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
-        window_show(n->client->window);
+        if (is_visible(d, n))
+            window_show(n->client->window);
 }
 
 void hide_desktop(desktop_t *d)
@@ -262,7 +264,8 @@ void hide_desktop(desktop_t *d)
     if (!visible)
         return;
     for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
-        window_hide(n->client->window);
+        if (is_visible(d, n))
+            window_hide(n->client->window);
 }
 
 bool is_urgent(desktop_t *d)
index 31fb0a9df59d9aea1182099c94d60393362ebb83..ebffb87d1bae11c7a17afbc5c91b4415ba985793 100644 (file)
--- a/desktop.h
+++ b/desktop.h
@@ -5,20 +5,20 @@
 #define WINDOW_GAP           6
 #define BORDER_WIDTH         1
 
-void focus_desktop(monitor_t *, desktop_t *);
-desktop_t *closest_desktop(monitor_t *, desktop_t *, cycle_dir_t, desktop_select_t);
-desktop_t *make_desktop(const char *);
-void change_layout(monitor_t *, desktop_t *, layout_t);
-void insert_desktop(monitor_t *, desktop_t *);
-void add_desktop(monitor_t *, desktop_t *);
-void empty_desktop(desktop_t *);
-void unlink_desktop(monitor_t *, desktop_t *);
-void remove_desktop(monitor_t *, desktop_t *);
-void merge_desktops(monitor_t *, desktop_t *, monitor_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 *);
-bool is_urgent(desktop_t *);
+void focus_desktop(monitor_t *m, desktop_t *d);
+desktop_t *closest_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, desktop_select_t sel);
+void change_layout(monitor_t *m, desktop_t *d, layout_t l);
+void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d);
+desktop_t *make_desktop(const char *name);
+void insert_desktop(monitor_t *m, desktop_t *d);
+void add_desktop(monitor_t *m, desktop_t *d);
+void empty_desktop(desktop_t *d);
+void unlink_desktop(monitor_t *m, desktop_t *d);
+void remove_desktop(monitor_t *m, desktop_t *d);
+void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd);
+void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2);
+void show_desktop(desktop_t *d);
+void hide_desktop(desktop_t *d);
+bool is_urgent(desktop_t *d);
 
 #endif
index a7ecdc915183778116d0fd5880a04443698dd341..93e3463de62541c5ffa8c9fe5f0838093f430333 100644 (file)
@@ -2,12 +2,12 @@
 .\"     Title: bspwm
 .\"    Author: [see the "Author" section]
 .\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\"      Date: 10/01/2013
+.\"      Date: 10/05/2013
 .\"    Manual: Bspwm Manual
 .\"    Source: Bspwm 0.8.5
 .\"  Language: English
 .\"
-.TH "BSPWM" "1" "10/01/2013" "Bspwm 0\&.8\&.5" "Bspwm Manual"
+.TH "BSPWM" "1" "10/05/2013" "Bspwm 0\&.8\&.5" "Bspwm Manual"
 .\" -----------------------------------------------------------------
 .\" * Define some portability stuff
 .\" -----------------------------------------------------------------
@@ -210,7 +210,7 @@ Selects the biggest window on the current desktop\&.
 .PP
 last
 .RS 4
-Selects the previously focused window on the current desktop\&.
+Selects the previously focused window\&.
 .RE
 .PP
 focused
@@ -635,6 +635,75 @@ Rename, add or remove desktops depending on whether the number of given names is
 Swap the selected monitor with the given monitor\&.
 .RE
 .RE
+.SS "Tag"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
+.RS 4
+.sp
+tag \fIOPTIONS\fR
+.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
+.RS 4
+.PP
+\fB\-l\fR, \fB\-\-list\fR
+.RS 4
+List the tags\&.
+.RE
+.PP
+\fB\-a\fR, \fB\-\-add\fR <name>\&...
+.RS 4
+Create tags with the given names\&.
+.RE
+.PP
+\fB\-r\fR, \fB\-\-remove\fR <name>|^<n>\&...
+.RS 4
+Remove tags with the given names or indexes\&.
+.RE
+.PP
+\fB\-e\fR, \fB\-\-enumerate\-tags\fR <name>\&...
+.RS 4
+Rename, add or remove tags depending on whether the number of given names is equal, superior or inferior to the number of existing tags\&.
+.RE
+.PP
+\fB\-d\fR, \fB\-\-desktop\fR \fIDESKTOP_SEL\fR
+.RS 4
+Select the given desktop as target for the
+\fB\-s\fR
+and
+\fB\-t\fR
+options\&.
+.RE
+.PP
+\fB\-w\fR, \fB\-\-window\fR \fIWINDOW_SEL\fR
+.RS 4
+Select the given window as target for the
+\fB\-s\fR
+and
+\fB\-t\fR
+options\&.
+.RE
+.PP
+\fB\-s\fR, \fB\-\-set\-tags\fR (<name>|^<n>\&...)|all
+.RS 4
+Set the tags of the selected object\&.
+.RE
+.PP
+\fB\-t\fR, \fB\-\-toggle\-tags\fR (<name>|^<n>)[=on|off]\&...
+.RS 4
+Toggle the tags of the selected object\&.
+.RE
+.RE
 .SS "Query"
 .sp
 .it 1 an-trap
@@ -815,7 +884,7 @@ rule \fIOPTIONS\fR
 \fBOptions\fR
 .RS 4
 .PP
-\fB\-a\fR, \fB\-\-add\fR <pattern> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-unmanage] [\-\-one\-shot]
+\fB\-a\fR, \fB\-\-add\fR <pattern> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-tags <name>|^<n>[,\&...]][\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-unmanage] [\-\-one\-shot]
 .RS 4
 Create a new rule (<pattern> must match the class or instance name)\&.
 .RE
index c853a0b3d8fd328afde01ad7a29198cb06652651..d135369ec0cc46613ffd69ca66b9f18fe0925455 100644 (file)
@@ -158,7 +158,7 @@ biggest::
     Selects the biggest window on the current desktop.
 
 last::
-    Selects the previously focused window on the current desktop.
+    Selects the previously focused window.
 
 focused::
     Selects the currently focused window.
@@ -399,6 +399,40 @@ Options
 *-s*, *--swap* 'MONITOR_SEL'::
     Swap the selected monitor with the given monitor.
 
+Tag
+~~~
+
+General Syntax
+^^^^^^^^^^^^^^
+
+tag 'OPTIONS'
+
+Options
+^^^^^^^
+*-l*, *--list*::
+    List the tags.
+
+*-a*, *--add* <name>...::
+    Create tags with the given names.
+
+*-r*, *--remove* <name>|^<n>...::
+    Remove tags with the given names or indexes.
+
+*-e*, *--enumerate-tags* <name>...::
+    Rename, add or remove tags depending on whether the number of given names is equal, superior or inferior to the number of existing tags.
+
+*-d*, *--desktop* 'DESKTOP_SEL'::
+    Select the given desktop as target for the *-s* and *-t* options.
+
+*-w*, *--window* 'WINDOW_SEL'::
+    Select the given window as target for the *-s* and *-t* options.
+
+*-s*, *--set-tags* (<name>|^<n>...)|all::
+    Set the tags of the selected object.
+
+*-t*, *--toggle-tags* (<name>|^<n>)[=on|off]...::
+    Toggle the tags of the selected object.
+
 Query
 ~~~~~
 
@@ -498,7 +532,7 @@ rule 'OPTIONS'
 Options
 ^^^^^^^
 
-*-a*, *--add* <pattern> [-d 'DESKTOP_SEL' [--follow]] [--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--unmanage] [--one-shot]::
+*-a*, *--add* <pattern> [-d 'DESKTOP_SEL' [--follow]] [--tags <name>|^<n>[,...]][--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--unmanage] [--one-shot]::
     Create a new rule (<pattern> must match the class or instance name).
 
 *-r*, *--remove* <rule_uid>|tail|head...::
index 973df0d6123d02683fec0ad303b81e0c97db08ed..71f700786fdf37fa016cb48b3dcd7186c0593d37 100644 (file)
--- a/events.h
+++ b/events.h
@@ -8,16 +8,16 @@ uint8_t randr_base;
 uint16_t last_motion_x, last_motion_y;
 xcb_timestamp_t last_motion_time;
 
-void handle_event(xcb_generic_event_t *);
-void map_request(xcb_generic_event_t *);
-void destroy_notify(xcb_generic_event_t *);
-void unmap_notify(xcb_generic_event_t *);
-void configure_request(xcb_generic_event_t *);
-void client_message(xcb_generic_event_t *);
-void property_notify(xcb_generic_event_t *);
-void focus_in(xcb_generic_event_t *);
-void enter_notify(xcb_generic_event_t *);
-void motion_notify(xcb_generic_event_t *);
-void handle_state(monitor_t *, desktop_t *, node_t *, xcb_atom_t, unsigned int);
+void handle_event(xcb_generic_event_t *evt);
+void map_request(xcb_generic_event_t *evt);
+void configure_request(xcb_generic_event_t *evt);
+void destroy_notify(xcb_generic_event_t *evt);
+void unmap_notify(xcb_generic_event_t *evt);
+void property_notify(xcb_generic_event_t *evt);
+void client_message(xcb_generic_event_t *evt);
+void focus_in(xcb_generic_event_t *evt);
+void enter_notify(xcb_generic_event_t *evt);
+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);
 
 #endif
diff --git a/ewmh.h b/ewmh.h
index 54124f25899e8ac586e3d9504fc460d6d6f86dd6..bcbf6a7494d59d799c16c9e28f2beb79c36768bc 100644 (file)
--- a/ewmh.h
+++ b/ewmh.h
@@ -8,13 +8,13 @@ xcb_ewmh_connection_t *ewmh;
 void ewmh_init(void);
 void ewmh_update_active_window(void);
 void ewmh_update_number_of_desktops(void);
-uint32_t ewmh_get_desktop_index(desktop_t *);
-bool ewmh_locate_desktop(uint32_t, coordinates_t *);
+uint32_t ewmh_get_desktop_index(desktop_t *d);
+bool ewmh_locate_desktop(uint32_t i, coordinates_t *loc);
 void ewmh_update_current_desktop(void);
-void ewmh_set_wm_desktop(node_t *, desktop_t *);
+void ewmh_set_wm_desktop(node_t *n, desktop_t *d);
 void ewmh_update_wm_desktops(void);
 void ewmh_update_desktop_names(void);
 void ewmh_update_client_list(void);
-void ewmh_set_supporting(xcb_window_t);
+void ewmh_set_supporting(xcb_window_t win);
 
 #endif
index 65d57825d55bf1bfa4031ca691797274acbd8a99..69023da676b7d44f109a8947063d8d04ee5a3305 100644 (file)
--- a/helpers.h
+++ b/helpers.h
 #  define PRINTF(x,...)   ((void)0)
 #endif
 
-void warn(char *, ...);
+void warn(char *fmt, ...);
 __attribute__((noreturn))
-void err(char *, ...);
-bool get_color(char *, xcb_window_t, uint32_t *);
-double distance(xcb_point_t, xcb_point_t);
+void err(char *fmt, ...);
+bool get_color(char *col, xcb_window_t win, uint32_t *pxl);
+double distance(xcb_point_t a, xcb_point_t b);
 
 #endif
index c99aa8ca486a256bc421b272c7f5d537f20aa45d..98a7c5e2f1b81ef64a9dd6a9aaae6cc45ea57747 100644 (file)
--- a/history.c
+++ b/history.c
@@ -1,5 +1,6 @@
 #include <stdlib.h>
 #include "bspwm.h"
+#include "tree.h"
 #include "query.h"
 
 history_t *make_history(monitor_t *m, desktop_t *d, node_t *n)
@@ -114,7 +115,7 @@ void empty_history(void)
 node_t *history_get_node(desktop_t *d, node_t *n)
 {
     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)
+        if (h->latest && h->loc.node != NULL && h->loc.node != n && h->loc.desktop == d && is_visible(h->loc.desktop, h->loc.node))
             return h->loc.node;
     return NULL;
 }
@@ -138,7 +139,9 @@ monitor_t *history_get_monitor(monitor_t *m)
 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))
+        if (!h->latest || h->loc.node == NULL || h->loc.node == n
+                || !is_visible(h->loc.desktop, h->loc.node)
+                || !node_matches(n, h->loc.node, sel))
             continue;
         *loc = h->loc;
         return true;
index 441b9c90228e7c3064b9d2d12487c6e7722c76a3..70683eed7e1bd2223824585a2f38cd887c9abd56 100644 (file)
--- a/history.h
+++ b/history.h
@@ -3,21 +3,20 @@
 
 #include "types.h"
 
-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 *);
+history_t *make_history(monitor_t *m, desktop_t *d, node_t *n);
+void history_add(monitor_t *m, desktop_t *d, node_t *n);
+void history_transfer_node(monitor_t *m, desktop_t *d, node_t *n);
+void history_transfer_desktop(monitor_t *m, desktop_t *d);
+void history_swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2);
+void history_swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2);
+void history_remove(desktop_t *d, node_t *n);
 void empty_history(void);
+node_t *history_get_node(desktop_t *d, node_t *n);
+desktop_t *history_get_desktop(monitor_t *m, desktop_t *d);
+monitor_t *history_get_monitor(monitor_t *m);
+bool history_last_node(node_t *n, client_select_t sel, coordinates_t *loc);
+bool history_last_desktop(desktop_t *d, desktop_select_t sel, coordinates_t *loc);
+bool history_last_monitor(monitor_t *m, desktop_select_t sel, coordinates_t *loc);
+int history_rank(desktop_t *d, node_t *n);
 
 #endif
index 93b2ad3b7721c5d76dfdc940269db5d976e9f983..245befae12acd9f62d2effb5cfb82bdd9aacbdc2 100644 (file)
@@ -7,6 +7,7 @@
 #include "ewmh.h"
 #include "history.h"
 #include "monitor.h"
+#include "tag.h"
 #include "pointer.h"
 #include "query.h"
 #include "restore.h"
@@ -62,6 +63,8 @@ bool process_message(char **args, int num, char *rsp)
         return cmd_monitor(++args, --num);
     } else if (streq("query", *args)) {
         return cmd_query(++args, --num, rsp);
+    } else if (streq("tag", *args)) {
+        return cmd_tag(++args, --num, rsp);
     } else if (streq("restore", *args)) {
         return cmd_restore(++args, --num);
     } else if (streq("control", *args)) {
@@ -167,7 +170,7 @@ bool cmd_window(char **args, int num)
                 return false;
             char *key = strtok(*args, EQL_TOK);
             char *val = strtok(NULL, EQL_TOK);
-            state_alter_t a = ALTER_NONE;
+            alter_state_t a;
             bool b;
             if (val == NULL) {
                 a = ALTER_TOGGLE;
@@ -281,6 +284,7 @@ bool cmd_window(char **args, int num)
         } else {
             return false;
         }
+
         num--, args++;
     }
 
@@ -519,7 +523,140 @@ bool cmd_monitor(char **args, int num)
     return true;
 }
 
-bool cmd_query(char **args, int num, char *rsp) {
+bool cmd_tag(char **args, int num, char *rsp)
+{
+    if (num < 1)
+        return false;
+
+    coordinates_t ref = {mon, mon->desk, mon->desk->focus};
+    coordinates_t trg = {NULL, NULL, NULL};
+
+    while (num > 0) {
+        if (streq("-d", *args) || streq("--desktop", *args)) {
+            num--, args++;
+            if (num < 1)
+                return false;
+            if (!desktop_from_desc(*args, &ref, &trg))
+                return false;
+        } else if (streq("-w", *args) || streq("--window", *args)) {
+            num--, args++;
+            if (num < 1)
+                return false;
+            if (!node_from_desc(*args, &ref, &trg))
+                return false;
+        } else if (streq("-s", *args) || streq("--set-tags", *args)) {
+            num--, args++;
+            if (num < 1 || trg.desktop == NULL)
+                return false;
+            unsigned int tf = 0;
+            if (streq("all", *args))
+                tf = (1 << num_tags) - 1;
+            else
+                while (num > 0) {
+                    tag_t *tag = NULL;
+                    int idx;
+                    if (parse_index(*args, &idx))
+                        tag = get_tag_by_index(idx - 1);
+                    else
+                        tag = get_tag(*args);
+                    if (tag != NULL)
+                        tf |= tag->mask;
+                    num--, args++;
+                }
+            if (trg.node == NULL)
+                tag_desktop(trg.monitor, trg.desktop, tf);
+            else
+                tag_node(trg.monitor, trg.desktop, trg.node, tf);
+            return true;
+        } else if (streq("-t", *args) || streq("--toggle-tags", *args)) {
+            num--, args++;
+            if (num < 1 || trg.desktop == NULL)
+                return false;
+            unsigned int tf;
+            if (trg.node == NULL)
+                tf = trg.desktop->tags_field;
+            else
+                tf = trg.node->client->tags_field;
+            while (num > 0) {
+                char *key;
+                bool value;
+                alter_state_t alt;
+                if (parse_bool_declaration(*args, &key, &value, &alt)) {
+                    tag_t *tag = NULL;
+                    int idx;
+                    if (parse_index(key, &idx))
+                        tag = get_tag_by_index(idx - 1);
+                    else
+                        tag = get_tag(key);
+                    if (tag != NULL) {
+                        if (alt == ALTER_SET) {
+                            if (value)
+                                tf |= tag->mask;
+                            else
+                                tf &= ~tag->mask;
+                        } else {
+                            tf ^= tag->mask;
+                        }
+                    }
+                }
+                num--, args++;
+            }
+            if (trg.node == NULL)
+                tag_desktop(trg.monitor, trg.desktop, tf);
+            else
+                tag_node(trg.monitor, trg.desktop, trg.node, tf);
+            return true;
+        } else if (streq("-e", *args) || streq("--enumerate-tags", *args)) {
+            num--, args++;
+            if (num < 1)
+                return false;
+            int i = 0;
+            while (i < num_tags && num > 0) {
+                snprintf(tags[i]->name, sizeof(tags[i]->name), "%s", *args);
+                tags[i]->mask = 1 << i;
+                i++, num--, args++;
+            }
+            while (i < num_tags) {
+                remove_tag_by_index(i);
+            }
+            while (num > 0) {
+                add_tag(*args);
+                num--, args++;
+            }
+            put_status();
+        } else if (streq("-a", *args) || streq("--add", *args)) {
+            num--, args++;
+            if (num < 1)
+                return false;
+            while (num > 0) {
+                add_tag(*args);
+                num--, args++;
+            }
+        } else if (streq("-r", *args) || streq("--remove", *args)) {
+            num--, args++;
+            if (num < 1)
+                return false;
+            int idx;
+            while (num > 0) {
+                if (parse_index(*args, &idx))
+                    remove_tag_by_index(idx - 1);
+                else
+                    remove_tag(*args);
+                num--, args++;
+            }
+        } else if (streq("-l", *args) || streq("--list", *args)) {
+            list_tags(rsp);
+        } else {
+            return false;
+        }
+        num--, args++;
+    }
+
+    return true;
+}
+
+bool cmd_query(char **args, int num, char *rsp)
+{
     coordinates_t ref = {mon, mon->desk, mon->desk->focus};
     coordinates_t trg = {NULL, NULL, NULL};
     domain_t dom = DOMAIN_TREE;
@@ -584,7 +721,8 @@ bool cmd_query(char **args, int num, char *rsp) {
     return true;
 }
 
-bool cmd_rule(char **args, int num, char *rsp) {
+bool cmd_rule(char **args, int num, char *rsp)
+{
     if (num < 1)
         return false;
     while (num > 0) {
@@ -612,6 +750,14 @@ bool cmd_rule(char **args, int num, char *rsp) {
                     rule->effect.unmanage = true;
                 } else if (streq("--one-shot", *args)) {
                     rule->one_shot = true;
+                } else if (streq("--tags", *args)) {
+                    num--, args++;
+                    if (num < 1) {
+                        free(rule);
+                        rule_uid--;
+                        return false;
+                    }
+                    snprintf(rule->effect.tags, sizeof(rule->effect.tags), "%s", *args);
                 } else if (streq("-d", *args) || streq("--desktop", *args)) {
                     num--, args++;
                     if (num < 1) {
@@ -656,7 +802,8 @@ bool cmd_rule(char **args, int num, char *rsp) {
     return true;
 }
 
-bool cmd_pointer(char **args, int num) {
+bool cmd_pointer(char **args, int num)
+{
     if (num < 1)
         return false;
     while (num > 0) {
@@ -687,7 +834,8 @@ bool cmd_pointer(char **args, int num) {
     return true;
 }
 
-bool cmd_restore(char **args, int num) {
+bool cmd_restore(char **args, int num)
+{
     if (num < 1)
         return false;
     while (num > 0) {
@@ -715,7 +863,8 @@ bool cmd_restore(char **args, int num) {
     return true;
 }
 
-bool cmd_control(char **args, int num) {
+bool cmd_control(char **args, int num)
+{
     if (num < 1)
         return false;
     while (num > 0) {
@@ -734,7 +883,8 @@ bool cmd_control(char **args, int num) {
     return true;
 }
 
-bool cmd_config(char **args, int num, char *rsp) {
+bool cmd_config(char **args, int num, char *rsp)
+{
     if (num < 1)
         return false;
     coordinates_t ref = {mon, mon->desk, mon->desk->focus};
@@ -765,7 +915,8 @@ bool cmd_config(char **args, int num, char *rsp) {
         return false;
 }
 
-bool cmd_quit(char **args, int num) {
+bool cmd_quit(char **args, int num)
+{
     if (num > 0 && sscanf(*args, "%i", &exit_status) != 1)
         return false;
     quit();
@@ -1078,7 +1229,29 @@ bool parse_window_id(char *s, long int *i)
     return true;
 }
 
+bool parse_bool_declaration(char *s, char **key, bool *value, alter_state_t *state)
+{
+    *key = strtok(s, EQL_TOK);
+    char *v = strtok(NULL, EQL_TOK);
+    if (v == NULL) {
+        *state = ALTER_TOGGLE;
+        return true;
+    } else {
+        if (parse_bool(v, value)) {
+            *state = ALTER_SET;
+            return true;
+        } else {
+            return false;
+        }
+    }
+    return false;
+}
+
 bool parse_index(char *s, int *i)
 {
-    return sscanf(s, "^%i", i) == 1;
+    int idx;
+    if (sscanf(s, "^%i", &idx) != 1 || idx < 1)
+        return false;
+    *i = idx;
+    return true;
 }
index e8d11b08e888661704afe97984a8e345f60ab084..e4c8997a4720c625659b58705d5acdb72e835736 100644 (file)
@@ -7,30 +7,32 @@
 #define CAT_CHR  '.'
 #define EQL_TOK  "="
 
-bool handle_message(char *, int, char *);
-bool process_message(char **, int, char *);
-bool cmd_window(char **, int);
-bool cmd_desktop(char **, int);
-bool cmd_monitor(char **, int);
-bool cmd_query(char **, int, char *);
-bool cmd_rule(char **, int, char *);
-bool cmd_pointer(char **, int);
-bool cmd_control(char **, int);
-bool cmd_restore(char **, int);
-bool cmd_config(char **, int, char *);
-bool cmd_quit(char **, int);
-bool set_setting(coordinates_t, char *, char *);
-bool get_setting(coordinates_t, char *, char *);
-bool parse_bool(char *, bool *);
-bool parse_layout(char *, layout_t *);
-bool parse_direction(char *, direction_t *);
-bool parse_cycle_direction(char *, cycle_dir_t *);
-bool parse_circulate_direction(char *, circulate_dir_t *);
-bool parse_flip(char *, flip_t *);
-bool parse_fence_move(char *, fence_move_t *);
-bool parse_pointer_action(char *, pointer_action_t *);
-bool parse_degree(char *, int *);
-bool parse_window_id(char *, long int *);
-bool parse_index(char *, int *);
+bool handle_message(char *msg, int msg_len, char *rsp);
+bool process_message(char **args, int num, char *rsp);
+bool cmd_window(char **args, int num);
+bool cmd_desktop(char **args, int num);
+bool cmd_monitor(char **args, int num);
+bool cmd_tag(char **args, int num, char *rsp);
+bool cmd_query(char **args, int num, char *rsp);
+bool cmd_rule(char **args, int num, char *rsp);
+bool cmd_pointer(char **args, int num);
+bool cmd_restore(char **args, int num);
+bool cmd_control(char **args, int num);
+bool cmd_config(char **args, int num, char *rsp);
+bool cmd_quit(char **args, int num);
+bool set_setting(coordinates_t loc, char *name, char *value);
+bool get_setting(coordinates_t loc, char *name, char* rsp);
+bool parse_bool(char *value, bool *b);
+bool parse_layout(char *s, layout_t *l);
+bool parse_direction(char *s, direction_t *d);
+bool parse_cycle_direction(char *s, cycle_dir_t *d);
+bool parse_circulate_direction(char *s, circulate_dir_t *d);
+bool parse_flip(char *s, flip_t *f);
+bool parse_fence_move(char *s, fence_move_t *m);
+bool parse_pointer_action(char *s, pointer_action_t *a);
+bool parse_degree(char *s, int *d);
+bool parse_window_id(char *s, long int *i);
+bool parse_bool_declaration(char *s, char **key, bool *value, alter_state_t *state);
+bool parse_index(char *s, int *i);
 
 #endif
index 2ceefbb6b997db65a7ddc0afb626164ecbe95f59..1e39c4d09d0f48f7a3a90889e1dd3e874a43f530 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -72,7 +72,7 @@ void focus_monitor(monitor_t *m)
     if (mon == m)
         return;
 
-    PRINTF("select monitor %s\n", m->name);
+    PRINTF("focus monitor %s\n", m->name);
 
     mon = m;
 
index cd7607a5d946c7e2ee9b882182a0ba81471fabdc..65dacf74e6787d0e76f7fa0fce18b017400a5452 100644 (file)
--- a/monitor.h
+++ b/monitor.h
@@ -3,17 +3,18 @@
 
 #define DEFAULT_MON_NAME     "MONITOR"
 
-monitor_t *make_monitor(xcb_rectangle_t);
-monitor_t *find_monitor(char *);
-void fit_monitor(monitor_t *, client_t *);
-monitor_t *get_monitor_by_id(xcb_randr_output_t);
-void focus_monitor(monitor_t *);
-monitor_t *nearest_monitor(monitor_t *, direction_t, desktop_select_t);
-monitor_t *closest_monitor(monitor_t *, cycle_dir_t, desktop_select_t);
-monitor_t *add_monitor(xcb_rectangle_t);
-void remove_monitor(monitor_t *);
-void merge_monitors(monitor_t *, monitor_t *);
-void swap_monitors(monitor_t *, monitor_t *);
+monitor_t *make_monitor(xcb_rectangle_t rect);
+monitor_t *find_monitor(char *name);
+monitor_t *get_monitor_by_id(xcb_randr_output_t id);
+void fit_monitor(monitor_t *m, client_t *c);
+void update_root(monitor_t *m);
+void focus_monitor(monitor_t *m);
+monitor_t *add_monitor(xcb_rectangle_t rect);
+void remove_monitor(monitor_t *m);
+void merge_monitors(monitor_t *ms, monitor_t *md);
+void swap_monitors(monitor_t *m1, monitor_t *m2);
+monitor_t *closest_monitor(monitor_t *m, cycle_dir_t dir, desktop_select_t sel);
+monitor_t *nearest_monitor(monitor_t *m, direction_t dir, desktop_select_t sel);
 bool import_monitors(void);
 
 #endif
index cdd4ef2e18a58cc78e583296fdabaf8d71796ade..b410d2f9c875f58e9187814d714d7b3714e49a24 100644 (file)
--- a/pointer.h
+++ b/pointer.h
@@ -1,7 +1,7 @@
 #ifndef _POINTER_H
 #define _POINTER_H
 
-void grab_pointer(pointer_action_t);
-void track_pointer(int, int);
+void grab_pointer(pointer_action_t pac);
+void track_pointer(int root_x, int root_y);
 
 #endif
diff --git a/query.c b/query.c
index 1ec200521f6869ad00a0322caa25852f5f9a240b..45eeb4e53b96099f9a7c3d2f6cadca7f94d832e3 100644 (file)
--- a/query.c
+++ b/query.c
@@ -44,7 +44,7 @@ void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int
             strncat(rsp, line, REMLEN(rsp));
             continue;
         } else {
-            snprintf(line, sizeof(line), "%s %u %i %c", d->name, d->border_width, d->window_gap, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
+            snprintf(line, sizeof(line), "%s %u %i %u %c", d->name, d->border_width, d->window_gap, d->tags_field, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
             strncat(rsp, line, REMLEN(rsp));
             if (d == m->desk)
                 strncat(rsp, " *", REMLEN(rsp));
@@ -66,7 +66,7 @@ void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
 
     if (is_leaf(n)) {
         client_t *c = n->client;
-        snprintf(line, sizeof(line), "%c %s 0x%X %u %ux%u%+i%+i %c %c%c%c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_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->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'), (n->split_mode ? 'p' : '-'));
+        snprintf(line, sizeof(line), "%c %s 0x%X %u %u %ux%u%+i%+i %c %c%c%c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_name, c->window, c->tags_field, 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->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'), (c->sticky ? 's' : '-'), (n->split_mode ? 'p' : '-'));
     } else {
         snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), n->split_ratio);
     }
@@ -371,7 +371,8 @@ bool node_matches(node_t *c, node_t *t, client_select_t sel)
     return true;
 }
 
-bool desktop_matches(desktop_t *t, desktop_select_t sel) {
+bool desktop_matches(desktop_t *t, desktop_select_t sel)
+{
     if (sel.status != DESKTOP_STATUS_ALL &&
             t->root == NULL
             ? sel.status == DESKTOP_STATUS_OCCUPIED
diff --git a/query.h b/query.h
index 113cfc3bd3900399159ca05ec9de588df43a3d5e..d6604f15b610508a9a55ccbab9a43c39b5d5bd55 100644 (file)
--- a/query.h
+++ b/query.h
@@ -10,21 +10,21 @@ typedef enum {
     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_stack(char *);
-bool locate_window(xcb_window_t, coordinates_t *);
-bool locate_desktop(char *, coordinates_t *);
-bool locate_monitor(char *, coordinates_t *);
-bool node_from_desc(char *, coordinates_t *, coordinates_t *);
-bool desktop_from_desc(char *, coordinates_t *, coordinates_t *);
-bool monitor_from_desc(char *, coordinates_t *, coordinates_t *);
-bool desktop_from_index(int, coordinates_t *);
-bool monitor_from_index(int, coordinates_t *);
-bool node_matches(node_t *, node_t *, client_select_t);
-bool desktop_matches(desktop_t *, desktop_select_t);
+void query_monitors(coordinates_t loc, domain_t dom, char *rsp);
+void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, char *rsp);
+void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth);
+void query_history(coordinates_t loc, char *rsp);
+void query_stack(char *rsp);
+void query_windows(coordinates_t loc, char *rsp);
+bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
+bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
+bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
+bool locate_window(xcb_window_t win, coordinates_t *loc);
+bool locate_desktop(char *name, coordinates_t *loc);
+bool locate_monitor(char *name, coordinates_t *loc);
+bool desktop_from_index(int i, coordinates_t *loc);
+bool monitor_from_index(int i, coordinates_t *loc);
+bool node_matches(node_t *c, node_t *t, client_select_t sel);
+bool desktop_matches(desktop_t *t, desktop_select_t sel);
 
 #endif
index 42f0645f8c6c1d02952224955f39a843b8b3ffe9..3915cf79e7bb00577fc70a4c2084b363a224a9ed 100644 (file)
--- a/restore.c
+++ b/restore.c
@@ -60,17 +60,18 @@ void restore_tree(char *file_path)
             if (m == NULL)
                 continue;
             int wg;
-            unsigned int bw;
+            unsigned int tf, bw;
             char layout = 0, end = 0;
             name[0] = '\0';
             loc.desktop = NULL;
-            sscanf(line + level, "%s %u %i %c %c", name, &bw, &wg, &layout, &end);
+            sscanf(line + level, "%s %u %i %u %c %c", name, &bw, &wg, &tf, &layout, &end);
             locate_desktop(name, &loc);
             d = loc.desktop;
             if (d == NULL)
                 continue;
             d->border_width = bw;
             d->window_gap = wg;
+            d->tags_field = tf;
             if (layout == 'M')
                 d->layout = LAYOUT_MONOCLE;
             else if (layout == 'T')
@@ -112,7 +113,7 @@ void restore_tree(char *file_path)
                 client_t *c = make_client(XCB_NONE);
                 num_clients++;
                 char floating, transient, fullscreen, urgent, locked, sticky, sd, sm, end = 0;
-                sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &sd, &floating, &transient, &fullscreen, &urgent, &locked, &sticky, &sm, &end);
+                sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c %c%c%c%c%c%c%c %c", &br, c->class_name, &c->window, &c->tags_field, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &sd, &floating, &transient, &fullscreen, &urgent, &locked, &sticky, &sm, &end);
                 c->floating = (floating == '-' ? false : true);
                 c->transient = (transient == '-' ? false : true);
                 c->fullscreen = (fullscreen == '-' ? false : true);
@@ -151,7 +152,7 @@ void restore_tree(char *file_path)
             for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
                 uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
                 xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
-                if (n->client->floating) {
+                if (n->client->floating || !is_visible(d, n)) {
                     n->vacant = true;
                     update_vacant_state(n->parent);
                 }
index 466f0bbcae4933a05a9a990880a554d92a946893..b963aa3335e70cf364fbbea7e41d309130710a4d 100644 (file)
--- a/restore.h
+++ b/restore.h
@@ -1,8 +1,8 @@
 #ifndef _RESTORE_H
 #define _RESTORE_H
 
-void restore_tree(char *);
-void restore_history(char *);
-void restore_stack(char *);
+void restore_tree(char *file_path);
+void restore_history(char *file_path);
+void restore_stack(char *file_path);
 
 #endif
diff --git a/rule.c b/rule.c
index 5911dad823d83f66a669352accf2067e8b167415..c82c2110346554d53dc3f851739062207141042c 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -3,7 +3,9 @@
 #include "bspwm.h"
 #include "ewmh.h"
 #include "window.h"
+#include "messages.h"
 #include "query.h"
+#include "tag.h"
 #include "rule.h"
 
 rule_t *make_rule(void)
@@ -19,6 +21,7 @@ rule_t *make_rule(void)
     r->effect.unmanage = false;
     r->one_shot = false;
     r->effect.desc[0] = '\0';
+    r->effect.tags[0] = '\0';
     r->prev = NULL;
     r->next = NULL;
     return r;
@@ -80,7 +83,7 @@ bool is_match(rule_t *r, xcb_window_t win)
     return false;
 }
 
-void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *manage)
+void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *manage)
 {
     xcb_ewmh_get_atoms_reply_t win_type;
 
@@ -156,6 +159,20 @@ void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, bool *floating
                     *d = loc.desktop;
                 }
             }
+            if (efc.tags[0] != '\0') {
+                char *name = strtok(efc.tags, LST_SEP);
+                while (name != NULL) {
+                    int idx;
+                    tag_t *tag = NULL;
+                    if (parse_index(name, &idx))
+                        tag = get_tag_by_index(idx - 1);
+                    else
+                        tag = get_tag(name);
+                    if (tag != NULL)
+                        *tags_field |= tag->mask;
+                    name = strtok(NULL, LST_SEP);
+                }
+            }
         }
         rule_t *next = rule->next;
         if (rule->one_shot)
@@ -198,6 +215,10 @@ void list_rules(char *pattern, char *rsp)
             snprintf(line, sizeof(line), " -d %s", r->effect.desc);
             strncat(rsp, line, REMLEN(rsp));
         }
+        if (r->effect.tags[0] != '\0') {
+            snprintf(line, sizeof(line), " --tags %s", r->effect.tags);
+            strncat(rsp, line, REMLEN(rsp));
+        }
         strncat(rsp, "\n", REMLEN(rsp));
     }
 }
diff --git a/rule.h b/rule.h
index 0b60d12a12b3bd72b2825ccba239fc9d014ff3aa..837980e7c9f2fc3dd067d59af548729aea0e900e 100644 (file)
--- a/rule.h
+++ b/rule.h
@@ -2,15 +2,15 @@
 #define _RULE_H
 
 #define MATCH_ALL  "*"
+#define LST_SEP    ","
 
 rule_t *make_rule(void);
-void add_rule(rule_t *);
-void remove_rule(rule_t *);
-void remove_rule_by_uid(unsigned int);
-void prune_rules(desktop_t *);
-rule_t *find_rule(unsigned int);
-bool is_match(rule_t *, xcb_window_t);
-void handle_rules(xcb_window_t, monitor_t **, desktop_t **, bool *, bool *, bool *, bool *, bool *, bool *, bool *, bool *);
-void list_rules(char *, char *);
+void add_rule(rule_t *r);
+void remove_rule(rule_t *r);
+void remove_rule_by_uid(unsigned int uid);
+rule_t *find_rule(unsigned int uid);
+bool is_match(rule_t *r, xcb_window_t win);
+void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *manage);
+void list_rules(char *pattern, char *rsp);
 
 #endif
index c1f5ffabe41b213b0bb8e39d60d98e2323b6ed0d..789a11b7c3f4cc30c540537c3bf9c96cbc1e1d1d 100644 (file)
@@ -55,7 +55,7 @@ bool auto_cancel;
 bool history_aware_focus;
 bool honor_ewmh_focus;
 
-void load_settings(void);
 void run_config(void);
+void load_settings(void);
 
 #endif
diff --git a/stack.h b/stack.h
index ecac932229c089623dafbfb7b545fae52ccc3d50..97a6f2954b03e7d95665bb44f26f5f87f22a1876 100644 (file)
--- a/stack.h
+++ b/stack.h
@@ -1,12 +1,12 @@
 #ifndef _STACK_H
 #define _STACK_H
 
-stack_t *make_stack(node_t *);
-void stack_insert_after(stack_t *, node_t *);
-void stack_insert_before(stack_t *, node_t *);
-void remove_stack(stack_t *);
-void remove_stack_node(node_t *);
-void stack(node_t *);
-void stack_under(node_t *);
+stack_t *make_stack(node_t *n);
+void stack_insert_after(stack_t *a, node_t *n);
+void stack_insert_before(stack_t *a, node_t *n);
+void remove_stack(stack_t *s);
+void remove_stack_node(node_t *n);
+void stack(node_t *n);
+void stack_under(node_t *n);
 
 #endif
diff --git a/tag.c b/tag.c
new file mode 100644 (file)
index 0000000..27b9904
--- /dev/null
+++ b/tag.c
@@ -0,0 +1,149 @@
+#include <stdlib.h>
+#include <string.h>
+#include "bspwm.h"
+#include "window.h"
+#include "history.h"
+#include "tree.h"
+#include "tag.h"
+
+tag_t *make_tag(char *name, int idx)
+{
+    tag_t *tag = malloc(sizeof(tag_t));
+    if (tag != NULL) {
+        snprintf(tag->name, sizeof(tag->name), "%s", name);
+        tag->mask = 1 << idx;
+    }
+    return tag;
+}
+
+bool add_tag(char *name)
+{
+    if (num_tags >= MAXTAGS)
+        return false;
+    tag_t *tag = make_tag(name, num_tags);
+    if (tag == NULL)
+        return false;
+    tags[num_tags] = tag;
+    num_tags++;
+    return true;
+}
+
+bool remove_tag(char *name)
+{
+    for (int i = 0; i < num_tags; i++)
+        if (streq(tags[i]->name, name))
+            return remove_tag_by_index(i);
+    return false;
+}
+
+bool remove_tag_by_index(int i)
+{
+    if (i >= num_tags)
+        return false;
+    for (monitor_t *m = mon_head; m != NULL; m = m->next)
+        for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+            tag_desktop(m, d, d->tags_field & ~tags[i]->mask);
+            for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
+                tag_node(m, d, n, n->client->tags_field & ~tags[i]->mask);
+        }
+    free(tags[i]);
+    for (int j = i; j < (num_tags - 1); j++)
+        tags[j] = tags[j + 1];
+    tags[num_tags - 1] = NULL;
+    num_tags--;
+    return true;
+}
+
+tag_t *get_tag(char *name)
+{
+    for (int i = 0; i < num_tags; i++)
+        if (streq(tags[i]->name, name))
+            return tags[i];
+    return NULL;
+}
+
+tag_t *get_tag_by_index(int i)
+{
+    if (i >= num_tags)
+        return NULL;
+    return tags[i];
+}
+
+void toggle_presence(monitor_t *m, desktop_t *d, node_t *n)
+{
+    PRINTF("toggle presence %X\n", n->client->window);
+
+    n->vacant = !n->vacant;
+    update_vacant_state(n->parent);
+    if (n->vacant) {
+        if (m->desk == d)
+            window_hide(n->client->window);
+        unrotate_brother(n);
+        if (d->focus == n) {
+            node_t *f = history_get_node(d, n);
+            if (f == NULL)
+                f = closest_visible(d, n);
+            if (mon->desk == d)
+                focus_node(m, d, f);
+            else
+                pseudo_focus(d, f);
+        }
+    } else {
+        if (m->desk == d)
+            window_show(n->client->window);
+        rotate_brother(n);
+        if (d->focus == NULL) {
+            if (mon->desk == d)
+                focus_node(m, d, n);
+            else
+                pseudo_focus(d, n);
+        }
+    }
+}
+
+void tag_node(monitor_t *m, desktop_t *d, node_t *n, unsigned int tags_field)
+{
+    if (num_tags < 1)
+        return;
+    n->client->tags_field = tags_field;
+    if ((n->vacant && (tags_field & d->tags_field) != 0)
+            || (!n->vacant && (tags_field & d->tags_field) == 0)) {
+        toggle_presence(m, d, n);
+        arrange(m, d);
+    }
+}
+
+void tag_desktop(monitor_t *m, desktop_t *d, unsigned int tags_field)
+{
+    if (num_tags < 1)
+        return;
+    d->tags_field = tags_field;
+    bool dirty = false;
+    for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
+        if ((n->vacant && (tags_field & n->client->tags_field) != 0)
+                || (!n->vacant && (tags_field & n->client->tags_field) == 0)) {
+            toggle_presence(m, d, n);
+            dirty = true;
+        }
+    if (dirty)
+        arrange(m, d);
+    if (d == mon->desk)
+        put_status();
+}
+
+void list_tags(char *rsp)
+{
+    char line[MAXLEN];
+    for (int i = 0; i < num_tags; i++) {
+        snprintf(line, sizeof(line), "%s %u\n", tags[i]->name, tags[i]->mask);
+        strncat(rsp, line, REMLEN(rsp));
+    }
+}
+
+void init_tags(void)
+{
+    num_tags = 0;
+    for (int i = 0; i < MAXTAGS; i++)
+        tags[i] = NULL;
+    add_tag(DEFAULT_TAG_NAME);
+}
diff --git a/tag.h b/tag.h
new file mode 100644 (file)
index 0000000..f4f577f
--- /dev/null
+++ b/tag.h
@@ -0,0 +1,27 @@
+#ifndef _TAG_H
+#define _TAG_H
+
+#define MAXTAGS           32
+#define DEFAULT_TAG_NAME  "*"
+
+typedef struct {
+    char name[SMALEN];
+    unsigned int mask;
+} tag_t;
+
+tag_t *tags[MAXTAGS];
+int num_tags;
+
+tag_t *make_tag(char *name, int idx);
+bool add_tag(char *name);
+bool remove_tag(char *name);
+bool remove_tag_by_index(int i);
+tag_t *get_tag(char *name);
+tag_t *get_tag_by_index(int i);
+void toggle_presence(monitor_t *m, desktop_t *d, node_t *n);
+void tag_node(monitor_t *m, desktop_t *d, node_t *n, unsigned int tags_field);
+void tag_desktop(monitor_t *m, desktop_t *d, unsigned int tags_field);
+void list_tags(char *rsp);
+void init_tags(void);
+
+#endif
diff --git a/tree.c b/tree.c
index 8f893a46c4ca8c65c7319fffa5dca17f7ac742f4..7f8133451d298e01e55e3a89070f172ea2a9a0ed 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -1,5 +1,6 @@
 #include <float.h>
 #include <limits.h>
+#include <math.h>
 #include "bspwm.h"
 #include "desktop.h"
 #include "ewmh.h"
@@ -8,8 +9,8 @@
 #include "query.h"
 #include "settings.h"
 #include "stack.h"
+#include "tag.h"
 #include "window.h"
-#include <math.h>
 #include "tree.h"
 
 void arrange(monitor_t *m, desktop_t *d)
@@ -114,12 +115,20 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
     /* p: parent of focus */
     /* g: grand parent of focus */
 
+    if (f == NULL)
+        f = d->root;
+
     if (f == NULL) {
         d->root = n;
         d->focus = n;
     } else {
         node_t *c = make_node();
         node_t *p = f->parent;
+        if (p != NULL && f->split_mode == MODE_AUTOMATIC
+                && (p->first_child->vacant || p->second_child->vacant)) {
+            f = p;
+            p = f->parent;
+        }
         n->parent = c;
         c->birth_rotation = f->birth_rotation;
         switch (f->split_mode) {
@@ -210,17 +219,13 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
 
 void pseudo_focus(desktop_t *d, node_t *n)
 {
-    if (n == NULL)
-        return;
     d->focus = n;
-    stack(n);
+    if (n != NULL)
+        stack(n);
 }
 
 void focus_node(monitor_t *m, desktop_t *d, node_t *n)
 {
-    if (n == NULL && d->root != NULL)
-        return;
-
     if (mon->desk != d || n == NULL)
         clear_input_focus();
 
@@ -259,6 +264,7 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
     }
 
     focus_desktop(m, d);
+    pseudo_focus(d, n);
 
     if (n == NULL) {
         history_add(m, d, NULL);
@@ -270,7 +276,8 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
 
     n->client->urgent = false;
 
-    pseudo_focus(d, n);
+    if (!is_visible(d, n))
+        tag_node(m, d, n, n->client->tags_field | d->tags_field);
     history_add(m, d, n);
     set_input_focus(n);
 
@@ -321,6 +328,11 @@ client_t *make_client(xcb_window_t win)
     return c;
 }
 
+bool is_visible(desktop_t *d, node_t *n)
+{
+    return (d->tags_field & n->client->tags_field) != 0;
+}
+
 bool is_leaf(node_t *n)
 {
     return (n != NULL && n->first_child == NULL && n->second_child == NULL);
@@ -379,6 +391,29 @@ node_t *brother_tree(node_t *n)
         return n->parent->first_child;
 }
 
+node_t *closest_visible(desktop_t *d, node_t *n)
+{
+    if (n == NULL)
+        return NULL;
+    node_t *prev = prev_leaf(n, d->root);
+    node_t *next = next_leaf(n, d->root);
+    while (prev != NULL || next != NULL) {
+        if (prev != NULL) {
+            if (is_visible(d, prev))
+                return prev;
+            else
+                prev = prev_leaf(prev, d->root);
+        }
+        if (next != NULL) {
+            if (is_visible(d, next))
+                return next;
+            else
+                next = next_leaf(next, d->root);
+        }
+    }
+    return NULL;
+}
+
 node_t *first_extrema(node_t *n)
 {
     if (n == NULL)
@@ -552,10 +587,12 @@ node_t *nearest_from_distance(desktop_t *d, node_t *n, direction_t dir, client_s
     double ds = DBL_MAX;
 
     for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
-        if (a == n) continue;
-        if (!node_matches(n, a, sel)) continue;
-        if (is_tiled(a->client) != is_tiled(n->client)) continue;
-        if (is_tiled(a->client) && !is_adjacent(n, a, dir)) continue;
+        if (a == n ||
+                !is_visible(d, a) ||
+                !node_matches(n, a, sel) ||
+                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);
         double ds2 = distance(pt, pt2);
@@ -603,7 +640,7 @@ node_t *find_biggest(desktop_t *d, node_t *c, client_select_t sel)
     int r_area = tiled_area(r);
 
     for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
-        if (!is_tiled(f->client) || !node_matches(c, f, sel))
+        if (!is_visible(d, f) || !is_tiled(f->client) || !node_matches(c, f, sel))
             continue;
         int f_area = tiled_area(f);
         if (r == NULL) {
@@ -722,8 +759,15 @@ void unlink_node(desktop_t *d, node_t *n)
         d->root = NULL;
         d->focus = NULL;
     } else {
+        if (n == d->focus) {
+            d->focus = history_get_node(d, n);
+            if (d->focus == NULL)
+                d->focus = closest_visible(d, n);
+        }
+
         node_t *b;
         node_t *g = p->parent;
+
         if (is_first_child(n)) {
             b = p->second_child;
             if (!n->vacant)
@@ -733,7 +777,9 @@ void unlink_node(desktop_t *d, node_t *n)
             if (!n->vacant)
                 unrotate_tree(b, n->birth_rotation);
         }
+
         b->parent = g;
+
         if (g != NULL) {
             if (is_first_child(p))
                 g->first_child = b;
@@ -746,13 +792,6 @@ void unlink_node(desktop_t *d, node_t *n)
         b->birth_rotation = p->birth_rotation;
         n->parent = NULL;
         free(p);
-
-        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);
     }
     if (n->client->sticky)
@@ -858,6 +897,9 @@ bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop
             window_show(n2->client->window);
         }
 
+        tag_node(m1, d1, n2, n2->client->tags_field);
+        tag_node(m2, d2, n1, n1->client->tags_field);
+
         update_input_focus();
     }
 
@@ -908,6 +950,7 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
             update_input_focus();
     }
 
+    tag_node(md, dd, ns, ns->client->tags_field);
     arrange(ms, ds);
     if (ds != dd)
         arrange(md, dd);
diff --git a/tree.h b/tree.h
index f3987f5d1dad53bfa5dd32adf1058fe97373b1db..36770273d3ac8dbdac7973039dcc384c9a7fc738 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -1,48 +1,50 @@
 #ifndef _TREE_H
 #define _TREE_H
 
-node_t *make_node(void);
-client_t *make_client(xcb_window_t);
-void arrange(monitor_t *, desktop_t *);
-void apply_layout(monitor_t *, desktop_t *, node_t *, xcb_rectangle_t, xcb_rectangle_t);
-void focus_node(monitor_t *, desktop_t *, node_t *);
-void insert_node(monitor_t *, desktop_t *, node_t *, node_t *);
-void unlink_node(desktop_t *, node_t *);
-void remove_node(desktop_t *, node_t *);
-bool transfer_node(monitor_t *, desktop_t *, node_t *, monitor_t *, desktop_t *, node_t *);
-bool swap_nodes(monitor_t *, desktop_t *, node_t *, monitor_t *, desktop_t *, node_t *);
-void pseudo_focus(desktop_t *, node_t *);
+void arrange(monitor_t *m, desktop_t *d);
+void apply_layout(monitor_t *m, desktop_t *d, node_t *n, xcb_rectangle_t rect, xcb_rectangle_t root_rect);
+void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f);
+void pseudo_focus(desktop_t *d, node_t *n);
+void focus_node(monitor_t *m, desktop_t *d, node_t *n);
 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(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 *);
-bool is_floating(client_t *);
-bool is_first_child(node_t *);
-bool is_second_child(node_t *);
-void change_split_ratio(node_t *, value_change_t);
-void reset_mode(coordinates_t *);
-node_t *brother_tree(node_t *);
-node_t *first_extrema(node_t *);
-node_t *second_extrema(node_t *);
-node_t *next_leaf(node_t *, node_t *);
-node_t *prev_leaf(node_t *, node_t *);
-bool is_adjacent(node_t *, node_t *, direction_t);
-void get_opposite(direction_t, direction_t *);
-int tiled_area(node_t *);
-void move_fence(node_t *, direction_t, fence_move_t);
-void rotate_tree(node_t *, int);
-void rotate_brother(node_t *);
-void unrotate_tree(node_t *, int);
-void unrotate_brother(node_t *);
-void flip_tree(node_t *, flip_t);
-int balance_tree(node_t *);
-void destroy_tree(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 *);
+node_t *make_node(void);
+client_t *make_client(xcb_window_t win);
+bool is_visible(desktop_t *d, node_t *n);
+bool is_leaf(node_t *n);
+bool is_tiled(client_t *c);
+bool is_floating(client_t *c);
+bool is_first_child(node_t *n);
+bool is_second_child(node_t *n);
+void change_split_ratio(node_t *n, value_change_t chg);
+void reset_mode(coordinates_t *loc);
+node_t *brother_tree(node_t *n);
+node_t *closest_visible(desktop_t *d, node_t *n);
+node_t *first_extrema(node_t *n);
+node_t *second_extrema(node_t *n);
+node_t *next_leaf(node_t *n, node_t *r);
+node_t *prev_leaf(node_t *n, node_t *r);
+bool is_adjacent(node_t *a, node_t *b, direction_t dir);
+node_t *find_fence(node_t *n, direction_t dir);
+node_t *nearest_neighbor(desktop_t *d, 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);
+node_t *nearest_from_distance(desktop_t *d, node_t *n, direction_t dir, client_select_t sel);
+void get_opposite(direction_t src, direction_t *dst);
+int tiled_area(node_t *n);
+node_t *find_biggest(desktop_t *d, node_t *c, client_select_t sel);
+void move_fence(node_t *n, direction_t dir, fence_move_t mov);
+void rotate_tree(node_t *n, int deg);
+void rotate_brother(node_t *n);
+void unrotate_tree(node_t *n, int rot);
+void unrotate_brother(node_t *n);
+void flip_tree(node_t *n, flip_t flp);
+int balance_tree(node_t *n);
+void unlink_node(desktop_t *d, node_t *n);
+void remove_node(desktop_t *d, node_t *n);
+void destroy_tree(node_t *n);
+bool swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2);
+bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desktop_t *dd, node_t *nd);
+node_t *closest_node(desktop_t *d, node_t *n, cycle_dir_t dir, client_select_t sel);
+void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir);
+void update_vacant_state(node_t *n);
 
 #endif
diff --git a/types.h b/types.h
index 39ed113bd63957d4196f7a134f004b17ddfa7a60..6310f4450f69b996c66b3b3daa248aad252c137d 100644 (file)
--- a/types.h
+++ b/types.h
@@ -61,10 +61,9 @@ typedef struct {
 } client_select_t;
 
 typedef enum {
-    ALTER_NONE,
     ALTER_TOGGLE,
     ALTER_SET
-} state_alter_t;
+} alter_state_t;
 
 typedef enum {
     CYCLE_NEXT,
@@ -145,6 +144,7 @@ typedef struct {
     bool icccm_focus;
     xcb_rectangle_t floating_rectangle;
     xcb_rectangle_t tiled_rectangle;
+    unsigned int tags_field;
 } client_t;
 
 typedef struct node_t node_t;
@@ -172,6 +172,7 @@ struct desktop_t {
     desktop_t *next;
     int window_gap;
     unsigned int border_width;
+    unsigned int tags_field;
 };
 
 typedef struct monitor_t monitor_t;
@@ -226,6 +227,7 @@ typedef struct {
     bool focus;
     bool unmanage;
     char desc[MAXLEN];
+    char tags[MAXLEN];
 } rule_effect_t;
 
 typedef struct rule_t rule_t;
index cd62cd078b7e6066c8653199d2fa08981a1bc439..5e421c36eb156d97a1a2c55b52b5bc29a4a26886 100644 (file)
--- a/window.c
+++ b/window.c
@@ -7,6 +7,7 @@
 #include "rule.h"
 #include "settings.h"
 #include "stack.h"
+#include "tag.h"
 #include "tree.h"
 #include "window.h"
 
@@ -25,7 +26,8 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
         return;
 
     bool floating = false, fullscreen = false, locked = false, sticky = false, follow = false, transient = false, takes_focus = true, manage = true;
-    handle_rules(win, &m, &d, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &manage);
+    unsigned int tags_field = 0;
+    handle_rules(win, &m, &d, &tags_field, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &manage);
 
     if (!manage) {
         disable_floating_atom(win);
@@ -37,6 +39,7 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
 
     client_t *c = make_client(win);
     update_floating_rectangle(c);
+    c->tags_field = (tags_field == 0 ? d->tags_field : tags_field);
 
     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) {
@@ -61,17 +64,22 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
         set_fullscreen(d->focus, false);
 
     set_fullscreen(n, fullscreen);
-
     c->transient = transient;
 
+    tag_node(m, d, n, n->client->tags_field);
+
     bool give_focus = (takes_focus && (d == mon->desk || follow));
 
-    if (give_focus)
-        focus_node(m, d, n);
-    else if (takes_focus)
-        pseudo_focus(d, n);
-    else
-        stack(n);
+    if (is_visible(d, n)) {
+        if (give_focus)
+            focus_node(m, d, n);
+        else if (takes_focus)
+            pseudo_focus(d, n);
+        else
+            stack(n);
+    } else {
+        stack_under(n);
+    }
 
     xcb_rectangle_t *frect = &n->client->floating_rectangle;
     if (frect->x == 0 && frect->y == 0)
@@ -81,10 +89,12 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
 
     arrange(m, d);
 
-    if (d == m->desk && visible)
-        window_show(c->window);
-    else
-        window_hide(c->window);
+    if (visible && is_visible(d, n)) {
+        if (d == m->desk)
+            window_show(n->client->window);
+        else
+            window_hide(n->client->window);
+    }
 
     /* the same function is already called in `focus_node` but has no effects on unmapped windows */
     if (give_focus)
index 2690bba3eb5b98d299d32d0042ad90fc2cbd118b..683ac399463806d7b2227123230397238ac6647e 100644 (file)
--- a/window.h
+++ b/window.h
@@ -7,54 +7,54 @@
 #include <xcb/xcb_icccm.h>
 #include "types.h"
 
+void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win);
+void window_draw_border(node_t *n, bool focused_window, bool focused_monitor);
 pointer_state_t *make_pointer_state(void);
-void center(xcb_rectangle_t, xcb_rectangle_t *);
-bool contains(xcb_rectangle_t, xcb_rectangle_t);
-bool is_inside(monitor_t *, xcb_point_t);
-xcb_rectangle_t get_rectangle(client_t *);
-void get_side_handle(client_t *, direction_t, xcb_point_t *);
-monitor_t *monitor_from_point(xcb_point_t);
-monitor_t *underlying_monitor(client_t *);
-void manage_window(monitor_t *, desktop_t *, xcb_window_t);
+void center(xcb_rectangle_t a, xcb_rectangle_t *b);
+bool contains(xcb_rectangle_t a, xcb_rectangle_t b);
+bool is_inside(monitor_t *m, xcb_point_t pt);
+xcb_rectangle_t get_rectangle(client_t *c);
+void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt);
+monitor_t *monitor_from_point(xcb_point_t pt);
+monitor_t *underlying_monitor(client_t *c);
 void adopt_orphans(void);
-void window_draw_border(node_t *, bool, bool);
-uint32_t get_border_color(client_t *, bool, bool);
-void update_floating_rectangle(client_t *);
-void query_pointer(xcb_window_t *, xcb_point_t *);
-void window_close(node_t *);
-void window_kill(desktop_t *, node_t *);
-void set_fullscreen(node_t *, bool);
-void set_floating(node_t *, bool);
-void set_locked(monitor_t *, desktop_t *, node_t *, bool);
-void set_sticky(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 enable_floating_atom(xcb_window_t);
-void disable_floating_atom(xcb_window_t);
-void window_border_width(xcb_window_t, uint32_t);
-void window_move(xcb_window_t, int16_t, int16_t);
-void window_resize(xcb_window_t, uint16_t, uint16_t);
-void window_move_resize(xcb_window_t, int16_t, int16_t, uint16_t, uint16_t);
-bool window_focus(xcb_window_t);
-void window_raise(xcb_window_t);
-void window_stack(xcb_window_t, xcb_window_t, uint32_t);
-void window_above(xcb_window_t, xcb_window_t);
-void window_below(xcb_window_t, xcb_window_t);
-void window_lower(xcb_window_t);
-void window_set_visibility(xcb_window_t, bool);
-void window_hide(xcb_window_t);
-void window_show(xcb_window_t);
+void window_close(node_t *n);
+void window_kill(desktop_t *d, node_t *n);
+void set_fullscreen(node_t *n, bool value);
+void set_floating(node_t *n, bool value);
+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_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value);
+void set_floating_atom(xcb_window_t win, uint32_t value);
+void enable_floating_atom(xcb_window_t win);
+void disable_floating_atom(xcb_window_t win);
+uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor);
+void update_floating_rectangle(client_t *c);
+void query_pointer(xcb_window_t *win, xcb_point_t *pt);
+bool window_focus(xcb_window_t win);
+void window_border_width(xcb_window_t win, uint32_t bw);
+void window_move(xcb_window_t win, int16_t x, int16_t y);
+void window_resize(xcb_window_t win, uint16_t w, uint16_t h);
+void window_move_resize(xcb_window_t win, int16_t x, int16_t y, uint16_t w, uint16_t h);
+void window_raise(xcb_window_t win);
+void window_stack(xcb_window_t w1, xcb_window_t w2, uint32_t mode);
+void window_above(xcb_window_t w1, xcb_window_t w2);
+void window_below(xcb_window_t w1, xcb_window_t w2);
+void window_lower(xcb_window_t win);
+void window_set_visibility(xcb_window_t win, bool visible);
+void window_hide(xcb_window_t win);
+void window_show(xcb_window_t win);
 void toggle_visibility(void);
 void enable_motion_recorder(void);
 void disable_motion_recorder(void);
 void update_motion_recorder(void);
 void update_input_focus(void);
-void set_input_focus(node_t *);
+void set_input_focus(node_t *n);
 void clear_input_focus(void);
-void center_pointer(monitor_t *);
-void get_atom(char *, xcb_atom_t *);
-void set_atom(xcb_window_t, xcb_atom_t, uint32_t);
-bool has_proto(xcb_atom_t, xcb_icccm_get_wm_protocols_reply_t *);
-void send_client_message(xcb_window_t, xcb_atom_t property, xcb_atom_t);
+void center_pointer(monitor_t *m);
+void get_atom(char *name, xcb_atom_t *atom);
+void set_atom(xcb_window_t win, xcb_atom_t atom, uint32_t value);
+bool has_proto(xcb_atom_t atom, xcb_icccm_get_wm_protocols_reply_t *protocols);
+void send_client_message(xcb_window_t win, xcb_atom_t property, xcb_atom_t value);
 
 #endif