Remove tags

Tags should generalize desktops.

To accomplish this, the main node attributes: (type, ratio) would have
to become a dictionary: ((tf1, (type1, ratio1)), (tf2, (type2, ratio2),
...). (`tf<n>` being a tag field.).
This commit is contained in:
Bastien Dejean 2013-10-19 10:56:34 +02:00
parent 6daf058c5d
commit 08e1c85ce0
19 changed files with 50 additions and 643 deletions

View file

@ -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 tag.c ewmh.c
events.c pointer.c window.c messages.c query.c restore.c rule.c ewmh.c
WM_OBJ = $(WM_SRC:.c=.o)
CL_SRC = bspc.c helpers.c
CL_OBJ = $(CL_SRC:.c=.o)

View file

@ -1,18 +1,17 @@
bspc.o: bspc.c common.h helpers.h
bspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h history.h messages.h monitor.h rule.h settings.h stack.h tag.h tree.h types.h window.h
bspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h history.h messages.h monitor.h rule.h settings.h stack.h tree.h types.h window.h
desktop.o: desktop.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h tree.h types.h window.h
events.o: events.c bspwm.h events.h ewmh.h helpers.h monitor.h query.h settings.h tree.h types.h window.h
ewmh.o: ewmh.c bspwm.h ewmh.h helpers.h settings.h tree.h types.h
helpers.o: helpers.c bspwm.h helpers.h types.h
history.o: history.c 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
messages.o: messages.c bspwm.h desktop.h ewmh.h helpers.h history.h messages.h monitor.h pointer.h query.h restore.h rule.h settings.h tree.h types.h window.h
monitor.o: monitor.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h tree.h types.h window.h
pointer.o: pointer.c bspwm.h helpers.h pointer.h query.h settings.h stack.h tree.h types.h window.h
query.o: query.c bspwm.h desktop.h helpers.h history.h messages.h monitor.h query.h tree.h types.h
restore.o: restore.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h restore.h settings.h stack.h tree.h types.h window.h
rule.o: rule.c bspwm.h ewmh.h helpers.h messages.h query.h rule.h tag.h types.h window.h
rule.o: rule.c bspwm.h ewmh.h helpers.h messages.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
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 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 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

View file

@ -45,7 +45,6 @@
#include "window.h"
#include "history.h"
#include "stack.h"
#include "tag.h"
#include "rule.h"
#include "ewmh.h"
#include "bspwm.h"
@ -197,7 +196,6 @@ void init(void)
rule_head = rule_tail = NULL;
history_head = history_tail = history_needle = NULL;
stack_head = stack_tail = NULL;
init_tags();
status_fifo = NULL;
last_motion_time = last_motion_x = last_motion_y = 0;
visible = auto_raise = sticky_still = record_history = true;
@ -301,8 +299,6 @@ 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);
}
@ -325,11 +321,8 @@ void put_status(void)
fprintf(status_fifo, "%c%s:", c, d->name);
}
}
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);
if (mon != NULL && mon->desk != NULL)
fprintf(status_fifo, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
}
fprintf(status_fifo, "\n");
fflush(status_fifo);
}

View file

@ -120,7 +120,6 @@ 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;
}
@ -280,7 +279,6 @@ 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))
if (is_visible(d, n))
window_show(n->client->window);
}
@ -289,7 +287,6 @@ 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))
if (is_visible(d, n))
window_hide(n->client->window);
}

