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)
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
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
-#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[])
{
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;
}
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);
}
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);
}
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
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);
d->root = d->focus = NULL;
d->window_gap = WINDOW_GAP;
d->border_width = BORDER_WIDTH;
+ d->tags_field = 1;
return 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)
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)
#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
.\" 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
.\" -----------------------------------------------------------------
.PP
last
.RS 4
-Selects the previously focused window on the current desktop\&.
+Selects the previously focused window\&.
.RE
.PP
focused
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
\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
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.
*-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
~~~~~
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...::
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
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
# 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
#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)
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;
}
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;
#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
#include "ewmh.h"
#include "history.h"
#include "monitor.h"
+#include "tag.h"
#include "pointer.h"
#include "query.h"
#include "restore.h"
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)) {
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;
} else {
return false;
}
+
num--, args++;
}
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;
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) {
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) {
return true;
}
-bool cmd_pointer(char **args, int num) {
+bool cmd_pointer(char **args, int num)
+{
if (num < 1)
return false;
while (num > 0) {
return true;
}
-bool cmd_restore(char **args, int num) {
+bool cmd_restore(char **args, int num)
+{
if (num < 1)
return false;
while (num > 0) {
return true;
}
-bool cmd_control(char **args, int num) {
+bool cmd_control(char **args, int num)
+{
if (num < 1)
return false;
while (num > 0) {
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};
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();
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;
}
#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
if (mon == m)
return;
- PRINTF("select monitor %s\n", m->name);
+ PRINTF("focus monitor %s\n", m->name);
mon = m;
#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
#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
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));
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);
}
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
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
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')
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);
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);
}
#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
#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)
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;
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;
*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)
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));
}
}
#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
bool history_aware_focus;
bool honor_ewmh_focus;
-void load_settings(void);
void run_config(void);
+void load_settings(void);
#endif
#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
--- /dev/null
+#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);
+}
--- /dev/null
+#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
#include <float.h>
#include <limits.h>
+#include <math.h>
#include "bspwm.h"
#include "desktop.h"
#include "ewmh.h"
#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)
/* 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) {
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();
}
focus_desktop(m, d);
+ pseudo_focus(d, n);
if (n == NULL) {
history_add(m, d, NULL);
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);
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);
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)
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);
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) {
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)
if (!n->vacant)
unrotate_tree(b, n->birth_rotation);
}
+
b->parent = g;
+
if (g != NULL) {
if (is_first_child(p))
g->first_child = b;
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)
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();
}
update_input_focus();
}
+ tag_node(md, dd, ns, ns->client->tags_field);
arrange(ms, ds);
if (ds != dd)
arrange(md, dd);
#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
} client_select_t;
typedef enum {
- ALTER_NONE,
ALTER_TOGGLE,
ALTER_SET
-} state_alter_t;
+} alter_state_t;
typedef enum {
CYCLE_NEXT,
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;
desktop_t *next;
int window_gap;
unsigned int border_width;
+ unsigned int tags_field;
};
typedef struct monitor_t monitor_t;
bool focus;
bool unmanage;
char desc[MAXLEN];
+ char tags[MAXLEN];
} rule_effect_t;
typedef struct rule_t rule_t;
#include "rule.h"
#include "settings.h"
#include "stack.h"
+#include "tag.h"
#include "tree.h"
#include "window.h"
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);
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) {
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)
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)
#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