View 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/12/2013
.\" Date: 10/19/2013
.\" Manual: Bspwm Manual
.\" Source: Bspwm 0.8.5
.\" Language: English
.\"
.TH "BSPWM" "1" "10/12/2013" "Bspwm 0\&.8\&.5" "Bspwm Manual"
.TH "BSPWM" "1" "10/19/2013" "Bspwm 0\&.8\&.5" "Bspwm Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
@ -518,7 +518,7 @@ Set the splitting ratio (or pull, or push) the edge located in the given directi
Rotate the tree holding the edge located in the given direction in relation to the selected window\&.
.RE
.PP
\fB\-t\fR, \fB\-\-toggle\fR floating|fullscreen|locked|sticky|private|visible[=on|off]
\fB\-t\fR, \fB\-\-toggle\fR floating|fullscreen|locked|sticky|private[=on|off]
.RS 4
Set or toggle the given state for the selected window\&.
.RE
@ -660,75 +660,6 @@ 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
@ -914,7 +845,7 @@ rule \fIOPTIONS\fR
\fBOptions\fR
.RS 4
.PP
\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-tags <name>|^<n>[,\&...]][\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-frame] [\-\-private] [\-\-unmanage] [\-\-one\-shot]
\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name> [\-d \fIDESKTOP_SEL\fR [\-\-follow]] [\-\-floating] [\-\-fullscreen] [\-\-locked] [\-\-sticky] [\-\-focus] [\-\-frame] [\-\-private] [\-\-unmanage] [\-\-one\-shot]
.RS 4
Create a new rule\&.
.RE
@ -1186,16 +1117,6 @@ Urgent unfocused desktop\&.
.RS 4
Layout of the focused desktop of the focused monitor\&.
.RE
.PP
\fIT<tag_name>\fR
.RS 4
Selected tag of the focused desktop of the focused monitor\&.
.RE
.PP
\fIt<tag_name>\fR
.RS 4
Non\-selected tag of the focused desktop of the focused monitor\&.
.RE
.SH "ENVIRONMENT VARIABLES"
.PP
\fIBSPWM_SOCKET\fR

View file

@ -334,7 +334,7 @@ Options
*-R*, *--rotate* 'DIR' '90|270|180'::
Rotate the tree holding the edge located in the given direction in relation to the selected window.
*-t*, *--toggle* floating|fullscreen|locked|sticky|private|visible[=on|off]::
*-t*, *--toggle* floating|fullscreen|locked|sticky|private[=on|off]::
Set or toggle the given state for the selected window.
*-c*, *--close*::
@ -414,40 +414,6 @@ 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
~~~~~
@ -550,7 +516,7 @@ rule 'OPTIONS'
Options
^^^^^^^
*-a*, *--add* <class_name>|<instance_name> [-d 'DESKTOP_SEL' [--follow]] [--tags <name>|^<n>[,...]][--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--frame] [--private] [--unmanage] [--one-shot]::
*-a*, *--add* <class_name>|<instance_name> [-d 'DESKTOP_SEL' [--follow]] [--floating] [--fullscreen] [--locked] [--sticky] [--focus] [--frame] [--private] [--unmanage] [--one-shot]::
Create a new rule.
*-r*, *--remove* <name>|^<n>|tail|head...::
@ -725,12 +691,6 @@ Each item as the form '<type><value>' where '<type>' is the first character of t
'L(tiled|monocle)'::
Layout of the focused desktop of the focused monitor.
'T<tag_name>'::
Selected tag of the focused desktop of the focused monitor.
't<tag_name>'::
Non-selected tag of the focused desktop of the focused monitor.
Environment Variables
---------------------

View file

@ -146,7 +146,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 && is_visible(h->loc.desktop, h->loc.node))
if (h->latest && h->loc.node != NULL && h->loc.node != n && h->loc.desktop == d)
return h->loc.node;
return NULL;
}
@ -177,7 +177,6 @@ bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst
if (!h->latest
|| h->loc.node == NULL
|| h->loc.node == ref->node
|| !is_visible(h->loc.desktop, h->loc.node)
|| !node_matches(&h->loc, ref, sel))
continue;
if (!record_history)

View file

@ -31,7 +31,6 @@
#include "ewmh.h"
#include "history.h"
#include "monitor.h"
#include "tag.h"
#include "pointer.h"
#include "query.h"
#include "restore.h"
@ -87,8 +86,6 @@ 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)) {
@ -216,8 +213,6 @@ bool cmd_window(char **args, int num)
set_sticky(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->sticky));
} else if (streq("private", key)) {
set_private(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->private));
} else if (streq("visible", key)) {
set_presence(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !is_visible(trg.desktop, trg.node)));
}
} else if (streq("-p", *args) || streq("--presel", *args)) {
num--, args++;
@ -547,138 +542,6 @@ bool cmd_monitor(char **args, int num)
return true;
}
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, trg.desktop, 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, trg.desktop, 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};
@ -778,13 +641,6 @@ 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);
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) {

View file

@ -36,7 +36,6 @@ 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);

View file

@ -68,7 +68,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 %u %c", d->name, d->border_width, d->window_gap, d->tags_field, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
snprintf(line, sizeof(line), "%s %u %i %c", d->name, d->border_width, d->window_gap, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
strncat(rsp, line, REMLEN(rsp));
if (d == m->desk)
strncat(rsp, " *", REMLEN(rsp));
@ -90,7 +90,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 %u %ux%u%+i%+i %c %c%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' : '-'), (c->frame ? 'e' : '-'), (c->private ? 'i' : '-'), (n->split_mode ? 'p' : '-'));
snprintf(line, sizeof(line), "%c %s 0x%X %u %ux%u%+i%+i %c %c%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' : '-'), (c->frame ? 'e' : '-'), (c->private ? 'i' : '-'), (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);
}

View file

@ -85,18 +85,17 @@ void restore_tree(char *file_path)
if (m == NULL)
continue;
int wg;
unsigned int tf, bw;
unsigned int bw;
char layout = 0, end = 0;
name[0] = '\0';
loc.desktop = NULL;
sscanf(line + level, "%s %u %i %u %c %c", name, &bw, &wg, &tf, &layout, &end);
sscanf(line + level, "%s %u %i %c %c", name, &bw, &wg, &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')
@ -138,7 +137,7 @@ void restore_tree(char *file_path)
client_t *c = make_client(XCB_NONE);
num_clients++;
char floating, transient, fullscreen, urgent, locked, sticky, frame, private, sd, sm, end = 0;
sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c %c%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, &frame, &private, &sm, &end);
sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c %c%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, &frame, &private, &sm, &end);
c->floating = (floating == '-' ? false : true);
c->transient = (transient == '-' ? false : true);
c->fullscreen = (fullscreen == '-' ? false : true);
@ -179,7 +178,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[] = {get_event_mask(n->client)};
xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
if (n->client->floating || !is_visible(d, n)) {
if (n->client->floating) {
n->vacant = true;
update_vacant_state(n->parent);
}

22
rule.c
View file

@ -29,7 +29,6 @@
#include "window.h"
#include "messages.h"
#include "query.h"
#include "tag.h"
#include "rule.h"
rule_t *make_rule(void)
@ -46,7 +45,6 @@ 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;
@ -116,7 +114,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, unsigned int *tags_field, bool *floating, bool *fullscreen, bool *locked, bool *sticky, bool *follow, bool *transient, bool *takes_focus, bool *frame, bool *private, bool *manage)
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 *frame, bool *private, bool *manage)
{
xcb_ewmh_get_atoms_reply_t win_type;
@ -196,20 +194,6 @@ void handle_rules(xcb_window_t win, monitor_t **m, desktop_t **d, unsigned int *
*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)
@ -256,10 +240,6 @@ 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));
}
}

2
rule.h
View file

@ -34,7 +34,7 @@ void remove_rule(rule_t *r);
void remove_rule_by_name(char *name);
bool remove_rule_by_index(int idx);
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 *frame, bool *private, bool *manage);
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 *frame, bool *private, bool *manage);
void list_rules(char *pattern, char *rsp);
#endif

191
tag.c
View file

@ -1,191 +0,0 @@
/* * Copyright (c) 2012-2013 Bastien Dejean
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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, d, 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 set_visibility(monitor_t *m, desktop_t *d, node_t *n, bool visible)
{
PRINTF("set visibilty %X: %s\n", n->client->window, BOOLSTR(visible));
if (!n->client->floating) {
n->vacant = !visible;
update_vacant_state(n->parent);
if (visible)
rotate_brother(n);
else
unrotate_brother(n);
}
if (visible) {
if (m->desk == d)
window_show(n->client->window);
if (d->focus == NULL) {
if (mon->desk == d)
focus_node(m, d, n);
else
pseudo_focus(d, n);
}
} else {
if (m->desk == d || n->client->sticky)
window_hide(n->client->window);
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);
}
}
}
void set_presence(monitor_t *m, desktop_t *d, node_t *n, bool present)
{
if (is_visible(d, n) != present) {
if (present)
tag_node(m, d, n, d, n->client->tags_field | d->tags_field);
else
tag_node(m, d, n, d, n->client->tags_field & ~d->tags_field);
}
}
void tag_node(monitor_t *m, desktop_t *d, node_t *n, desktop_t *ds, unsigned int tags_field)
{
if (num_tags < 1)
return;
bool visible = is_visible(ds, n);
n->client->tags_field = tags_field;
if ((visible && (tags_field & d->tags_field) == 0)
|| (!visible && (tags_field & d->tags_field) != 0)) {
set_visibility(m, d, n, !visible);
arrange(m, d);
}
}
void tag_desktop(monitor_t *m, desktop_t *d, unsigned int tags_field)
{
if (num_tags < 1)
return;
bool dirty = false;
unsigned int old_tags_field = d->tags_field;
d->tags_field = tags_field;
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
bool old_visible = (old_tags_field & n->client->tags_field) != 0;
bool visible = (tags_field & n->client->tags_field) != 0;
if (old_visible != visible) {
set_visibility(m, d, n, visible);
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);
}

52
tag.h
View file

@ -1,52 +0,0 @@
/* * Copyright (c) 2012-2013 Bastien Dejean
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BSPWM_TAG_H
#define BSPWM_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 set_visibility(monitor_t *m, desktop_t *d, node_t *n, bool visible);
void set_presence(monitor_t *m, desktop_t *d, node_t *n, bool present);
void tag_node(monitor_t *m, desktop_t *d, node_t *n, desktop_t *ds, 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

67
tree.c
View file

@ -33,7 +33,6 @@
#include "query.h"
#include "settings.h"
#include "stack.h"
#include "tag.h"
#include "window.h"
#include "tree.h"
@ -256,7 +255,7 @@ void insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f)
}
if (n->client->private)
update_privacy_level(n, true);
if (d->focus == NULL && is_visible(d, n))
if (d->focus == NULL)
d->focus = n;
if (n->client->sticky)
m->num_sticky++;
@ -285,7 +284,7 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
a = b;
}
sticky_still = true;
if (n == NULL && d->focus != NULL && is_visible(d, d->focus))
if (n == NULL && d->focus != NULL)
n = d->focus;
}
@ -322,8 +321,6 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n)
n->client->urgent = false;
if (!is_visible(d, n))
tag_node(m, d, n, d, n->client->tags_field | d->tags_field);
history_add(m, d, n);
set_input_focus(n);
@ -382,11 +379,6 @@ 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);
@ -445,29 +437,6 @@ 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;
}
void closest_public(desktop_t *d, node_t *n, node_t **closest, node_t **public)
{
if (n == NULL)
@ -477,7 +446,7 @@ void closest_public(desktop_t *d, node_t *n, node_t **closest, node_t **public)
while (prev != NULL || next != NULL) {
#define TESTLOOP(n) \
if (n != NULL) { \
if (is_visible(d, n) && is_tiled(n->client)) { \
if (is_tiled(n->client)) { \
if (n->privacy_level == 0) { \
if (n->parent == NULL || n->parent->privacy_level == 0) { \
*public = n; \
@ -539,22 +508,22 @@ node_t *prev_leaf(node_t *n, node_t *r)
return second_extrema(p->parent->first_child);
}
node_t *next_visible_leaf(desktop_t *d, node_t *n, node_t *r)
node_t *next_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
{
node_t *next = next_leaf(n, r);
if (next == NULL || is_visible(d, next))
if (next == NULL || is_tiled(next->client))
return next;
else
return next_visible_leaf(d, next, r);
return next_tiled_leaf(d, next, r);
}
node_t *prev_visible_leaf(desktop_t *d, node_t *n, node_t *r)
node_t *prev_tiled_leaf(desktop_t *d, node_t *n, node_t *r)
{
node_t *prev = prev_leaf(n, r);
if (prev == NULL || is_visible(d, prev))
if (prev == NULL || is_tiled(prev->client))
return prev;
else
return prev_visible_leaf(d, prev, r);
return prev_tiled_leaf(d, prev, r);
}
/* bool is_adjacent(node_t *a, node_t *r) */
@ -611,7 +580,6 @@ node_t *find_fence(node_t *n, direction_t dir)
return NULL;
}
node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel)
{
if (n == NULL || n->client->fullscreen
@ -691,7 +659,6 @@ node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
coordinates_t loc = {m, d, a};
if (a == n ||
!is_visible(d, a) ||
!node_matches(&loc, &ref, sel) ||
is_tiled(a->client) != is_tiled(n->client) ||
(is_tiled(a->client) && !is_adjacent(n, a, dir)))
@ -745,7 +712,7 @@ node_t *find_biggest(monitor_t *m, desktop_t *d, node_t *n, client_select_t sel)
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
coordinates_t loc = {m, d, f};
if (!is_visible(d, f) || !is_tiled(f->client) || !node_matches(&loc, &ref, sel))
if (!is_tiled(f->client) || !node_matches(&loc, &ref, sel))
continue;
int f_area = tiled_area(f);
if (r == NULL) {
@ -867,7 +834,7 @@ void unlink_node(monitor_t *m, desktop_t *d, node_t *n)
if (n == d->focus) {
d->focus = history_get_node(d, n);
if (d->focus == NULL)
d->focus = closest_visible(d, n);
d->focus = first_extrema(d->root);
}
if (n->client->private)
@ -1015,9 +982,6 @@ 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, d2, n2->client->tags_field);
tag_node(m2, d2, n1, d1, n1->client->tags_field);
update_input_focus();
}
@ -1068,7 +1032,6 @@ bool transfer_node(monitor_t *ms, desktop_t *ds, node_t *ns, monitor_t *md, desk
update_input_focus();
}
tag_node(md, dd, ns, ds, ns->client->tags_field);
arrange(ms, ds);
if (ds != dd)
arrange(md, dd);
@ -1104,17 +1067,17 @@ void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir)
node_t *p = d->focus->parent;
bool focus_first_child = is_first_child(d->focus);
node_t *head, *tail;
for (head = first_extrema(d->root); head != NULL && !is_visible(d, head); head = next_leaf(head, d->root))
for (head = first_extrema(d->root); head != NULL; head = next_leaf(head, d->root))
;
for (tail = second_extrema(d->root); tail != NULL && !is_visible(d, tail); tail = prev_leaf(tail, d->root))
for (tail = second_extrema(d->root); tail != NULL; tail = prev_leaf(tail, d->root))
;
if (head == tail)
return;
if (dir == CIRCULATE_FORWARD)
for (node_t *s = tail, *f = prev_visible_leaf(d, s, d->root); f != NULL; s = prev_visible_leaf(d, f, d->root), f = prev_visible_leaf(d, s, d->root))
for (node_t *s = tail, *f = prev_tiled_leaf(d, s, d->root); f != NULL; s = prev_tiled_leaf(d, f, d->root), f = prev_tiled_leaf(d, s, d->root))
swap_nodes(m, d, f, m, d, s);
else
for (node_t *f = head, *s = next_visible_leaf(d, f, d->root); s != NULL; f = next_visible_leaf(d, s, d->root), s = next_visible_leaf(d, f, d->root))
for (node_t *f = head, *s = next_tiled_leaf(d, f, d->root); s != NULL; f = next_tiled_leaf(d, s, d->root), s = next_tiled_leaf(d, f, d->root))
swap_nodes(m, d, f, m, d, s);
if (focus_first_child)
focus_node(m, d, p->first_child);

6
tree.h
View file

@ -33,7 +33,6 @@ void focus_node(monitor_t *m, desktop_t *d, node_t *n);
void update_current(void);
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);
@ -42,14 +41,13 @@ 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);
void closest_public(desktop_t *d, node_t *n, node_t **closest, node_t **public);
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);
node_t *next_visible_leaf(desktop_t *d, node_t *n, node_t *r);
node_t *prev_visible_leaf(desktop_t *d, node_t *n, node_t *r);
node_t *next_tiled_leaf(desktop_t *d, node_t *n, node_t *r);
node_t *prev_tiled_leaf(desktop_t *d, node_t *n, node_t *r);
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(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel);

View file

@ -166,7 +166,6 @@ typedef struct {
bool icccm_focus;
xcb_rectangle_t floating_rectangle;
xcb_rectangle_t tiled_rectangle;
unsigned int tags_field;
xcb_atom_t wm_state[MAX_STATE];
int num_states;
} client_t;
@ -197,7 +196,6 @@ struct desktop_t {
desktop_t *next;
int window_gap;
unsigned int border_width;
unsigned int tags_field;
};
typedef struct monitor_t monitor_t;
@ -255,7 +253,6 @@ typedef struct {
bool frame;
bool private;
char desc[MAXLEN];
char tags[MAXLEN];
} rule_effect_t;
typedef struct rule_t rule_t;

View file

@ -31,7 +31,6 @@
#include "rule.h"
#include "settings.h"
#include "stack.h"
#include "tag.h"
#include "tree.h"
#include "window.h"
@ -50,8 +49,7 @@ 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, frame = false, private = false, manage = true;
unsigned int tags_field = 0;
handle_rules(win, &m, &d, &tags_field, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &frame, &private, &manage);
handle_rules(win, &m, &d, &floating, &fullscreen, &locked, &sticky, &follow, &transient, &takes_focus, &frame, &private, &manage);
if (!manage) {
disable_floating_atom(win);
@ -63,7 +61,6 @@ 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);
c->frame = frame;
xcb_icccm_get_wm_class_reply_t reply;
@ -92,9 +89,6 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
set_fullscreen(n, fullscreen);
c->transient = transient;
if (!is_visible(d, n))
set_visibility(m, d, n, false);
xcb_rectangle_t *frect = &n->client->floating_rectangle;
if (frect->x == 0 && frect->y == 0)
center(m->rectangle, frect);
@ -104,21 +98,17 @@ void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
bool give_focus = (takes_focus && (d == mon->desk || follow));
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);
}
uint32_t values[] = {get_event_mask(n->client)};
xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values);
if (visible && is_visible(d, n)) {
if (visible) {
if (d == m->desk)
window_show(n->client->window);
else
@ -677,7 +667,6 @@ void toggle_visibility(void)
clear_input_focus();
for (monitor_t *m = mon_head; m != NULL; m = m->next)
for (node_t *n = first_extrema(m->desk->root); n != NULL; n = next_leaf(n, m->desk->root))
if (is_visible(m->desk, n))
window_set_visibility(n->client->window, visible);
if (visible)
update_input_focus();