mirror of
https://github.com/vale981/bspwm
synced 2025-03-04 09:21:42 -05:00
Generalize window commands to nodes
This commit is contained in:
parent
e434521fc3
commit
eb07d2fc06
69 changed files with 4225 additions and 2783 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@ tags
|
|||
bspwm
|
||||
bspc
|
||||
*.o
|
||||
tests/test_window
|
||||
|
|
45
Makefile
45
Makefile
|
@ -1,46 +1,37 @@
|
|||
VERSION = 0.9
|
||||
VERSION = $(shell git describe || cat VERSION)
|
||||
|
||||
CC ?= gcc
|
||||
LIBS = -lm -lxcb -lxcb-util -lxcb-icccm -lxcb-ewmh -lxcb-randr -lxcb-xinerama
|
||||
CFLAGS += -std=c99 -pedantic -Wall -Wextra -I$(PREFIX)/include
|
||||
CFLAGS += -D_POSIX_C_SOURCE=200112L -DVERSION=\"$(VERSION)\"
|
||||
LDFLAGS += -L$(PREFIX)/lib
|
||||
CPPFLAGS += -D_POSIX_C_SOURCE=200112L -DVERSION=\"$(VERSION)\"
|
||||
CFLAGS += -std=c99 -pedantic -Wall -Wextra
|
||||
LDLIBS = -lm -lxcb -lxcb-util -lxcb-icccm -lxcb-ewmh -lxcb-randr -lxcb-xinerama
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BINPREFIX = $(PREFIX)/bin
|
||||
MANPREFIX = $(PREFIX)/share/man
|
||||
BASHCPL = $(PREFIX)/share/bash-completion/completions
|
||||
ZSHCPL = $(PREFIX)/share/zsh/site-functions
|
||||
DOCPREFIX = $(PREFIX)/share/doc/bspwm
|
||||
PREFIX ?= /usr/local
|
||||
BINPREFIX ?= $(PREFIX)/bin
|
||||
MANPREFIX ?= $(PREFIX)/share/man
|
||||
DOCPREFIX ?= $(PREFIX)/share/doc/bspwm
|
||||
BASHCPL ?= $(PREFIX)/share/bash-completion/completions
|
||||
ZSHCPL ?= $(PREFIX)/share/zsh/site-functions
|
||||
|
||||
MD_DOCS = README.md doc/CONTRIBUTING.md doc/INSTALL.md doc/MISC.md doc/TODO.md
|
||||
XSESSIONS = $(PREFIX)/share/xsessions
|
||||
XSESSIONS ?= $(PREFIX)/share/xsessions
|
||||
|
||||
WM_SRC = bspwm.c helpers.c jsmn.c settings.c monitor.c desktop.c tree.c stack.c history.c \
|
||||
events.c pointer.c window.c messages.c parse.c query.c restore.c rule.c ewmh.c subscribe.c
|
||||
WM_OBJ = $(WM_SRC:.c=.o)
|
||||
CL_SRC = bspc.c helpers.c
|
||||
CL_OBJ = $(CL_SRC:.c=.o)
|
||||
CLI_SRC = bspc.c helpers.c
|
||||
CLI_OBJ = $(CLI_SRC:.c=.o)
|
||||
|
||||
all: CFLAGS += -Os
|
||||
all: LDFLAGS += -s
|
||||
all: bspwm bspc
|
||||
|
||||
debug: CFLAGS += -O0 -g -DDEBUG
|
||||
debug: CFLAGS += -O0 -g
|
||||
debug: bspwm bspc
|
||||
|
||||
include Sourcedeps
|
||||
|
||||
$(WM_OBJ) $(CL_OBJ): Makefile
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) $(OPTFLAGS) -c -o $@ $<
|
||||
$(WM_OBJ) $(CLI_OBJ): Makefile
|
||||
|
||||
bspwm: $(WM_OBJ)
|
||||
$(CC) -o $@ $(WM_OBJ) $(LDFLAGS) $(LIBS)
|
||||
|
||||
bspc: $(CL_OBJ)
|
||||
$(CC) -o $@ $(CL_OBJ) $(LDFLAGS) $(LIBS)
|
||||
bspc: $(CLI_OBJ)
|
||||
|
||||
install:
|
||||
mkdir -p "$(DESTDIR)$(BINPREFIX)"
|
||||
|
@ -73,6 +64,6 @@ doc:
|
|||
a2x -v -d manpage -f manpage -a revnumber=$(VERSION) doc/bspwm.1.asciidoc
|
||||
|
||||
clean:
|
||||
rm -f $(WM_OBJ) $(CL_OBJ) bspwm bspc
|
||||
rm -f $(WM_OBJ) $(CLI_OBJ) bspwm bspc
|
||||
|
||||
.PHONY: all debug install uninstall doc deps clean
|
||||
.PHONY: all debug install uninstall doc clean
|
||||
|
|
|
@ -97,7 +97,7 @@ The automatic mode generates window spirals that rotate clockwise (resp. anti-cl
|
|||
|
||||
### Manual Mode
|
||||
|
||||
The user can specify a region in the insertion point where the next new window should appear by sending a *window --presel DIR* message to *bspwm*.
|
||||
The user can specify a region in the insertion point where the next new window should appear by sending a *node -p|--presel-dir DIR* message to *bspwm*.
|
||||
|
||||
The *DIR* argument allows to specify how the insertion point should be split (horizontally or vertically) and if the new window should be the first or the second child of the new internal node (the insertion point will become its *brother*).
|
||||
|
||||
|
@ -130,13 +130,13 @@ For example, let's consider the following scenario:
|
|||
|
||||
In state *X*, the insertion point is *1*.
|
||||
|
||||
We send the following message to *bspwm*: *window --presel up*.
|
||||
We send the following message to *bspwm*: *node -p north*.
|
||||
|
||||
Then add a new window: *4*, this leads to state *Y*: the new internal node, *c* becomes *a*'s first child.
|
||||
|
||||
Finally we send another message: *window --presel left* and add window *5*.
|
||||
Finally we send another message: *node -p west* and add window *5*.
|
||||
|
||||
The ratio of the preselection (that ends up being the ratio of the split of the new internal node) can be change with the *window --ratio* message.
|
||||
The ratio of the preselection (that ends up being the ratio of the split of the new internal node) can be changed with the *node -o|--presel-ratio* message.
|
||||
|
||||
## Supported protocols and standards
|
||||
|
||||
|
|
18
Sourcedeps
18
Sourcedeps
|
@ -1,20 +1,20 @@
|
|||
bspc.o: bspc.c common.h helpers.h
|
||||
bspwm.o: bspwm.c bspwm.h common.h desktop.h events.h ewmh.h helpers.h history.h messages.h monitor.h rule.h settings.h stack.h subscribe.h types.h window.h
|
||||
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 subscribe.h types.h window.h
|
||||
desktop.o: desktop.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h subscribe.h tree.h types.h window.h
|
||||
events.o: events.c bspwm.h events.h ewmh.h helpers.h monitor.h query.h settings.h subscribe.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
|
||||
history.o: history.c bspwm.h helpers.h query.h tree.h types.h
|
||||
jsmn.o: jsmn.c jsmn.h
|
||||
messages.o: messages.c bspwm.h common.h desktop.h ewmh.h helpers.h history.h jsmn.h messages.h monitor.h parse.h pointer.h query.h restore.h rule.h settings.h subscribe.h tree.h types.h window.h
|
||||
messages.o: messages.c bspwm.h common.h desktop.h helpers.h jsmn.h messages.h monitor.h parse.h pointer.h query.h restore.h rule.h settings.h subscribe.h tree.h types.h window.h
|
||||
monitor.o: monitor.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h subscribe.h tree.h types.h window.h
|
||||
parse.o: parse.c helpers.h parse.h types.h
|
||||
pointer.o: pointer.c bspwm.h helpers.h monitor.h pointer.h query.h settings.h stack.h subscribe.h tree.h types.h window.h
|
||||
query.o: query.c bspwm.h desktop.h helpers.h history.h jsmn.h monitor.h parse.h query.h tree.h types.h
|
||||
restore.o: restore.c bspwm.h common.h desktop.h ewmh.h helpers.h history.h jsmn.h monitor.h parse.h query.h restore.h settings.h stack.h tree.h types.h
|
||||
rule.o: rule.c bspwm.h ewmh.h helpers.h parse.h rule.h settings.h types.h window.h
|
||||
parse.o: parse.c helpers.h parse.h subscribe.h types.h
|
||||
pointer.o: pointer.c bspwm.h helpers.h monitor.h query.h settings.h stack.h subscribe.h tree.h types.h window.h
|
||||
query.o: query.c bspwm.h desktop.h helpers.h history.h monitor.h parse.h query.h subscribe.h tree.h types.h
|
||||
restore.o: restore.c bspwm.h desktop.h ewmh.h helpers.h history.h jsmn.h monitor.h parse.h query.h restore.h settings.h stack.h subscribe.h tree.h types.h
|
||||
rule.o: rule.c bspwm.h ewmh.h helpers.h parse.h rule.h settings.h subscribe.h types.h window.h
|
||||
settings.o: settings.c bspwm.h helpers.h settings.h types.h
|
||||
stack.o: stack.c bspwm.h helpers.h stack.h types.h window.h
|
||||
stack.o: stack.c bspwm.h ewmh.h helpers.h stack.h subscribe.h tree.h types.h window.h
|
||||
subscribe.o: subscribe.c bspwm.h helpers.h settings.h subscribe.h tree.h types.h
|
||||
tree.o: tree.c bspwm.h desktop.h ewmh.h helpers.h history.h monitor.h query.h settings.h stack.h subscribe.h tree.h types.h window.h
|
||||
window.o: window.c bspwm.h ewmh.h helpers.h monitor.h parse.h query.h rule.h settings.h stack.h subscribe.h tree.h types.h window.h
|
||||
|
|
1
VERSION
Normal file
1
VERSION
Normal file
|
@ -0,0 +1 @@
|
|||
0.9
|
20
bspc.c
20
bspc.c
|
@ -22,14 +22,13 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include "helpers.h"
|
||||
#include "common.h"
|
||||
|
||||
|
@ -39,14 +38,16 @@ int main(int argc, char *argv[])
|
|||
struct sockaddr_un sock_address;
|
||||
char msg[BUFSIZ], rsp[BUFSIZ];
|
||||
|
||||
if (argc < 2)
|
||||
if (argc < 2) {
|
||||
err("No arguments given.\n");
|
||||
}
|
||||
|
||||
sock_address.sun_family = AF_UNIX;
|
||||
char *sp;
|
||||
|
||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
|
||||
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
err("Failed to create the socket.\n");
|
||||
}
|
||||
|
||||
sp = getenv(SOCKET_ENV_VAR);
|
||||
if (sp != NULL) {
|
||||
|
@ -54,13 +55,15 @@ int main(int argc, char *argv[])
|
|||
} else {
|
||||
char *host = NULL;
|
||||
int dn = 0, sn = 0;
|
||||
if (xcb_parse_display(NULL, &host, &dn, &sn) != 0)
|
||||
if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
|
||||
snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), SOCKET_PATH_TPL, host, dn, sn);
|
||||
}
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (connect(fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1)
|
||||
if (connect(fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
|
||||
err("Failed to connect to the socket.\n");
|
||||
}
|
||||
|
||||
argc--, argv++;
|
||||
int msg_len = 0;
|
||||
|
@ -70,8 +73,9 @@ int main(int argc, char *argv[])
|
|||
msg_len += n;
|
||||
}
|
||||
|
||||
if (send(fd, msg, msg_len, 0) == -1)
|
||||
if (send(fd, msg, msg_len, 0) == -1) {
|
||||
err("Failed to send the data.\n");
|
||||
}
|
||||
|
||||
int ret = 0, nb;
|
||||
while ((nb = recv(fd, rsp, sizeof(rsp)-1, 0)) > 0) {
|
||||
|
|
57
bspwm.c
57
bspwm.c
|
@ -24,28 +24,25 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#ifdef __OpenBSD__
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <xcb/xinerama.h>
|
||||
#include "types.h"
|
||||
#include "desktop.h"
|
||||
#include "monitor.h"
|
||||
#include "settings.h"
|
||||
#include "messages.h"
|
||||
#include "subscribe.h"
|
||||
#include "events.h"
|
||||
#include "common.h"
|
||||
#include "window.h"
|
||||
#include "history.h"
|
||||
#include "stack.h"
|
||||
#include "ewmh.h"
|
||||
#include "rule.h"
|
||||
#include "bspwm.h"
|
||||
|
@ -83,8 +80,9 @@ int main(int argc, char *argv[])
|
|||
} else {
|
||||
char *host = NULL;
|
||||
int dn = 0, sn = 0;
|
||||
if (xcb_parse_display(NULL, &host, &dn, &sn) != 0)
|
||||
if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
|
||||
snprintf(socket_path, sizeof(socket_path), SOCKET_PATH_TPL, host, dn, sn);
|
||||
}
|
||||
free(host);
|
||||
}
|
||||
|
||||
|
@ -93,28 +91,33 @@ int main(int argc, char *argv[])
|
|||
|
||||
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (sock_fd == -1)
|
||||
if (sock_fd == -1) {
|
||||
err("Couldn't create the socket.\n");
|
||||
}
|
||||
|
||||
unlink(socket_path);
|
||||
if (bind(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1)
|
||||
if (bind(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
|
||||
err("Couldn't bind a name to the socket.\n");
|
||||
}
|
||||
|
||||
if (listen(sock_fd, SOMAXCONN) == -1)
|
||||
if (listen(sock_fd, SOMAXCONN) == -1) {
|
||||
err("Couldn't listen to the socket.\n");
|
||||
}
|
||||
|
||||
if (config_path[0] == '\0') {
|
||||
char *config_home = getenv(CONFIG_HOME_ENV);
|
||||
if (config_home != NULL)
|
||||
if (config_home != NULL) {
|
||||
snprintf(config_path, sizeof(config_path), "%s/%s/%s", config_home, WM_NAME, CONFIG_NAME);
|
||||
else
|
||||
} else {
|
||||
snprintf(config_path, sizeof(config_path), "%s/%s/%s/%s", getenv("HOME"), ".config", WM_NAME, CONFIG_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
dpy = xcb_connect(NULL, &default_screen);
|
||||
|
||||
if (!check_connection(dpy))
|
||||
if (!check_connection(dpy)) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
load_settings();
|
||||
setup();
|
||||
|
@ -137,10 +140,12 @@ int main(int argc, char *argv[])
|
|||
FD_SET(sock_fd, &descriptors);
|
||||
FD_SET(dpy_fd, &descriptors);
|
||||
max_fd = MAX(sock_fd, dpy_fd);
|
||||
|
||||
for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
|
||||
FD_SET(pr->fd, &descriptors);
|
||||
if (pr->fd > max_fd)
|
||||
if (pr->fd > max_fd) {
|
||||
max_fd = pr->fd;
|
||||
}
|
||||
}
|
||||
|
||||
if (select(max_fd + 1, &descriptors, NULL, NULL, NULL) > 0) {
|
||||
|
@ -163,8 +168,9 @@ int main(int argc, char *argv[])
|
|||
if (rsp != NULL) {
|
||||
int ret = handle_message(msg, n, rsp);
|
||||
if (ret != MSG_SUBSCRIBE) {
|
||||
if (ret != MSG_SUCCESS)
|
||||
if (ret != MSG_SUCCESS) {
|
||||
fprintf(rsp, "%c", ret);
|
||||
}
|
||||
fflush(rsp);
|
||||
fclose(rsp);
|
||||
}
|
||||
|
@ -181,10 +187,12 @@ int main(int argc, char *argv[])
|
|||
free(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!check_connection(dpy))
|
||||
if (!check_connection(dpy)) {
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup();
|
||||
|
@ -201,7 +209,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
void init(void)
|
||||
{
|
||||
num_clients = 0;
|
||||
clients_count = 0;
|
||||
monitor_uid = desktop_uid = 0;
|
||||
mon = mon_head = mon_tail = pri_mon = NULL;
|
||||
history_head = history_tail = history_needle = NULL;
|
||||
|
@ -210,7 +218,7 @@ void init(void)
|
|||
subscribe_head = subscribe_tail = NULL;
|
||||
pending_rule_head = pending_rule_tail = NULL;
|
||||
last_motion_time = last_motion_x = last_motion_y = 0;
|
||||
visible = auto_raise = sticky_still = record_history = true;
|
||||
auto_raise = sticky_still = record_history = true;
|
||||
randr_base = 0;
|
||||
exit_status = 0;
|
||||
}
|
||||
|
@ -220,14 +228,16 @@ void setup(void)
|
|||
init();
|
||||
ewmh_init();
|
||||
screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
|
||||
if (screen == NULL)
|
||||
|
||||
if (screen == NULL) {
|
||||
err("Can't acquire the default screen.\n");
|
||||
}
|
||||
|
||||
root = screen->root;
|
||||
register_events();
|
||||
|
||||
screen_width = screen->width_in_pixels;
|
||||
screen_height = screen->height_in_pixels;
|
||||
root_depth = screen->root_depth;
|
||||
|
||||
meta_window = xcb_generate_id(dpy);
|
||||
xcb_create_window(dpy, XCB_COPY_FROM_PARENT, meta_window, root, -1, -1, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, XCB_NONE, NULL);
|
||||
|
@ -280,6 +290,7 @@ void setup(void)
|
|||
randr = false;
|
||||
warn("Couldn't retrieve monitors via RandR.\n");
|
||||
bool xinerama_is_active = false;
|
||||
|
||||
if (xcb_get_extension_data(dpy, &xcb_xinerama_id)->present) {
|
||||
xcb_xinerama_is_active_reply_t *xia = xcb_xinerama_is_active_reply(dpy, xcb_xinerama_is_active(dpy), NULL);
|
||||
if (xia != NULL) {
|
||||
|
@ -314,8 +325,9 @@ void setup(void)
|
|||
ewmh_update_current_desktop();
|
||||
frozen_pointer = make_pointer_state();
|
||||
xcb_get_input_focus_reply_t *ifo = xcb_get_input_focus_reply(dpy, xcb_get_input_focus(dpy), NULL);
|
||||
if (ifo != NULL && (ifo->focus == XCB_INPUT_FOCUS_POINTER_ROOT || ifo->focus == XCB_NONE))
|
||||
if (ifo != NULL && (ifo->focus == XCB_INPUT_FOCUS_POINTER_ROOT || ifo->focus == XCB_NONE)) {
|
||||
clear_input_focus();
|
||||
}
|
||||
free(ifo);
|
||||
}
|
||||
|
||||
|
@ -331,6 +343,8 @@ void register_events(void)
|
|||
|
||||
void cleanup(void)
|
||||
{
|
||||
mon = NULL;
|
||||
|
||||
while (mon_head != NULL) {
|
||||
remove_monitor(mon_head);
|
||||
}
|
||||
|
@ -343,6 +357,7 @@ void cleanup(void)
|
|||
while (pending_rule_head != NULL) {
|
||||
remove_pending_rule(pending_rule_head);
|
||||
}
|
||||
|
||||
empty_history();
|
||||
free(frozen_pointer);
|
||||
}
|
||||
|
|
5
bspwm.h
5
bspwm.h
|
@ -31,16 +31,16 @@
|
|||
#define CLIENT_EVENT_MASK (XCB_EVENT_MASK_PROPERTY_CHANGE | XCB_EVENT_MASK_FOCUS_CHANGE)
|
||||
#define META_WINDOW_IC "wm\0Bspwm"
|
||||
#define ROOT_WINDOW_IC "root\0Bspwm"
|
||||
#define PRESEL_FEEDBACK_IC "presel_feedback\0Bspwm"
|
||||
#define MOTION_RECORDER_IC "motion_recorder\0Bspwm"
|
||||
|
||||
xcb_connection_t *dpy;
|
||||
int default_screen, screen_width, screen_height;
|
||||
uint32_t num_clients;
|
||||
uint32_t clients_count;
|
||||
unsigned int monitor_uid;
|
||||
unsigned int desktop_uid;
|
||||
xcb_screen_t *screen;
|
||||
xcb_window_t root;
|
||||
uint8_t root_depth;
|
||||
char config_path[MAXLEN];
|
||||
|
||||
monitor_t *mon;
|
||||
|
@ -66,7 +66,6 @@ xcb_atom_t WM_TAKE_FOCUS;
|
|||
xcb_atom_t WM_DELETE_WINDOW;
|
||||
int exit_status;
|
||||
|
||||
bool visible;
|
||||
bool auto_raise;
|
||||
bool sticky_still;
|
||||
bool record_history;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
_bspc() {
|
||||
local commands='window desktop monitor query pointer rule restore control config quit'
|
||||
|
||||
local settings='external_rules_command status_prefix focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color focused_sticky_border_color normal_sticky_border_color focused_private_border_color active_private_border_color normal_private_border_color urgent_border_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio initial_polarity borderless_monocle gapless_monocle leaf_monocle focus_follows_pointer pointer_follows_focus pointer_follows_monitor history_aware_focus focus_by_distance ignore_ewmh_focus center_pseudo_tiled remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors'
|
||||
local settings='external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio initial_polarity borderless_monocle gapless_monocle leaf_monocle focus_follows_pointer pointer_follows_focus pointer_follows_monitor history_aware_focus focus_by_distance ignore_ewmh_focus center_pseudo_tiled remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors'
|
||||
|
||||
COMPREPLY=()
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
_bspc() {
|
||||
local -a commands settings
|
||||
commands=('window' 'desktop' 'monitor' 'query' 'pointer' 'rule' 'restore' 'control' 'config' 'quit')
|
||||
settings=('external_rules_command' 'status_prefix' 'focused_border_color' 'active_border_color' 'normal_border_color' 'presel_border_color' 'focused_locked_border_color' 'active_locked_border_color' 'normal_locked_border_color' 'focused_sticky_border_color' 'normal_sticky_border_color' 'focused_private_border_color' 'active_private_border_color' 'normal_private_border_color' 'urgent_border_color' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'initial_polarity' 'borderless_monocle' 'gapless_monocle' 'leaf_monocle' 'focus_follows_pointer' 'pointer_follows_focus' 'pointer_follows_monitor' 'history_aware_focus' 'focus_by_distance' 'ignore_ewmh_focus' 'center_pseudo_tiled' 'remove_disabled_monitors' 'remove_unplugged_monitors' 'merge_overlapping_monitors')
|
||||
settings=('external_rules_command' 'status_prefix' 'normal_border_color' 'active_border_color' 'focused_border_color' 'presel_feedback_color' 'border_width' 'window_gap' 'top_padding' 'right_padding' 'bottom_padding' 'left_padding' 'split_ratio' 'initial_polarity' 'borderless_monocle' 'gapless_monocle' 'leaf_monocle' 'focus_follows_pointer' 'pointer_follows_focus' 'pointer_follows_monitor' 'history_aware_focus' 'focus_by_distance' 'ignore_ewmh_focus' 'center_pseudo_tiled' 'remove_disabled_monitors' 'remove_unplugged_monitors' 'merge_overlapping_monitors')
|
||||
if (( CURRENT == 2 )) ; then
|
||||
_values 'command' "$commands[@]"
|
||||
elif (( CURRENT == 3 )) ; then
|
||||
|
|
265
desktop.c
265
desktop.c
|
@ -22,14 +22,16 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "bspwm.h"
|
||||
#include "ewmh.h"
|
||||
#include "history.h"
|
||||
#include "monitor.h"
|
||||
#include "query.h"
|
||||
#include "tree.h"
|
||||
#include "window.h"
|
||||
#include "desktop.h"
|
||||
#include "subscribe.h"
|
||||
#include "settings.h"
|
||||
|
@ -38,33 +40,48 @@ void focus_desktop(monitor_t *m, desktop_t *d)
|
|||
{
|
||||
focus_monitor(m);
|
||||
|
||||
if (d == mon->desk)
|
||||
return;
|
||||
show_desktop(d);
|
||||
if (m->desk != d) {
|
||||
hide_desktop(m->desk);
|
||||
}
|
||||
|
||||
m->desk = d;
|
||||
ewmh_update_current_desktop();
|
||||
|
||||
put_status(SBSC_MASK_DESKTOP_FOCUS, "desktop_focus %s %s\n", m->name, d->name);
|
||||
}
|
||||
|
||||
void activate_desktop(monitor_t *m, desktop_t *d)
|
||||
{
|
||||
if (d == m->desk) {
|
||||
return;
|
||||
}
|
||||
|
||||
show_desktop(d);
|
||||
hide_desktop(mon->desk);
|
||||
hide_desktop(m->desk);
|
||||
|
||||
mon->desk = d;
|
||||
m->desk = d;
|
||||
|
||||
ewmh_update_current_desktop();
|
||||
put_status(SBSC_MASK_DESKTOP_ACTIVATE, "desktop_activate %s %s\n", m->name, d->name);
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
desktop_t *closest_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, desktop_select_t sel)
|
||||
{
|
||||
desktop_t *f = (dir == CYCLE_PREV ? d->prev : d->next);
|
||||
if (f == NULL)
|
||||
if (f == NULL) {
|
||||
f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
|
||||
}
|
||||
|
||||
while (f != d) {
|
||||
coordinates_t loc = {m, f, NULL};
|
||||
if (desktop_matches(&loc, &loc, sel))
|
||||
if (desktop_matches(&loc, &loc, sel)) {
|
||||
return f;
|
||||
}
|
||||
f = (dir == CYCLE_PREV ? f->prev : f->next);
|
||||
if (f == NULL)
|
||||
if (f == NULL) {
|
||||
f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -72,51 +89,66 @@ desktop_t *closest_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, desktop_
|
|||
|
||||
void change_layout(monitor_t *m, desktop_t *d, layout_t l)
|
||||
{
|
||||
put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout %s %s %s\n", m->name, d->name, l==LAYOUT_TILED?"tiled":"monocle");
|
||||
d->layout = l;
|
||||
arrange(m, d);
|
||||
|
||||
put_status(SBSC_MASK_DESKTOP_LAYOUT, "desktop_layout %s %s %s\n", m->name, d->name, l==LAYOUT_TILED?"tiled":"monocle");
|
||||
|
||||
if (d == m->desk) {
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
}
|
||||
|
||||
void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
|
||||
bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
|
||||
{
|
||||
if (ms == md) {
|
||||
return;
|
||||
if (ms == NULL || md == NULL || d == NULL || ms == md) {
|
||||
return false;
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_DESKTOP_TRANSFER, "desktop_transfer %s %s %s\n", ms->name, d->name, md->name);
|
||||
bool was_active = (d == ms->desk);
|
||||
|
||||
desktop_t *dd = ms->desk;
|
||||
unlink_desktop(ms, d);
|
||||
|
||||
if (ms->sticky_count > 0 && was_active && ms->desk != NULL) {
|
||||
sticky_still = false;
|
||||
transfer_sticky_nodes(ms, d, ms->desk, d->root);
|
||||
sticky_still = true;
|
||||
}
|
||||
|
||||
if (md->desk != NULL) {
|
||||
hide_desktop(d);
|
||||
}
|
||||
|
||||
insert_desktop(md, d);
|
||||
|
||||
if (d == dd) {
|
||||
if (ms->desk != NULL) {
|
||||
show_desktop(ms->desk);
|
||||
}
|
||||
if (md->desk != d) {
|
||||
hide_desktop(d);
|
||||
}
|
||||
}
|
||||
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
translate_client(ms, md, n->client);
|
||||
}
|
||||
|
||||
history_transfer_desktop(md, d);
|
||||
adapt_geometry(&ms->rectangle, &md->rectangle, d->root);
|
||||
arrange(md, d);
|
||||
|
||||
if (d != dd && md->desk == d) {
|
||||
show_desktop(d);
|
||||
if (was_active && ms->desk != NULL) {
|
||||
if (mon == ms) {
|
||||
focus_node(ms, ms->desk, ms->desk->focus);
|
||||
} else {
|
||||
activate_node(ms, ms->desk, ms->desk->focus);
|
||||
}
|
||||
}
|
||||
|
||||
history_transfer_desktop(md, d);
|
||||
if (md->desk == d) {
|
||||
if (mon == md) {
|
||||
focus_node(md, d, d->focus);
|
||||
} else {
|
||||
activate_node(md, d, d->focus);
|
||||
}
|
||||
}
|
||||
|
||||
ewmh_update_wm_desktops();
|
||||
ewmh_update_desktop_names();
|
||||
ewmh_update_current_desktop();
|
||||
|
||||
put_status(SBSC_MASK_DESKTOP_TRANSFER, "desktop_transfer %s %s %s\n", ms->name, d->name, md->name);
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
desktop_t *make_desktop(const char *name)
|
||||
|
@ -176,9 +208,24 @@ void add_desktop(monitor_t *m, desktop_t *d)
|
|||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
void empty_desktop(desktop_t *d)
|
||||
desktop_t *find_desktop_in(const char *name, monitor_t *m)
|
||||
{
|
||||
destroy_tree(d->root);
|
||||
if (m == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
if (streq(d->name, name)) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void empty_desktop(monitor_t *m, desktop_t *d)
|
||||
{
|
||||
destroy_tree(m, d, d->root);
|
||||
d->root = d->focus = NULL;
|
||||
}
|
||||
|
||||
|
@ -186,17 +233,30 @@ void unlink_desktop(monitor_t *m, desktop_t *d)
|
|||
{
|
||||
desktop_t *prev = d->prev;
|
||||
desktop_t *next = d->next;
|
||||
desktop_t *last_desk = history_get_desktop(m, d);
|
||||
if (prev != NULL)
|
||||
|
||||
if (prev != NULL) {
|
||||
prev->next = next;
|
||||
if (next != NULL)
|
||||
}
|
||||
|
||||
if (next != NULL) {
|
||||
next->prev = prev;
|
||||
if (m->desk_head == d)
|
||||
}
|
||||
|
||||
if (m->desk_head == d) {
|
||||
m->desk_head = next;
|
||||
if (m->desk_tail == d)
|
||||
}
|
||||
|
||||
if (m->desk_tail == d) {
|
||||
m->desk_tail = prev;
|
||||
if (m->desk == d)
|
||||
m->desk = (last_desk == NULL ? (prev == NULL ? next : prev) : last_desk);
|
||||
}
|
||||
|
||||
if (m->desk == d) {
|
||||
m->desk = history_last_desktop(m, d);
|
||||
if (m->desk == NULL) {
|
||||
m->desk = (prev == NULL ? next : prev);
|
||||
}
|
||||
}
|
||||
|
||||
d->prev = d->next = NULL;
|
||||
}
|
||||
|
||||
|
@ -204,22 +264,33 @@ void remove_desktop(monitor_t *m, desktop_t *d)
|
|||
{
|
||||
put_status(SBSC_MASK_DESKTOP_REMOVE, "desktop_remove %s %s\n", m->name, d->name);
|
||||
|
||||
bool was_focused = (mon != NULL && d == mon->desk);
|
||||
bool was_active = (d == m->desk);
|
||||
history_remove(d, NULL, false);
|
||||
unlink_desktop(m, d);
|
||||
history_remove(d, NULL);
|
||||
empty_desktop(d);
|
||||
empty_desktop(m, d);
|
||||
free(d);
|
||||
|
||||
ewmh_update_current_desktop();
|
||||
ewmh_update_number_of_desktops();
|
||||
ewmh_update_desktop_names();
|
||||
|
||||
if (mon != NULL && m->desk != NULL) {
|
||||
if (was_focused) {
|
||||
update_focused();
|
||||
} else if (was_active) {
|
||||
activate_node(m, m->desk, m->desk->focus);
|
||||
}
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
void merge_desktops(monitor_t *ms, desktop_t *ds, monitor_t *md, desktop_t *dd)
|
||||
{
|
||||
if (ds == NULL || dd == NULL || ds == dd)
|
||||
if (ds == NULL || dd == NULL || ds == dd) {
|
||||
return;
|
||||
}
|
||||
node_t *n = first_extrema(ds->root);
|
||||
while (n != NULL) {
|
||||
node_t *next = next_leaf(n, ds->root);
|
||||
|
@ -228,10 +299,12 @@ 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)
|
||||
bool swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
|
||||
{
|
||||
if (d1 == NULL || d2 == NULL || d1 == d2) {
|
||||
return;
|
||||
if (d1 == NULL || d2 == NULL || d1 == d2 ||
|
||||
(m1->desk == d1 && m1->sticky_count > 0) ||
|
||||
(m2->desk == d2 && m2->sticky_count > 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_DESKTOP_SWAP, "desktop_swap %s %s %s %s\n", m1->name, d1->name, m2->name, d2->name);
|
||||
|
@ -240,27 +313,40 @@ void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
|
|||
bool d2_focused = (m2->desk == d2);
|
||||
|
||||
if (m1 != m2) {
|
||||
if (m1->desk == d1)
|
||||
if (m1->desk == d1) {
|
||||
m1->desk = d2;
|
||||
if (m1->desk_head == d1)
|
||||
}
|
||||
if (m1->desk_head == d1) {
|
||||
m1->desk_head = d2;
|
||||
if (m1->desk_tail == d1)
|
||||
}
|
||||
if (m1->desk_tail == d1) {
|
||||
m1->desk_tail = d2;
|
||||
if (m2->desk == d2)
|
||||
}
|
||||
if (m2->desk == d2) {
|
||||
m2->desk = d1;
|
||||
if (m2->desk_head == d2)
|
||||
}
|
||||
if (m2->desk_head == d2) {
|
||||
m2->desk_head = d1;
|
||||
if (m2->desk_tail == d2)
|
||||
}
|
||||
if (m2->desk_tail == d2) {
|
||||
m2->desk_tail = d1;
|
||||
}
|
||||
} else {
|
||||
if (m1->desk_head == d1)
|
||||
if (m1->desk == d1) {
|
||||
m1->desk = d2;
|
||||
} else if (m1->desk == d2) {
|
||||
m1->desk = d1;
|
||||
}
|
||||
if (m1->desk_head == d1) {
|
||||
m1->desk_head = d2;
|
||||
else if (m1->desk_head == d2)
|
||||
} else if (m1->desk_head == d2) {
|
||||
m1->desk_head = d1;
|
||||
if (m1->desk_tail == d1)
|
||||
}
|
||||
if (m1->desk_tail == d1) {
|
||||
m1->desk_tail = d2;
|
||||
else if (m1->desk_tail == d2)
|
||||
} else if (m1->desk_tail == d2) {
|
||||
m1->desk_tail = d1;
|
||||
}
|
||||
}
|
||||
|
||||
desktop_t *p1 = d1->prev;
|
||||
|
@ -268,14 +354,18 @@ void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
|
|||
desktop_t *p2 = d2->prev;
|
||||
desktop_t *n2 = d2->next;
|
||||
|
||||
if (p1 != NULL && p1 != d2)
|
||||
if (p1 != NULL && p1 != d2) {
|
||||
p1->next = d2;
|
||||
if (n1 != NULL && n1 != d2)
|
||||
}
|
||||
if (n1 != NULL && n1 != d2) {
|
||||
n1->prev = d2;
|
||||
if (p2 != NULL && p2 != d1)
|
||||
}
|
||||
if (p2 != NULL && p2 != d1) {
|
||||
p2->next = d1;
|
||||
if (n2 != NULL && n2 != d1)
|
||||
}
|
||||
if (n2 != NULL && n2 != d1) {
|
||||
n2->prev = d1;
|
||||
}
|
||||
|
||||
d1->prev = p2 == d1 ? d2 : p2;
|
||||
d1->next = n2 == d1 ? d2 : n2;
|
||||
|
@ -283,49 +373,64 @@ void swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
|
|||
d2->next = n1 == d2 ? d1 : n1;
|
||||
|
||||
if (m1 != m2) {
|
||||
for (node_t *n = first_extrema(d1->root); n != NULL; n = next_leaf(n, d1->root))
|
||||
translate_client(m1, m2, n->client);
|
||||
for (node_t *n = first_extrema(d2->root); n != NULL; n = next_leaf(n, d2->root))
|
||||
translate_client(m2, m1, n->client);
|
||||
adapt_geometry(&m1->rectangle, &m2->rectangle, d1->root);
|
||||
adapt_geometry(&m2->rectangle, &m1->rectangle, d2->root);
|
||||
history_swap_desktops(m1, d1, m2, d2);
|
||||
arrange(m1, d2);
|
||||
arrange(m2, d1);
|
||||
if (d1_focused && !d2_focused) {
|
||||
hide_desktop(d1);
|
||||
show_desktop(d2);
|
||||
} else if (!d1_focused && d2_focused) {
|
||||
show_desktop(d1);
|
||||
hide_desktop(d2);
|
||||
}
|
||||
}
|
||||
|
||||
update_input_focus();
|
||||
if (d1_focused && !d2_focused) {
|
||||
hide_desktop(d1);
|
||||
show_desktop(d2);
|
||||
} else if (!d1_focused && d2_focused) {
|
||||
show_desktop(d1);
|
||||
hide_desktop(d2);
|
||||
}
|
||||
|
||||
if (d1 == mon->desk) {
|
||||
focus_node(m2, d1, d1->focus);
|
||||
} else if (d1 == m2->desk) {
|
||||
activate_node(m2, d1, d1->focus);
|
||||
}
|
||||
|
||||
if (d2 == mon->desk) {
|
||||
focus_node(m1, d2, d2->focus);
|
||||
} else if (d2 == m1->desk) {
|
||||
activate_node(m1, d2, d2->focus);
|
||||
}
|
||||
|
||||
ewmh_update_wm_desktops();
|
||||
ewmh_update_desktop_names();
|
||||
ewmh_update_current_desktop();
|
||||
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void show_desktop(desktop_t *d)
|
||||
{
|
||||
if (!visible)
|
||||
if (d == NULL) {
|
||||
return;
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
|
||||
window_show(n->client->window);
|
||||
}
|
||||
show_node(d->root);
|
||||
}
|
||||
|
||||
void hide_desktop(desktop_t *d)
|
||||
{
|
||||
if (!visible)
|
||||
if (d == NULL) {
|
||||
return;
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
|
||||
window_hide(n->client->window);
|
||||
}
|
||||
hide_node(d->root);
|
||||
}
|
||||
|
||||
bool is_urgent(desktop_t *d)
|
||||
{
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
|
||||
if (n->client->urgent)
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
if (n->client->urgent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -28,19 +28,21 @@
|
|||
#define DEFAULT_DESK_NAME "Desktop"
|
||||
|
||||
void focus_desktop(monitor_t *m, desktop_t *d);
|
||||
void activate_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);
|
||||
bool transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d);
|
||||
desktop_t *make_desktop(const char *name);
|
||||
void rename_desktop(monitor_t *m, desktop_t *d, const char *name);
|
||||
void initialize_desktop(desktop_t *d);
|
||||
void insert_desktop(monitor_t *m, desktop_t *d);
|
||||
void add_desktop(monitor_t *m, desktop_t *d);
|
||||
void empty_desktop(desktop_t *d);
|
||||
desktop_t *find_desktop_in(const char *name, monitor_t *m);
|
||||
void empty_desktop(monitor_t *m, 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);
|
||||
bool 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);
|
||||
|
|
11
doc/TODO.md
11
doc/TODO.md
|
@ -1,7 +1,12 @@
|
|||
- Internal nodes selectors/actions: labels?
|
||||
- Clean up ewmh.c.
|
||||
- Add `--activate` command for desktops and monitors.
|
||||
- Provide a class and instance name flag for rules
|
||||
- Write tests.
|
||||
- Make panel example respond to pointer events.
|
||||
- Implement all the MUSTs in the EWMH specification.
|
||||
- Add zoom feature (view point distinct from root).
|
||||
- Add receptacles (leaves with NULL client pointer).
|
||||
- Handle window size constraints specified by size hints.
|
||||
- Add support for showing/hiding nodes.
|
||||
- Set more attributes in `make_client` (instead of doing it in `apply_rules`) and don't pass `XCB_NONE` as argument.
|
||||
- Invisible state.
|
||||
- Use BSD `sys/{queue/tree}.h` for {list,tree} structures?
|
||||
- Handle malloc failure everywhere.
|
||||
|
|
495
doc/bspwm.1
495
doc/bspwm.1
|
@ -2,12 +2,12 @@
|
|||
.\" Title: bspwm
|
||||
.\" Author: [see the "Author" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 11/26/2015
|
||||
.\" Date: 12/22/2015
|
||||
.\" Manual: Bspwm Manual
|
||||
.\" Source: Bspwm 0.9
|
||||
.\" Source: Bspwm 0.9-104-ge434521
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "BSPWM" "1" "11/26/2015" "Bspwm 0\&.9" "Bspwm Manual"
|
||||
.TH "BSPWM" "1" "12/22/2015" "Bspwm 0\&.9\-104\-ge434521" "Bspwm Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
|
@ -33,7 +33,7 @@ bspwm \- Binary space partitioning window manager
|
|||
.sp
|
||||
\fBbspwm\fR [\fB\-h\fR|\fB\-v\fR|\fB\-c\fR \fICONFIG_PATH\fR]
|
||||
.sp
|
||||
\fBbspc\fR \fICOMMAND\fR [\fIARGUMENTS\fR]
|
||||
\fBbspc\fR \fIDOMAIN\fR [\fISELECTOR\fR] \fICOMMANDS\fR
|
||||
.SH "DESCRIPTION"
|
||||
.sp
|
||||
\fBbspwm\fR is a tiling window manager that represents windows as the leaves of a full binary tree\&.
|
||||
|
@ -61,7 +61,7 @@ Use the given configuration file\&.
|
|||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
DIR := left | right | up | down
|
||||
DIR := north | west | south | east
|
||||
CYCLE_DIR := next | prev
|
||||
.fi
|
||||
.if n \{\
|
||||
|
@ -69,32 +69,40 @@ CYCLE_DIR := next | prev
|
|||
.\}
|
||||
.SH "SELECTORS"
|
||||
.sp
|
||||
Selectors are used to select a target window, desktop, or monitor\&. A selector can either describe the target relatively or name it globally\&.
|
||||
Selectors are used to select a target node, desktop, or monitor\&. A selector can either describe the target relatively or name it globally\&.
|
||||
.sp
|
||||
Descriptive (relative) selectors consist of a primary selector and any number of non\-conflicting modifiers as follows:
|
||||
Selectors consist of a descriptor and any number of non\-conflicting modifiers as follows:
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
PRIMARY_SELECTOR[\&.MODIFIER]*
|
||||
DESCRIPTOR(\&.MODIFIER)*
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.sp
|
||||
For obvious reasons, neither desktop nor monitor names may be valid descriptive selectors\&.
|
||||
.sp
|
||||
An exclamation mark can be prepended to certain modifiers in order to reverse their meaning\&.
|
||||
.SS "Window"
|
||||
.SS "Node"
|
||||
.sp
|
||||
Select a window\&.
|
||||
Select a node\&.
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
WINDOW_SEL := (<window_id>|DIR|CYCLE_DIR|biggest|last|focused|older|newer)[\&.[!]automatic][\&.[!](tiled|pseudo_tiled|floating|fullscreen)][\&.[!](below|normal|above)][\&.[!]local][\&.[!]same_class][\&.[!]focused][\&.[!](urgent|sticky|private|locked)]
|
||||
NODE_SEL := (<node_id>|PATH|DIR|CYCLE_DIR|last|older|newer|biggest|focused)[\&.[!]focused][\&.[!]automatic][\&.[!]local][\&.[!]leaf][\&.[!]STATE][\&.[!]FLAG][\&.[!]LAYER][\&.[!]same_class]
|
||||
|
||||
STATE := tiled|pseudo_tiled|floating|fullscreen
|
||||
|
||||
FLAG := urgent|sticky|private|locked
|
||||
|
||||
LAYER := below|normal|above
|
||||
|
||||
PATH := @[DESK_SEL:][[/]JUMP](/JUMP)*
|
||||
|
||||
JUMP := first|1|second|2|brother|parent|DIR
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
|
@ -105,12 +113,22 @@ WINDOW_SEL := (<window_id>|DIR|CYCLE_DIR|biggest|last|focused|older|newer)[\&.[!
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBPrimary Selectors\fR
|
||||
\fBDescriptors\fR
|
||||
.RS 4
|
||||
.PP
|
||||
<node_id>
|
||||
.RS 4
|
||||
Selects the node with the given ID\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIPATH\fR
|
||||
.RS 4
|
||||
Selects the node at the given path\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIDIR\fR
|
||||
.RS 4
|
||||
Selects the window in the given (spacial) direction relative to the active window\&.
|
||||
Selects the window in the given (spacial) direction relative to the active node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fICYCLE_DIR\fR
|
||||
|
@ -125,22 +143,58 @@ Selects the biggest window on the current desktop\&.
|
|||
.PP
|
||||
last
|
||||
.RS 4
|
||||
Selects the previously focused window\&.
|
||||
Selects the previously focused node\&.
|
||||
.RE
|
||||
.PP
|
||||
focused
|
||||
.RS 4
|
||||
Selects the currently focused window\&.
|
||||
Selects the currently focused node\&.
|
||||
.RE
|
||||
.PP
|
||||
older
|
||||
.RS 4
|
||||
Selects the window older than the focused window in the history\&.
|
||||
Selects the node older than the focused node in the history\&.
|
||||
.RE
|
||||
.PP
|
||||
newer
|
||||
.RS 4
|
||||
Selects the window newer than the focused window in the history\&.
|
||||
Selects the node newer than the focused node in the history\&.
|
||||
.RE
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBPath Jumps\fR
|
||||
.RS 4
|
||||
.sp
|
||||
The initial node is the focused node (or the root if the path starts with \fI/\fR) of the focused desktop (or the selected desktop if the path has a \fIDESK_SEL\fR prefix)\&.
|
||||
.PP
|
||||
1|first
|
||||
.RS 4
|
||||
Jumps to the first child\&.
|
||||
.RE
|
||||
.PP
|
||||
2|second
|
||||
.RS 4
|
||||
Jumps to the second child\&.
|
||||
.RE
|
||||
.PP
|
||||
brother
|
||||
.RS 4
|
||||
Jumps to the brother node\&.
|
||||
.RE
|
||||
.PP
|
||||
parent
|
||||
.RS 4
|
||||
Jumps to the parent node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIDIR\fR
|
||||
.RS 4
|
||||
Jumps to the node holding the edge in the given direction\&.
|
||||
.RE
|
||||
.RE
|
||||
.sp
|
||||
|
@ -152,19 +206,29 @@ Selects the window newer than the focused window in the history\&.
|
|||
\fBModifiers\fR
|
||||
.RS 4
|
||||
.PP
|
||||
[!](tiled|pseudo_tiled|floating|fullscreen)
|
||||
[!]focused
|
||||
.RS 4
|
||||
Only consider windows having or not having the given state\&.
|
||||
Only consider focused or unfocused nodes\&.
|
||||
.RE
|
||||
.PP
|
||||
[!]automatic
|
||||
.RS 4
|
||||
Only consider windows in automatic or manual insertion mode\&.
|
||||
Only consider nodes in automatic or manual insertion mode\&.
|
||||
.RE
|
||||
.PP
|
||||
[!]focused
|
||||
[!]local
|
||||
.RS 4
|
||||
Only consider focused or unfocused windows\&.
|
||||
Only consider nodes in or not in the current desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
[!]leaf
|
||||
.RS 4
|
||||
Only consider leaves or internal nodes\&.
|
||||
.RE
|
||||
.PP
|
||||
[!](tiled|pseudo_tiled|floating|fullscreen)
|
||||
.RS 4
|
||||
Only consider windows in or not in the given state\&.
|
||||
.RE
|
||||
.PP
|
||||
[!]same_class
|
||||
|
@ -172,11 +236,6 @@ Only consider focused or unfocused windows\&.
|
|||
Only consider windows that have or don\(cqt have the same class as the current window\&.
|
||||
.RE
|
||||
.PP
|
||||
[!]local
|
||||
.RS 4
|
||||
Only consider windows in or not in the current desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
[!](private|urgent|sticky|locked)
|
||||
.RS 4
|
||||
Only consider windows that have or don\(cqt have the given flag set\&.
|
||||
|
@ -206,7 +265,7 @@ DESKTOP_SEL := (<desktop_name>|[MONITOR_SEL:](focused|^<n>)CYCLE_DIR|last|older|
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBPrimary Selectors\fR
|
||||
\fBDescriptors\fR
|
||||
.RS 4
|
||||
.PP
|
||||
<desktop_name>
|
||||
|
@ -292,7 +351,7 @@ MONITOR_SEL := (<monitor_name>|^<n>|DIR|CYCLE_DIR|last|primary|focused|older|new
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBPrimary Selectors\fR
|
||||
\fBDescriptors\fR
|
||||
.RS 4
|
||||
.PP
|
||||
<monitor_name>
|
||||
|
@ -380,12 +439,12 @@ fullscreen
|
|||
.RS 4
|
||||
Fills its monitor rectangle and has no borders\&. It is send in the ABOVE layer by default\&.
|
||||
.RE
|
||||
.SH "WINDOW FLAGS"
|
||||
.SH "NODE FLAGS"
|
||||
.PP
|
||||
locked
|
||||
.RS 4
|
||||
Ignores the
|
||||
\fBwindow \-\-close\fR
|
||||
\fBnode \-\-close\fR
|
||||
message\&.
|
||||
.RE
|
||||
.PP
|
||||
|
@ -408,8 +467,8 @@ Has its urgency hint set\&. This flag is set externally\&.
|
|||
There\(cqs three stacking layers: BELOW, NORMAL and ABOVE\&.
|
||||
.sp
|
||||
In each layer, the window are orderered as follow: tiled & pseudo\-tiled < fullscreen < floating\&.
|
||||
.SH "COMMANDS"
|
||||
.SS "Window"
|
||||
.SH "DOMAINS"
|
||||
.SS "Node"
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
|
@ -419,7 +478,7 @@ In each layer, the window are orderered as follow: tiled & pseudo\-tiled < fulls
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
window [\fIWINDOW_SEL\fR] \fIOPTIONS\fR
|
||||
node [\fINODE_SEL\fR] \fICOMMANDS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -427,69 +486,89 @@ window [\fIWINDOW_SEL\fR] \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCommands\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-f\fR, \fB\-\-focus\fR [\fIWINDOW_SEL\fR]
|
||||
\fB\-f\fR, \fB\-\-focus\fR [\fINODE_SEL\fR]
|
||||
.RS 4
|
||||
Focus the selected or given window\&.
|
||||
Focus the selected or given node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-a\fR, \fB\-\-activate\fR [\fIWINDOW_SEL\fR]
|
||||
\fB\-a\fR, \fB\-\-activate\fR [\fINODE_SEL\fR]
|
||||
.RS 4
|
||||
Activate the selected or given window\&.
|
||||
Activate the selected or given node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-d\fR, \fB\-\-to\-desktop\fR \fIDESKTOP_SEL\fR
|
||||
.RS 4
|
||||
Send the selected window to the given desktop\&.
|
||||
Send the selected node to the given desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-m\fR, \fB\-\-to\-monitor\fR \fIMONITOR_SEL\fR
|
||||
.RS 4
|
||||
Send the selected window to the given monitor\&.
|
||||
Send the selected node to the given monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-w\fR, \fB\-\-to\-window\fR \fIWINDOW_SEL\fR
|
||||
\fB\-n\fR, \fB\-\-to\-node\fR \fINODE_SEL\fR
|
||||
.RS 4
|
||||
Transplant the selected window to the given window\&.
|
||||
Transplant the selected node to the given node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-s\fR, \fB\-\-swap\fR \fIWINDOW_SEL\fR
|
||||
\fB\-s\fR, \fB\-\-swap\fR \fINODE_SEL\fR
|
||||
.RS 4
|
||||
Swap the selected window with the given window\&.
|
||||
Swap the selected node with the given node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-p\fR, \fB\-\-presel\fR \fIDIR\fR|cancel
|
||||
\fB\-p\fR, \fB\-\-presel\-dir\fR \fIDIR\fR|cancel
|
||||
.RS 4
|
||||
Preselect the splitting area of the selected window (or cancel the preselection)\&.
|
||||
Preselect the splitting area of the selected node (or cancel the preselection)\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-r\fR, \fB\-\-ratio\fR \fIRATIO\fR
|
||||
\fB\-o\fR, \fB\-\-presel\-ratio\fR \fIRATIO\fR
|
||||
.RS 4
|
||||
Set the splitting ratio of the selected window (0 <
|
||||
Set the splitting ratio of the preselection area\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-r\fR, \fB\-\-ratio\fR \fIRATIO\fR|\(+-\fIPIXELS\fR
|
||||
.RS 4
|
||||
Set the splitting ratio of the selected node (0 <
|
||||
\fIRATIO\fR
|
||||
< 1)\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-e\fR, \fB\-\-edge\fR \fIDIR\fR \fIRATIO\fR|\(+-\fIPIXELS\fR
|
||||
\fB\-R\fR, \fB\-\-rotate\fR \fI90|270|180\fR
|
||||
.RS 4
|
||||
Set or change the splitting ratio of the edge located in the given direction in relation to the selected window\&.
|
||||
Rotate the tree rooted at the selected node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-R\fR, \fB\-\-rotate\fR \fIDIR\fR \fI90|270|180\fR
|
||||
\fB\-F\fR, \fB\-\-flip\fR \fIhorizontal|vertical\fR
|
||||
.RS 4
|
||||
Rotate the tree holding the edge located in the given direction in relation to the selected window\&.
|
||||
Flip the the tree rooted at selected node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-t\fR, \fB\-\-state\fR tiled|pseudo_tiled|floating|fullscreen
|
||||
\fB\-E\fR, \fB\-\-equalize\fR
|
||||
.RS 4
|
||||
Reset the split ratios of the tree rooted at the selected node to their default value\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-B\fR, \fB\-\-balance\fR
|
||||
.RS 4
|
||||
Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-C\fR, \fB\-\-circulate\fR forward|backward
|
||||
.RS 4
|
||||
Circulate the windows of the tree rooted at the selected node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-t\fR, \fB\-\-state\fR [~](tiled|pseudo_tiled|floating|fullscreen)
|
||||
.RS 4
|
||||
Set the state of the selected window\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-g\fR, \fB\-\-flag\fR locked|sticky|private[=on|off]
|
||||
.RS 4
|
||||
Set or toggle the given flag for the selected window\&.
|
||||
Set or toggle the given flag for the selected node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-l\fR, \fB\-\-layer\fR below|normal|above
|
||||
|
@ -499,12 +578,12 @@ Set the stacking layer of the selected window\&.
|
|||
.PP
|
||||
\fB\-c\fR, \fB\-\-close\fR
|
||||
.RS 4
|
||||
Close the selected window\&.
|
||||
Close the windows rooted at the selected node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-k\fR, \fB\-\-kill\fR
|
||||
.RS 4
|
||||
Kill the selected window\&.
|
||||
Kill the windows rooted at the selected node\&.
|
||||
.RE
|
||||
.RE
|
||||
.SS "Desktop"
|
||||
|
@ -517,7 +596,7 @@ Kill the selected window\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
desktop [\fIDESKTOP_SEL\fR] \fIOPTIONS\fR
|
||||
desktop [\fIDESKTOP_SEL\fR] \fICOMMANDS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -525,7 +604,7 @@ desktop [\fIDESKTOP_SEL\fR] \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCOMMANDS\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-f\fR, \fB\-\-focus\fR [\fIDESKTOP_SEL\fR]
|
||||
|
@ -533,6 +612,11 @@ desktop [\fIDESKTOP_SEL\fR] \fIOPTIONS\fR
|
|||
Focus the selected or given desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-a\fR, \fB\-\-activate\fR [\fIDESKTOP_SEL\fR]
|
||||
.RS 4
|
||||
Activate the selected or given desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-m\fR, \fB\-\-to\-monitor\fR \fIMONITOR_SEL\fR
|
||||
.RS 4
|
||||
Send the selected desktop to the given monitor\&.
|
||||
|
@ -562,36 +646,6 @@ Bubble the selected desktop in the given direction\&.
|
|||
.RS 4
|
||||
Remove the selected desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-c\fR, \fB\-\-cancel\-presel\fR
|
||||
.RS 4
|
||||
Cancel the preselection of all the windows of the selected desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-F\fR, \fB\-\-flip\fR \fIhorizontal|vertical\fR
|
||||
.RS 4
|
||||
Flip the tree of the selected desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-R\fR, \fB\-\-rotate\fR \fI90|270|180\fR
|
||||
.RS 4
|
||||
Rotate the tree of the selected desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-E\fR, \fB\-\-equalize\fR
|
||||
.RS 4
|
||||
Reset the split ratios of the tree of the selected desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-B\fR, \fB\-\-balance\fR
|
||||
.RS 4
|
||||
Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-C\fR, \fB\-\-circulate\fR forward|backward
|
||||
.RS 4
|
||||
Circulate the leaves of the tree of the selected desktop\&.
|
||||
.RE
|
||||
.RE
|
||||
.SS "Monitor"
|
||||
.sp
|
||||
|
@ -603,7 +657,7 @@ Circulate the leaves of the tree of the selected desktop\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
monitor [\fIMONITOR_SEL\fR] \fIOPTIONS\fR
|
||||
monitor [\fIMONITOR_SEL\fR] \fICOMMANDS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -611,7 +665,7 @@ monitor [\fIMONITOR_SEL\fR] \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCommands\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-f\fR, \fB\-\-focus\fR [\fIMONITOR_SEL\fR]
|
||||
|
@ -659,7 +713,7 @@ Swap the selected monitor with the given monitor\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
query \fIOPTIONS\fR
|
||||
query \fICOMMANDS\fR [\fIOPTIONS\fR]
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -667,12 +721,12 @@ query \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCommands\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-W\fR, \fB\-\-windows\fR
|
||||
\fB\-N\fR, \fB\-\-nodes\fR
|
||||
.RS 4
|
||||
List the IDs of the matching windows\&.
|
||||
List the IDs of the matching nodes\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-D\fR, \fB\-\-desktops\fR
|
||||
|
@ -689,33 +743,6 @@ List the names of the matching monitors\&.
|
|||
.RS 4
|
||||
Print a JSON representation of the matching item\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-H\fR, \fB\-\-history\fR
|
||||
.RS 4
|
||||
Print the focus history as it relates to the query\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-S\fR, \fB\-\-stack\fR
|
||||
.RS 4
|
||||
Print the window stacking order\&.
|
||||
.RE
|
||||
.PP
|
||||
[\fB\-m\fR,\fB\-\-monitor\fR [\fIMONITOR_SEL\fR]] | [\fB\-d\fR,\fB\-\-desktop\fR [\fIDESKTOP_SEL\fR]] | [\fB\-w\fR, \fB\-\-window\fR [\fIWINDOW_SEL\fR]]
|
||||
.RS 4
|
||||
Constrain matches to the selected monitor, desktop or window\&.
|
||||
.RE
|
||||
.RE
|
||||
.SS "Restore"
|
||||
.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
|
||||
restore \fIOPTIONS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -726,22 +753,16 @@ restore \fIOPTIONS\fR
|
|||
\fBOptions\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-T\fR, \fB\-\-tree\fR <file_path>
|
||||
[\fB\-m\fR,\fB\-\-monitor\fR [\fIMONITOR_SEL\fR]] | [\fB\-d\fR,\fB\-\-desktop\fR [\fIDESKTOP_SEL\fR]] | [\fB\-n\fR, \fB\-\-node\fR [\fINODE_SEL\fR]]
|
||||
.RS 4
|
||||
Load the desktop trees from the given file\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-H\fR, \fB\-\-history\fR <file_path>
|
||||
.RS 4
|
||||
Load the focus history from the given file\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-S\fR, \fB\-\-stack\fR <file_path>
|
||||
.RS 4
|
||||
Load the window stacking order from the given file\&.
|
||||
Constrain matches to the selected monitor, desktop or node\&. The descriptor can be omitted for
|
||||
\fI\-M\fR,
|
||||
\fI\-D\fR
|
||||
and
|
||||
\fI\-N\fR\&.
|
||||
.RE
|
||||
.RE
|
||||
.SS "Control"
|
||||
.SS "Wm"
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
|
@ -751,7 +772,7 @@ Load the window stacking order from the given file\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
control \fIOPTIONS\fR
|
||||
wm \fICOMMANDS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -759,32 +780,40 @@ control \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCommands\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-\-adopt\-orphans\fR
|
||||
\fB\-d\fR, \fB\-\-dump\-state\fR
|
||||
.RS 4
|
||||
Dump the current world state on standard output\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-l\fR, \fB\-\-load\-state\fR <file_path>
|
||||
.RS 4
|
||||
Load a world state from the given file\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-a\fR, \fB\-\-add\-monitor\fR <name> WxH+X+Y
|
||||
.RS 4
|
||||
Add a monitor for the given name and rectangle\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-r\fR, \fB\-\-remove\-monitor\fR <name>
|
||||
.RS 4
|
||||
Remove the monitor with the given name\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-o\fR, \fB\-\-adopt\-orphans\fR
|
||||
.RS 4
|
||||
Manage all the unmanaged windows remaining from a previous session\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-toggle\-visibility\fR
|
||||
\fB\-h\fR, \fB\-\-record\-history\fR on|off
|
||||
.RS 4
|
||||
Toggle the visibility of all the windows\&.
|
||||
Enable or disable the recording of node focus history\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-record\-history\fR on|off
|
||||
.RS 4
|
||||
Enable or disable the recording of window focus history\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-subscribe\fR (all|report|monitor|desktop|window|\&...)*
|
||||
.RS 4
|
||||
Continuously print status information\&. See the
|
||||
\fBEVENTS\fR
|
||||
section for the detailed description of each event\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-\-get\-status\fR
|
||||
\fB\-g\fR, \fB\-\-get\-status\fR
|
||||
.RS 4
|
||||
Print the current status information\&.
|
||||
.RE
|
||||
|
@ -799,7 +828,7 @@ Print the current status information\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
pointer \fIOPTIONS\fR
|
||||
pointer \fICOMMANDS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -807,7 +836,7 @@ pointer \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCommands\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-g\fR, \fB\-\-grab\fR focus|move|resize_side|resize_corner
|
||||
|
@ -835,7 +864,7 @@ Terminate the current pointer action\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.sp
|
||||
rule \fIOPTIONS\fR
|
||||
rule \fICOMMANDS\fR
|
||||
.RE
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -843,20 +872,20 @@ rule \fIOPTIONS\fR
|
|||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBOptions\fR
|
||||
\fBCommands\fR
|
||||
.RS 4
|
||||
.PP
|
||||
\fB\-a\fR, \fB\-\-add\fR <class_name>|<instance_name>|* [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]
|
||||
\fB\-a\fR, \fB\-\-add\fR (<class_name>|\fB)[:(<instance_name>|\fR)] [\fB\-o\fR|\fB\-\-one\-shot\fR] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]
|
||||
.RS 4
|
||||
Create a new rule\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-r\fR, \fB\-\-remove\fR ^<n>|head|tail|<class_name>|<instance_name>|*\&...
|
||||
\fB\-r\fR, \fB\-\-remove\fR ^<n>|head|tail|(<class_name>|\fB)[:(<instance_name>|\fR)]\&...
|
||||
.RS 4
|
||||
Remove the given rules\&.
|
||||
.RE
|
||||
.PP
|
||||
\fB\-l\fR, \fB\-\-list\fR [<class_name>|<instance_name>|*]
|
||||
\fB\-l\fR, \fB\-\-list\fR
|
||||
.RS 4
|
||||
List the rules\&.
|
||||
.RE
|
||||
|
@ -871,11 +900,28 @@ List the rules\&.
|
|||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.PP
|
||||
config [\-m \fIMONITOR_SEL\fR|\-d \fIDESKTOP_SEL\fR|\-w \fIWINDOW_SEL\fR] <key> [<value>]
|
||||
config [\-m \fIMONITOR_SEL\fR|\-d \fIDESKTOP_SEL\fR|\-n \fINODE_SEL\fR] <key> [<value>]
|
||||
.RS 4
|
||||
Get or set the value of <key>\&.
|
||||
.RE
|
||||
.RE
|
||||
.SS "Subscribe"
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
.br
|
||||
.ps +1
|
||||
\fBGeneral Syntax\fR
|
||||
.RS 4
|
||||
.PP
|
||||
subscribe (all|report|monitor|desktop|window|\&...)*
|
||||
.RS 4
|
||||
Continuously print status information\&. See the
|
||||
\fBEVENTS\fR
|
||||
section for the detailed description of each event\&.
|
||||
.RE
|
||||
.RE
|
||||
.SS "Quit"
|
||||
.sp
|
||||
.it 1 an-trap
|
||||
|
@ -911,14 +957,14 @@ Unknown command\&.
|
|||
.RE
|
||||
.SH "SETTINGS"
|
||||
.sp
|
||||
Colors are either \fI#RRGGBB\fR or X color names, booleans are \fItrue\fR, \fIon\fR, \fIfalse\fR or \fIoff\fR\&.
|
||||
Colors are in the form \fI#RRGGBB\fR, booleans are \fItrue\fR, \fIon\fR, \fIfalse\fR or \fIoff\fR\&.
|
||||
.sp
|
||||
All the boolean settings are \fIfalse\fR by default unless stated otherwise\&.
|
||||
.SS "Global Settings"
|
||||
.PP
|
||||
\fIfocused_border_color\fR
|
||||
\fInormal_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused window of a focused monitor\&.
|
||||
Color of the border of an unfocused window\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIactive_border_color\fR
|
||||
|
@ -926,66 +972,16 @@ Color of the border of a focused window of a focused monitor\&.
|
|||
Color of the border of a focused window of an unfocused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fInormal_border_color\fR
|
||||
\fIfocused_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of an unfocused window\&.
|
||||
Color of the border of a focused window of a focused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIpresel_border_color\fR
|
||||
\fIpresel_feedback_color\fR
|
||||
.RS 4
|
||||
Color of the
|
||||
\fBwindow \-\-presel\fR
|
||||
message feedback\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIfocused_locked_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused locked window of a focused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIactive_locked_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused locked window of an unfocused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fInormal_locked_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of an unfocused locked window\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIfocused_sticky_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused sticky window of a focused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIactive_sticky_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused sticky window of an unfocused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fInormal_sticky_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of an unfocused sticky window\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIfocused_private_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused private window of a focused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIactive_private_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of a focused private window of an unfocused monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fInormal_private_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of an unfocused private window\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIurgent_border_color\fR
|
||||
.RS 4
|
||||
Color of the border of an urgent window\&.
|
||||
\fBnode \-\-presel\-{dir,ratio}\fR
|
||||
message feedback area\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIsplit_ratio\fR
|
||||
|
@ -1038,7 +1034,7 @@ Remove gaps of tiled windows for the
|
|||
desktop layout\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIleaf_monocle\fR
|
||||
\fIsingle_monocle\fR
|
||||
.RS 4
|
||||
Set the desktop layout to
|
||||
\fBmonocle\fR
|
||||
|
@ -1165,57 +1161,72 @@ A desktop is transferred\&.
|
|||
A desktop is focused\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIdesktop_activate <monitor_name> <desktop_name>\fR
|
||||
.RS 4
|
||||
A desktop is activated\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIdesktop_layout <monitor_name> <desktop_name> tiled|monocle\fR
|
||||
.RS 4
|
||||
The layout of a desktop changed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_manage <monitor_name> <desktop_name> <window_id> <ip_id>\fR
|
||||
\fInode_manage <monitor_name> <desktop_name> <node_id> <ip_id>\fR
|
||||
.RS 4
|
||||
A window is managed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_unmanage <monitor_name> <desktop_name> <window_id>\fR
|
||||
\fInode_unmanage <monitor_name> <desktop_name> <node_id>\fR
|
||||
.RS 4
|
||||
A window is unmanaged\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_swap <src_monitor_name> <src_desktop_name> <src_window_id> <dst_monitor_name> <dst_desktop_name> <dst_window_id>\fR
|
||||
\fInode_swap <src_monitor_name> <src_desktop_name> <src_node_id> <dst_monitor_name> <dst_desktop_name> <dst_node_id>\fR
|
||||
.RS 4
|
||||
A window is swapped\&.
|
||||
A node is swapped\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_transfer <src_monitor_name> <src_desktop_name> <src_window_id> <dst_monitor_name> <dst_desktop_name> <dst_window_id>\fR
|
||||
\fInode_transfer <src_monitor_name> <src_desktop_name> <src_node_id> <dst_monitor_name> <dst_desktop_name> <dst_node_id>\fR
|
||||
.RS 4
|
||||
A window is transferred\&.
|
||||
A node is transferred\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_focus <monitor_name> <desktop_name> <window_id>\fR
|
||||
\fInode_focus <monitor_name> <desktop_name> <node_id>\fR
|
||||
.RS 4
|
||||
A window is focused\&.
|
||||
A node is focused\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_activate <monitor_name> <desktop_name> <window_id>\fR
|
||||
\fInode_activate <monitor_name> <desktop_name> <node_id>\fR
|
||||
.RS 4
|
||||
A window is activated\&.
|
||||
A node is activated\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_geometry <monitor_name> <desktop_name> <window_id> <window_geometry>\fR
|
||||
\fInode_presel <monitor_name> <desktop_name> <node_id> (dir DIR|ratio RATIO|cancel)\fR
|
||||
.RS 4
|
||||
A node is preselected\&.
|
||||
.RE
|
||||
.PP
|
||||
\fInode_stack <node_id_1> below|above <node_id_2>\fR
|
||||
.RS 4
|
||||
A node is stacked below or above another node\&.
|
||||
.RE
|
||||
.PP
|
||||
\fInode_geometry <monitor_name> <desktop_name> <node_id> <node_geometry>\fR
|
||||
.RS 4
|
||||
The geometry of a window changed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_state <monitor_name> <desktop_name> <window_id> tiled|pseudo_tiled|floating|fullscreen on|off\fR
|
||||
\fInode_state <monitor_name> <desktop_name> <node_id> tiled|pseudo_tiled|floating|fullscreen on|off\fR
|
||||
.RS 4
|
||||
The state of a window changed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_flag <monitor_name> <desktop_name> <window_id> sticky|private|locked|urgent on|off\fR
|
||||
\fInode_flag <monitor_name> <desktop_name> <node_id> sticky|private|locked|urgent on|off\fR
|
||||
.RS 4
|
||||
One of the flags of a window changed\&.
|
||||
One of the flags of a node changed\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIwindow_layer <monitor_name> <desktop_name> <window_id> below|normal|above\fR
|
||||
\fInode_layer <monitor_name> <desktop_name> <node_id> below|normal|above\fR
|
||||
.RS 4
|
||||
The layer of a window changed\&.
|
||||
.RE
|
||||
|
@ -1271,6 +1282,16 @@ Urgent unfocused desktop\&.
|
|||
.RS 4
|
||||
Layout of the focused desktop of a monitor\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIT(T|P|F|=|@)\fR
|
||||
.RS 4
|
||||
State of the focused node of a focused desktop\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIG(S?P?L?)\fR
|
||||
.RS 4
|
||||
Active flags of the focused node of a focused desktop\&.
|
||||
.RE
|
||||
.SH "ENVIRONMENT VARIABLES"
|
||||
.PP
|
||||
\fIBSPWM_SOCKET\fR
|
||||
|
|
|
@ -15,7 +15,7 @@ Synopsis
|
|||
|
||||
*bspwm* [*-h*|*-v*|*-c* 'CONFIG_PATH']
|
||||
|
||||
*bspc* 'COMMAND' ['ARGUMENTS']
|
||||
*bspc* 'DOMAIN' ['SELECTOR'] 'COMMANDS'
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
@ -41,40 +41,53 @@ Common Definitions
|
|||
------------------
|
||||
|
||||
----
|
||||
DIR := left | right | up | down
|
||||
DIR := north | west | south | east
|
||||
CYCLE_DIR := next | prev
|
||||
----
|
||||
|
||||
Selectors
|
||||
---------
|
||||
|
||||
Selectors are used to select a target window, desktop, or monitor. A selector
|
||||
Selectors are used to select a target node, desktop, or monitor. A selector
|
||||
can either describe the target relatively or name it globally.
|
||||
|
||||
Descriptive (relative) selectors consist of a primary selector and any number
|
||||
of non-conflicting modifiers as follows:
|
||||
Selectors consist of a descriptor and any number of non-conflicting modifiers
|
||||
as follows:
|
||||
|
||||
PRIMARY_SELECTOR[.MODIFIER]*
|
||||
|
||||
For obvious reasons, neither desktop nor monitor names may be valid descriptive
|
||||
selectors.
|
||||
DESCRIPTOR(.MODIFIER)*
|
||||
|
||||
An exclamation mark can be prepended to certain modifiers in order to reverse their meaning.
|
||||
|
||||
Window
|
||||
~~~~~~
|
||||
Node
|
||||
~~~~
|
||||
|
||||
Select a window.
|
||||
Select a node.
|
||||
|
||||
----
|
||||
WINDOW_SEL := (<window_id>|DIR|CYCLE_DIR|biggest|last|focused|older|newer)[.[!]automatic][.[!](tiled|pseudo_tiled|floating|fullscreen)][.[!](below|normal|above)][.[!]local][.[!]same_class][.[!]focused][.[!](urgent|sticky|private|locked)]
|
||||
NODE_SEL := (<node_id>|PATH|DIR|CYCLE_DIR|last|older|newer|biggest|focused)[.[!]focused][.[!]automatic][.[!]local][.[!]leaf][.[!]STATE][.[!]FLAG][.[!]LAYER][.[!]same_class]
|
||||
|
||||
STATE := tiled|pseudo_tiled|floating|fullscreen
|
||||
|
||||
FLAG := urgent|sticky|private|locked
|
||||
|
||||
LAYER := below|normal|above
|
||||
|
||||
PATH := @[DESK_SEL:][[/]JUMP](/JUMP)*
|
||||
|
||||
JUMP := first|1|second|2|brother|parent|DIR
|
||||
----
|
||||
|
||||
Primary Selectors
|
||||
^^^^^^^^^^^^^^^^^
|
||||
Descriptors
|
||||
^^^^^^^^^^^
|
||||
|
||||
<node_id>::
|
||||
Selects the node with the given ID.
|
||||
|
||||
'PATH'::
|
||||
Selects the node at the given path.
|
||||
|
||||
'DIR'::
|
||||
Selects the window in the given (spacial) direction relative to the active window.
|
||||
Selects the window in the given (spacial) direction relative to the active node.
|
||||
|
||||
'CYCLE_DIR'::
|
||||
Selects the window in the given (cyclic) direction.
|
||||
|
@ -83,35 +96,58 @@ biggest::
|
|||
Selects the biggest window on the current desktop.
|
||||
|
||||
last::
|
||||
Selects the previously focused window.
|
||||
Selects the previously focused node.
|
||||
|
||||
focused::
|
||||
Selects the currently focused window.
|
||||
Selects the currently focused node.
|
||||
|
||||
older::
|
||||
Selects the window older than the focused window in the history.
|
||||
Selects the node older than the focused node in the history.
|
||||
|
||||
newer::
|
||||
Selects the window newer than the focused window in the history.
|
||||
Selects the node newer than the focused node in the history.
|
||||
|
||||
Path Jumps
|
||||
^^^^^^^^^^
|
||||
|
||||
The initial node is the focused node (or the root if the path starts with '/') of the focused desktop (or the selected desktop if the path has a 'DESK_SEL' prefix).
|
||||
|
||||
1|first::
|
||||
Jumps to the first child.
|
||||
|
||||
2|second::
|
||||
Jumps to the second child.
|
||||
|
||||
brother::
|
||||
Jumps to the brother node.
|
||||
|
||||
parent::
|
||||
Jumps to the parent node.
|
||||
|
||||
'DIR'::
|
||||
Jumps to the node holding the edge in the given direction.
|
||||
|
||||
Modifiers
|
||||
^^^^^^^^^
|
||||
|
||||
[!](tiled|pseudo_tiled|floating|fullscreen)::
|
||||
Only consider windows having or not having the given state.
|
||||
[!]focused::
|
||||
Only consider focused or unfocused nodes.
|
||||
|
||||
[!]automatic::
|
||||
Only consider windows in automatic or manual insertion mode.
|
||||
Only consider nodes in automatic or manual insertion mode.
|
||||
|
||||
[!]focused::
|
||||
Only consider focused or unfocused windows.
|
||||
[!]local::
|
||||
Only consider nodes in or not in the current desktop.
|
||||
|
||||
[!]leaf::
|
||||
Only consider leaves or internal nodes.
|
||||
|
||||
[!](tiled|pseudo_tiled|floating|fullscreen)::
|
||||
Only consider windows in or not in the given state.
|
||||
|
||||
[!]same_class::
|
||||
Only consider windows that have or don't have the same class as the current window.
|
||||
|
||||
[!]local::
|
||||
Only consider windows in or not in the current desktop.
|
||||
|
||||
[!](private|urgent|sticky|locked)::
|
||||
Only consider windows that have or don't have the given flag set.
|
||||
|
||||
|
@ -127,8 +163,8 @@ Select a desktop.
|
|||
DESKTOP_SEL := (<desktop_name>|[MONITOR_SEL:](focused|^<n>)CYCLE_DIR|last|older|newer)[.[!]occupied][.[!]focused][.[!]urgent][.[!]local]
|
||||
----
|
||||
|
||||
Primary Selectors
|
||||
^^^^^^^^^^^^^^^^^
|
||||
Descriptors
|
||||
^^^^^^^^^^^
|
||||
|
||||
<desktop_name>::
|
||||
Selects the desktop with the given name.
|
||||
|
@ -175,8 +211,8 @@ Select a monitor.
|
|||
MONITOR_SEL := (<monitor_name>|^<n>|DIR|CYCLE_DIR|last|primary|focused|older|newer)[.[!]occupied][.[!]focused]
|
||||
----
|
||||
|
||||
Primary Selectors
|
||||
^^^^^^^^^^^^^^^^^
|
||||
Descriptors
|
||||
^^^^^^^^^^^
|
||||
|
||||
<monitor_name>::
|
||||
Selects the monitor with the given name.
|
||||
|
@ -231,11 +267,11 @@ fullscreen::
|
|||
Fills its monitor rectangle and has no borders. It is send in the ABOVE layer by default.
|
||||
|
||||
|
||||
Window Flags
|
||||
-------------
|
||||
Node Flags
|
||||
----------
|
||||
|
||||
locked::
|
||||
Ignores the *window --close* message.
|
||||
Ignores the *node --close* message.
|
||||
|
||||
sticky::
|
||||
Stays in the focused desktop of its monitor.
|
||||
|
@ -255,63 +291,75 @@ There's three stacking layers: BELOW, NORMAL and ABOVE.
|
|||
In each layer, the window are orderered as follow: tiled & pseudo-tiled < fullscreen < floating.
|
||||
|
||||
|
||||
Commands
|
||||
--------
|
||||
Domains
|
||||
-------
|
||||
|
||||
Window
|
||||
~~~~~~
|
||||
Node
|
||||
~~~~
|
||||
|
||||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
window ['WINDOW_SEL'] 'OPTIONS'
|
||||
node ['NODE_SEL'] 'COMMANDS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
*-f*, *--focus* ['WINDOW_SEL']::
|
||||
Focus the selected or given window.
|
||||
Commands
|
||||
^^^^^^^^
|
||||
*-f*, *--focus* ['NODE_SEL']::
|
||||
Focus the selected or given node.
|
||||
|
||||
*-a*, *--activate* ['WINDOW_SEL']::
|
||||
Activate the selected or given window.
|
||||
*-a*, *--activate* ['NODE_SEL']::
|
||||
Activate the selected or given node.
|
||||
|
||||
*-d*, *--to-desktop* 'DESKTOP_SEL'::
|
||||
Send the selected window to the given desktop.
|
||||
Send the selected node to the given desktop.
|
||||
|
||||
*-m*, *--to-monitor* 'MONITOR_SEL'::
|
||||
Send the selected window to the given monitor.
|
||||
Send the selected node to the given monitor.
|
||||
|
||||
*-w*, *--to-window* 'WINDOW_SEL'::
|
||||
Transplant the selected window to the given window.
|
||||
*-n*, *--to-node* 'NODE_SEL'::
|
||||
Transplant the selected node to the given node.
|
||||
|
||||
*-s*, *--swap* 'WINDOW_SEL'::
|
||||
Swap the selected window with the given window.
|
||||
*-s*, *--swap* 'NODE_SEL'::
|
||||
Swap the selected node with the given node.
|
||||
|
||||
*-p*, *--presel* 'DIR'|cancel::
|
||||
Preselect the splitting area of the selected window (or cancel the preselection).
|
||||
*-p*, *--presel-dir* [~]'DIR'|cancel::
|
||||
Preselect the splitting area of the selected node (or cancel the preselection).
|
||||
|
||||
*-r*, *--ratio* 'RATIO'::
|
||||
Set the splitting ratio of the selected window (0 < 'RATIO' < 1).
|
||||
*-o*, *--presel-ratio* 'RATIO'::
|
||||
Set the splitting ratio of the preselection area.
|
||||
|
||||
*-e*, *--edge* 'DIR' 'RATIO'|±'PIXELS'::
|
||||
Set or change the splitting ratio of the edge located in the given direction in relation to the selected window.
|
||||
*-r*, *--ratio* 'RATIO'|±'PIXELS'::
|
||||
Set the splitting ratio of the selected node (0 < 'RATIO' < 1).
|
||||
|
||||
*-R*, *--rotate* 'DIR' '90|270|180'::
|
||||
Rotate the tree holding the edge located in the given direction in relation to the selected window.
|
||||
*-R*, *--rotate* '90|270|180'::
|
||||
Rotate the tree rooted at the selected node.
|
||||
|
||||
*-t*, *--state* tiled|pseudo_tiled|floating|fullscreen::
|
||||
*-F*, *--flip* 'horizontal|vertical'::
|
||||
Flip the the tree rooted at selected node.
|
||||
|
||||
*-E*, *--equalize*::
|
||||
Reset the split ratios of the tree rooted at the selected node to their default value.
|
||||
|
||||
*-B*, *--balance*::
|
||||
Adjust the split ratios of the tree rooted at the selected node so that all windows occupy the same area.
|
||||
|
||||
*-C*, *--circulate* forward|backward::
|
||||
Circulate the windows of the tree rooted at the selected node.
|
||||
|
||||
*-t*, *--state* [~](tiled|pseudo_tiled|floating|fullscreen)::
|
||||
Set the state of the selected window.
|
||||
|
||||
*-g*, *--flag* locked|sticky|private[=on|off]::
|
||||
Set or toggle the given flag for the selected window.
|
||||
Set or toggle the given flag for the selected node.
|
||||
|
||||
*-l*, *--layer* below|normal|above::
|
||||
Set the stacking layer of the selected window.
|
||||
|
||||
*-c*, *--close*::
|
||||
Close the selected window.
|
||||
Close the windows rooted at the selected node.
|
||||
|
||||
*-k*, *--kill*::
|
||||
Kill the selected window.
|
||||
Kill the windows rooted at the selected node.
|
||||
|
||||
Desktop
|
||||
~~~~~~~
|
||||
|
@ -319,13 +367,16 @@ Desktop
|
|||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
desktop ['DESKTOP_SEL'] 'OPTIONS'
|
||||
desktop ['DESKTOP_SEL'] 'COMMANDS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
COMMANDS
|
||||
^^^^^^^^
|
||||
*-f*, *--focus* ['DESKTOP_SEL']::
|
||||
Focus the selected or given desktop.
|
||||
|
||||
*-a*, *--activate* ['DESKTOP_SEL']::
|
||||
Activate the selected or given desktop.
|
||||
|
||||
*-m*, *--to-monitor* 'MONITOR_SEL'::
|
||||
Send the selected desktop to the given monitor.
|
||||
|
||||
|
@ -344,35 +395,16 @@ Options
|
|||
*-r*, *--remove*::
|
||||
Remove the selected desktop.
|
||||
|
||||
*-c*, *--cancel-presel*::
|
||||
Cancel the preselection of all the windows of the selected desktop.
|
||||
|
||||
*-F*, *--flip* 'horizontal|vertical'::
|
||||
Flip the tree of the selected desktop.
|
||||
|
||||
*-R*, *--rotate* '90|270|180'::
|
||||
Rotate the tree of the selected desktop.
|
||||
|
||||
*-E*, *--equalize*::
|
||||
Reset the split ratios of the tree of the selected desktop.
|
||||
|
||||
*-B*, *--balance*::
|
||||
Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area.
|
||||
|
||||
*-C*, *--circulate* forward|backward::
|
||||
Circulate the leaves of the tree of the selected desktop.
|
||||
|
||||
|
||||
Monitor
|
||||
~~~~~~~
|
||||
|
||||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
monitor ['MONITOR_SEL'] 'OPTIONS'
|
||||
monitor ['MONITOR_SEL'] 'COMMANDS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
Commands
|
||||
^^^^^^^^
|
||||
*-f*, *--focus* ['MONITOR_SEL']::
|
||||
Focus the selected or given monitor.
|
||||
|
||||
|
@ -400,12 +432,13 @@ Query
|
|||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
query 'OPTIONS'
|
||||
query 'COMMANDS' ['OPTIONS']
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
*-W*, *--windows*::
|
||||
List the IDs of the matching windows.
|
||||
Commands
|
||||
^^^^^^^^
|
||||
|
||||
*-N*, *--nodes*::
|
||||
List the IDs of the matching nodes.
|
||||
|
||||
*-D*, *--desktops*::
|
||||
List the names of the matching desktops.
|
||||
|
@ -416,59 +449,42 @@ Options
|
|||
*-T*, *--tree*::
|
||||
Print a JSON representation of the matching item.
|
||||
|
||||
*-H*, *--history*::
|
||||
Print the focus history as it relates to the query.
|
||||
Options
|
||||
^^^^^^^
|
||||
|
||||
*-S*, *--stack*::
|
||||
Print the window stacking order.
|
||||
[*-m*,*--monitor* ['MONITOR_SEL']] | [*-d*,*--desktop* ['DESKTOP_SEL']] | [*-n*, *--node* ['NODE_SEL']]::
|
||||
Constrain matches to the selected monitor, desktop or node. The descriptor can be omitted for '-M', '-D' and '-N'.
|
||||
|
||||
[*-m*,*--monitor* ['MONITOR_SEL']] | [*-d*,*--desktop* ['DESKTOP_SEL']] | [*-w*, *--window* ['WINDOW_SEL']]::
|
||||
Constrain matches to the selected monitor, desktop or window.
|
||||
|
||||
Restore
|
||||
~~~~~~~
|
||||
Wm
|
||||
~~
|
||||
|
||||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
restore 'OPTIONS'
|
||||
wm 'COMMANDS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
Commands
|
||||
^^^^^^^^
|
||||
|
||||
*-T*, *--tree* <file_path>::
|
||||
Load the desktop trees from the given file.
|
||||
*-d*, *--dump-state*::
|
||||
Dump the current world state on standard output.
|
||||
|
||||
*-H*, *--history* <file_path>::
|
||||
Load the focus history from the given file.
|
||||
*-l*, *--load-state* <file_path>::
|
||||
Load a world state from the given file.
|
||||
|
||||
*-S*, *--stack* <file_path>::
|
||||
Load the window stacking order from the given file.
|
||||
*-a*, *--add-monitor* <name> WxH+X+Y::
|
||||
Add a monitor for the given name and rectangle.
|
||||
|
||||
Control
|
||||
~~~~~~~
|
||||
*-r*, *--remove-monitor* <name>::
|
||||
Remove the monitor with the given name.
|
||||
|
||||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
control 'OPTIONS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
|
||||
*--adopt-orphans*::
|
||||
*-o*, *--adopt-orphans*::
|
||||
Manage all the unmanaged windows remaining from a previous session.
|
||||
|
||||
*--toggle-visibility*::
|
||||
Toggle the visibility of all the windows.
|
||||
*-h*, *--record-history* on|off::
|
||||
Enable or disable the recording of node focus history.
|
||||
|
||||
*--record-history* on|off::
|
||||
Enable or disable the recording of window focus history.
|
||||
|
||||
*--subscribe* (all|report|monitor|desktop|window|...)*::
|
||||
Continuously print status information. See the *EVENTS* section for the detailed description of each event.
|
||||
|
||||
*--get-status*::
|
||||
*-g*, *--get-status*::
|
||||
Print the current status information.
|
||||
|
||||
Pointer
|
||||
|
@ -477,10 +493,10 @@ Pointer
|
|||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
pointer 'OPTIONS'
|
||||
pointer 'COMMANDS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
Commands
|
||||
^^^^^^^^
|
||||
|
||||
*-g*, *--grab* focus|move|resize_side|resize_corner::
|
||||
Initiate the given pointer action.
|
||||
|
@ -497,18 +513,18 @@ Rule
|
|||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
rule 'OPTIONS'
|
||||
rule 'COMMANDS'
|
||||
|
||||
Options
|
||||
^^^^^^^
|
||||
Commands
|
||||
^^^^^^^^
|
||||
|
||||
*-a*, *--add* <class_name>|<instance_name>|* [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|window=WINDOW_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]::
|
||||
*-a*, *--add* (<class_name>|*)[:(<instance_name>|*)] [*-o*|*--one-shot*] [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] [(locked|sticky|private|center|follow|manage|focus|border)=(on|off)]::
|
||||
Create a new rule.
|
||||
|
||||
*-r*, *--remove* ^<n>|head|tail|<class_name>|<instance_name>|*...::
|
||||
*-r*, *--remove* ^<n>|head|tail|(<class_name>|*)[:(<instance_name>|*)]...::
|
||||
Remove the given rules.
|
||||
|
||||
*-l*, *--list* [<class_name>|<instance_name>|*]::
|
||||
*-l*, *--list*::
|
||||
List the rules.
|
||||
|
||||
Config
|
||||
|
@ -517,9 +533,17 @@ Config
|
|||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
config [-m 'MONITOR_SEL'|-d 'DESKTOP_SEL'|-w 'WINDOW_SEL'] <key> [<value>]::
|
||||
config [-m 'MONITOR_SEL'|-d 'DESKTOP_SEL'|-n 'NODE_SEL'] <key> [<value>]::
|
||||
Get or set the value of <key>.
|
||||
|
||||
Subscribe
|
||||
~~~~~~~~~
|
||||
|
||||
General Syntax
|
||||
^^^^^^^^^^^^^^
|
||||
subscribe (all|report|monitor|desktop|window|...)*::
|
||||
Continuously print status information. See the *EVENTS* section for the detailed description of each event.
|
||||
|
||||
Quit
|
||||
~~~~
|
||||
|
||||
|
@ -544,54 +568,24 @@ If the server can't handle a message, *bspc* will return with one of the followi
|
|||
|
||||
Settings
|
||||
--------
|
||||
Colors are either '#RRGGBB' or http://en.wikipedia.org/wiki/X11_color_names[X color names], booleans are 'true', 'on', 'false' or 'off'.
|
||||
Colors are in the form '#RRGGBB', booleans are 'true', 'on', 'false' or 'off'.
|
||||
|
||||
All the boolean settings are 'false' by default unless stated otherwise.
|
||||
|
||||
Global Settings
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
'focused_border_color'::
|
||||
Color of the border of a focused window of a focused monitor.
|
||||
'normal_border_color'::
|
||||
Color of the border of an unfocused window.
|
||||
|
||||
'active_border_color'::
|
||||
Color of the border of a focused window of an unfocused monitor.
|
||||
|
||||
'normal_border_color'::
|
||||
Color of the border of an unfocused window.
|
||||
'focused_border_color'::
|
||||
Color of the border of a focused window of a focused monitor.
|
||||
|
||||
'presel_border_color'::
|
||||
Color of the *window --presel* message feedback.
|
||||
|
||||
'focused_locked_border_color'::
|
||||
Color of the border of a focused locked window of a focused monitor.
|
||||
|
||||
'active_locked_border_color'::
|
||||
Color of the border of a focused locked window of an unfocused monitor.
|
||||
|
||||
'normal_locked_border_color'::
|
||||
Color of the border of an unfocused locked window.
|
||||
|
||||
'focused_sticky_border_color'::
|
||||
Color of the border of a focused sticky window of a focused monitor.
|
||||
|
||||
'active_sticky_border_color'::
|
||||
Color of the border of a focused sticky window of an unfocused monitor.
|
||||
|
||||
'normal_sticky_border_color'::
|
||||
Color of the border of an unfocused sticky window.
|
||||
|
||||
'focused_private_border_color'::
|
||||
Color of the border of a focused private window of a focused monitor.
|
||||
|
||||
'active_private_border_color'::
|
||||
Color of the border of a focused private window of an unfocused monitor.
|
||||
|
||||
'normal_private_border_color'::
|
||||
Color of the border of an unfocused private window.
|
||||
|
||||
'urgent_border_color'::
|
||||
Color of the border of an urgent window.
|
||||
'presel_feedback_color'::
|
||||
Color of the *node --presel-{dir,ratio}* message feedback area.
|
||||
|
||||
'split_ratio'::
|
||||
Default split ratio.
|
||||
|
@ -617,7 +611,7 @@ Global Settings
|
|||
'gapless_monocle'::
|
||||
Remove gaps of tiled windows for the *monocle* desktop layout.
|
||||
|
||||
'leaf_monocle'::
|
||||
'single_monocle'::
|
||||
Set the desktop layout to *monocle* if there's only one tiled window in the tree.
|
||||
|
||||
'focus_follows_pointer'::
|
||||
|
@ -705,37 +699,46 @@ Events
|
|||
'desktop_focus <monitor_name> <desktop_name>'::
|
||||
A desktop is focused.
|
||||
|
||||
'desktop_activate <monitor_name> <desktop_name>'::
|
||||
A desktop is activated.
|
||||
|
||||
'desktop_layout <monitor_name> <desktop_name> tiled|monocle'::
|
||||
The layout of a desktop changed.
|
||||
|
||||
'window_manage <monitor_name> <desktop_name> <window_id> <ip_id>'::
|
||||
'node_manage <monitor_name> <desktop_name> <node_id> <ip_id>'::
|
||||
A window is managed.
|
||||
|
||||
'window_unmanage <monitor_name> <desktop_name> <window_id>'::
|
||||
'node_unmanage <monitor_name> <desktop_name> <node_id>'::
|
||||
A window is unmanaged.
|
||||
|
||||
'window_swap <src_monitor_name> <src_desktop_name> <src_window_id> <dst_monitor_name> <dst_desktop_name> <dst_window_id>'::
|
||||
A window is swapped.
|
||||
'node_swap <src_monitor_name> <src_desktop_name> <src_node_id> <dst_monitor_name> <dst_desktop_name> <dst_node_id>'::
|
||||
A node is swapped.
|
||||
|
||||
'window_transfer <src_monitor_name> <src_desktop_name> <src_window_id> <dst_monitor_name> <dst_desktop_name> <dst_window_id>'::
|
||||
A window is transferred.
|
||||
'node_transfer <src_monitor_name> <src_desktop_name> <src_node_id> <dst_monitor_name> <dst_desktop_name> <dst_node_id>'::
|
||||
A node is transferred.
|
||||
|
||||
'window_focus <monitor_name> <desktop_name> <window_id>'::
|
||||
A window is focused.
|
||||
'node_focus <monitor_name> <desktop_name> <node_id>'::
|
||||
A node is focused.
|
||||
|
||||
'window_activate <monitor_name> <desktop_name> <window_id>'::
|
||||
A window is activated.
|
||||
'node_activate <monitor_name> <desktop_name> <node_id>'::
|
||||
A node is activated.
|
||||
|
||||
'window_geometry <monitor_name> <desktop_name> <window_id> <window_geometry>'::
|
||||
'node_presel <monitor_name> <desktop_name> <node_id> (dir DIR|ratio RATIO|cancel)'::
|
||||
A node is preselected.
|
||||
|
||||
'node_stack <node_id_1> below|above <node_id_2>'::
|
||||
A node is stacked below or above another node.
|
||||
|
||||
'node_geometry <monitor_name> <desktop_name> <node_id> <node_geometry>'::
|
||||
The geometry of a window changed.
|
||||
|
||||
'window_state <monitor_name> <desktop_name> <window_id> tiled|pseudo_tiled|floating|fullscreen on|off'::
|
||||
'node_state <monitor_name> <desktop_name> <node_id> tiled|pseudo_tiled|floating|fullscreen on|off'::
|
||||
The state of a window changed.
|
||||
|
||||
'window_flag <monitor_name> <desktop_name> <window_id> sticky|private|locked|urgent on|off'::
|
||||
One of the flags of a window changed.
|
||||
'node_flag <monitor_name> <desktop_name> <node_id> sticky|private|locked|urgent on|off'::
|
||||
One of the flags of a node changed.
|
||||
|
||||
'window_layer <monitor_name> <desktop_name> <window_id> below|normal|above'::
|
||||
'node_layer <monitor_name> <desktop_name> <node_id> below|normal|above'::
|
||||
The layer of a window changed.
|
||||
|
||||
Please note that *bspwm* initializes monitors before it reads messages on its socket, therefore the initial monitor events can't be received.
|
||||
|
@ -774,6 +777,12 @@ Each item has the form '<type><value>' where '<type>' is the first character of
|
|||
'L(T|M)'::
|
||||
Layout of the focused desktop of a monitor.
|
||||
|
||||
'T(T|P|F|=|@)'::
|
||||
State of the focused node of a focused desktop.
|
||||
|
||||
'G(S?P?L?)'::
|
||||
Active flags of the focused node of a focused desktop.
|
||||
|
||||
Environment Variables
|
||||
---------------------
|
||||
|
||||
|
|
71
events.c
71
events.c
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "bspwm.h"
|
||||
#include "ewmh.h"
|
||||
#include "monitor.h"
|
||||
|
@ -68,8 +69,9 @@ void handle_event(xcb_generic_event_t *evt)
|
|||
process_error(evt);
|
||||
break;
|
||||
default:
|
||||
if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY)
|
||||
if (randr && resp_type == randr_base + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
|
||||
update_monitors();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -91,14 +93,18 @@ void configure_request(xcb_generic_event_t *evt)
|
|||
int w = 0, h = 0;
|
||||
|
||||
if (is_managed && !IS_FLOATING(c)) {
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_X)
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_X) {
|
||||
c->floating_rectangle.x = e->x;
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_Y)
|
||||
}
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
|
||||
c->floating_rectangle.y = e->y;
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH)
|
||||
}
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
|
||||
w = e->width;
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT)
|
||||
}
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
|
||||
h = e->height;
|
||||
}
|
||||
|
||||
if (w != 0) {
|
||||
restrain_floating_width(c, &w);
|
||||
|
@ -111,14 +117,13 @@ void configure_request(xcb_generic_event_t *evt)
|
|||
}
|
||||
|
||||
xcb_configure_notify_event_t evt;
|
||||
xcb_window_t win = c->window;
|
||||
unsigned int bw = c->border_width;
|
||||
|
||||
xcb_rectangle_t rect = get_rectangle(loc.monitor, c);
|
||||
xcb_rectangle_t rect = get_rectangle(loc.monitor, loc.desktop, loc.node);
|
||||
|
||||
evt.response_type = XCB_CONFIGURE_NOTIFY;
|
||||
evt.event = win;
|
||||
evt.window = win;
|
||||
evt.event = e->window;
|
||||
evt.window = e->window;
|
||||
evt.above_sibling = XCB_NONE;
|
||||
evt.x = rect.x;
|
||||
evt.y = rect.y;
|
||||
|
@ -127,7 +132,7 @@ void configure_request(xcb_generic_event_t *evt)
|
|||
evt.border_width = bw;
|
||||
evt.override_redirect = false;
|
||||
|
||||
xcb_send_event(dpy, false, win, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
|
||||
xcb_send_event(dpy, false, e->window, XCB_EVENT_MASK_STRUCTURE_NOTIFY, (const char *) &evt);
|
||||
|
||||
if (c->state == STATE_PSEUDO_TILED) {
|
||||
arrange(loc.monitor, loc.desktop);
|
||||
|
@ -140,15 +145,17 @@ void configure_request(xcb_generic_event_t *evt)
|
|||
if (e->value_mask & XCB_CONFIG_WINDOW_X) {
|
||||
mask |= XCB_CONFIG_WINDOW_X;
|
||||
values[i++] = e->x;
|
||||
if (is_managed)
|
||||
if (is_managed) {
|
||||
c->floating_rectangle.x = e->x;
|
||||
}
|
||||
}
|
||||
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
|
||||
mask |= XCB_CONFIG_WINDOW_Y;
|
||||
values[i++] = e->y;
|
||||
if (is_managed)
|
||||
if (is_managed) {
|
||||
c->floating_rectangle.y = e->y;
|
||||
}
|
||||
}
|
||||
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
|
||||
|
@ -176,26 +183,27 @@ void configure_request(xcb_generic_event_t *evt)
|
|||
values[i++] = e->border_width;
|
||||
}
|
||||
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
|
||||
if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
|
||||
mask |= XCB_CONFIG_WINDOW_SIBLING;
|
||||
values[i++] = e->sibling;
|
||||
}
|
||||
|
||||
if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
|
||||
if (!is_managed && e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
|
||||
mask |= XCB_CONFIG_WINDOW_STACK_MODE;
|
||||
values[i++] = e->stack_mode;
|
||||
}
|
||||
|
||||
xcb_configure_window(dpy, e->window, mask, values);
|
||||
|
||||
if (is_managed && (mask & XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT)) {
|
||||
if (is_managed && mask & XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT) {
|
||||
xcb_rectangle_t r = c->floating_rectangle;
|
||||
put_status(SBSC_MASK_WINDOW_GEOMETRY, "window_geometry %s %s 0x%X %ux%u+%i+%i\n", loc.monitor->name, loc.desktop->name, c->window, r.width, r.height, r.x, r.y);
|
||||
put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry %s %s 0x%X %ux%u+%i+%i\n", loc.monitor->name, loc.desktop->name, e->window, r.width, r.height, r.x, r.y);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_managed) {
|
||||
translate_client(monitor_from_client(c), loc.monitor, c);
|
||||
monitor_t *m = monitor_from_client(c);
|
||||
adapt_geometry(&m->rectangle, &loc.monitor->rectangle, loc.node);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -222,14 +230,15 @@ void property_notify(xcb_generic_event_t *evt)
|
|||
}
|
||||
|
||||
coordinates_t loc;
|
||||
if (!locate_window(e->window, &loc))
|
||||
if (!locate_window(e->window, &loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->atom == XCB_ATOM_WM_HINTS) {
|
||||
xcb_icccm_wm_hints_t hints;
|
||||
if (xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1 &&
|
||||
(hints.flags & XCB_ICCCM_WM_HINT_X_URGENCY))
|
||||
set_urgency(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
|
||||
set_urgent(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
|
||||
} else if (e->atom == XCB_ATOM_WM_NORMAL_HINTS) {
|
||||
client_t *c = loc.node->client;
|
||||
xcb_size_hints_t size_hints;
|
||||
|
@ -255,27 +264,31 @@ void client_message(xcb_generic_event_t *evt)
|
|||
|
||||
if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
|
||||
coordinates_t loc;
|
||||
if (ewmh_locate_desktop(e->data.data32[0], &loc))
|
||||
if (ewmh_locate_desktop(e->data.data32[0], &loc)) {
|
||||
focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
coordinates_t loc;
|
||||
if (!locate_window(e->window, &loc))
|
||||
if (!locate_window(e->window, &loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->type == ewmh->_NET_WM_STATE) {
|
||||
handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[1], e->data.data32[0]);
|
||||
handle_state(loc.monitor, loc.desktop, loc.node, e->data.data32[2], e->data.data32[0]);
|
||||
} else if (e->type == ewmh->_NET_ACTIVE_WINDOW) {
|
||||
if ((ignore_ewmh_focus && e->data.data32[0] == XCB_EWMH_CLIENT_SOURCE_TYPE_NORMAL) ||
|
||||
loc.node == mon->desk->focus)
|
||||
loc.node == mon->desk->focus) {
|
||||
return;
|
||||
}
|
||||
focus_node(loc.monitor, loc.desktop, loc.node);
|
||||
} else if (e->type == ewmh->_NET_WM_DESKTOP) {
|
||||
coordinates_t dloc;
|
||||
if (ewmh_locate_desktop(e->data.data32[0], &dloc))
|
||||
if (ewmh_locate_desktop(e->data.data32[0], &dloc)) {
|
||||
transfer_node(loc.monitor, loc.desktop, loc.node, dloc.monitor, dloc.desktop, dloc.desktop->focus);
|
||||
}
|
||||
} else if (e->type == ewmh->_NET_CLOSE_WINDOW) {
|
||||
window_close(loc.node);
|
||||
}
|
||||
|
@ -291,7 +304,7 @@ void focus_in(xcb_generic_event_t *evt)
|
|||
return;
|
||||
}
|
||||
|
||||
if (mon->desk->focus != NULL && e->event == mon->desk->focus->client->window) {
|
||||
if (mon->desk->focus != NULL && e->event == mon->desk->focus->id) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -309,7 +322,7 @@ void enter_notify(xcb_generic_event_t *evt)
|
|||
|
||||
if (e->mode != XCB_NOTIFY_MODE_NORMAL ||
|
||||
(mon->desk->focus != NULL &&
|
||||
mon->desk->focus->client->window == win)) {
|
||||
mon->desk->focus->id == win)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -409,15 +422,15 @@ void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsig
|
|||
} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
|
||||
set_sticky(m, d, n, false);
|
||||
} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
|
||||
set_sticky(m, d, n, !n->client->sticky);
|
||||
set_sticky(m, d, n, !n->sticky);
|
||||
}
|
||||
} else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
|
||||
if (action == XCB_EWMH_WM_STATE_ADD) {
|
||||
set_urgency(m, d, n, true);
|
||||
set_urgent(m, d, n, true);
|
||||
} else if (action == XCB_EWMH_WM_STATE_REMOVE) {
|
||||
set_urgency(m, d, n, false);
|
||||
set_urgent(m, d, n, false);
|
||||
} else if (action == XCB_EWMH_WM_STATE_TOGGLE) {
|
||||
set_urgency(m, d, n, !n->client->urgent);
|
||||
set_urgent(m, d, n, !n->client->urgent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
88
ewmh.c
88
ewmh.c
|
@ -22,6 +22,8 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "bspwm.h"
|
||||
|
@ -32,27 +34,28 @@
|
|||
void ewmh_init(void)
|
||||
{
|
||||
ewmh = malloc(sizeof(xcb_ewmh_connection_t));
|
||||
if (xcb_ewmh_init_atoms_replies(ewmh, xcb_ewmh_init_atoms(dpy, ewmh), NULL) == 0)
|
||||
if (xcb_ewmh_init_atoms_replies(ewmh, xcb_ewmh_init_atoms(dpy, ewmh), NULL) == 0) {
|
||||
err("Can't initialize EWMH atoms.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void ewmh_update_active_window(void)
|
||||
{
|
||||
xcb_window_t win = (mon->desk->focus == NULL ? XCB_NONE : mon->desk->focus->client->window);
|
||||
xcb_window_t win = ((mon->desk->focus == NULL || mon->desk->focus->client == NULL) ? XCB_NONE : mon->desk->focus->id);
|
||||
xcb_ewmh_set_active_window(ewmh, default_screen, win);
|
||||
}
|
||||
|
||||
void ewmh_update_number_of_desktops(void)
|
||||
{
|
||||
uint32_t num_desktops = 0;
|
||||
uint32_t desktops_count = 0;
|
||||
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
num_desktops++;
|
||||
desktops_count++;
|
||||
}
|
||||
}
|
||||
|
||||
xcb_ewmh_set_number_of_desktops(ewmh, default_screen, num_desktops);
|
||||
xcb_ewmh_set_number_of_desktops(ewmh, default_screen, desktops_count);
|
||||
}
|
||||
|
||||
uint32_t ewmh_get_desktop_index(desktop_t *d)
|
||||
|
@ -70,19 +73,24 @@ uint32_t ewmh_get_desktop_index(desktop_t *d)
|
|||
|
||||
bool ewmh_locate_desktop(uint32_t i, coordinates_t *loc)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next)
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--)
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--) {
|
||||
if (i == 0) {
|
||||
loc->monitor = m;
|
||||
loc->desktop = d;
|
||||
loc->node = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ewmh_update_current_desktop(void)
|
||||
{
|
||||
if (mon == NULL) {
|
||||
return;
|
||||
}
|
||||
uint32_t i = ewmh_get_desktop_index(mon->desk);
|
||||
xcb_ewmh_set_current_desktop(ewmh, default_screen, i);
|
||||
}
|
||||
|
@ -90,7 +98,9 @@ void ewmh_update_current_desktop(void)
|
|||
void ewmh_set_wm_desktop(node_t *n, desktop_t *d)
|
||||
{
|
||||
uint32_t i = ewmh_get_desktop_index(d);
|
||||
xcb_ewmh_set_wm_desktop(ewmh, n->client->window, i);
|
||||
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
|
||||
xcb_ewmh_set_wm_desktop(ewmh, f->id, i);
|
||||
}
|
||||
}
|
||||
|
||||
void ewmh_update_wm_desktops(void)
|
||||
|
@ -99,7 +109,7 @@ void ewmh_update_wm_desktops(void)
|
|||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
uint32_t i = ewmh_get_desktop_index(d);
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
xcb_ewmh_set_wm_desktop(ewmh, n->client->window, i);
|
||||
xcb_ewmh_set_wm_desktop(ewmh, n->id, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,56 +143,70 @@ void ewmh_update_desktop_names(void)
|
|||
xcb_ewmh_set_desktop_names(ewmh, default_screen, names_len, names);
|
||||
}
|
||||
|
||||
void ewmh_update_client_list(void)
|
||||
void ewmh_update_client_list(bool stacking)
|
||||
{
|
||||
if (num_clients == 0) {
|
||||
if (clients_count == 0) {
|
||||
xcb_ewmh_set_client_list(ewmh, default_screen, 0, NULL);
|
||||
xcb_ewmh_set_client_list_stacking(ewmh, default_screen, 0, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
xcb_window_t wins[num_clients];
|
||||
xcb_window_t wins[clients_count];
|
||||
unsigned int i = 0;
|
||||
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
wins[i++] = n->client->window;
|
||||
if (stacking) {
|
||||
for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
|
||||
wins[i++] = s->node->id;
|
||||
}
|
||||
xcb_ewmh_set_client_list_stacking(ewmh, default_screen, clients_count, wins);
|
||||
} else {
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
wins[i++] = n->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
xcb_ewmh_set_client_list(ewmh, default_screen, clients_count, wins);
|
||||
}
|
||||
|
||||
xcb_ewmh_set_client_list(ewmh, default_screen, num_clients, wins);
|
||||
xcb_ewmh_set_client_list_stacking(ewmh, default_screen, num_clients, wins);
|
||||
}
|
||||
|
||||
bool ewmh_wm_state_add(client_t *c, xcb_atom_t state)
|
||||
bool ewmh_wm_state_add(node_t *n, xcb_atom_t state)
|
||||
{
|
||||
if (c->num_states >= MAX_STATE) {
|
||||
client_t *c = n->client;
|
||||
|
||||
if (c == NULL || c->wm_states_count >= MAX_WM_STATES) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < c->num_states; i++) {
|
||||
|
||||
for (int i = 0; i < c->wm_states_count; i++) {
|
||||
if (c->wm_state[i] == state) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
c->wm_state[c->num_states] = state;
|
||||
c->num_states++;
|
||||
xcb_ewmh_set_wm_state(ewmh, c->window, c->num_states, c->wm_state);
|
||||
|
||||
c->wm_state[c->wm_states_count] = state;
|
||||
c->wm_states_count++;
|
||||
xcb_ewmh_set_wm_state(ewmh, n->id, c->wm_states_count, c->wm_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ewmh_wm_state_remove(client_t *c, xcb_atom_t state)
|
||||
bool ewmh_wm_state_remove(node_t *n, xcb_atom_t state)
|
||||
{
|
||||
for (int i = 0; i < c->num_states; i++)
|
||||
if (c->wm_state[i] == state)
|
||||
{
|
||||
for (int j = i; j < (c->num_states - 1); j++)
|
||||
client_t *c = n->client;
|
||||
if (c == NULL) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < c->wm_states_count; i++) {
|
||||
if (c->wm_state[i] == state) {
|
||||
for (int j = i; j < (c->wm_states_count - 1); j++) {
|
||||
c->wm_state[j] = c->wm_state[j + 1];
|
||||
c->num_states--;
|
||||
xcb_ewmh_set_wm_state(ewmh, c->window, c->num_states, c->wm_state);
|
||||
}
|
||||
c->wm_states_count--;
|
||||
xcb_ewmh_set_wm_state(ewmh, n->id, c->wm_states_count, c->wm_state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
6
ewmh.h
6
ewmh.h
|
@ -38,9 +38,9 @@ void ewmh_update_current_desktop(void);
|
|||
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);
|
||||
bool ewmh_wm_state_add(client_t *c, xcb_atom_t state);
|
||||
bool ewmh_wm_state_remove(client_t *c, xcb_atom_t state);
|
||||
void ewmh_update_client_list(bool stacking);
|
||||
bool ewmh_wm_state_add(node_t *n, xcb_atom_t state);
|
||||
bool ewmh_wm_state_remove(node_t *n, xcb_atom_t state);
|
||||
void ewmh_set_supporting(xcb_window_t win);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
sxhkd &
|
||||
|
||||
bspc config border_width 2
|
||||
bspc config window_gap 12
|
||||
bspc config border_width 2
|
||||
bspc config window_gap 12
|
||||
|
||||
bspc config split_ratio 0.52
|
||||
bspc config borderless_monocle true
|
||||
bspc config gapless_monocle true
|
||||
bspc config focus_by_distance true
|
||||
bspc config split_ratio 0.52
|
||||
bspc config borderless_monocle true
|
||||
bspc config gapless_monocle true
|
||||
bspc config focus_by_distance true
|
||||
bspc config history_aware_focus true
|
||||
|
||||
bspc monitor -d I II III IV V VI VII VIII IX X
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#! /bin/sh
|
||||
|
||||
fwid=$(bspc query -W -w focused.automatic)
|
||||
fwid=$(bspc query -N -n focused.automatic)
|
||||
|
||||
if [ -n "$fwid" ] ; then
|
||||
wattr wh $fwid | {
|
||||
read width height
|
||||
if [ $width -gt $height ] ; then
|
||||
echo "split_dir=left"
|
||||
echo "split_dir=west"
|
||||
else
|
||||
echo "split_dir=down"
|
||||
echo "split_dir=south"
|
||||
fi
|
||||
echo "split_ratio=0.5"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
|
||||
if [ -e "$BSPWM_TREE" ] ; then
|
||||
bspc restore -T "$BSPWM_TREE" -H "$BSPWM_HISTORY" -S "$BSPWM_STACK"
|
||||
rm "$BSPWM_TREE" "$BSPWM_HISTORY" "$BSPWM_STACK"
|
||||
if [ -e "$BSPWM_STATE" ] ; then
|
||||
bspc wm -l "$BSPWM_STATE"
|
||||
rm "$BSPWM_STATE"
|
||||
fi
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
export BSPWM_TREE=/tmp/bspwm-tree.json
|
||||
export BSPWM_HISTORY=/tmp/bspwm-history.txt
|
||||
export BSPWM_STACK=/tmp/bspwm-stack.txt
|
||||
export BSPWM_STATE=/tmp/bspwm-state.json
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
# refresh or quit bspwm
|
||||
super + alt + {_,shift + }Escape
|
||||
{bspc query -T > "$BSPWM_TREE"; \
|
||||
bspc query -H > "$BSPWM_HISTORY"; \
|
||||
bspc query -S > "$BSPWM_STACK"; \
|
||||
bspc quit,\
|
||||
{bspc wm -d > "$BSPWM_STATE" && bspc quit, \
|
||||
bspc quit 1}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
|
||||
if [ $(pgrep -cx panel) -gt 1 ] ; then
|
||||
if xdo id -a "$PANEL_WM_NAME" > /dev/null ; then
|
||||
printf "%s\n" "The panel is already running." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
@ -11,12 +11,21 @@ trap 'trap - TERM; kill 0' INT TERM QUIT EXIT
|
|||
mkfifo "$PANEL_FIFO"
|
||||
|
||||
bspc config top_padding $PANEL_HEIGHT
|
||||
bspc control --subscribe > "$PANEL_FIFO" &
|
||||
bspc subscribe report > "$PANEL_FIFO" &
|
||||
xtitle -sf 'T%s' > "$PANEL_FIFO" &
|
||||
clock -sf 'S%a %H:%M' > "$PANEL_FIFO" &
|
||||
|
||||
. panel_colors
|
||||
|
||||
cat "$PANEL_FIFO" | panel_bar | lemonbar -n "$PANEL_WM_NAME" -g x$PANEL_HEIGHT -f "$PANEL_FONT_FAMILY" -F "$COLOR_FOREGROUND" -B "$COLOR_BACKGROUND" &
|
||||
cat "$PANEL_FIFO" | panel_bar | lemonbar -n "$PANEL_WM_NAME" -g x$PANEL_HEIGHT -f "$PANEL_FONT" -F "$COLOR_DEFAULT_FG" -B "$COLOR_DEFAULT_BG" &
|
||||
|
||||
wid=$(xdo id -a "$PANEL_WM_NAME")
|
||||
tries_left=20
|
||||
while [ -z "$wid" -a "$tries_left" -gt 0 ] ; do
|
||||
sleep 0.05
|
||||
wid=$(xdo id -a "$PANEL_WM_NAME")
|
||||
tries_left=$((tries_left - 1))
|
||||
done
|
||||
[ -n "$wid" ] && xdo above -t "$(xdo id -N Bspwm -n root | sort | head -n 1)" "$wid"
|
||||
|
||||
wait
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Example panel for LemonBoy's bar
|
||||
# Example panel for lemonbar
|
||||
|
||||
. panel_colors
|
||||
|
||||
|
@ -10,65 +10,80 @@ while read -r line ; do
|
|||
case $line in
|
||||
S*)
|
||||
# clock output
|
||||
sys_infos="%{F$COLOR_STATUS_FG}%{B$COLOR_STATUS_BG} ${line#?} %{B-}%{F-}"
|
||||
sys="%{F$COLOR_SYS_FG}%{B$COLOR_SYS_BG} ${line#?} %{B-}%{F-}"
|
||||
;;
|
||||
T*)
|
||||
# xtitle output
|
||||
title="%{F$COLOR_TITLE_FG}%{B$COLOR_TITLE_BG} ${line#?} %{B-}%{F-}"
|
||||
;;
|
||||
W*)
|
||||
# bspwm internal state
|
||||
wm_infos=""
|
||||
# bspwm's state
|
||||
wm=""
|
||||
IFS=':'
|
||||
set -- ${line#?}
|
||||
while [ $# -gt 0 ] ; do
|
||||
item=$1
|
||||
name=${item#?}
|
||||
case $item in
|
||||
M*)
|
||||
# active monitor
|
||||
if [ $num_mon -gt 1 ] ; then
|
||||
wm_infos="$wm_infos %{F$COLOR_ACTIVE_MONITOR_FG}%{B$COLOR_ACTIVE_MONITOR_BG} ${name} %{B-}%{F-} "
|
||||
fi
|
||||
[mM]*)
|
||||
[ $num_mon -lt 2 ] && shift && continue
|
||||
case $item in
|
||||
m*)
|
||||
# monitor
|
||||
FG=$COLOR_MONITOR_FG
|
||||
BG=$COLOR_MONITOR_BG
|
||||
;;
|
||||
M*)
|
||||
# focused monitor
|
||||
FG=$COLOR_FOCUSED_MONITOR_FG
|
||||
BG=$COLOR_FOCUSED_MONITOR_BG
|
||||
;;
|
||||
esac
|
||||
wm="${wm}%{F${FG}}%{B${BG}} ${name} %{B-}%{F-}"
|
||||
;;
|
||||
m*)
|
||||
# inactive monitor
|
||||
if [ $num_mon -gt 1 ] ; then
|
||||
wm_infos="$wm_infos %{F$COLOR_INACTIVE_MONITOR_FG}%{B$COLOR_INACTIVE_MONITOR_BG} ${name} %{B-}%{F-} "
|
||||
fi
|
||||
[fFoOuU]*)
|
||||
case $item in
|
||||
f*)
|
||||
# free desktop
|
||||
FG=$COLOR_FREE_FG
|
||||
BG=$COLOR_FREE_BG
|
||||
;;
|
||||
F*)
|
||||
# focused free desktop
|
||||
FG=$COLOR_FOCUSED_FREE_FG
|
||||
BG=$COLOR_FOCUSED_FREE_BG
|
||||
;;
|
||||
o*)
|
||||
# occupied desktop
|
||||
FG=$COLOR_OCCUPIED_FG
|
||||
BG=$COLOR_OCCUPIED_BG
|
||||
;;
|
||||
O*)
|
||||
# focused occupied desktop
|
||||
FG=$COLOR_FOCUSED_OCCUPIED_FG
|
||||
BG=$COLOR_FOCUSED_OCCUPIED_BG
|
||||
;;
|
||||
u*)
|
||||
# urgent desktop
|
||||
FG=$COLOR_URGENT_FG
|
||||
BG=$COLOR_URGENT_BG
|
||||
;;
|
||||
U*)
|
||||
# focused urgent desktop
|
||||
FG=$COLOR_FOCUSED_URGENT_FG
|
||||
BG=$COLOR_FOCUSED_URGENT_BG
|
||||
;;
|
||||
esac
|
||||
wm="${wm}%{F${FG}}%{B${BG}} ${name} %{B-}%{F-}"
|
||||
;;
|
||||
O*)
|
||||
# focused occupied desktop
|
||||
wm_infos="${wm_infos}%{F$COLOR_FOCUSED_OCCUPIED_FG}%{B$COLOR_FOCUSED_OCCUPIED_BG}%{U$COLOR_FOREGROUND}%{+u} ${name} %{-u}%{B-}%{F-}"
|
||||
;;
|
||||
F*)
|
||||
# focused free desktop
|
||||
wm_infos="${wm_infos}%{F$COLOR_FOCUSED_FREE_FG}%{B$COLOR_FOCUSED_FREE_BG}%{U$COLOR_FOREGROUND}%{+u} ${name} %{-u}%{B-}%{F-}"
|
||||
;;
|
||||
U*)
|
||||
# focused urgent desktop
|
||||
wm_infos="${wm_infos}%{F$COLOR_FOCUSED_URGENT_FG}%{B$COLOR_FOCUSED_URGENT_BG}%{U$COLOR_FOREGROUND}%{+u} ${name} %{-u}%{B-}%{F-}"
|
||||
;;
|
||||
o*)
|
||||
# occupied desktop
|
||||
wm_infos="${wm_infos}%{F$COLOR_OCCUPIED_FG}%{B$COLOR_OCCUPIED_BG} ${name} %{B-}%{F-}"
|
||||
;;
|
||||
f*)
|
||||
# free desktop
|
||||
wm_infos="${wm_infos}%{F$COLOR_FREE_FG}%{B$COLOR_FREE_BG} ${name} %{B-}%{F-}"
|
||||
;;
|
||||
u*)
|
||||
# urgent desktop
|
||||
wm_infos="${wm_infos}%{F$COLOR_URGENT_FG}%{B$COLOR_URGENT_BG} ${name} %{B-}%{F-}"
|
||||
;;
|
||||
L*)
|
||||
# layout
|
||||
wm_infos="$wm_infos %{F$COLOR_LAYOUT_FG}%{B$COLOR_LAYOUT_BG} ${name} %{B-}%{F-}"
|
||||
[LTG]*)
|
||||
# layout, state and flags
|
||||
wm="${wm}%{F$COLOR_STATE_FG}%{B$COLOR_STATE_BG} ${name} %{B-}%{F-}"
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
;;
|
||||
esac
|
||||
printf "%s\n" "%{l}${wm_infos}%{c}${title}%{r}${sys_infos}"
|
||||
printf "%s\n" "%{l}${wm}%{c}${title}%{r}${sys}"
|
||||
done
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
COLOR_FOREGROUND='#FFA3A6AB'
|
||||
COLOR_BACKGROUND='#FF34322E'
|
||||
COLOR_ACTIVE_MONITOR_FG='#FF34322E'
|
||||
COLOR_ACTIVE_MONITOR_BG='#FF58C5F1'
|
||||
COLOR_INACTIVE_MONITOR_FG='#FF58C5F1'
|
||||
COLOR_INACTIVE_MONITOR_BG='#FF34322E'
|
||||
COLOR_FOCUSED_OCCUPIED_FG='#FFF6F9FF'
|
||||
COLOR_FOCUSED_OCCUPIED_BG='#FF5C5955'
|
||||
COLOR_FOCUSED_FREE_FG='#FFF6F9FF'
|
||||
COLOR_FOCUSED_FREE_BG='#FF6D561C'
|
||||
COLOR_FOCUSED_URGENT_FG='#FF34322E'
|
||||
COLOR_FOCUSED_URGENT_BG='#FFF9A299'
|
||||
COLOR_OCCUPIED_FG='#FFA3A6AB'
|
||||
COLOR_OCCUPIED_BG='#FF34322E'
|
||||
COLOR_FREE_FG='#FF6F7277'
|
||||
COLOR_FREE_BG='#FF34322E'
|
||||
COLOR_URGENT_FG='#FFF9A299'
|
||||
COLOR_URGENT_BG='#FF34322E'
|
||||
COLOR_LAYOUT_FG='#FFA3A6AB'
|
||||
COLOR_LAYOUT_BG='#FF34322E'
|
||||
COLOR_TITLE_FG='#FFA3A6AB'
|
||||
COLOR_TITLE_BG='#FF34322E'
|
||||
COLOR_STATUS_FG='#FFA3A6AB'
|
||||
COLOR_STATUS_BG='#FF34322E'
|
||||
COLOR_DEFAULT_FG="#a7a5a5"
|
||||
COLOR_DEFAULT_BG="#333232"
|
||||
COLOR_MONITOR_FG="#8dbcdf"
|
||||
COLOR_MONITOR_BG="#333232"
|
||||
COLOR_FOCUSED_MONITOR_FG="#b1d0e8"
|
||||
COLOR_FOCUSED_MONITOR_BG="#144b6c"
|
||||
COLOR_FREE_FG="#737171"
|
||||
COLOR_FREE_BG="#333232"
|
||||
COLOR_FOCUSED_FREE_FG="#000000"
|
||||
COLOR_FOCUSED_FREE_BG="#504e4e"
|
||||
COLOR_OCCUPIED_FG="#a7a5a5"
|
||||
COLOR_OCCUPIED_BG="#333232"
|
||||
COLOR_FOCUSED_OCCUPIED_FG="#d6d3d2"
|
||||
COLOR_FOCUSED_OCCUPIED_BG="#504e4e"
|
||||
COLOR_URGENT_FG="#f15d66"
|
||||
COLOR_URGENT_BG="#333232"
|
||||
COLOR_FOCUSED_URGENT_FG="#501d1f"
|
||||
COLOR_FOCUSED_URGENT_BG="#d5443e"
|
||||
COLOR_STATE_FG="#89b09c"
|
||||
COLOR_STATE_BG="#333232"
|
||||
COLOR_TITLE_FG="#a8a2c0"
|
||||
COLOR_TITLE_BG="#333232"
|
||||
COLOR_SYS_FG="#b1a57d"
|
||||
COLOR_SYS_BG="#333232"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
PANEL_FIFO=/tmp/panel-fifo
|
||||
PANEL_HEIGHT=24
|
||||
PANEL_FONT_FAMILY="-*-terminus-medium-r-normal-*-12-*-*-*-c-*-*-1"
|
||||
PANEL_WM_NAME=lemonpanel
|
||||
export PANEL_FIFO PANEL_HEIGHT PANEL_FONT_FAMILY PANEL_WM_NAME
|
||||
PANEL_FONT="-*-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
|
||||
PANEL_WM_NAME=bspwm_panel
|
||||
export PANEL_FIFO PANEL_HEIGHT PANEL_FONT PANEL_WM_NAME
|
||||
|
|
195
examples/sxhkdrc
195
examples/sxhkdrc
|
@ -1,88 +1,133 @@
|
|||
#
|
||||
# bspwm hotkeys
|
||||
#
|
||||
|
||||
super + alt + Escape
|
||||
bspc quit
|
||||
|
||||
super + w
|
||||
bspc window -c
|
||||
|
||||
super + n
|
||||
bspc desktop -l next
|
||||
|
||||
super + {t,p,s,f}
|
||||
bspc window -t {tiled,pseudo_tiled,floating,fullscreen}
|
||||
|
||||
super + {grave,Tab}
|
||||
bspc {window,desktop} -f last
|
||||
|
||||
super + apostrophe
|
||||
bspc window -s last
|
||||
|
||||
super + {o,i}
|
||||
bspc control --record-history off; \
|
||||
bspc window {older,newer} -f; \
|
||||
bspc control --record-history on
|
||||
|
||||
super + y
|
||||
bspc window -w last.!automatic
|
||||
|
||||
super + m
|
||||
bspc window -s biggest
|
||||
|
||||
super + {_,shift + }{h,j,k,l}
|
||||
bspc window -{f,s} {left,down,up,right}
|
||||
|
||||
super + {_,shift + }c
|
||||
bspc window -f {next,prev}
|
||||
|
||||
super + {comma,period}
|
||||
bspc desktop -C {backward,forward}
|
||||
|
||||
super + bracket{left,right}
|
||||
bspc desktop -f {prev,next}
|
||||
|
||||
super + ctrl + {h,j,k,l}
|
||||
bspc window -p {left,down,up,right}
|
||||
|
||||
super + ctrl + {_,shift + }space
|
||||
bspc {window -p cancel,desktop -c}
|
||||
|
||||
super + alt + {h,j,k,l}
|
||||
bspc window -e {left -10,down +10,up -10,right +10}
|
||||
|
||||
super + alt + shift + {h,j,k,l}
|
||||
bspc window -e {right -10,up +10,down -10,left +10}
|
||||
|
||||
super + ctrl + {1-9}
|
||||
bspc window -r 0.{1-9}
|
||||
|
||||
super + {Left,Down,Up,Right}
|
||||
xdo move {-x -20,-y +20,-y -20,-x +20}
|
||||
|
||||
super + {_,shift + }{1-9,0}
|
||||
bspc {desktop -f,window -d} '^{1-9,10}'
|
||||
|
||||
~button1
|
||||
bspc pointer -g focus
|
||||
|
||||
super + button{1-3}
|
||||
; bspc pointer -g {move,resize_side,resize_corner}
|
||||
|
||||
super + @button{1-3}
|
||||
bspc pointer -u
|
||||
|
||||
#
|
||||
# wm independent hotkeys
|
||||
#
|
||||
|
||||
# terminal emulator
|
||||
super + Return
|
||||
urxvt
|
||||
|
||||
# program launcher
|
||||
super + space
|
||||
dmenu_run
|
||||
|
||||
# make sxhkd reload its configuration files:
|
||||
super + Escape
|
||||
pkill -USR1 -x sxhkd
|
||||
|
||||
#
|
||||
# bspwm hotkeys
|
||||
#
|
||||
|
||||
# quit bspwm normally
|
||||
super + alt + Escape
|
||||
bspc quit
|
||||
|
||||
# close and kill
|
||||
super + {_,shift + }w
|
||||
bspc node -{c,k}
|
||||
|
||||
# alternate between the tiled and monocle layout
|
||||
super + m
|
||||
bspc desktop -l next
|
||||
|
||||
# if the current node is automatic, send it to the last manual, otherwise pull the last leaf
|
||||
super + y
|
||||
bspc query -N -n focused.automatic && bspc node -n last.!automatic || bspc node last.leaf -n focused
|
||||
|
||||
# swap the current node and the biggest node
|
||||
super + g
|
||||
bspc node -s biggest
|
||||
|
||||
#
|
||||
# state/flags
|
||||
#
|
||||
|
||||
# set the window state
|
||||
super + {t,shift + t,s,f}
|
||||
bspc node -t {tiled,pseudo_tiled,floating,fullscreen}
|
||||
|
||||
# set the node flags
|
||||
super + ctrl + {x,y,z}
|
||||
bspc node -g {locked,sticky,private}
|
||||
|
||||
#
|
||||
# focus/swap
|
||||
#
|
||||
|
||||
# focus the node in the given direction
|
||||
super + {_,shift + }{h,j,k,l}
|
||||
bspc node -{f,s} {west,south,north,east}
|
||||
|
||||
# focus the node for the given path jump
|
||||
super + {p,b,comma,period}
|
||||
bspc node -f @{parent,brother,first,second}
|
||||
|
||||
# focus the next/previous node
|
||||
super + {_,shift + }c
|
||||
bspc node -f {next,prev}
|
||||
|
||||
# focus the next/previous desktop
|
||||
super + bracket{left,right}
|
||||
bspc desktop -f {prev,next}
|
||||
|
||||
# focus the last node/desktop
|
||||
super + {grave,Tab}
|
||||
bspc {node,desktop} -f last
|
||||
|
||||
# focus the older or newer node in the focus history
|
||||
super + {o,i}
|
||||
bspc wm -h off; \
|
||||
bspc node {older,newer} -f; \
|
||||
bspc wm -h on
|
||||
|
||||
# focus or send to the given desktop
|
||||
super + {_,shift + }{1-9,0}
|
||||
bspc {desktop -f,node -d} '^{1-9,10}'
|
||||
|
||||
#
|
||||
# preselect
|
||||
#
|
||||
|
||||
# preselect the direction
|
||||
super + ctrl + {h,j,k,l}
|
||||
bspc node -p {west,south,north,east}
|
||||
|
||||
# preselect the ratio
|
||||
super + ctrl + {1-9}
|
||||
bspc node -o 0.{1-9}
|
||||
|
||||
# cancel the preselection for the focused node or desktop
|
||||
super + ctrl + {_,shift + }space
|
||||
bspc node @{_,/} -p cancel
|
||||
|
||||
#
|
||||
# resize tiled/floating
|
||||
#
|
||||
|
||||
# expand the tiled space in the given direction
|
||||
super + alt + {h,j,k,l}
|
||||
bspc node {@west -r -10,@south -r +10,@north -r -10,@east -r +10}
|
||||
|
||||
# contract the tiled space in the given direction
|
||||
super + alt + shift + {h,j,k,l}
|
||||
bspc node {@east -r -10,@north -r +10,@south -r -10,@west -r +10}
|
||||
|
||||
# move a floating window
|
||||
super + {Left,Down,Up,Right}
|
||||
xdo move {-x -20,-y +20,-y -20,-x +20}
|
||||
|
||||
#
|
||||
# pointer focus/move/resize
|
||||
#
|
||||
|
||||
# focus
|
||||
~button1
|
||||
bspc pointer -g focus
|
||||
|
||||
# start move/resize
|
||||
super + button{1-3}
|
||||
; bspc pointer -g {move,resize_side,resize_corner}
|
||||
|
||||
# end move/resize
|
||||
super + @button{1-3}
|
||||
bspc pointer -u
|
||||
|
|
54
helpers.c
54
helpers.c
|
@ -22,10 +22,15 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include "bspwm.h"
|
||||
|
||||
|
@ -99,38 +104,31 @@ char *read_string(const char *file_path, size_t *tlen)
|
|||
return content;
|
||||
}
|
||||
|
||||
bool get_color(char *col, xcb_window_t win, uint32_t *pxl)
|
||||
{
|
||||
xcb_colormap_t map = screen->default_colormap;
|
||||
xcb_get_window_attributes_reply_t *reply = xcb_get_window_attributes_reply(dpy, xcb_get_window_attributes(dpy, win), NULL);
|
||||
if (reply != NULL)
|
||||
map = reply->colormap;
|
||||
free(reply);
|
||||
|
||||
if (col[0] == '#') {
|
||||
unsigned int red, green, blue;
|
||||
if (sscanf(col + 1, "%02x%02x%02x", &red, &green, &blue) == 3) {
|
||||
/* 2**16 - 1 == 0xffff and 0x101 * 0xij == 0xijij */
|
||||
red *= 0x101;
|
||||
green *= 0x101;
|
||||
blue *= 0x101;
|
||||
xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(dpy, xcb_alloc_color(dpy, map, red, green, blue), NULL);
|
||||
if (reply != NULL) {
|
||||
*pxl = reply->pixel;
|
||||
free(reply);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/* Adapted from i3wm */
|
||||
uint32_t get_color_pixel(const char *color)
|
||||
{
|
||||
unsigned int red, green, blue;
|
||||
if (sscanf(color + 1, "%02x%02x%02x", &red, &green, &blue) == 3) {
|
||||
/* We set the first 8 bits high to have 100% opacity in case of a 32 bit
|
||||
* color depth visual. */
|
||||
return (0xFF << 24) | (red << 16 | green << 8 | blue);
|
||||
} else {
|
||||
xcb_alloc_named_color_reply_t *reply = xcb_alloc_named_color_reply(dpy, xcb_alloc_named_color(dpy, map, strlen(col), col), NULL);
|
||||
if (reply != NULL) {
|
||||
*pxl = reply->pixel;
|
||||
free(reply);
|
||||
return true;
|
||||
return screen->black_pixel;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_hex_color(const char *color)
|
||||
{
|
||||
if (color[0] != '#' || strlen(color) != 7) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < 7; i++) {
|
||||
if (!isxdigit(color[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*pxl = 0;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
double distance(xcb_point_t a, xcb_point_t b)
|
||||
|
|
|
@ -42,10 +42,12 @@
|
|||
#define BOOL_STR(A) ((A) ? "true" : "false")
|
||||
#define ON_OFF_STR(A) ((A) ? "on" : "off")
|
||||
#define LAYOUT_STR(A) ((A) == LAYOUT_TILED ? "tiled" : "monocle")
|
||||
#define LAYOUT_CHR(A) ((A) == LAYOUT_TILED ? 'T' : 'M')
|
||||
#define SPLIT_TYPE_STR(A) ((A) == TYPE_HORIZONTAL ? "horizontal" : "vertical")
|
||||
#define SPLIT_MODE_STR(A) ((A) == MODE_AUTOMATIC ? "automatic" : "manual")
|
||||
#define SPLIT_DIR_STR(A) ((A) == DIR_RIGHT ? "right" : ((A) == DIR_UP ? "up" : ((A) == DIR_LEFT ? "left" : "down")))
|
||||
#define SPLIT_DIR_STR(A) ((A) == DIR_NORTH ? "north" : ((A) == DIR_WEST ? "west" : ((A) == DIR_SOUTH ? "south" : "east")))
|
||||
#define STATE_STR(A) ((A) == STATE_TILED ? "tiled" : ((A) == STATE_FLOATING ? "floating" : ((A) == STATE_FULLSCREEN ? "fullscreen" : "pseudo_tiled")))
|
||||
#define STATE_CHR(A) ((A) == STATE_TILED ? 'T' : ((A) == STATE_FLOATING ? 'F' : ((A) == STATE_FULLSCREEN ? '=' : 'P')))
|
||||
#define LAYER_STR(A) ((A) == LAYER_BELOW ? "below" : ((A) == LAYER_NORMAL ? "normal" : "above"))
|
||||
|
||||
#define XCB_CONFIG_WINDOW_X_Y (XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y)
|
||||
|
@ -61,7 +63,8 @@
|
|||
void warn(char *fmt, ...);
|
||||
void err(char *fmt, ...);
|
||||
char *read_string(const char *file_path, size_t *tlen);
|
||||
bool get_color(char *col, xcb_window_t win, uint32_t *pxl);
|
||||
uint32_t get_color_pixel(const char *color);
|
||||
bool is_hex_color(const char *color);
|
||||
double distance(xcb_point_t a, xcb_point_t b);
|
||||
|
||||
#endif
|
||||
|
|
109
history.c
109
history.c
|
@ -23,7 +23,9 @@
|
|||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "bspwm.h"
|
||||
#include "tree.h"
|
||||
#include "query.h"
|
||||
|
||||
history_t *make_history(monitor_t *m, desktop_t *d, node_t *n)
|
||||
|
@ -37,16 +39,19 @@ 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)
|
||||
{
|
||||
if (!record_history)
|
||||
if (!record_history) {
|
||||
return;
|
||||
}
|
||||
history_needle = NULL;
|
||||
history_t *h = make_history(m, d, n);
|
||||
if (history_head == NULL) {
|
||||
history_head = history_tail = h;
|
||||
} else if ((n != NULL && history_tail->loc.node != n) || (n == NULL && d != history_tail->loc.desktop)) {
|
||||
for (history_t *hh = history_tail; hh != NULL; hh = hh->prev)
|
||||
if ((n != NULL && hh->loc.node == n) || (n == NULL && d == hh->loc.desktop))
|
||||
for (history_t *hh = history_tail; hh != NULL; hh = hh->prev) {
|
||||
if ((n != NULL && hh->loc.node == n) || (n == NULL && d == hh->loc.desktop)) {
|
||||
hh->latest = false;
|
||||
}
|
||||
}
|
||||
history_tail->next = h;
|
||||
h->prev = history_tail;
|
||||
history_tail = h;
|
||||
|
@ -57,48 +62,55 @@ 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)
|
||||
{
|
||||
for (history_t *h = history_head; h != NULL; h = h->next)
|
||||
if (h->loc.node == n) {
|
||||
for (history_t *h = history_head; h != NULL; h = h->next) {
|
||||
if (is_descendant(h->loc.node, n)) {
|
||||
h->loc.monitor = m;
|
||||
h->loc.desktop = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void history_transfer_desktop(monitor_t *m, desktop_t *d)
|
||||
{
|
||||
for (history_t *h = history_head; h != NULL; h = h->next)
|
||||
if (h->loc.desktop == d)
|
||||
for (history_t *h = history_head; h != NULL; h = h->next) {
|
||||
if (h->loc.desktop == d) {
|
||||
h->loc.monitor = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void history_swap_nodes(monitor_t *m1, desktop_t *d1, node_t *n1, monitor_t *m2, desktop_t *d2, node_t *n2)
|
||||
{
|
||||
for (history_t *h = history_head; h != NULL; h = h->next)
|
||||
if (h->loc.node == n1) {
|
||||
for (history_t *h = history_head; h != NULL; h = h->next) {
|
||||
if (is_descendant(h->loc.node, n1)) {
|
||||
h->loc.monitor = m2;
|
||||
h->loc.desktop = d2;
|
||||
} else if (h->loc.node == n2) {
|
||||
} else if (is_descendant(h->loc.node, n2)) {
|
||||
h->loc.monitor = m1;
|
||||
h->loc.desktop = d1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void history_swap_desktops(monitor_t *m1, desktop_t *d1, monitor_t *m2, desktop_t *d2)
|
||||
{
|
||||
for (history_t *h = history_head; h != NULL; h = h->next)
|
||||
if (h->loc.desktop == d1)
|
||||
for (history_t *h = history_head; h != NULL; h = h->next) {
|
||||
if (h->loc.desktop == d1) {
|
||||
h->loc.monitor = m2;
|
||||
else if (h->loc.desktop == d2)
|
||||
} else if (h->loc.desktop == d2) {
|
||||
h->loc.monitor = m1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void history_remove(desktop_t *d, node_t *n)
|
||||
void history_remove(desktop_t *d, node_t *n, bool deep)
|
||||
{
|
||||
/* removing from the newest to the oldest is required */
|
||||
/* for maintaining the *latest* attribute */
|
||||
history_t *b = history_tail;
|
||||
while (b != NULL) {
|
||||
if ((n != NULL && n == b->loc.node) || (n == NULL && d == b->loc.desktop)) {
|
||||
if ((n != NULL && ((deep && is_descendant(b->loc.node, n)) || (!deep && b->loc.node == n))) ||
|
||||
(n == NULL && d == b->loc.desktop)) {
|
||||
history_t *a = b->next;
|
||||
history_t *c = b->prev;
|
||||
if (a != NULL) {
|
||||
|
@ -106,23 +118,29 @@ void history_remove(desktop_t *d, node_t *n)
|
|||
while (c != NULL && ((a->loc.node != NULL && a->loc.node == c->loc.node) ||
|
||||
(a->loc.node == NULL && a->loc.desktop == c->loc.desktop))) {
|
||||
history_t *p = c->prev;
|
||||
if (history_head == c)
|
||||
if (history_head == c) {
|
||||
history_head = history_tail;
|
||||
if (history_needle == c)
|
||||
}
|
||||
if (history_needle == c) {
|
||||
history_needle = history_tail;
|
||||
}
|
||||
free(c);
|
||||
c = p;
|
||||
}
|
||||
a->prev = c;
|
||||
}
|
||||
if (c != NULL)
|
||||
if (c != NULL) {
|
||||
c->next = a;
|
||||
if (history_tail == b)
|
||||
}
|
||||
if (history_tail == b) {
|
||||
history_tail = c;
|
||||
if (history_head == b)
|
||||
}
|
||||
if (history_head == b) {
|
||||
history_head = a;
|
||||
if (history_needle == b)
|
||||
}
|
||||
if (history_needle == b) {
|
||||
history_needle = c;
|
||||
}
|
||||
free(b);
|
||||
b = c;
|
||||
} else {
|
||||
|
@ -142,44 +160,53 @@ void empty_history(void)
|
|||
history_head = history_tail = NULL;
|
||||
}
|
||||
|
||||
node_t *history_get_node(desktop_t *d, node_t *n)
|
||||
node_t *history_last_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)
|
||||
for (history_t *h = history_tail; h != NULL; h = h->prev) {
|
||||
if (h->latest && h->loc.node != NULL && !is_descendant(h->loc.node, n) && h->loc.desktop == d) {
|
||||
return h->loc.node;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
desktop_t *history_get_desktop(monitor_t *m, desktop_t *d)
|
||||
desktop_t *history_last_desktop(monitor_t *m, desktop_t *d)
|
||||
{
|
||||
for (history_t *h = history_tail; h != NULL; h = h->prev)
|
||||
if (h->latest && h->loc.desktop != d && h->loc.monitor == m)
|
||||
for (history_t *h = history_tail; h != NULL; h = h->prev) {
|
||||
if (h->latest && h->loc.desktop != d && h->loc.monitor == m) {
|
||||
return h->loc.desktop;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
monitor_t *history_get_monitor(monitor_t *m)
|
||||
monitor_t *history_last_monitor(monitor_t *m)
|
||||
{
|
||||
for (history_t *h = history_tail; h != NULL; h = h->prev)
|
||||
if (h->latest && h->loc.monitor != m)
|
||||
for (history_t *h = history_tail; h != NULL; h = h->prev) {
|
||||
if (h->latest && h->loc.monitor != m) {
|
||||
return h->loc.monitor;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, client_select_t sel)
|
||||
bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, node_select_t sel)
|
||||
{
|
||||
if (history_needle == NULL || record_history)
|
||||
if (history_needle == NULL || record_history) {
|
||||
history_needle = history_tail;
|
||||
}
|
||||
|
||||
history_t *h;
|
||||
for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
|
||||
if (!h->latest ||
|
||||
h->loc.node == NULL ||
|
||||
h->loc.node == ref->node ||
|
||||
!node_matches(&h->loc, ref, sel))
|
||||
!node_matches(&h->loc, ref, sel)) {
|
||||
continue;
|
||||
if (!record_history)
|
||||
}
|
||||
if (!record_history) {
|
||||
history_needle = h;
|
||||
}
|
||||
*dst = h->loc;
|
||||
return true;
|
||||
}
|
||||
|
@ -188,17 +215,20 @@ bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst
|
|||
|
||||
bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel)
|
||||
{
|
||||
if (history_needle == NULL || record_history)
|
||||
if (history_needle == NULL || record_history) {
|
||||
history_needle = history_tail;
|
||||
}
|
||||
|
||||
history_t *h;
|
||||
for (h = history_needle; h != NULL; h = (hdi == HISTORY_OLDER ? h->prev : h->next)) {
|
||||
if (!h->latest ||
|
||||
h->loc.desktop == ref->desktop ||
|
||||
!desktop_matches(&h->loc, ref, sel))
|
||||
!desktop_matches(&h->loc, ref, sel)) {
|
||||
continue;
|
||||
if (!record_history)
|
||||
}
|
||||
if (!record_history) {
|
||||
history_needle = h;
|
||||
}
|
||||
*dst = h->loc;
|
||||
return true;
|
||||
}
|
||||
|
@ -237,8 +267,9 @@ int history_rank(desktop_t *d, node_t *n)
|
|||
h = h->prev;
|
||||
i++;
|
||||
}
|
||||
if (h == NULL)
|
||||
if (h == NULL) {
|
||||
return -1;
|
||||
else
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
10
history.h
10
history.h
|
@ -33,12 +33,12 @@ 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 history_remove(desktop_t *d, node_t *n, bool deep);
|
||||
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_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, client_select_t sel);
|
||||
node_t *history_last_node(desktop_t *d, node_t *n);
|
||||
desktop_t *history_last_desktop(monitor_t *m, desktop_t *d);
|
||||
monitor_t *history_last_monitor(monitor_t *m);
|
||||
bool history_find_node(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, node_select_t sel);
|
||||
bool history_find_desktop(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, desktop_select_t sel);
|
||||
bool history_find_monitor(history_dir_t hdi, coordinates_t *ref, coordinates_t *dst, monitor_select_t sel);
|
||||
int history_rank(desktop_t *d, node_t *n);
|
||||
|
|
2
jsmn.c
2
jsmn.c
|
@ -1,5 +1,3 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "jsmn.h"
|
||||
|
||||
/**
|
||||
|
|
812
messages.c
812
messages.c
File diff suppressed because it is too large
Load diff
22
messages.h
22
messages.h
|
@ -30,33 +30,17 @@
|
|||
|
||||
int handle_message(char *msg, int msg_len, FILE *rsp);
|
||||
int process_message(char **args, int num, FILE *rsp);
|
||||
int cmd_window(char **args, int num);
|
||||
int cmd_node(char **args, int num);
|
||||
int cmd_desktop(char **args, int num);
|
||||
int cmd_monitor(char **args, int num);
|
||||
int cmd_query(char **args, int num, FILE *rsp);
|
||||
int cmd_rule(char **args, int num, FILE *rsp);
|
||||
int cmd_pointer(char **args, int num);
|
||||
int cmd_restore(char **args, int num);
|
||||
int cmd_control(char **args, int num, FILE *rsp);
|
||||
int cmd_wm(char **args, int num, FILE *rsp);
|
||||
int cmd_config(char **args, int num, FILE *rsp);
|
||||
int cmd_subscribe(char **args, int num, FILE *rsp);
|
||||
int cmd_quit(char **args, int num);
|
||||
int set_setting(coordinates_t loc, char *name, char *value);
|
||||
int get_setting(coordinates_t loc, char *name, FILE* rsp);
|
||||
bool parse_subscriber_mask(char *s, subscriber_mask_t *mask);
|
||||
bool parse_bool(char *value, bool *b);
|
||||
bool parse_layout(char *s, layout_t *l);
|
||||
bool parse_client_state(char *s, client_state_t *t);
|
||||
bool parse_stack_layer(char *s, stack_layer_t *l);
|
||||
bool parse_direction(char *s, direction_t *d);
|
||||
bool parse_cycle_direction(char *s, cycle_dir_t *d);
|
||||
bool parse_circulate_direction(char *s, circulate_dir_t *d);
|
||||
bool parse_history_direction(char *s, history_dir_t *d);
|
||||
bool parse_flip(char *s, flip_t *f);
|
||||
bool parse_pointer_action(char *s, pointer_action_t *a);
|
||||
bool parse_child_polarity(char *s, child_polarity_t *p);
|
||||
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
|
||||
|
|
171
monitor.c
171
monitor.c
|
@ -25,6 +25,8 @@
|
|||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include "bspwm.h"
|
||||
#include "desktop.h"
|
||||
#include "ewmh.h"
|
||||
|
@ -40,12 +42,13 @@ monitor_t *make_monitor(xcb_rectangle_t *rect)
|
|||
{
|
||||
monitor_t *m = malloc(sizeof(monitor_t));
|
||||
snprintf(m->name, sizeof(m->name), "%s%02d", DEFAULT_MON_NAME, ++monitor_uid);
|
||||
m->id = XCB_NONE;
|
||||
m->root = XCB_NONE;
|
||||
m->prev = m->next = NULL;
|
||||
m->desk = m->desk_head = m->desk_tail = NULL;
|
||||
m->top_padding = m->right_padding = m->bottom_padding = m->left_padding = 0;
|
||||
m->wired = true;
|
||||
m->num_sticky = 0;
|
||||
m->sticky_count = 0;
|
||||
if (rect != NULL) {
|
||||
update_root(m, rect);
|
||||
} else {
|
||||
|
@ -83,74 +86,83 @@ void rename_monitor(monitor_t *m, const char *name)
|
|||
|
||||
monitor_t *find_monitor(char *name)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next)
|
||||
if (streq(m->name, name))
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (streq(m->name, name)) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
monitor_t *get_monitor_by_id(xcb_randr_output_t id)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next)
|
||||
if (m->id == id)
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (m->id == id) {
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void embrace_client(monitor_t *m, client_t *c)
|
||||
{
|
||||
if ((c->floating_rectangle.x + c->floating_rectangle.width) <= m->rectangle.x)
|
||||
if ((c->floating_rectangle.x + c->floating_rectangle.width) <= m->rectangle.x) {
|
||||
c->floating_rectangle.x = m->rectangle.x;
|
||||
else if (c->floating_rectangle.x >= (m->rectangle.x + m->rectangle.width))
|
||||
} else if (c->floating_rectangle.x >= (m->rectangle.x + m->rectangle.width)) {
|
||||
c->floating_rectangle.x = (m->rectangle.x + m->rectangle.width) - c->floating_rectangle.width;
|
||||
if ((c->floating_rectangle.y + c->floating_rectangle.height) <= m->rectangle.y)
|
||||
}
|
||||
if ((c->floating_rectangle.y + c->floating_rectangle.height) <= m->rectangle.y) {
|
||||
c->floating_rectangle.y = m->rectangle.y;
|
||||
else if (c->floating_rectangle.y >= (m->rectangle.y + m->rectangle.height))
|
||||
} else if (c->floating_rectangle.y >= (m->rectangle.y + m->rectangle.height)) {
|
||||
c->floating_rectangle.y = (m->rectangle.y + m->rectangle.height) - c->floating_rectangle.height;
|
||||
}
|
||||
}
|
||||
|
||||
void translate_client(monitor_t *ms, monitor_t *md, client_t *c)
|
||||
void adapt_geometry(xcb_rectangle_t *rs, xcb_rectangle_t *rd, node_t *n)
|
||||
{
|
||||
if (frozen_pointer->action != ACTION_NONE || ms == md)
|
||||
if (frozen_pointer->action != ACTION_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clip the rectangle to fit into the monitor. Without this, the fitting
|
||||
* algorithm doesn't work as expected. This also conserves the
|
||||
* out-of-bounds regions */
|
||||
int left_adjust = MAX((ms->rectangle.x - c->floating_rectangle.x), 0);
|
||||
int top_adjust = MAX((ms->rectangle.y - c->floating_rectangle.y), 0);
|
||||
int right_adjust = MAX((c->floating_rectangle.x + c->floating_rectangle.width) - (ms->rectangle.x + ms->rectangle.width), 0);
|
||||
int bottom_adjust = MAX((c->floating_rectangle.y + c->floating_rectangle.height) - (ms->rectangle.y + ms->rectangle.height), 0);
|
||||
c->floating_rectangle.x += left_adjust;
|
||||
c->floating_rectangle.y += top_adjust;
|
||||
c->floating_rectangle.width -= (left_adjust + right_adjust);
|
||||
c->floating_rectangle.height -= (top_adjust + bottom_adjust);
|
||||
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
|
||||
client_t *c = f->client;
|
||||
/* Clip the rectangle to fit into the monitor. Without this, the fitting
|
||||
* algorithm doesn't work as expected. This also conserves the
|
||||
* out-of-bounds regions */
|
||||
int left_adjust = MAX((rs->x - c->floating_rectangle.x), 0);
|
||||
int top_adjust = MAX((rs->y - c->floating_rectangle.y), 0);
|
||||
int right_adjust = MAX((c->floating_rectangle.x + c->floating_rectangle.width) - (rs->x + rs->width), 0);
|
||||
int bottom_adjust = MAX((c->floating_rectangle.y + c->floating_rectangle.height) - (rs->y + rs->height), 0);
|
||||
c->floating_rectangle.x += left_adjust;
|
||||
c->floating_rectangle.y += top_adjust;
|
||||
c->floating_rectangle.width -= (left_adjust + right_adjust);
|
||||
c->floating_rectangle.height -= (top_adjust + bottom_adjust);
|
||||
|
||||
int dx_s = c->floating_rectangle.x - ms->rectangle.x;
|
||||
int dy_s = c->floating_rectangle.y - ms->rectangle.y;
|
||||
int dx_s = c->floating_rectangle.x - rs->x;
|
||||
int dy_s = c->floating_rectangle.y - rs->y;
|
||||
|
||||
int nume_x = dx_s * (md->rectangle.width - c->floating_rectangle.width);
|
||||
int nume_y = dy_s * (md->rectangle.height - c->floating_rectangle.height);
|
||||
int nume_x = dx_s * (rd->width - c->floating_rectangle.width);
|
||||
int nume_y = dy_s * (rd->height - c->floating_rectangle.height);
|
||||
|
||||
int deno_x = ms->rectangle.width - c->floating_rectangle.width;
|
||||
int deno_y = ms->rectangle.height - c->floating_rectangle.height;
|
||||
int deno_x = rs->width - c->floating_rectangle.width;
|
||||
int deno_y = rs->height - c->floating_rectangle.height;
|
||||
|
||||
int dx_d = (deno_x == 0 ? 0 : nume_x / deno_x);
|
||||
int dy_d = (deno_y == 0 ? 0 : nume_y / deno_y);
|
||||
int dx_d = (deno_x == 0 ? 0 : nume_x / deno_x);
|
||||
int dy_d = (deno_y == 0 ? 0 : nume_y / deno_y);
|
||||
|
||||
/* Translate and undo clipping */
|
||||
c->floating_rectangle.width += left_adjust + right_adjust;
|
||||
c->floating_rectangle.height += top_adjust + bottom_adjust;
|
||||
c->floating_rectangle.x = md->rectangle.x + dx_d - left_adjust;
|
||||
c->floating_rectangle.y = md->rectangle.y + dy_d - top_adjust;
|
||||
/* Translate and undo clipping */
|
||||
c->floating_rectangle.width += left_adjust + right_adjust;
|
||||
c->floating_rectangle.height += top_adjust + bottom_adjust;
|
||||
c->floating_rectangle.x = rd->x + dx_d - left_adjust;
|
||||
c->floating_rectangle.y = rd->y + dy_d - top_adjust;
|
||||
}
|
||||
}
|
||||
|
||||
void focus_monitor(monitor_t *m)
|
||||
{
|
||||
if (mon == m)
|
||||
if (mon == m) {
|
||||
return;
|
||||
|
||||
put_status(SBSC_MASK_MONITOR_FOCUS, "monitor_focus %s\n", m->name);
|
||||
}
|
||||
|
||||
mon = m;
|
||||
|
||||
|
@ -158,16 +170,13 @@ void focus_monitor(monitor_t *m)
|
|||
center_pointer(m->rectangle);
|
||||
}
|
||||
|
||||
ewmh_update_current_desktop();
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
put_status(SBSC_MASK_MONITOR_FOCUS, "monitor_focus %s\n", m->name);
|
||||
}
|
||||
|
||||
void add_monitor(monitor_t *m)
|
||||
{
|
||||
xcb_rectangle_t r = m->rectangle;
|
||||
|
||||
put_status(SBSC_MASK_MONITOR_ADD, "monitor_add %s 0x%X %ux%u+%i+%i\n", m->name, m->id, r.width, r.height, r.x, r.y);
|
||||
|
||||
if (mon == NULL) {
|
||||
mon = m;
|
||||
mon_head = m;
|
||||
|
@ -177,19 +186,21 @@ void add_monitor(monitor_t *m)
|
|||
m->prev = mon_tail;
|
||||
mon_tail = m;
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_MONITOR_ADD, "monitor_add %s 0x%X %ux%u+%i+%i\n", m->name, m->id, r.width, r.height, r.x, r.y);
|
||||
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
void remove_monitor(monitor_t *m)
|
||||
{
|
||||
put_status(SBSC_MASK_MONITOR_REMOVE, "monitor_remove %s\n", m->name);
|
||||
|
||||
while (m->desk_head != NULL) {
|
||||
remove_desktop(m, m->desk_head);
|
||||
}
|
||||
|
||||
monitor_t *prev = m->prev;
|
||||
monitor_t *next = m->next;
|
||||
monitor_t *last_mon = history_get_monitor(m);
|
||||
monitor_t *last_mon = history_last_monitor(m);
|
||||
|
||||
if (prev != NULL) {
|
||||
prev->next = next;
|
||||
|
@ -214,12 +225,15 @@ void remove_monitor(monitor_t *m)
|
|||
if (mon == m) {
|
||||
mon = (last_mon == NULL ? (prev == NULL ? next : prev) : last_mon);
|
||||
if (mon != NULL && mon->desk != NULL) {
|
||||
update_current();
|
||||
update_focused();
|
||||
}
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_MONITOR_REMOVE, "monitor_remove %s\n", m->name);
|
||||
|
||||
xcb_destroy_window(dpy, m->root);
|
||||
free(m);
|
||||
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
|
@ -232,39 +246,47 @@ void merge_monitors(monitor_t *ms, monitor_t *md)
|
|||
desktop_t *d = ms->desk_head;
|
||||
while (d != NULL) {
|
||||
desktop_t *next = d->next;
|
||||
if (d->root != NULL || strstr(d->name, DEFAULT_DESK_NAME) == NULL)
|
||||
if (d->root != NULL || strstr(d->name, DEFAULT_DESK_NAME) == NULL) {
|
||||
transfer_desktop(ms, md, d);
|
||||
}
|
||||
d = next;
|
||||
}
|
||||
}
|
||||
|
||||
void swap_monitors(monitor_t *m1, monitor_t *m2)
|
||||
{
|
||||
if (m1 == NULL || m2 == NULL || m1 == m2)
|
||||
if (m1 == NULL || m2 == NULL || m1 == m2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mon_head == m1)
|
||||
if (mon_head == m1) {
|
||||
mon_head = m2;
|
||||
else if (mon_head == m2)
|
||||
} else if (mon_head == m2) {
|
||||
mon_head = m1;
|
||||
if (mon_tail == m1)
|
||||
}
|
||||
if (mon_tail == m1) {
|
||||
mon_tail = m2;
|
||||
else if (mon_tail == m2)
|
||||
} else if (mon_tail == m2) {
|
||||
mon_tail = m1;
|
||||
}
|
||||
|
||||
monitor_t *p1 = m1->prev;
|
||||
monitor_t *n1 = m1->next;
|
||||
monitor_t *p2 = m2->prev;
|
||||
monitor_t *n2 = m2->next;
|
||||
|
||||
if (p1 != NULL && p1 != m2)
|
||||
if (p1 != NULL && p1 != m2) {
|
||||
p1->next = m2;
|
||||
if (n1 != NULL && n1 != m2)
|
||||
}
|
||||
if (n1 != NULL && n1 != m2) {
|
||||
n1->prev = m2;
|
||||
if (p2 != NULL && p2 != m1)
|
||||
}
|
||||
if (p2 != NULL && p2 != m1) {
|
||||
p2->next = m1;
|
||||
if (n2 != NULL && n2 != m1)
|
||||
}
|
||||
if (n2 != NULL && n2 != m1) {
|
||||
n2->prev = m1;
|
||||
}
|
||||
|
||||
m1->prev = p2 == m1 ? m2 : p2;
|
||||
m1->next = n2 == m1 ? m2 : n2;
|
||||
|
@ -274,6 +296,7 @@ void swap_monitors(monitor_t *m1, monitor_t *m2)
|
|||
ewmh_update_wm_desktops();
|
||||
ewmh_update_desktop_names();
|
||||
ewmh_update_current_desktop();
|
||||
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
|
@ -350,10 +373,10 @@ monitor_t *nearest_monitor(monitor_t *m, direction_t dir, monitor_select_t sel)
|
|||
continue;
|
||||
}
|
||||
xcb_rectangle_t r = f->rectangle;
|
||||
if ((dir == DIR_LEFT && r.x < rect.x) ||
|
||||
(dir == DIR_RIGHT && r.x >= (rect.x + rect.width)) ||
|
||||
(dir == DIR_UP && r.y < rect.y) ||
|
||||
(dir == DIR_DOWN && r.y >= (rect.y + rect.height))) {
|
||||
if ((dir == DIR_WEST && r.x < rect.x) ||
|
||||
(dir == DIR_EAST && r.x >= (rect.x + rect.width)) ||
|
||||
(dir == DIR_NORTH && r.y < rect.y) ||
|
||||
(dir == DIR_SOUTH && r.y >= (rect.y + rect.height))) {
|
||||
int d = abs((r.x + r.width / 2) - (rect.x + rect.width / 2)) +
|
||||
abs((r.y + r.height / 2) - (rect.y + rect.height / 2));
|
||||
if (d < dmin) {
|
||||
|
@ -368,8 +391,9 @@ monitor_t *nearest_monitor(monitor_t *m, direction_t dir, monitor_select_t sel)
|
|||
bool update_monitors(void)
|
||||
{
|
||||
xcb_randr_get_screen_resources_reply_t *sres = xcb_randr_get_screen_resources_reply(dpy, xcb_randr_get_screen_resources(dpy, root), NULL);
|
||||
if (sres == NULL)
|
||||
if (sres == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
monitor_t *m, *mm = NULL;
|
||||
|
||||
|
@ -377,11 +401,13 @@ bool update_monitors(void)
|
|||
xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_outputs(sres);
|
||||
|
||||
xcb_randr_get_output_info_cookie_t cookies[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
for (int i = 0; i < len; i++) {
|
||||
cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
|
||||
}
|
||||
|
||||
for (m = mon_head; m != NULL; m = m->next)
|
||||
for (m = mon_head; m != NULL; m = m->next) {
|
||||
m->wired = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
xcb_randr_get_output_info_reply_t *info = xcb_randr_get_output_info_reply(dpy, cookies[i], NULL);
|
||||
|
@ -392,10 +418,11 @@ bool update_monitors(void)
|
|||
xcb_rectangle_t rect = (xcb_rectangle_t) {cir->x, cir->y, cir->width, cir->height};
|
||||
mm = get_monitor_by_id(outputs[i]);
|
||||
if (mm != NULL) {
|
||||
xcb_rectangle_t last_rect = mm->rectangle;
|
||||
update_root(mm, &rect);
|
||||
for (desktop_t *d = mm->desk_head; d != NULL; d = d->next) {
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
translate_client(mm, mm, n->client);
|
||||
adapt_geometry(&last_rect, &rect, n);
|
||||
}
|
||||
}
|
||||
arrange(mm, mm->desk);
|
||||
|
@ -412,8 +439,9 @@ bool update_monitors(void)
|
|||
free(cir);
|
||||
} else if (!remove_disabled_monitors && info->connection != XCB_RANDR_CONNECTION_DISCONNECTED) {
|
||||
m = get_monitor_by_id(outputs[i]);
|
||||
if (m != NULL)
|
||||
if (m != NULL) {
|
||||
m->wired = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(info);
|
||||
|
@ -424,12 +452,14 @@ bool update_monitors(void)
|
|||
if (gpo != NULL) {
|
||||
pri_mon = get_monitor_by_id(gpo->output);
|
||||
if (!running && pri_mon != NULL) {
|
||||
if (mon != pri_mon)
|
||||
if (mon != pri_mon) {
|
||||
mon = pri_mon;
|
||||
}
|
||||
add_desktop(pri_mon, make_desktop(NULL));
|
||||
ewmh_update_current_desktop();
|
||||
}
|
||||
}
|
||||
|
||||
free(gpo);
|
||||
|
||||
/* handle overlapping monitors */
|
||||
|
@ -472,12 +502,15 @@ bool update_monitors(void)
|
|||
}
|
||||
|
||||
/* add one desktop to each new monitor */
|
||||
for (m = mon_head; m != NULL; m = m->next)
|
||||
if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon))
|
||||
for (m = mon_head; m != NULL; m = m->next) {
|
||||
if (m->desk == NULL && (running || pri_mon == NULL || m != pri_mon)) {
|
||||
add_desktop(m, make_desktop(NULL));
|
||||
}
|
||||
}
|
||||
|
||||
if (!running && pri_mon != NULL && mon_head != pri_mon)
|
||||
if (!running && pri_mon != NULL && mon_head != pri_mon) {
|
||||
swap_monitors(mon_head, pri_mon);
|
||||
}
|
||||
|
||||
free(sres);
|
||||
update_motion_recorder();
|
||||
|
|
|
@ -33,7 +33,7 @@ void rename_monitor(monitor_t *m, const char *name);
|
|||
monitor_t *find_monitor(char *name);
|
||||
monitor_t *get_monitor_by_id(xcb_randr_output_t id);
|
||||
void embrace_client(monitor_t *m, client_t *c);
|
||||
void translate_client(monitor_t *ms, monitor_t *md, client_t *c);
|
||||
void adapt_geometry(xcb_rectangle_t *rs, xcb_rectangle_t *rd, node_t *n);
|
||||
void focus_monitor(monitor_t *m);
|
||||
void add_monitor(monitor_t *m);
|
||||
void remove_monitor(monitor_t *m);
|
||||
|
|
195
parse.c
195
parse.c
|
@ -1,7 +1,8 @@
|
|||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "helpers.h"
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include "parse.h"
|
||||
|
||||
bool parse_bool(char *value, bool *b)
|
||||
|
@ -87,17 +88,17 @@ bool parse_stack_layer(char *s, stack_layer_t *l)
|
|||
|
||||
bool parse_direction(char *s, direction_t *d)
|
||||
{
|
||||
if (streq("right", s)) {
|
||||
*d = DIR_RIGHT;
|
||||
if (streq("north", s)) {
|
||||
*d = DIR_NORTH;
|
||||
return true;
|
||||
} else if (streq("down", s)) {
|
||||
*d = DIR_DOWN;
|
||||
} else if (streq("west", s)) {
|
||||
*d = DIR_WEST;
|
||||
return true;
|
||||
} else if (streq("left", s)) {
|
||||
*d = DIR_LEFT;
|
||||
} else if (streq("south", s)) {
|
||||
*d = DIR_SOUTH;
|
||||
return true;
|
||||
} else if (streq("up", s)) {
|
||||
*d = DIR_UP;
|
||||
} else if (streq("east", s)) {
|
||||
*d = DIR_EAST;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -197,15 +198,16 @@ bool parse_degree(char *s, int *d)
|
|||
}
|
||||
}
|
||||
|
||||
bool parse_window_id(char *s, long int *i)
|
||||
bool parse_id(char *s, uint32_t *i)
|
||||
{
|
||||
char *end;
|
||||
errno = 0;
|
||||
long int ret = strtol(s, &end, 0);
|
||||
if (errno != 0 || *end != '\0')
|
||||
uint32_t ret = strtol(s, &end, 0);
|
||||
if (errno != 0 || *end != '\0') {
|
||||
return false;
|
||||
else
|
||||
} else {
|
||||
*i = ret;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -230,8 +232,171 @@ bool parse_bool_declaration(char *s, char **key, bool *value, alter_state_t *sta
|
|||
bool parse_index(char *s, int *i)
|
||||
{
|
||||
int idx;
|
||||
if (sscanf(s, "^%i", &idx) != 1 || idx < 1)
|
||||
if (sscanf(s, "^%i", &idx) != 1 || idx < 1) {
|
||||
return false;
|
||||
}
|
||||
*i = idx;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_rectangle(char *s, xcb_rectangle_t *r)
|
||||
{
|
||||
uint16_t w, h;
|
||||
int16_t x, y;
|
||||
if (sscanf(s, "%hux%hu+%hi+%hi", &w, &h, &x, &y) != 4) {
|
||||
return false;
|
||||
}
|
||||
r->width = w;
|
||||
r->height = h;
|
||||
r->x = x;
|
||||
r->y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_subscriber_mask(char *s, subscriber_mask_t *mask)
|
||||
{
|
||||
if (streq("all", s)) {
|
||||
*mask = SBSC_MASK_ALL;
|
||||
} else if (streq("node", s)) {
|
||||
*mask = SBSC_MASK_NODE;
|
||||
} else if (streq("desktop", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP;
|
||||
} else if (streq("monitor", s)) {
|
||||
*mask = SBSC_MASK_MONITOR;
|
||||
} else if (streq("node_manage", s)) {
|
||||
*mask = SBSC_MASK_NODE_MANAGE;
|
||||
} else if (streq("node_unmanage", s)) {
|
||||
*mask = SBSC_MASK_NODE_UNMANAGE;
|
||||
} else if (streq("node_swap", s)) {
|
||||
*mask = SBSC_MASK_NODE_SWAP;
|
||||
} else if (streq("node_transfer", s)) {
|
||||
*mask = SBSC_MASK_NODE_TRANSFER;
|
||||
} else if (streq("node_focus", s)) {
|
||||
*mask = SBSC_MASK_NODE_FOCUS;
|
||||
} else if (streq("node_presel", s)) {
|
||||
*mask = SBSC_MASK_NODE_PRESEL;
|
||||
} else if (streq("node_stack", s)) {
|
||||
*mask = SBSC_MASK_NODE_STACK;
|
||||
} else if (streq("node_activate", s)) {
|
||||
*mask = SBSC_MASK_NODE_ACTIVATE;
|
||||
} else if (streq("node_geometry", s)) {
|
||||
*mask = SBSC_MASK_NODE_GEOMETRY;
|
||||
} else if (streq("node_state", s)) {
|
||||
*mask = SBSC_MASK_NODE_STATE;
|
||||
} else if (streq("node_flag", s)) {
|
||||
*mask = SBSC_MASK_NODE_FLAG;
|
||||
} else if (streq("node_layer", s)) {
|
||||
*mask = SBSC_MASK_NODE_LAYER;
|
||||
} else if (streq("desktop_add", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_ADD;
|
||||
} else if (streq("desktop_rename", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_RENAME;
|
||||
} else if (streq("desktop_remove", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_REMOVE;
|
||||
} else if (streq("desktop_swap", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_SWAP;
|
||||
} else if (streq("desktop_transfer", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_TRANSFER;
|
||||
} else if (streq("desktop_focus", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_FOCUS;
|
||||
} else if (streq("desktop_activate", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_ACTIVATE;
|
||||
} else if (streq("desktop_layout", s)) {
|
||||
*mask = SBSC_MASK_DESKTOP_LAYOUT;
|
||||
} else if (streq("monitor_add", s)) {
|
||||
*mask = SBSC_MASK_MONITOR_ADD;
|
||||
} else if (streq("monitor_rename", s)) {
|
||||
*mask = SBSC_MASK_MONITOR_RENAME;
|
||||
} else if (streq("monitor_remove", s)) {
|
||||
*mask = SBSC_MASK_MONITOR_REMOVE;
|
||||
} else if (streq("monitor_focus", s)) {
|
||||
*mask = SBSC_MASK_MONITOR_FOCUS;
|
||||
} else if (streq("monitor_geometry", s)) {
|
||||
*mask = SBSC_MASK_MONITOR_GEOMETRY;
|
||||
} else if (streq("report", s)) {
|
||||
*mask = SBSC_MASK_REPORT;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#define GET_MOD(k) \
|
||||
} else if (streq(#k, tok)) { \
|
||||
sel->k = OPTION_TRUE; \
|
||||
} else if (streq("!" #k, tok)) { \
|
||||
sel->k = OPTION_FALSE;
|
||||
|
||||
bool parse_monitor_modifiers(char *desc, monitor_select_t *sel)
|
||||
{
|
||||
char *tok;
|
||||
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
|
||||
tok[0] = '\0';
|
||||
tok++;
|
||||
if (streq("occupied", tok)) {
|
||||
sel->occupied = OPTION_TRUE;
|
||||
} else if (streq("!occupied", tok)) {
|
||||
sel->occupied = OPTION_FALSE;
|
||||
GET_MOD(focused)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_desktop_modifiers(char *desc, desktop_select_t *sel)
|
||||
{
|
||||
char *tok;
|
||||
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
|
||||
tok[0] = '\0';
|
||||
tok++;
|
||||
if (streq("occupied", tok)) {
|
||||
sel->occupied = OPTION_TRUE;
|
||||
} else if (streq("!occupied", tok)) {
|
||||
sel->occupied = OPTION_FALSE;
|
||||
GET_MOD(focused)
|
||||
GET_MOD(urgent)
|
||||
GET_MOD(local)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool parse_node_modifiers(char *desc, node_select_t *sel)
|
||||
{
|
||||
char *tok;
|
||||
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
|
||||
tok[0] = '\0';
|
||||
tok++;
|
||||
if (streq("tiled", tok)) {
|
||||
sel->tiled = OPTION_TRUE;
|
||||
} else if (streq("!tiled", tok)) {
|
||||
sel->tiled = OPTION_FALSE;
|
||||
GET_MOD(automatic)
|
||||
GET_MOD(focused)
|
||||
GET_MOD(local)
|
||||
GET_MOD(leaf)
|
||||
GET_MOD(pseudo_tiled)
|
||||
GET_MOD(floating)
|
||||
GET_MOD(fullscreen)
|
||||
GET_MOD(locked)
|
||||
GET_MOD(sticky)
|
||||
GET_MOD(private)
|
||||
GET_MOD(urgent)
|
||||
GET_MOD(same_class)
|
||||
GET_MOD(below)
|
||||
GET_MOD(normal)
|
||||
GET_MOD(above)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#undef GET_MOD
|
||||
|
|
9
parse.h
9
parse.h
|
@ -2,10 +2,12 @@
|
|||
#define BSPWM_PARSE_H
|
||||
|
||||
#include "types.h"
|
||||
#include "subscribe.h"
|
||||
|
||||
#define OPT_CHR '-'
|
||||
#define CAT_CHR '.'
|
||||
#define EQL_TOK "="
|
||||
#define COL_TOK ":"
|
||||
|
||||
bool parse_bool(char *value, bool *b);
|
||||
bool parse_split_type(char *s, split_type_t *t);
|
||||
|
@ -21,8 +23,13 @@ bool parse_flip(char *s, flip_t *f);
|
|||
bool parse_pointer_action(char *s, pointer_action_t *a);
|
||||
bool parse_child_polarity(char *s, child_polarity_t *p);
|
||||
bool parse_degree(char *s, int *d);
|
||||
bool parse_window_id(char *s, long int *i);
|
||||
bool parse_id(char *s, uint32_t *i);
|
||||
bool parse_bool_declaration(char *s, char **key, bool *value, alter_state_t *state);
|
||||
bool parse_index(char *s, int *i);
|
||||
bool parse_rectangle(char *s, xcb_rectangle_t *r);
|
||||
bool parse_subscriber_mask(char *s, subscriber_mask_t *mask);
|
||||
bool parse_monitor_modifiers(char *desc, monitor_select_t *sel);
|
||||
bool parse_desktop_modifiers(char *desc, desktop_select_t *sel);
|
||||
bool parse_node_modifiers(char *desc, node_select_t *sel);
|
||||
|
||||
#endif
|
||||
|
|
83
pointer.c
83
pointer.c
|
@ -22,6 +22,7 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "bspwm.h"
|
||||
#include "query.h"
|
||||
#include "settings.h"
|
||||
|
@ -30,7 +31,6 @@
|
|||
#include "monitor.h"
|
||||
#include "subscribe.h"
|
||||
#include "window.h"
|
||||
#include "pointer.h"
|
||||
|
||||
void grab_pointer(pointer_action_t pac)
|
||||
{
|
||||
|
@ -41,15 +41,15 @@ void grab_pointer(pointer_action_t pac)
|
|||
|
||||
coordinates_t loc;
|
||||
if (locate_window(win, &loc)) {
|
||||
client_t *c = NULL;
|
||||
client_t *c = loc.node->client;
|
||||
|
||||
frozen_pointer->position = pos;
|
||||
frozen_pointer->action = pac;
|
||||
c = loc.node->client;
|
||||
frozen_pointer->monitor = loc.monitor;
|
||||
frozen_pointer->desktop = loc.desktop;
|
||||
frozen_pointer->node = loc.node;
|
||||
frozen_pointer->client = c;
|
||||
frozen_pointer->window = c->window;
|
||||
frozen_pointer->window = loc.node->id;
|
||||
frozen_pointer->horizontal_fence = NULL;
|
||||
frozen_pointer->vertical_fence = NULL;
|
||||
|
||||
|
@ -61,7 +61,7 @@ void grab_pointer(pointer_action_t pac)
|
|||
focus_node(loc.monitor, loc.desktop, loc.node);
|
||||
pointer_follows_monitor = backup;
|
||||
} else if (focus_follows_pointer) {
|
||||
stack(loc.node, true);
|
||||
stack(loc.desktop, loc.node, true);
|
||||
}
|
||||
frozen_pointer->action = ACTION_NONE;
|
||||
break;
|
||||
|
@ -87,71 +87,77 @@ void grab_pointer(pointer_action_t pac)
|
|||
float diag_a = ratio * y;
|
||||
float diag_b = W - diag_a;
|
||||
if (x < diag_a) {
|
||||
if (x < diag_b)
|
||||
if (x < diag_b) {
|
||||
frozen_pointer->side = SIDE_LEFT;
|
||||
else
|
||||
} else {
|
||||
frozen_pointer->side = SIDE_BOTTOM;
|
||||
}
|
||||
} else {
|
||||
if (x < diag_b)
|
||||
if (x < diag_b) {
|
||||
frozen_pointer->side = SIDE_TOP;
|
||||
else
|
||||
} else {
|
||||
frozen_pointer->side = SIDE_RIGHT;
|
||||
}
|
||||
}
|
||||
} else if (pac == ACTION_RESIZE_CORNER) {
|
||||
int16_t mid_x = frozen_pointer->rectangle.x + (frozen_pointer->rectangle.width / 2);
|
||||
int16_t mid_y = frozen_pointer->rectangle.y + (frozen_pointer->rectangle.height / 2);
|
||||
if (pos.x > mid_x) {
|
||||
if (pos.y > mid_y)
|
||||
if (pos.y > mid_y) {
|
||||
frozen_pointer->corner = CORNER_BOTTOM_RIGHT;
|
||||
else
|
||||
} else {
|
||||
frozen_pointer->corner = CORNER_TOP_RIGHT;
|
||||
}
|
||||
} else {
|
||||
if (pos.y > mid_y)
|
||||
if (pos.y > mid_y) {
|
||||
frozen_pointer->corner = CORNER_BOTTOM_LEFT;
|
||||
else
|
||||
} else {
|
||||
frozen_pointer->corner = CORNER_TOP_LEFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (frozen_pointer->is_tiled) {
|
||||
if (pac == ACTION_RESIZE_SIDE) {
|
||||
switch (frozen_pointer->side) {
|
||||
case SIDE_TOP:
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH);
|
||||
break;
|
||||
case SIDE_RIGHT:
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST);
|
||||
break;
|
||||
case SIDE_BOTTOM:
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH);
|
||||
break;
|
||||
case SIDE_LEFT:
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST);
|
||||
break;
|
||||
}
|
||||
} else if (pac == ACTION_RESIZE_CORNER) {
|
||||
switch (frozen_pointer->corner) {
|
||||
case CORNER_TOP_LEFT:
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST);
|
||||
break;
|
||||
case CORNER_TOP_RIGHT:
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_UP);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_NORTH);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST);
|
||||
break;
|
||||
case CORNER_BOTTOM_RIGHT:
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_RIGHT);
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_EAST);
|
||||
break;
|
||||
case CORNER_BOTTOM_LEFT:
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_DOWN);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_LEFT);
|
||||
frozen_pointer->horizontal_fence = find_fence(loc.node, DIR_SOUTH);
|
||||
frozen_pointer->vertical_fence = find_fence(loc.node, DIR_WEST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (frozen_pointer->horizontal_fence != NULL)
|
||||
if (frozen_pointer->horizontal_fence != NULL) {
|
||||
frozen_pointer->horizontal_ratio = frozen_pointer->horizontal_fence->split_ratio;
|
||||
if (frozen_pointer->vertical_fence != NULL)
|
||||
}
|
||||
if (frozen_pointer->vertical_fence != NULL) {
|
||||
frozen_pointer->vertical_ratio = frozen_pointer->vertical_fence->split_ratio;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_NONE:
|
||||
|
@ -160,8 +166,9 @@ void grab_pointer(pointer_action_t pac)
|
|||
} else {
|
||||
if (pac == ACTION_FOCUS) {
|
||||
monitor_t *m = monitor_from_point(pos);
|
||||
if (m != NULL && m != mon)
|
||||
if (m != NULL && m != mon) {
|
||||
focus_node(m, m->desk, m->desk->focus);
|
||||
}
|
||||
}
|
||||
frozen_pointer->action = ACTION_NONE;
|
||||
}
|
||||
|
@ -169,8 +176,9 @@ void grab_pointer(pointer_action_t pac)
|
|||
|
||||
void track_pointer(int root_x, int root_y)
|
||||
{
|
||||
if (frozen_pointer->action == ACTION_NONE)
|
||||
if (frozen_pointer->action == ACTION_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
int delta_x, delta_y, x = 0, y = 0, w = 1, h = 1;
|
||||
|
||||
|
@ -192,13 +200,13 @@ void track_pointer(int root_x, int root_y)
|
|||
if (frozen_pointer->is_tiled) {
|
||||
xcb_window_t pwin = XCB_NONE;
|
||||
query_pointer(&pwin, NULL);
|
||||
if (pwin == win)
|
||||
if (pwin == win) {
|
||||
return;
|
||||
}
|
||||
coordinates_t loc;
|
||||
bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
|
||||
if (is_managed && !IS_FLOATING(loc.node->client) && loc.monitor == m) {
|
||||
swap_nodes(m, d, n, m, d, loc.node);
|
||||
arrange(m, d);
|
||||
} else {
|
||||
if (is_managed && loc.monitor == m) {
|
||||
return;
|
||||
|
@ -214,8 +222,9 @@ void track_pointer(int root_x, int root_y)
|
|||
}
|
||||
bool focused = (n == mon->desk->focus);
|
||||
transfer_node(m, d, n, loc.monitor, loc.desktop, loc.desktop->focus);
|
||||
if (focused)
|
||||
if (focused) {
|
||||
focus_node(loc.monitor, loc.desktop, n);
|
||||
}
|
||||
frozen_pointer->monitor = loc.monitor;
|
||||
frozen_pointer->desktop = loc.desktop;
|
||||
}
|
||||
|
@ -227,12 +236,14 @@ void track_pointer(int root_x, int root_y)
|
|||
c->floating_rectangle.y = y;
|
||||
xcb_point_t pt = (xcb_point_t) {root_x, root_y};
|
||||
monitor_t *pmon = monitor_from_point(pt);
|
||||
if (pmon == NULL || pmon == m)
|
||||
if (pmon == NULL || pmon == m) {
|
||||
return;
|
||||
}
|
||||
bool focused = (n == mon->desk->focus);
|
||||
transfer_node(m, d, n, pmon, pmon->desk, pmon->desk->focus);
|
||||
if (focused)
|
||||
if (focused) {
|
||||
focus_node(pmon, pmon->desk, n);
|
||||
}
|
||||
frozen_pointer->monitor = pmon;
|
||||
frozen_pointer->desktop = pmon->desk;
|
||||
}
|
||||
|
@ -342,8 +353,8 @@ void track_pointer(int root_x, int root_y)
|
|||
void ungrab_pointer(void)
|
||||
{
|
||||
if (frozen_pointer->action != ACTION_NONE) {
|
||||
xcb_rectangle_t r = get_rectangle(frozen_pointer->monitor, frozen_pointer->client);
|
||||
put_status(SBSC_MASK_WINDOW_GEOMETRY, "window_geometry %s %s 0x%X %ux%u+%i+%i\n", frozen_pointer->monitor->name, frozen_pointer->desktop->name, frozen_pointer->window, r.width, r.height, r.x, r.y);
|
||||
xcb_rectangle_t r = get_rectangle(frozen_pointer->monitor, frozen_pointer->desktop, frozen_pointer->node);
|
||||
put_status(SBSC_MASK_NODE_GEOMETRY, "node_geometry %s %s 0x%X %ux%u+%i+%i\n", frozen_pointer->monitor->name, frozen_pointer->desktop->name, frozen_pointer->window, r.width, r.height, r.x, r.y);
|
||||
}
|
||||
frozen_pointer->action = ACTION_NONE;
|
||||
}
|
||||
|
|
430
query.c
430
query.c
|
@ -23,8 +23,6 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include "bspwm.h"
|
||||
#include "desktop.h"
|
||||
|
@ -33,13 +31,12 @@
|
|||
#include "monitor.h"
|
||||
#include "tree.h"
|
||||
#include "query.h"
|
||||
#include "jsmn.h"
|
||||
|
||||
void query_tree(FILE *rsp)
|
||||
{
|
||||
fprintf(rsp, "{");
|
||||
fprintf(rsp, "\"focusedMonitorName\":\"%s\",", mon->name);
|
||||
fprintf(rsp, "\"numClients\":%i,", num_clients);
|
||||
fprintf(rsp, "\"clientsCount\":%i,", clients_count);
|
||||
fprintf(rsp, "\"monitors\":");
|
||||
fprintf(rsp, "[");
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
|
@ -49,6 +46,12 @@ void query_tree(FILE *rsp)
|
|||
}
|
||||
}
|
||||
fprintf(rsp, "]");
|
||||
fprintf(rsp,",");
|
||||
fprintf(rsp, "\"focusHistory\":");
|
||||
query_history(rsp);
|
||||
fprintf(rsp,",");
|
||||
fprintf(rsp, "\"stackingList\":");
|
||||
query_stack(rsp);
|
||||
fprintf(rsp, "}");
|
||||
|
||||
}
|
||||
|
@ -63,7 +66,7 @@ void query_monitor(monitor_t *m, FILE *rsp)
|
|||
fprintf(rsp, "\"rightPadding\":%i,", m->right_padding);
|
||||
fprintf(rsp, "\"bottomPadding\":%i,", m->bottom_padding);
|
||||
fprintf(rsp, "\"leftPadding\":%i,", m->left_padding);
|
||||
fprintf(rsp, "\"numSticky\":%i,", m->num_sticky);
|
||||
fprintf(rsp, "\"stickyCount\":%i,", m->sticky_count);
|
||||
fprintf(rsp, "\"rectangle\":");
|
||||
query_rectangle(m->rectangle, rsp);
|
||||
fprintf(rsp,",");
|
||||
|
@ -91,7 +94,7 @@ void query_desktop(desktop_t *d, FILE *rsp)
|
|||
fprintf(rsp, "\"leftPadding\":%i,", d->left_padding);
|
||||
fprintf(rsp, "\"windowGap\":%i,", d->window_gap);
|
||||
fprintf(rsp, "\"borderWidth\":%u,", d->border_width);
|
||||
fprintf(rsp, "\"focusedWindow\":%u,", d->focus != NULL ? d->focus->client->window : 0);
|
||||
fprintf(rsp, "\"focusedNodeId\":%u,", d->focus != NULL ? d->focus->id : 0);
|
||||
fprintf(rsp, "\"root\":");
|
||||
query_node(d->root, rsp);
|
||||
fprintf(rsp, "}");
|
||||
|
@ -103,13 +106,17 @@ void query_node(node_t *n, FILE *rsp)
|
|||
fprintf(rsp, "null");
|
||||
} else {
|
||||
fprintf(rsp, "{");
|
||||
fprintf(rsp, "\"id\":%u,", n->id);
|
||||
fprintf(rsp, "\"splitType\":\"%s\",", SPLIT_TYPE_STR(n->split_type));
|
||||
fprintf(rsp, "\"splitRatio\":%lf,", n->split_ratio);
|
||||
fprintf(rsp, "\"splitMode\":\"%s\",", SPLIT_MODE_STR(n->split_mode));
|
||||
fprintf(rsp, "\"splitDir\":\"%s\",", SPLIT_DIR_STR(n->split_dir));
|
||||
fprintf(rsp, "\"birthRotation\":%i,", n->birth_rotation);
|
||||
fprintf(rsp, "\"privacyLevel\":%i,", n->privacy_level);
|
||||
fprintf(rsp, "\"vacant\":%s,", BOOL_STR(n->vacant));
|
||||
fprintf(rsp, "\"sticky\":%s,", BOOL_STR(n->sticky));
|
||||
fprintf(rsp, "\"private\":%s,", BOOL_STR(n->private));
|
||||
fprintf(rsp, "\"locked\":%s,", BOOL_STR(n->locked));
|
||||
fprintf(rsp, "\"presel\":");
|
||||
query_presel(n->presel, rsp);
|
||||
fprintf(rsp,",");
|
||||
fprintf(rsp, "\"rectangle\":");
|
||||
query_rectangle(n->rectangle, rsp);
|
||||
fprintf(rsp,",");
|
||||
|
@ -125,13 +132,21 @@ void query_node(node_t *n, FILE *rsp)
|
|||
}
|
||||
}
|
||||
|
||||
void query_presel(presel_t *p, FILE *rsp)
|
||||
{
|
||||
if (p == NULL) {
|
||||
fprintf(rsp, "null");
|
||||
} else {
|
||||
fprintf(rsp, "{\"splitDir\":\"%s\",\"splitRatio\":%lf}", SPLIT_DIR_STR(p->split_dir), p->split_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
void query_client(client_t *c, FILE *rsp)
|
||||
{
|
||||
if (c == NULL) {
|
||||
fprintf(rsp, "null");
|
||||
} else {
|
||||
fprintf(rsp, "{");
|
||||
fprintf(rsp, "\"window\":%u,", c->window);
|
||||
fprintf(rsp, "\"className\":\"%s\",", c->class_name);
|
||||
fprintf(rsp, "\"instanceName\":\"%s\",", c->instance_name);
|
||||
fprintf(rsp, "\"borderWidth\":%u,", c->border_width);
|
||||
|
@ -139,19 +154,16 @@ void query_client(client_t *c, FILE *rsp)
|
|||
fprintf(rsp, "\"lastState\":\"%s\",", STATE_STR(c->last_state));
|
||||
fprintf(rsp, "\"layer\":\"%s\",", LAYER_STR(c->layer));
|
||||
fprintf(rsp, "\"lastLayer\":\"%s\",", LAYER_STR(c->last_layer));
|
||||
fprintf(rsp, "\"locked\":%s,", BOOL_STR(c->locked));
|
||||
fprintf(rsp, "\"sticky\":%s,", BOOL_STR(c->sticky));
|
||||
fprintf(rsp, "\"urgent\":%s,", BOOL_STR(c->urgent));
|
||||
fprintf(rsp, "\"private\":%s,", BOOL_STR(c->private));
|
||||
fprintf(rsp, "\"icccmFocus\":%s,", BOOL_STR(c->icccm_focus));
|
||||
fprintf(rsp, "\"icccmInput\":%s,", BOOL_STR(c->icccm_input));
|
||||
fprintf(rsp, "\"minWidth\":%u,", c->min_width);
|
||||
fprintf(rsp, "\"maxWidth\":%u,", c->max_width);
|
||||
fprintf(rsp, "\"minHeight\":%u,", c->min_height);
|
||||
fprintf(rsp, "\"maxHeight\":%u,", c->max_height);
|
||||
fprintf(rsp, "\"numStates\":%i,", c->num_states);
|
||||
fprintf(rsp, "\"wmStatesCount\":%i,", c->wm_states_count);
|
||||
fprintf(rsp, "\"wmState\":");
|
||||
query_wm_state(c->wm_state, c->num_states, rsp);
|
||||
query_wm_state(c->wm_state, c->wm_states_count, rsp);
|
||||
fprintf(rsp,",");
|
||||
fprintf(rsp, "\"tiledRectangle\":");
|
||||
query_rectangle(c->tiled_rectangle, rsp);
|
||||
|
@ -167,80 +179,116 @@ void query_rectangle(xcb_rectangle_t r, FILE *rsp)
|
|||
fprintf(rsp, "{\"x\":%i,\"y\":%i,\"width\":%u,\"height\":%u}", r.x, r.y, r.width, r.height);
|
||||
}
|
||||
|
||||
void query_wm_state(xcb_atom_t *wm_state, int num_states, FILE *rsp)
|
||||
void query_wm_state(xcb_atom_t *wm_state, int wm_states_count, FILE *rsp)
|
||||
{
|
||||
fprintf(rsp, "[");
|
||||
for (int i = 0; i < num_states; i++) {
|
||||
for (int i = 0; i < wm_states_count; i++) {
|
||||
fprintf(rsp, "%u", wm_state[i]);
|
||||
if (i < num_states - 1) {
|
||||
if (i < wm_states_count - 1) {
|
||||
fprintf(rsp, ",");
|
||||
}
|
||||
}
|
||||
fprintf(rsp, "]");
|
||||
}
|
||||
|
||||
void query_history(coordinates_t loc, FILE *rsp)
|
||||
void query_history(FILE *rsp)
|
||||
{
|
||||
fprintf(rsp, "[");
|
||||
for (history_t *h = history_head; h != NULL; h = h->next) {
|
||||
if ((loc.monitor != NULL && h->loc.monitor != loc.monitor)
|
||||
|| (loc.desktop != NULL && h->loc.desktop != loc.desktop)) {
|
||||
continue;
|
||||
query_coordinates(&h->loc, rsp);
|
||||
if (h->next != NULL) {
|
||||
fprintf(rsp, ",");
|
||||
}
|
||||
xcb_window_t win = XCB_NONE;
|
||||
if (h->loc.node != NULL) {
|
||||
win = h->loc.node->client->window;
|
||||
}
|
||||
fprintf(rsp, "%s %s 0x%X\n", h->loc.monitor->name, h->loc.desktop->name, win);
|
||||
}
|
||||
fprintf(rsp, "]");
|
||||
}
|
||||
|
||||
void query_coordinates(coordinates_t *loc, FILE *rsp)
|
||||
{
|
||||
fprintf(rsp, "{\"monitorName\":\"%s\",\"desktopName\":\"%s\",\"nodeId\":%u}", loc->monitor->name, loc->desktop->name, loc->node!=NULL?loc->node->id:0);
|
||||
}
|
||||
|
||||
void query_stack(FILE *rsp)
|
||||
{
|
||||
fprintf(rsp, "[");
|
||||
for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
|
||||
fprintf(rsp, "0x%X\n", s->node->client->window);
|
||||
}
|
||||
}
|
||||
|
||||
void query_windows(coordinates_t loc, FILE *rsp)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (loc.monitor != NULL && m != loc.monitor)
|
||||
continue;
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
if (loc.desktop != NULL && d != loc.desktop)
|
||||
continue;
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
if (loc.node != NULL && n != loc.node)
|
||||
continue;
|
||||
fprintf(rsp, "0x%X\n", n->client->window);
|
||||
}
|
||||
fprintf(rsp, "%u", s->node->id);
|
||||
if (s->next != NULL) {
|
||||
fprintf(rsp, ",");
|
||||
}
|
||||
}
|
||||
fprintf(rsp, "]");
|
||||
}
|
||||
|
||||
void query_names(domain_t dom, coordinates_t loc, FILE *rsp)
|
||||
void query_node_ids(coordinates_t loc, node_select_t *sel, FILE *rsp)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (loc.monitor != NULL && m != loc.monitor) {
|
||||
continue;
|
||||
}
|
||||
if (dom == DOMAIN_MONITOR) {
|
||||
fprintf(rsp, "%s\n", m->name);
|
||||
}
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
if (loc.desktop != NULL && d != loc.desktop) {
|
||||
continue;
|
||||
}
|
||||
if (dom == DOMAIN_DESKTOP) {
|
||||
fprintf(rsp, "%s\n", d->name);
|
||||
}
|
||||
query_node_ids_in(d->root, d, m, loc, sel, rsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client_select_t make_client_select(void)
|
||||
void query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates_t loc, node_select_t *sel, FILE *rsp)
|
||||
{
|
||||
client_select_t sel = {
|
||||
if (n == NULL) {
|
||||
return;
|
||||
} else {
|
||||
coordinates_t ref = {mon, mon->desk, mon->desk->focus};
|
||||
coordinates_t trg = {m, d, n};
|
||||
if ((loc.node == NULL || n == loc.node) &&
|
||||
(sel == NULL || node_matches(&trg, &ref, *sel))) {
|
||||
fprintf(rsp, "0x%07X\n", n->id);
|
||||
}
|
||||
query_node_ids_in(n->first_child, d, m, loc, sel, rsp);
|
||||
query_node_ids_in(n->second_child, d, m, loc, sel, rsp);
|
||||
}
|
||||
}
|
||||
|
||||
void query_desktop_names(coordinates_t loc, desktop_select_t *sel, FILE *rsp)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (loc.monitor != NULL && m != loc.monitor) {
|
||||
continue;
|
||||
}
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
coordinates_t ref = {mon, mon->desk, NULL};
|
||||
coordinates_t trg = {m, d, NULL};
|
||||
if ((loc.desktop != NULL && d != loc.desktop) ||
|
||||
(sel != NULL && !desktop_matches(&trg, &ref, *sel))) {
|
||||
continue;
|
||||
}
|
||||
fprintf(rsp, "%s\n", d->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void query_monitor_names(coordinates_t loc, monitor_select_t *sel, FILE *rsp)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
coordinates_t ref = {mon, NULL, NULL};
|
||||
coordinates_t trg = {m, NULL, NULL};
|
||||
if ((loc.monitor != NULL && m != loc.monitor) ||
|
||||
(sel != NULL && !monitor_matches(&trg, &ref, *sel))) {
|
||||
continue;
|
||||
}
|
||||
fprintf(rsp, "%s\n", m->name);
|
||||
}
|
||||
}
|
||||
|
||||
node_select_t make_node_select(void)
|
||||
{
|
||||
node_select_t sel = {
|
||||
.automatic = OPTION_NONE,
|
||||
.focused = OPTION_NONE,
|
||||
.local = OPTION_NONE,
|
||||
.leaf = OPTION_NONE,
|
||||
.tiled = OPTION_NONE,
|
||||
.pseudo_tiled = OPTION_NONE,
|
||||
.floating = OPTION_NONE,
|
||||
|
@ -250,9 +298,6 @@ client_select_t make_client_select(void)
|
|||
.private = OPTION_NONE,
|
||||
.urgent = OPTION_NONE,
|
||||
.same_class = OPTION_NONE,
|
||||
.automatic = OPTION_NONE,
|
||||
.local = OPTION_NONE,
|
||||
.focused = OPTION_NONE,
|
||||
.below = OPTION_NONE,
|
||||
.normal = OPTION_NONE,
|
||||
.above = OPTION_NONE
|
||||
|
@ -280,40 +325,12 @@ monitor_select_t make_monitor_select(void)
|
|||
return sel;
|
||||
}
|
||||
|
||||
#define GET_MOD(k) \
|
||||
} else if (streq(#k, tok)) { \
|
||||
sel.k = OPTION_TRUE; \
|
||||
} else if (streq("!" #k, tok)) { \
|
||||
sel.k = OPTION_FALSE;
|
||||
|
||||
bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
||||
{
|
||||
client_select_t sel = make_client_select();
|
||||
char *tok;
|
||||
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
|
||||
tok[0] = '\0';
|
||||
tok++;
|
||||
if (streq("tiled", tok)) {
|
||||
sel.tiled = OPTION_TRUE;
|
||||
} else if (streq("!tiled", tok)) {
|
||||
sel.tiled = OPTION_FALSE;
|
||||
GET_MOD(pseudo_tiled)
|
||||
GET_MOD(floating)
|
||||
GET_MOD(fullscreen)
|
||||
GET_MOD(locked)
|
||||
GET_MOD(sticky)
|
||||
GET_MOD(private)
|
||||
GET_MOD(urgent)
|
||||
GET_MOD(same_class)
|
||||
GET_MOD(automatic)
|
||||
GET_MOD(local)
|
||||
GET_MOD(focused)
|
||||
GET_MOD(below)
|
||||
GET_MOD(normal)
|
||||
GET_MOD(above)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
node_select_t sel = make_node_select();
|
||||
|
||||
if (!parse_node_modifiers(desc, &sel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->monitor = ref->monitor;
|
||||
|
@ -351,9 +368,44 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
|||
dst->desktop = mon->desk;
|
||||
dst->node = mon->desk->focus;
|
||||
}
|
||||
} else if (*desc == '@') {
|
||||
desc++;
|
||||
char *colon;
|
||||
if ((colon = strrchr(desc, ':')) != NULL) {
|
||||
*colon = '\0';
|
||||
if (desktop_from_desc(desc, ref, dst)) {
|
||||
desc = colon + 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dst->node = (*desc == '/' ? dst->desktop->root : dst->desktop->focus);
|
||||
char *move = strtok(desc, PTH_TOK);
|
||||
while (move != NULL && dst->node != NULL) {
|
||||
if (streq("first", move) || streq("1", move)) {
|
||||
dst->node = dst->node->first_child;
|
||||
} else if (streq("second", move) || streq("2", move)) {
|
||||
dst->node = dst->node->second_child;
|
||||
} else if (streq("parent", move)) {
|
||||
dst->node = dst->node->parent;
|
||||
} else if (streq("brother", move)) {
|
||||
dst->node = brother_tree(dst->node);
|
||||
} else {
|
||||
direction_t dir;
|
||||
if (parse_direction(move, &dir)) {
|
||||
dst->node = find_fence(dst->node, dir);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
move = strtok(NULL, PTH_TOK);
|
||||
}
|
||||
if (dst->node != NULL) {
|
||||
return node_matches(dst, ref, sel);
|
||||
}
|
||||
} else {
|
||||
long int wid;
|
||||
if (parse_window_id(desc, &wid) && locate_window(wid, dst)) {
|
||||
uint32_t id;
|
||||
if (parse_id(desc, &id) && find_by_id(id, dst)) {
|
||||
return node_matches(dst, ref, sel);
|
||||
}
|
||||
}
|
||||
|
@ -364,20 +416,9 @@ bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
|||
bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
||||
{
|
||||
desktop_select_t sel = make_desktop_select();
|
||||
char *tok;
|
||||
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
|
||||
tok[0] = '\0';
|
||||
tok++;
|
||||
if (streq("occupied", tok)) {
|
||||
sel.occupied = OPTION_TRUE;
|
||||
} else if (streq("!occupied", tok)) {
|
||||
sel.occupied = OPTION_FALSE;
|
||||
GET_MOD(focused)
|
||||
GET_MOD(urgent)
|
||||
GET_MOD(local)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_desktop_modifiers(desc, &sel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->desktop = NULL;
|
||||
|
@ -429,18 +470,9 @@ bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
|||
bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
||||
{
|
||||
monitor_select_t sel = make_monitor_select();
|
||||
char *tok;
|
||||
while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
|
||||
tok[0] = '\0';
|
||||
tok++;
|
||||
if (streq("occupied", tok)) {
|
||||
sel.occupied = OPTION_TRUE;
|
||||
} else if (streq("!occupied", tok)) {
|
||||
sel.occupied = OPTION_FALSE;
|
||||
GET_MOD(focused)
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!parse_monitor_modifiers(desc, &sel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->monitor = NULL;
|
||||
|
@ -482,127 +514,94 @@ bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
|
|||
return (dst->monitor != NULL);
|
||||
}
|
||||
|
||||
#undef GET_MOD
|
||||
|
||||
bool locate_window(xcb_window_t win, coordinates_t *loc)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next)
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root))
|
||||
if (n->client->window == win) {
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
if (n->id == win) {
|
||||
loc->monitor = m;
|
||||
loc->desktop = d;
|
||||
loc->node = n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool locate_desktop(char *name, coordinates_t *loc)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next)
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
if (streq(d->name, name)) {
|
||||
loc->monitor = m;
|
||||
loc->desktop = d;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool locate_monitor(char *name, coordinates_t *loc)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next)
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (streq(m->name, name)) {
|
||||
loc->monitor = m;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool desktop_from_index(int i, coordinates_t *loc, monitor_t *mm)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
if (mm != NULL && m != mm)
|
||||
if (mm != NULL && m != mm) {
|
||||
continue;
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--)
|
||||
}
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next, i--) {
|
||||
if (i == 1) {
|
||||
loc->monitor = m;
|
||||
loc->desktop = d;
|
||||
loc->node = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool monitor_from_index(int i, coordinates_t *loc)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next, i--)
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next, i--) {
|
||||
if (i == 1) {
|
||||
loc->monitor = m;
|
||||
loc->desktop = NULL;
|
||||
loc->node = NULL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
|
||||
bool node_matches(coordinates_t *loc, coordinates_t *ref, node_select_t sel)
|
||||
{
|
||||
if (loc->node == NULL)
|
||||
return false;
|
||||
|
||||
#define WSTATE(prop) \
|
||||
if (sel.prop != OPTION_NONE && \
|
||||
!loc->node->client->prop \
|
||||
? sel.prop == OPTION_TRUE \
|
||||
: sel.prop == OPTION_FALSE) { \
|
||||
return false; \
|
||||
}
|
||||
WSTATE(locked)
|
||||
WSTATE(sticky)
|
||||
WSTATE(private)
|
||||
WSTATE(urgent)
|
||||
#undef MATCHSTATE
|
||||
|
||||
if (sel.tiled != OPTION_NONE &&
|
||||
loc->node->client->state != STATE_TILED
|
||||
? sel.tiled == OPTION_TRUE
|
||||
: sel.tiled == OPTION_FALSE) {
|
||||
if (loc->node == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.pseudo_tiled != OPTION_NONE &&
|
||||
loc->node->client->state != STATE_PSEUDO_TILED
|
||||
? sel.pseudo_tiled == OPTION_TRUE
|
||||
: sel.pseudo_tiled == OPTION_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.floating != OPTION_NONE &&
|
||||
loc->node->client->state != STATE_FLOATING
|
||||
? sel.floating == OPTION_TRUE
|
||||
: sel.floating == OPTION_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.fullscreen != OPTION_NONE &&
|
||||
loc->node->client->state != STATE_FULLSCREEN
|
||||
? sel.fullscreen == OPTION_TRUE
|
||||
: sel.fullscreen == OPTION_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.same_class != OPTION_NONE && ref->node != NULL &&
|
||||
streq(loc->node->client->class_name, ref->node->client->class_name)
|
||||
? sel.same_class == OPTION_FALSE
|
||||
: sel.same_class == OPTION_TRUE) {
|
||||
if (sel.focused != OPTION_NONE &&
|
||||
loc->node != mon->desk->focus
|
||||
? sel.focused == OPTION_TRUE
|
||||
: sel.focused == OPTION_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.automatic != OPTION_NONE &&
|
||||
loc->node->split_mode == MODE_MANUAL
|
||||
loc->node->presel != NULL
|
||||
? sel.automatic == OPTION_TRUE
|
||||
: sel.automatic == OPTION_FALSE) {
|
||||
return false;
|
||||
|
@ -615,33 +614,80 @@ bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (sel.below != OPTION_NONE &&
|
||||
loc->node->client->layer != LAYER_BELOW
|
||||
? sel.below == OPTION_TRUE
|
||||
: sel.below == OPTION_FALSE) {
|
||||
if (sel.leaf != OPTION_NONE &&
|
||||
loc->node->client == NULL
|
||||
? sel.leaf == OPTION_TRUE
|
||||
: sel.leaf == OPTION_FALSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.normal != OPTION_NONE &&
|
||||
loc->node->client->layer != LAYER_NORMAL
|
||||
? sel.normal == OPTION_TRUE
|
||||
: sel.normal == OPTION_FALSE) {
|
||||
#define NFLAG(p) \
|
||||
if (sel.p != OPTION_NONE && \
|
||||
!loc->node->p \
|
||||
? sel.p == OPTION_TRUE \
|
||||
: sel.p == OPTION_FALSE) { \
|
||||
return false; \
|
||||
}
|
||||
NFLAG(sticky)
|
||||
NFLAG(private)
|
||||
NFLAG(locked)
|
||||
#undef WFLAG
|
||||
|
||||
if (loc->node->client == NULL &&
|
||||
(sel.same_class != OPTION_NONE ||
|
||||
sel.tiled != OPTION_NONE ||
|
||||
sel.pseudo_tiled != OPTION_NONE ||
|
||||
sel.floating != OPTION_NONE ||
|
||||
sel.fullscreen != OPTION_NONE ||
|
||||
sel.below != OPTION_NONE ||
|
||||
sel.normal != OPTION_NONE ||
|
||||
sel.above != OPTION_NONE ||
|
||||
sel.urgent != OPTION_NONE)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.above != OPTION_NONE &&
|
||||
loc->node->client->layer != LAYER_ABOVE
|
||||
? sel.above == OPTION_TRUE
|
||||
: sel.above == OPTION_FALSE) {
|
||||
if (ref->node != NULL && ref->node->client != NULL &&
|
||||
sel.same_class != OPTION_NONE &&
|
||||
streq(loc->node->client->class_name, ref->node->client->class_name)
|
||||
? sel.same_class == OPTION_FALSE
|
||||
: sel.same_class == OPTION_TRUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sel.focused != OPTION_NONE &&
|
||||
loc->node != mon->desk->focus
|
||||
? sel.focused == OPTION_TRUE
|
||||
: sel.focused == OPTION_FALSE) {
|
||||
return false;
|
||||
#define WSTATE(p, e) \
|
||||
if (sel.p != OPTION_NONE && \
|
||||
loc->node->client->state != e \
|
||||
? sel.p == OPTION_TRUE \
|
||||
: sel.p == OPTION_FALSE) { \
|
||||
return false; \
|
||||
}
|
||||
WSTATE(tiled, STATE_TILED)
|
||||
WSTATE(pseudo_tiled, STATE_PSEUDO_TILED)
|
||||
WSTATE(floating, STATE_FLOATING)
|
||||
WSTATE(fullscreen, STATE_FULLSCREEN)
|
||||
#undef WSTATE
|
||||
|
||||
#define WLAYER(p, e) \
|
||||
if (sel.p != OPTION_NONE && \
|
||||
loc->node->client->layer != e \
|
||||
? sel.p == OPTION_TRUE \
|
||||
: sel.p == OPTION_FALSE) { \
|
||||
return false; \
|
||||
}
|
||||
WLAYER(below, LAYER_BELOW)
|
||||
WLAYER(normal, LAYER_NORMAL)
|
||||
WLAYER(above, LAYER_ABOVE)
|
||||
#undef WLAYER
|
||||
|
||||
#define WFLAG(p) \
|
||||
if (sel.p != OPTION_NONE && \
|
||||
!loc->node->client->p \
|
||||
? sel.p == OPTION_TRUE \
|
||||
: sel.p == OPTION_FALSE) { \
|
||||
return false; \
|
||||
}
|
||||
WFLAG(urgent)
|
||||
#undef WFLAG
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
24
query.h
24
query.h
|
@ -25,27 +25,31 @@
|
|||
#ifndef BSPWM_QUERY_H
|
||||
#define BSPWM_QUERY_H
|
||||
|
||||
#define PTH_TOK "/"
|
||||
|
||||
typedef enum {
|
||||
DOMAIN_TREE,
|
||||
DOMAIN_MONITOR,
|
||||
DOMAIN_DESKTOP,
|
||||
DOMAIN_WINDOW,
|
||||
DOMAIN_TREE,
|
||||
DOMAIN_HISTORY,
|
||||
DOMAIN_STACK
|
||||
DOMAIN_NODE
|
||||
} domain_t;
|
||||
|
||||
void query_tree(FILE *rsp);
|
||||
void query_monitor(monitor_t *m, FILE *rsp);
|
||||
void query_desktop(desktop_t *d, FILE *rsp);
|
||||
void query_node(node_t *n, FILE *rsp);
|
||||
void query_presel(presel_t *p, FILE *rsp);
|
||||
void query_client(client_t *c, FILE *rsp);
|
||||
void query_rectangle(xcb_rectangle_t r, FILE *rsp);
|
||||
void query_wm_state(xcb_atom_t *wm_state, int num_states, FILE *rsp);
|
||||
void query_history(coordinates_t loc, FILE *rsp);
|
||||
void query_wm_state(xcb_atom_t *wm_state, int wm_states_count, FILE *rsp);
|
||||
void query_history(FILE *rsp);
|
||||
void query_coordinates(coordinates_t *loc, FILE *rsp);
|
||||
void query_stack(FILE *rsp);
|
||||
void query_windows(coordinates_t loc, FILE *rsp);
|
||||
void query_names(domain_t dom, coordinates_t loc, FILE *rsp);
|
||||
client_select_t make_client_select(void);
|
||||
void query_node_ids(coordinates_t loc, node_select_t *sel, FILE *rsp);
|
||||
void query_node_ids_in(node_t *n, desktop_t *d, monitor_t *m, coordinates_t loc, node_select_t *sel, FILE *rsp);
|
||||
void query_desktop_names(coordinates_t loc, desktop_select_t *sel, FILE *rsp);
|
||||
void query_monitor_names(coordinates_t loc, monitor_select_t *sel, FILE *rsp);
|
||||
node_select_t make_node_select(void);
|
||||
desktop_select_t make_desktop_select(void);
|
||||
monitor_select_t make_monitor_select(void);
|
||||
bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst);
|
||||
|
@ -56,7 +60,7 @@ 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, monitor_t *mm);
|
||||
bool monitor_from_index(int i, coordinates_t *loc);
|
||||
bool node_matches(coordinates_t *loc, coordinates_t *ref, client_select_t sel);
|
||||
bool node_matches(coordinates_t *loc, coordinates_t *ref, node_select_t sel);
|
||||
bool desktop_matches(coordinates_t *loc, coordinates_t *ref, desktop_select_t sel);
|
||||
bool monitor_matches(coordinates_t *loc, __attribute__((unused)) coordinates_t *ref, monitor_select_t sel);
|
||||
|
||||
|
|
326
restore.c
326
restore.c
|
@ -22,10 +22,10 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "bspwm.h"
|
||||
#include "desktop.h"
|
||||
#include "ewmh.h"
|
||||
|
@ -36,10 +36,8 @@
|
|||
#include "tree.h"
|
||||
#include "settings.h"
|
||||
#include "restore.h"
|
||||
#include "helpers.h"
|
||||
#include "common.h"
|
||||
#include "window.h"
|
||||
#include "parse.h"
|
||||
#include "jsmn.h"
|
||||
|
||||
bool restore_tree(const char *file_path)
|
||||
{
|
||||
|
@ -99,6 +97,8 @@ bool restore_tree(const char *file_path)
|
|||
return false;
|
||||
}
|
||||
|
||||
mon = NULL;
|
||||
|
||||
while (mon_head != NULL) {
|
||||
remove_monitor(mon_head);
|
||||
}
|
||||
|
@ -112,9 +112,9 @@ bool restore_tree(const char *file_path)
|
|||
free(focusedMonitorName);
|
||||
focusedMonitorName = copy_string(t+1, json);
|
||||
t++;
|
||||
} else if (keyeq("numClients", t, json)) {
|
||||
} else if (keyeq("clientsCount", t, json)) {
|
||||
t++;
|
||||
sscanf(json + t->start, "%u", &num_clients);
|
||||
sscanf(json + t->start, "%u", &clients_count);
|
||||
} else if (keyeq("monitors", t, json)) {
|
||||
t++;
|
||||
int s = t->size;
|
||||
|
@ -123,6 +123,15 @@ bool restore_tree(const char *file_path)
|
|||
monitor_t *m = restore_monitor(&t, json);
|
||||
add_monitor(m);
|
||||
}
|
||||
continue;
|
||||
} else if (keyeq("focusHistory", t, json)) {
|
||||
t++;
|
||||
restore_history(&t, json);
|
||||
continue;
|
||||
} else if (keyeq("stackingList", t, json)) {
|
||||
t++;
|
||||
restore_stack(&t, json);
|
||||
continue;
|
||||
}
|
||||
t++;
|
||||
}
|
||||
|
@ -138,14 +147,18 @@ bool restore_tree(const char *file_path)
|
|||
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
refresh_presel_feebacks_in(d->root, d, m);
|
||||
restack_presel_feedback(d);
|
||||
for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
|
||||
uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
|
||||
xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
|
||||
xcb_change_window_attributes(dpy, n->id, XCB_CW_EVENT_MASK, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ewmh_update_client_list();
|
||||
ewmh_update_client_list(false);
|
||||
ewmh_update_client_list(true);
|
||||
ewmh_update_active_window();
|
||||
ewmh_update_number_of_desktops();
|
||||
ewmh_update_current_desktop();
|
||||
ewmh_update_desktop_names();
|
||||
|
@ -156,34 +169,34 @@ bool restore_tree(const char *file_path)
|
|||
return true;
|
||||
}
|
||||
|
||||
#define RESTORE_INT(o, k, p) \
|
||||
#define RESTORE_INT(k, p) \
|
||||
} else if (keyeq(#k, *t, json)) { \
|
||||
(*t)++; \
|
||||
sscanf(json + (*t)->start, "%i", &o->p);
|
||||
sscanf(json + (*t)->start, "%i", p);
|
||||
|
||||
#define RESTORE_UINT(o, k, p) \
|
||||
#define RESTORE_UINT(k, p) \
|
||||
} else if (keyeq(#k, *t, json)) { \
|
||||
(*t)++; \
|
||||
sscanf(json + (*t)->start, "%u", &o->p);
|
||||
sscanf(json + (*t)->start, "%u", p);
|
||||
|
||||
#define RESTORE_USINT(o, k, p) \
|
||||
#define RESTORE_USINT(k, p) \
|
||||
} else if (keyeq(#k, *t, json)) { \
|
||||
(*t)++; \
|
||||
sscanf(json + (*t)->start, "%hu", &o->p);
|
||||
sscanf(json + (*t)->start, "%hu", p);
|
||||
|
||||
#define RESTORE_DOUBLE(o, k, p) \
|
||||
#define RESTORE_DOUBLE(k, p) \
|
||||
} else if (keyeq(#k, *t, json)) { \
|
||||
(*t)++; \
|
||||
sscanf(json + (*t)->start, "%lf", &o->p);
|
||||
sscanf(json + (*t)->start, "%lf", p);
|
||||
|
||||
#define RESTORE_ANY(o, k, p, f) \
|
||||
#define RESTORE_ANY(k, p, f) \
|
||||
} else if (keyeq(#k, *t, json)) { \
|
||||
(*t)++; \
|
||||
char *val = copy_string(*t, json); \
|
||||
f(val, &o->p); \
|
||||
f(val, p); \
|
||||
free(val);
|
||||
|
||||
#define RESTORE_BOOL(o, k, p) RESTORE_ANY(o, k, p, parse_bool)
|
||||
#define RESTORE_BOOL(k, p) RESTORE_ANY(k, p, parse_bool)
|
||||
|
||||
monitor_t *restore_monitor(jsmntok_t **t, char *json)
|
||||
{
|
||||
|
@ -196,13 +209,13 @@ monitor_t *restore_monitor(jsmntok_t **t, char *json)
|
|||
if (keyeq("name", *t, json)) {
|
||||
(*t)++;
|
||||
snprintf(m->name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
|
||||
RESTORE_UINT(m, id, id)
|
||||
RESTORE_BOOL(m, wired, wired)
|
||||
RESTORE_INT(m, topPadding, top_padding)
|
||||
RESTORE_INT(m, rightPadding, right_padding)
|
||||
RESTORE_INT(m, bottomPadding, bottom_padding)
|
||||
RESTORE_INT(m, leftPadding, left_padding)
|
||||
RESTORE_INT(m, numSticky, num_sticky)
|
||||
RESTORE_UINT(id, &m->id)
|
||||
RESTORE_BOOL(wired, &m->wired)
|
||||
RESTORE_INT(topPadding, &m->top_padding)
|
||||
RESTORE_INT(rightPadding, &m->right_padding)
|
||||
RESTORE_INT(bottomPadding, &m->bottom_padding)
|
||||
RESTORE_INT(leftPadding, &m->left_padding)
|
||||
RESTORE_UINT(stickyCount, &m->sticky_count)
|
||||
} else if (keyeq("rectangle", *t, json)) {
|
||||
(*t)++;
|
||||
restore_rectangle(&m->rectangle, t, json);
|
||||
|
@ -247,7 +260,7 @@ desktop_t *restore_desktop(jsmntok_t **t, char *json)
|
|||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
desktop_t *d = make_desktop(NULL);
|
||||
xcb_window_t focusedWindow = XCB_NONE;
|
||||
xcb_window_t focusedNodeId = XCB_NONE;
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (keyeq("name", *t, json)) {
|
||||
|
@ -261,15 +274,15 @@ desktop_t *restore_desktop(jsmntok_t **t, char *json)
|
|||
d->layout = lyt;
|
||||
}
|
||||
free(val);
|
||||
RESTORE_INT(d, topPadding, top_padding)
|
||||
RESTORE_INT(d, rightPadding, right_padding)
|
||||
RESTORE_INT(d, bottomPadding, bottom_padding)
|
||||
RESTORE_INT(d, leftPadding, left_padding)
|
||||
RESTORE_INT(d, windowGap, window_gap)
|
||||
RESTORE_UINT(d, borderWidth, border_width)
|
||||
} else if (keyeq("focusedWindow", *t, json)) {
|
||||
RESTORE_INT(topPadding, &d->top_padding)
|
||||
RESTORE_INT(rightPadding, &d->right_padding)
|
||||
RESTORE_INT(bottomPadding, &d->bottom_padding)
|
||||
RESTORE_INT(leftPadding, &d->left_padding)
|
||||
RESTORE_INT(windowGap, &d->window_gap)
|
||||
RESTORE_UINT(borderWidth, &d->border_width)
|
||||
} else if (keyeq("focusedNodeId", *t, json)) {
|
||||
(*t)++;
|
||||
sscanf(json + (*t)->start, "%u", &focusedWindow);
|
||||
sscanf(json + (*t)->start, "%u", &focusedNodeId);
|
||||
} else if (keyeq("root", *t, json)) {
|
||||
(*t)++;
|
||||
d->root = restore_node(t, json);
|
||||
|
@ -281,13 +294,8 @@ desktop_t *restore_desktop(jsmntok_t **t, char *json)
|
|||
(*t)++;
|
||||
}
|
||||
|
||||
if (focusedWindow != XCB_NONE) {
|
||||
for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root)) {
|
||||
if (f->client->window == focusedWindow) {
|
||||
d->focus = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (focusedNodeId != XCB_NONE) {
|
||||
d->focus = find_by_id_in(d->root, focusedNodeId);
|
||||
}
|
||||
|
||||
return d;
|
||||
|
@ -301,20 +309,24 @@ node_t *restore_node(jsmntok_t **t, char *json)
|
|||
} else {
|
||||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
node_t *n = make_node();
|
||||
/* hack to prevent a new ID from being generated */
|
||||
node_t *n = make_node(UINT32_MAX);
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (keyeq("splitType", *t, json)) {
|
||||
if (keyeq("id", *t, json)) {
|
||||
(*t)++;
|
||||
char *val = copy_string(*t, json);
|
||||
parse_split_type(val, &n->split_type);
|
||||
free(val);
|
||||
RESTORE_DOUBLE(n, splitRatio, split_ratio)
|
||||
RESTORE_ANY(n, splitMode, split_mode, parse_split_mode)
|
||||
RESTORE_ANY(n, splitDir, split_dir, parse_direction)
|
||||
RESTORE_INT(n, birthRotation, birth_rotation)
|
||||
RESTORE_INT(n, privacyLevel, privacy_level)
|
||||
RESTORE_ANY(n, vacant, vacant, parse_bool)
|
||||
sscanf(json + (*t)->start, "%u", &n->id);
|
||||
RESTORE_ANY(splitType, &n->split_type, parse_split_type)
|
||||
RESTORE_DOUBLE(splitRatio, &n->split_ratio)
|
||||
RESTORE_INT(birthRotation, &n->birth_rotation)
|
||||
RESTORE_ANY(vacant, &n->vacant, parse_bool)
|
||||
RESTORE_ANY(sticky, &n->sticky, parse_bool)
|
||||
RESTORE_ANY(private, &n->private, parse_bool)
|
||||
RESTORE_ANY(locked, &n->locked, parse_bool)
|
||||
} else if (keyeq("presel", *t, json)) {
|
||||
(*t)++;
|
||||
n->presel = restore_presel(t, json);
|
||||
continue;
|
||||
} else if (keyeq("rectangle", *t, json)) {
|
||||
(*t)++;
|
||||
restore_rectangle(&n->rectangle, t, json);
|
||||
|
@ -339,6 +351,9 @@ node_t *restore_node(jsmntok_t **t, char *json)
|
|||
(*t)++;
|
||||
n->client = restore_client(t, json);
|
||||
continue;
|
||||
} else {
|
||||
warn("Restore node: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
|
||||
(*t)++;
|
||||
}
|
||||
(*t)++;
|
||||
}
|
||||
|
@ -347,6 +362,31 @@ node_t *restore_node(jsmntok_t **t, char *json)
|
|||
}
|
||||
}
|
||||
|
||||
presel_t *restore_presel(jsmntok_t **t, char *json)
|
||||
{
|
||||
if ((*t)->type == JSMN_PRIMITIVE) {
|
||||
(*t)++;
|
||||
return NULL;
|
||||
} else {
|
||||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
presel_t *p = make_presel();
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (keyeq("splitRatio", *t, json)) {
|
||||
(*t)++;
|
||||
sscanf(json + (*t)->start, "%lf", &p->split_ratio);
|
||||
RESTORE_ANY(splitDir, &p->split_dir, parse_direction)
|
||||
}
|
||||
|
||||
(*t)++;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
client_t *restore_client(jsmntok_t **t, char *json)
|
||||
{
|
||||
if ((*t)->type == JSMN_PRIMITIVE) {
|
||||
|
@ -355,34 +395,28 @@ client_t *restore_client(jsmntok_t **t, char *json)
|
|||
} else {
|
||||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
client_t *c = make_client(XCB_NONE, 0);
|
||||
client_t *c = make_client();
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (keyeq("window", *t, json)) {
|
||||
(*t)++;
|
||||
sscanf(json + (*t)->start, "%u", &c->window);
|
||||
} else if (keyeq("className", *t, json)) {
|
||||
if (keyeq("className", *t, json)) {
|
||||
(*t)++;
|
||||
snprintf(c->class_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
|
||||
} else if (keyeq("instanceName", *t, json)) {
|
||||
(*t)++;
|
||||
snprintf(c->instance_name, (*t)->end - (*t)->start + 1, "%s", json + (*t)->start);
|
||||
RESTORE_ANY(c, state, state, parse_client_state)
|
||||
RESTORE_ANY(c, lastState, last_state, parse_client_state)
|
||||
RESTORE_ANY(c, layer, layer, parse_stack_layer)
|
||||
RESTORE_ANY(c, lastLayer, last_layer, parse_stack_layer)
|
||||
RESTORE_UINT(c, borderWidth, border_width)
|
||||
RESTORE_BOOL(c, locked, locked)
|
||||
RESTORE_BOOL(c, sticky, sticky)
|
||||
RESTORE_BOOL(c, urgent, urgent)
|
||||
RESTORE_BOOL(c, private, private)
|
||||
RESTORE_BOOL(c, icccmFocus, icccm_focus)
|
||||
RESTORE_BOOL(c, icccmInput, icccm_input)
|
||||
RESTORE_USINT(c, minWidth, min_width)
|
||||
RESTORE_USINT(c, maxWidth, max_width)
|
||||
RESTORE_USINT(c, minHeight, min_height)
|
||||
RESTORE_USINT(c, maxHeight, max_height)
|
||||
RESTORE_INT(c, numStates, num_states)
|
||||
RESTORE_ANY(state, &c->state, parse_client_state)
|
||||
RESTORE_ANY(lastState, &c->last_state, parse_client_state)
|
||||
RESTORE_ANY(layer, &c->layer, parse_stack_layer)
|
||||
RESTORE_ANY(lastLayer, &c->last_layer, parse_stack_layer)
|
||||
RESTORE_UINT(borderWidth, &c->border_width)
|
||||
RESTORE_BOOL(urgent, &c->urgent)
|
||||
RESTORE_BOOL(icccmFocus, &c->icccm_focus)
|
||||
RESTORE_BOOL(icccmInput, &c->icccm_input)
|
||||
RESTORE_USINT(minWidth, &c->min_width)
|
||||
RESTORE_USINT(maxWidth, &c->max_width)
|
||||
RESTORE_USINT(minHeight, &c->min_height)
|
||||
RESTORE_USINT(maxHeight, &c->max_height)
|
||||
RESTORE_INT(wmStatesCount, &c->wm_states_count)
|
||||
} else if (keyeq("wmState", *t, json)) {
|
||||
(*t)++;
|
||||
restore_wm_state(c->wm_state, t, json);
|
||||
|
@ -395,6 +429,9 @@ client_t *restore_client(jsmntok_t **t, char *json)
|
|||
(*t)++;
|
||||
restore_rectangle(&c->floating_rectangle, t, json);
|
||||
continue;
|
||||
} else {
|
||||
warn("Restore client: unknown key: '%.*s'.\n", (*t)->end - (*t)->start, json + (*t)->start);
|
||||
(*t)++;
|
||||
}
|
||||
|
||||
(*t)++;
|
||||
|
@ -427,6 +464,62 @@ void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json)
|
|||
}
|
||||
}
|
||||
|
||||
void restore_history(jsmntok_t **t, char *json)
|
||||
{
|
||||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
coordinates_t loc = {NULL, NULL, NULL};
|
||||
restore_coordinates(&loc, t, json);
|
||||
if (loc.monitor != NULL && loc.desktop != NULL) {
|
||||
history_add(loc.monitor, loc.desktop, loc.node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json)
|
||||
{
|
||||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
if (keyeq("monitorName", *t, json)) {
|
||||
(*t)++;
|
||||
char *name = copy_string(*t, json);
|
||||
loc->monitor = find_monitor(name);
|
||||
free(name);
|
||||
} else if (keyeq("desktopName", *t, json)) {
|
||||
(*t)++;
|
||||
char *name = copy_string(*t, json);
|
||||
loc->desktop = find_desktop_in(name, loc->monitor);
|
||||
free(name);
|
||||
} else if (keyeq("nodeId", *t, json)) {
|
||||
(*t)++;
|
||||
uint32_t id;
|
||||
sscanf(json + (*t)->start, "%u", &id);
|
||||
loc->node = find_by_id_in(loc->desktop!=NULL?loc->desktop->root:NULL, id);
|
||||
}
|
||||
(*t)++;
|
||||
}
|
||||
}
|
||||
|
||||
void restore_stack(jsmntok_t **t, char *json)
|
||||
{
|
||||
int s = (*t)->size;
|
||||
(*t)++;
|
||||
|
||||
for (int i = 0; i < s; i++) {
|
||||
uint32_t id;
|
||||
sscanf(json + (*t)->start, "%u", &id);
|
||||
coordinates_t loc;
|
||||
if (locate_window(id, &loc)) {
|
||||
stack_insert_after(stack_tail, loc.node);
|
||||
}
|
||||
(*t)++;
|
||||
}
|
||||
}
|
||||
|
||||
void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json)
|
||||
{
|
||||
int s = (*t)->size;
|
||||
|
@ -463,86 +556,3 @@ char *copy_string(jsmntok_t *tok, char *json)
|
|||
res[len-1] = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
bool restore_history(const char *file_path)
|
||||
{
|
||||
if (file_path == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *snapshot = fopen(file_path, "r");
|
||||
if (snapshot == NULL) {
|
||||
perror("Restore history: fopen");
|
||||
return false;
|
||||
}
|
||||
|
||||
char line[MAXLEN];
|
||||
char mnm[SMALEN];
|
||||
char dnm[SMALEN];
|
||||
xcb_window_t win;
|
||||
|
||||
empty_history();
|
||||
|
||||
while (fgets(line, sizeof(line), snapshot) != NULL) {
|
||||
if (sscanf(line, "%s %s %X", mnm, dnm, &win) == 3) {
|
||||
coordinates_t loc;
|
||||
if (win != XCB_NONE && !locate_window(win, &loc)) {
|
||||
warn("Can't locate window 0x%X.\n", win);
|
||||
continue;
|
||||
}
|
||||
node_t *n = (win == XCB_NONE ? NULL : loc.node);
|
||||
if (!locate_desktop(dnm, &loc)) {
|
||||
warn("Can't locate desktop '%s'.\n", dnm);
|
||||
continue;
|
||||
}
|
||||
desktop_t *d = loc.desktop;
|
||||
if (!locate_monitor(mnm, &loc)) {
|
||||
warn("Can't locate monitor '%s'.\n", mnm);
|
||||
continue;
|
||||
}
|
||||
monitor_t *m = loc.monitor;
|
||||
history_add(m, d, n);
|
||||
} else {
|
||||
warn("Can't parse history entry: '%s'\n", line);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(snapshot);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool restore_stack(const char *file_path)
|
||||
{
|
||||
if (file_path == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *snapshot = fopen(file_path, "r");
|
||||
if (snapshot == NULL) {
|
||||
perror("Restore stack: fopen");
|
||||
return false;
|
||||
}
|
||||
|
||||
char line[MAXLEN];
|
||||
xcb_window_t win;
|
||||
|
||||
while (stack_head != NULL) {
|
||||
remove_stack(stack_head);
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), snapshot) != NULL) {
|
||||
if (sscanf(line, "%X", &win) == 1) {
|
||||
coordinates_t loc;
|
||||
if (locate_window(win, &loc)) {
|
||||
stack_insert_after(stack_tail, loc.node);
|
||||
} else {
|
||||
warn("Can't locate window 0x%X.\n", win);
|
||||
}
|
||||
} else {
|
||||
warn("Can't parse stack entry: '%s'\n", line);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(snapshot);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -31,12 +31,14 @@ bool restore_tree(const char *file_path);
|
|||
monitor_t *restore_monitor(jsmntok_t **t, char *json);
|
||||
desktop_t *restore_desktop(jsmntok_t **t, char *json);
|
||||
node_t *restore_node(jsmntok_t **t, char *json);
|
||||
presel_t *restore_presel(jsmntok_t **t, char *json);
|
||||
client_t *restore_client(jsmntok_t **t, char *json);
|
||||
void restore_rectangle(xcb_rectangle_t *r, jsmntok_t **t, char *json);
|
||||
void restore_history(jsmntok_t **t, char *json);
|
||||
void restore_coordinates(coordinates_t *loc, jsmntok_t **t, char *json);
|
||||
void restore_stack(jsmntok_t **t, char *json);
|
||||
void restore_wm_state(xcb_atom_t *w, jsmntok_t **t, char *json);
|
||||
bool keyeq(char *s, jsmntok_t *key, char *json);
|
||||
char *copy_string(jsmntok_t *tok, char *json);
|
||||
bool restore_history(const char *file_path);
|
||||
bool restore_stack(const char *file_path);
|
||||
|
||||
#endif
|
||||
|
|
48
rule.c
48
rule.c
|
@ -23,6 +23,9 @@
|
|||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "bspwm.h"
|
||||
|
@ -35,7 +38,7 @@
|
|||
rule_t *make_rule(void)
|
||||
{
|
||||
rule_t *r = malloc(sizeof(rule_t));
|
||||
r->cause[0] = r->effect[0] = '\0';
|
||||
r->class_name[0] = r->instance_name[0] = r->effect[0] = '\0';
|
||||
r->next = r->prev = NULL;
|
||||
r->one_shot = false;
|
||||
return r;
|
||||
|
@ -72,21 +75,26 @@ void remove_rule(rule_t *r)
|
|||
void remove_rule_by_cause(char *cause)
|
||||
{
|
||||
rule_t *r = rule_head;
|
||||
char *class_name = strtok(cause, COL_TOK);
|
||||
char *instance_name = strtok(NULL, COL_TOK);
|
||||
while (r != NULL) {
|
||||
rule_t *next = r->next;
|
||||
if (streq(r->cause, cause))
|
||||
if ((streq(class_name, MATCH_ANY) || streq(r->class_name, class_name)) &&
|
||||
(instance_name == NULL || streq(instance_name, MATCH_ANY) || streq(r->instance_name, instance_name))) {
|
||||
remove_rule(r);
|
||||
}
|
||||
r = next;
|
||||
}
|
||||
}
|
||||
|
||||
bool remove_rule_by_index(int idx)
|
||||
{
|
||||
for (rule_t *r = rule_head; r != NULL; r = r->next, idx--)
|
||||
for (rule_t *r = rule_head; r != NULL; r = r->next, idx--) {
|
||||
if (idx == 0) {
|
||||
remove_rule(r);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -111,8 +119,9 @@ pending_rule_t *make_pending_rule(int fd, xcb_window_t win, rule_consequence_t *
|
|||
|
||||
void add_pending_rule(pending_rule_t *pr)
|
||||
{
|
||||
if (pr == NULL)
|
||||
if (pr == NULL) {
|
||||
return;
|
||||
}
|
||||
if (pending_rule_head == NULL) {
|
||||
pending_rule_head = pending_rule_tail = pr;
|
||||
} else {
|
||||
|
@ -124,18 +133,23 @@ void add_pending_rule(pending_rule_t *pr)
|
|||
|
||||
void remove_pending_rule(pending_rule_t *pr)
|
||||
{
|
||||
if (pr == NULL)
|
||||
if (pr == NULL) {
|
||||
return;
|
||||
}
|
||||
pending_rule_t *a = pr->prev;
|
||||
pending_rule_t *b = pr->next;
|
||||
if (a != NULL)
|
||||
if (a != NULL) {
|
||||
a->next = b;
|
||||
if (b != NULL)
|
||||
}
|
||||
if (b != NULL) {
|
||||
b->prev = a;
|
||||
if (pr == pending_rule_head)
|
||||
}
|
||||
if (pr == pending_rule_head) {
|
||||
pending_rule_head = b;
|
||||
if (pr == pending_rule_tail)
|
||||
}
|
||||
if (pr == pending_rule_tail) {
|
||||
pending_rule_tail = a;
|
||||
}
|
||||
close(pr->fd);
|
||||
free(pr->csq);
|
||||
free(pr);
|
||||
|
@ -231,9 +245,8 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq)
|
|||
rule_t *rule = rule_head;
|
||||
while (rule != NULL) {
|
||||
rule_t *next = rule->next;
|
||||
if (streq(rule->cause, MATCH_ANY) ||
|
||||
streq(rule->cause, csq->class_name) ||
|
||||
streq(rule->cause, csq->instance_name)) {
|
||||
if ((streq(rule->class_name, MATCH_ANY) || streq(rule->class_name, csq->class_name)) &&
|
||||
(streq(rule->instance_name, MATCH_ANY) || streq(rule->instance_name, csq->instance_name))) {
|
||||
char effect[MAXLEN];
|
||||
snprintf(effect, sizeof(effect), "%s", rule->effect);
|
||||
char *key = strtok(effect, CSQ_BLK);
|
||||
|
@ -282,8 +295,9 @@ bool schedule_rules(xcb_window_t win, rule_consequence_t *csq)
|
|||
|
||||
void parse_rule_consequence(int fd, rule_consequence_t *csq)
|
||||
{
|
||||
if (fd == -1)
|
||||
if (fd == -1) {
|
||||
return;
|
||||
}
|
||||
char data[BUFSIZ];
|
||||
int nb;
|
||||
while ((nb = read(fd, data, sizeof(data))) > 0) {
|
||||
|
@ -306,7 +320,7 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
|
|||
snprintf(csq->monitor_desc, sizeof(csq->monitor_desc), "%s", value);
|
||||
} else if (streq("desktop", key)) {
|
||||
snprintf(csq->desktop_desc, sizeof(csq->desktop_desc), "%s", value);
|
||||
} else if (streq("window", key)) {
|
||||
} else if (streq("node", key)) {
|
||||
snprintf(csq->node_desc, sizeof(csq->node_desc), "%s", value);
|
||||
} else if (streq("split_dir", key)) {
|
||||
snprintf(csq->split_dir, sizeof(csq->split_dir), "%s", value);
|
||||
|
@ -348,11 +362,9 @@ void parse_key_value(char *key, char *value, rule_consequence_t *csq)
|
|||
}
|
||||
}
|
||||
|
||||
void list_rules(char *pattern, FILE *rsp)
|
||||
void list_rules(FILE *rsp)
|
||||
{
|
||||
for (rule_t *r = rule_head; r != NULL; r = r->next) {
|
||||
if (pattern != NULL && !streq(pattern, r->cause))
|
||||
continue;
|
||||
fprintf(rsp, "%s => %s\n", r->cause, r->effect);
|
||||
fprintf(rsp, "%s:%s => %s\n", r->class_name, r->instance_name, r->effect);
|
||||
}
|
||||
}
|
||||
|
|
2
rule.h
2
rule.h
|
@ -41,6 +41,6 @@ void apply_rules(xcb_window_t win, rule_consequence_t *csq);
|
|||
bool schedule_rules(xcb_window_t win, rule_consequence_t *csq);
|
||||
void parse_rule_consequence(int fd, rule_consequence_t *csq);
|
||||
void parse_key_value(char *key, char *value, rule_consequence_t *csq);
|
||||
void list_rules(char *pattern, FILE *rsp);
|
||||
void list_rules(FILE *rsp);
|
||||
|
||||
#endif
|
||||
|
|
23
settings.c
23
settings.c
|
@ -22,15 +22,18 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include "bspwm.h"
|
||||
#include "settings.h"
|
||||
|
||||
void run_config(void)
|
||||
{
|
||||
if (fork() == 0) {
|
||||
if (dpy != NULL)
|
||||
if (dpy != NULL) {
|
||||
close(xcb_get_file_descriptor(dpy));
|
||||
}
|
||||
setsid();
|
||||
execl(config_path, config_path, NULL);
|
||||
err("Couldn't execute the configuration file.\n");
|
||||
|
@ -43,28 +46,18 @@ void load_settings(void)
|
|||
snprintf(status_prefix, sizeof(status_prefix), "%s", STATUS_PREFIX);
|
||||
|
||||
snprintf(normal_border_color, sizeof(normal_border_color), "%s", NORMAL_BORDER_COLOR);
|
||||
snprintf(focused_border_color, sizeof(focused_border_color), "%s", FOCUSED_BORDER_COLOR);
|
||||
snprintf(active_border_color, sizeof(active_border_color), "%s", ACTIVE_BORDER_COLOR);
|
||||
snprintf(presel_border_color, sizeof(presel_border_color), "%s", PRESEL_BORDER_COLOR);
|
||||
snprintf(focused_locked_border_color, sizeof(focused_locked_border_color), "%s", FOCUSED_LOCKED_BORDER_COLOR);
|
||||
snprintf(active_locked_border_color, sizeof(active_locked_border_color), "%s", ACTIVE_LOCKED_BORDER_COLOR);
|
||||
snprintf(normal_locked_border_color, sizeof(normal_locked_border_color), "%s", NORMAL_LOCKED_BORDER_COLOR);
|
||||
snprintf(focused_sticky_border_color, sizeof(focused_sticky_border_color), "%s", FOCUSED_STICKY_BORDER_COLOR);
|
||||
snprintf(active_sticky_border_color, sizeof(active_sticky_border_color), "%s", ACTIVE_STICKY_BORDER_COLOR);
|
||||
snprintf(normal_sticky_border_color, sizeof(normal_sticky_border_color), "%s", NORMAL_STICKY_BORDER_COLOR);
|
||||
snprintf(focused_private_border_color, sizeof(focused_private_border_color), "%s", FOCUSED_PRIVATE_BORDER_COLOR);
|
||||
snprintf(active_private_border_color, sizeof(active_private_border_color), "%s", ACTIVE_PRIVATE_BORDER_COLOR);
|
||||
snprintf(normal_private_border_color, sizeof(normal_private_border_color), "%s", NORMAL_PRIVATE_BORDER_COLOR);
|
||||
snprintf(urgent_border_color, sizeof(urgent_border_color), "%s", URGENT_BORDER_COLOR);
|
||||
snprintf(focused_border_color, sizeof(focused_border_color), "%s", FOCUSED_BORDER_COLOR);
|
||||
snprintf(presel_feedback_color, sizeof(presel_feedback_color), "%s", PRESEL_FEEDBACK_COLOR);
|
||||
|
||||
split_ratio = SPLIT_RATIO;
|
||||
window_gap = WINDOW_GAP;
|
||||
border_width = BORDER_WIDTH;
|
||||
split_ratio = SPLIT_RATIO;
|
||||
initial_polarity = FIRST_CHILD;
|
||||
|
||||
borderless_monocle = BORDERLESS_MONOCLE;
|
||||
gapless_monocle = GAPLESS_MONOCLE;
|
||||
leaf_monocle = LEAF_MONOCLE;
|
||||
single_monocle = SINGLE_MONOCLE;
|
||||
focus_follows_pointer = FOCUS_FOLLOWS_POINTER;
|
||||
pointer_follows_focus = POINTER_FOLLOWS_FOCUS;
|
||||
pointer_follows_monitor = POINTER_FOLLOWS_MONITOR;
|
||||
|
|
47
settings.h
47
settings.h
|
@ -33,30 +33,20 @@
|
|||
#define EXTERNAL_RULES_COMMAND ""
|
||||
#define STATUS_PREFIX "W"
|
||||
|
||||
#define FOCUSED_BORDER_COLOR "#7E7F89"
|
||||
#define ACTIVE_BORDER_COLOR "#545350"
|
||||
#define NORMAL_BORDER_COLOR "#3F3E3B"
|
||||
#define PRESEL_BORDER_COLOR "#E8E8F4"
|
||||
#define FOCUSED_LOCKED_BORDER_COLOR "#C7B579"
|
||||
#define ACTIVE_LOCKED_BORDER_COLOR "#545350"
|
||||
#define NORMAL_LOCKED_BORDER_COLOR "#3F3E3B"
|
||||
#define FOCUSED_STICKY_BORDER_COLOR "#E3A5DA"
|
||||
#define ACTIVE_STICKY_BORDER_COLOR "#545350"
|
||||
#define NORMAL_STICKY_BORDER_COLOR "#3F3E3B"
|
||||
#define FOCUSED_PRIVATE_BORDER_COLOR "#42CAD9"
|
||||
#define ACTIVE_PRIVATE_BORDER_COLOR "#5C5955"
|
||||
#define NORMAL_PRIVATE_BORDER_COLOR "#34322E"
|
||||
#define URGENT_BORDER_COLOR "#EFA29A"
|
||||
#define NORMAL_BORDER_COLOR "#30302f"
|
||||
#define ACTIVE_BORDER_COLOR "#474645"
|
||||
#define FOCUSED_BORDER_COLOR "#817f7f"
|
||||
#define PRESEL_FEEDBACK_COLOR "#f4d775"
|
||||
|
||||
#define SPLIT_RATIO 0.5
|
||||
#define WINDOW_GAP 6
|
||||
#define BORDER_WIDTH 1
|
||||
#define WINDOW_GAP 6
|
||||
#define BORDER_WIDTH 1
|
||||
#define SPLIT_RATIO 0.5
|
||||
|
||||
#define HISTORY_AWARE_FOCUS false
|
||||
#define FOCUS_BY_DISTANCE false
|
||||
#define BORDERLESS_MONOCLE false
|
||||
#define GAPLESS_MONOCLE false
|
||||
#define LEAF_MONOCLE false
|
||||
#define SINGLE_MONOCLE false
|
||||
#define FOCUS_FOLLOWS_POINTER false
|
||||
#define POINTER_FOLLOWS_FOCUS false
|
||||
#define POINTER_FOLLOWS_MONITOR false
|
||||
|
@ -69,29 +59,20 @@
|
|||
char external_rules_command[MAXLEN];
|
||||
char status_prefix[MAXLEN];
|
||||
|
||||
char focused_border_color[MAXLEN];
|
||||
char active_border_color[MAXLEN];
|
||||
char normal_border_color[MAXLEN];
|
||||
char presel_border_color[MAXLEN];
|
||||
char focused_locked_border_color[MAXLEN];
|
||||
char active_locked_border_color[MAXLEN];
|
||||
char normal_locked_border_color[MAXLEN];
|
||||
char focused_sticky_border_color[MAXLEN];
|
||||
char active_sticky_border_color[MAXLEN];
|
||||
char normal_sticky_border_color[MAXLEN];
|
||||
char focused_private_border_color[MAXLEN];
|
||||
char active_private_border_color[MAXLEN];
|
||||
char normal_private_border_color[MAXLEN];
|
||||
char urgent_border_color[MAXLEN];
|
||||
char active_border_color[MAXLEN];
|
||||
char focused_border_color[MAXLEN];
|
||||
char presel_feedback_color[MAXLEN];
|
||||
|
||||
double split_ratio;
|
||||
int window_gap;
|
||||
unsigned int border_width;
|
||||
double split_ratio;
|
||||
|
||||
child_polarity_t initial_polarity;
|
||||
|
||||
bool borderless_monocle;
|
||||
bool gapless_monocle;
|
||||
bool leaf_monocle;
|
||||
bool single_monocle;
|
||||
bool focus_follows_pointer;
|
||||
bool pointer_follows_focus;
|
||||
bool pointer_follows_monitor;
|
||||
|
|
107
stack.c
107
stack.c
|
@ -25,6 +25,9 @@
|
|||
#include <stdlib.h>
|
||||
#include "bspwm.h"
|
||||
#include "window.h"
|
||||
#include "subscribe.h"
|
||||
#include "ewmh.h"
|
||||
#include "tree.h"
|
||||
#include "stack.h"
|
||||
|
||||
stacking_list_t *make_stack(node_t *n)
|
||||
|
@ -47,13 +50,15 @@ void stack_insert_after(stacking_list_t *a, node_t *n)
|
|||
}
|
||||
remove_stack_node(n);
|
||||
stacking_list_t *b = a->next;
|
||||
if (b != NULL)
|
||||
if (b != NULL) {
|
||||
b->prev = s;
|
||||
}
|
||||
s->next = b;
|
||||
s->prev = a;
|
||||
a->next = s;
|
||||
if (stack_tail == a)
|
||||
if (stack_tail == a) {
|
||||
stack_tail = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,39 +74,48 @@ void stack_insert_before(stacking_list_t *a, node_t *n)
|
|||
}
|
||||
remove_stack_node(n);
|
||||
stacking_list_t *b = a->prev;
|
||||
if (b != NULL)
|
||||
if (b != NULL) {
|
||||
b->next = s;
|
||||
}
|
||||
s->prev = b;
|
||||
s->next = a;
|
||||
a->prev = s;
|
||||
if (stack_head == a)
|
||||
if (stack_head == a) {
|
||||
stack_head = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remove_stack(stacking_list_t *s)
|
||||
{
|
||||
if (s == NULL)
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
stacking_list_t *a = s->prev;
|
||||
stacking_list_t *b = s->next;
|
||||
if (a != NULL)
|
||||
if (a != NULL) {
|
||||
a->next = b;
|
||||
if (b != NULL)
|
||||
}
|
||||
if (b != NULL) {
|
||||
b->prev = a;
|
||||
if (s == stack_head)
|
||||
}
|
||||
if (s == stack_head) {
|
||||
stack_head = b;
|
||||
if (s == stack_tail)
|
||||
}
|
||||
if (s == stack_tail) {
|
||||
stack_tail = a;
|
||||
}
|
||||
free(s);
|
||||
}
|
||||
|
||||
void remove_stack_node(node_t *n)
|
||||
{
|
||||
for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
|
||||
if (s->node == n) {
|
||||
remove_stack(s);
|
||||
return;
|
||||
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
|
||||
for (stacking_list_t *s = stack_head; s != NULL; s = s->next) {
|
||||
if (s->node == f) {
|
||||
remove_stack(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,26 +162,57 @@ stacking_list_t *limit_below(node_t *n)
|
|||
return s;
|
||||
}
|
||||
|
||||
void stack(node_t *n, bool focused)
|
||||
void stack(desktop_t *d, node_t *n, bool focused)
|
||||
{
|
||||
if (IS_FLOATING(n->client) && !auto_raise) {
|
||||
return;
|
||||
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
|
||||
if (IS_FLOATING(f->client) && !auto_raise) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (stack_head == NULL) {
|
||||
stack_insert_after(NULL, f);
|
||||
} else {
|
||||
stacking_list_t *s = (focused ? limit_above(f) : limit_below(f));
|
||||
if (s == NULL) {
|
||||
continue;
|
||||
}
|
||||
int i = stack_cmp(f->client, s->node->client);
|
||||
if (i < 0 || (i == 0 && !focused)) {
|
||||
stack_insert_before(s, f);
|
||||
window_below(f->id, s->node->id);
|
||||
put_status(SBSC_MASK_NODE_STACK, "node_stack 0x%X below 0x%X\n", f->id, s->node->id);
|
||||
} else {
|
||||
stack_insert_after(s, f);
|
||||
window_above(f->id, s->node->id);
|
||||
put_status(SBSC_MASK_NODE_STACK, "node_stack 0x%X above 0x%X\n", f->id, s->node->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stack_head == NULL) {
|
||||
stack_insert_after(NULL, n);
|
||||
} else {
|
||||
stacking_list_t *s = (focused ? limit_above(n) : limit_below(n));
|
||||
if (s == NULL) {
|
||||
return;
|
||||
}
|
||||
int i = stack_cmp(n->client, s->node->client);
|
||||
if (i < 0 || (i == 0 && !focused)) {
|
||||
stack_insert_before(s, n);
|
||||
window_below(n->client->window, s->node->client->window);
|
||||
} else {
|
||||
stack_insert_after(s, n);
|
||||
window_above(n->client->window, s->node->client->window);
|
||||
}
|
||||
ewmh_update_client_list(true);
|
||||
restack_presel_feedback(d);
|
||||
}
|
||||
|
||||
void restack_presel_feedback(desktop_t *d)
|
||||
{
|
||||
stacking_list_t *s = stack_tail;
|
||||
while (s != NULL && !IS_TILED(s->node->client)) {
|
||||
s = s->prev;
|
||||
}
|
||||
if (s != NULL) {
|
||||
restack_presel_feedback_in(d->root, s->node);
|
||||
}
|
||||
}
|
||||
|
||||
void restack_presel_feedback_in(node_t *r, node_t *n)
|
||||
{
|
||||
if (r == NULL) {
|
||||
return;
|
||||
} else {
|
||||
if (r->presel != NULL) {
|
||||
window_above(r->presel->feedback, n->id);
|
||||
}
|
||||
restack_presel_feedback_in(r->first_child, n);
|
||||
restack_presel_feedback_in(r->second_child, n);
|
||||
}
|
||||
}
|
||||
|
|
4
stack.h
4
stack.h
|
@ -34,6 +34,8 @@ int stack_level(client_t *c);
|
|||
int stack_cmp(client_t *c1, client_t *c2);
|
||||
stacking_list_t *limit_above(node_t *n);
|
||||
stacking_list_t *limit_below(node_t *n);
|
||||
void stack(node_t *n, bool focused);
|
||||
void stack(desktop_t *d, node_t *n, bool focused);
|
||||
void restack_presel_feedback(desktop_t *d);
|
||||
void restack_presel_feedback_in(node_t *r, node_t *n);
|
||||
|
||||
#endif
|
||||
|
|
57
subscribe.c
57
subscribe.c
|
@ -22,8 +22,9 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include "bspwm.h"
|
||||
|
@ -42,18 +43,23 @@ subscriber_list_t *make_subscriber_list(FILE *stream, int field)
|
|||
|
||||
void remove_subscriber(subscriber_list_t *sb)
|
||||
{
|
||||
if (sb == NULL)
|
||||
if (sb == NULL) {
|
||||
return;
|
||||
}
|
||||
subscriber_list_t *a = sb->prev;
|
||||
subscriber_list_t *b = sb->next;
|
||||
if (a != NULL)
|
||||
if (a != NULL) {
|
||||
a->next = b;
|
||||
if (b != NULL)
|
||||
}
|
||||
if (b != NULL) {
|
||||
b->prev = a;
|
||||
if (sb == subscribe_head)
|
||||
}
|
||||
if (sb == subscribe_head) {
|
||||
subscribe_head = b;
|
||||
if (sb == subscribe_tail)
|
||||
}
|
||||
if (sb == subscribe_tail) {
|
||||
subscribe_tail = a;
|
||||
}
|
||||
fclose(sb->stream);
|
||||
free(sb);
|
||||
}
|
||||
|
@ -78,17 +84,44 @@ int print_report(FILE *stream)
|
|||
fprintf(stream, "%s", status_prefix);
|
||||
bool urgent = false;
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
fprintf(stream, "%c%s:", (mon == m ? 'M' : 'm'), m->name);
|
||||
fprintf(stream, "%c%s", (mon == m ? 'M' : 'm'), m->name);
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next, urgent = false) {
|
||||
for (node_t *n = first_extrema(d->root); n != NULL && !urgent; n = next_leaf(n, d->root))
|
||||
for (node_t *n = first_extrema(d->root); n != NULL && !urgent; n = next_leaf(n, d->root)) {
|
||||
urgent |= n->client->urgent;
|
||||
}
|
||||
char c = (urgent ? 'u' : (d->root == NULL ? 'f' : 'o'));
|
||||
if (m->desk == d)
|
||||
if (m->desk == d) {
|
||||
c = toupper(c);
|
||||
fprintf(stream, "%c%s:", c, d->name);
|
||||
}
|
||||
fprintf(stream, ":%c%s", c, d->name);
|
||||
}
|
||||
if (m->desk != NULL) {
|
||||
fprintf(stream, ":L%c", LAYOUT_CHR(m->desk->layout));
|
||||
if (m->desk->focus != NULL) {
|
||||
node_t *n = m->desk->focus;
|
||||
if (n->client != NULL) {
|
||||
fprintf(stream, ":T%c", STATE_CHR(n->client->state));
|
||||
} else {
|
||||
fprintf(stream, ":T@");
|
||||
}
|
||||
int i = 0;
|
||||
char flags[4];
|
||||
if (n->sticky) {
|
||||
flags[i++] = 'S';
|
||||
}
|
||||
if (n->private) {
|
||||
flags[i++] = 'P';
|
||||
}
|
||||
if (n->locked) {
|
||||
flags[i++] = 'L';
|
||||
}
|
||||
flags[i] = '\0';
|
||||
fprintf(stream, ":G%s", flags);
|
||||
}
|
||||
}
|
||||
if (m != mon_tail) {
|
||||
fprintf(stream, "%s", ":");
|
||||
}
|
||||
if (m->desk != NULL)
|
||||
fprintf(stream, "L%c%s", (m->desk->layout == LAYOUT_TILED ? 'T' : 'M'), (m != mon_tail ? ":" : ""));
|
||||
}
|
||||
fprintf(stream, "%s", "\n");
|
||||
return fflush(stream);
|
||||
|
|
31
subscribe.h
31
subscribe.h
|
@ -38,21 +38,24 @@ typedef enum {
|
|||
SBSC_MASK_DESKTOP_SWAP = 1 << 9,
|
||||
SBSC_MASK_DESKTOP_TRANSFER = 1 << 10,
|
||||
SBSC_MASK_DESKTOP_FOCUS = 1 << 11,
|
||||
SBSC_MASK_DESKTOP_LAYOUT = 1 << 12,
|
||||
SBSC_MASK_WINDOW_MANAGE = 1 << 13,
|
||||
SBSC_MASK_WINDOW_UNMANAGE = 1 << 14,
|
||||
SBSC_MASK_WINDOW_SWAP = 1 << 15,
|
||||
SBSC_MASK_WINDOW_TRANSFER = 1 << 16,
|
||||
SBSC_MASK_WINDOW_FOCUS = 1 << 17,
|
||||
SBSC_MASK_WINDOW_ACTIVATE = 1 << 18,
|
||||
SBSC_MASK_WINDOW_GEOMETRY = 1 << 19,
|
||||
SBSC_MASK_WINDOW_STATE = 1 << 20,
|
||||
SBSC_MASK_WINDOW_FLAG = 1 << 21,
|
||||
SBSC_MASK_WINDOW_LAYER = 1 << 22,
|
||||
SBSC_MASK_DESKTOP_ACTIVATE = 1 << 12,
|
||||
SBSC_MASK_DESKTOP_LAYOUT = 1 << 13,
|
||||
SBSC_MASK_NODE_MANAGE = 1 << 14,
|
||||
SBSC_MASK_NODE_UNMANAGE = 1 << 15,
|
||||
SBSC_MASK_NODE_SWAP = 1 << 16,
|
||||
SBSC_MASK_NODE_TRANSFER = 1 << 17,
|
||||
SBSC_MASK_NODE_FOCUS = 1 << 18,
|
||||
SBSC_MASK_NODE_PRESEL = 1 << 19,
|
||||
SBSC_MASK_NODE_STACK = 1 << 20,
|
||||
SBSC_MASK_NODE_ACTIVATE = 1 << 21,
|
||||
SBSC_MASK_NODE_GEOMETRY = 1 << 22,
|
||||
SBSC_MASK_NODE_STATE = 1 << 23,
|
||||
SBSC_MASK_NODE_FLAG = 1 << 24,
|
||||
SBSC_MASK_NODE_LAYER = 1 << 25,
|
||||
SBSC_MASK_MONITOR = (1 << 6) - (1 << 1),
|
||||
SBSC_MASK_DESKTOP = (1 << 13) - (1 << 6),
|
||||
SBSC_MASK_WINDOW = (1 << 23) - (1 << 13),
|
||||
SBSC_MASK_ALL = (1 << 23) - 1
|
||||
SBSC_MASK_DESKTOP = (1 << 14) - (1 << 6),
|
||||
SBSC_MASK_NODE = (1 << 26) - (1 << 14),
|
||||
SBSC_MASK_ALL = (1 << 26) - 1
|
||||
} subscriber_mask_t;
|
||||
|
||||
subscriber_list_t *make_subscriber_list(FILE *stream, int field);
|
||||
|
|
13
tests/Makefile
Normal file
13
tests/Makefile
Normal file
|
@ -0,0 +1,13 @@
|
|||
OUT = test_window
|
||||
CFLAGS += -std=c99 -pedantic -Wall -Wextra
|
||||
LDLIBS = -lxcb -lxcb-icccm
|
||||
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
|
||||
all: $(OUT)
|
||||
|
||||
clean:
|
||||
$(RM) $(OUT) $(OBJ)
|
||||
|
||||
.PHONY: all clean
|
3
tests/README.md
Normal file
3
tests/README.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
- Install *jshon*.
|
||||
- Run `make` once.
|
||||
- Run `./run`.
|
27
tests/desktop/swap
Executable file
27
tests/desktop/swap
Executable file
|
@ -0,0 +1,27 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc wm -a "TEST-SWAP-A" 1024x512+0+0
|
||||
bspc wm -a "TEST-SWAP-B" 1024x512+0+512
|
||||
|
||||
bspc monitor -f "TEST-SWAP-A"
|
||||
window add 3
|
||||
|
||||
bspc monitor -f "TEST-SWAP-B"
|
||||
window add 2
|
||||
|
||||
nodes_a=$(bspc query -N -m "TEST-SWAP-A")
|
||||
nodes_b=$(bspc query -N -m "TEST-SWAP-B")
|
||||
|
||||
bspc desktop "TEST-SWAP-A:^1" -s "TEST-SWAP-B:^1"
|
||||
|
||||
[ "$(bspc query -N -m 'TEST-SWAP-A')" = "$nodes_b" ] || fail "Wrong nodes in first monitor"
|
||||
[ "$(bspc query -N -m 'TEST-SWAP-B')" = "$nodes_a" ] || fail "Wrong nodes in second monitor"
|
||||
|
||||
window remove 3
|
||||
bspc monitor -f "TEST-SWAP-A"
|
||||
window remove 2
|
||||
|
||||
bspc wm -r "TEST-SWAP-A"
|
||||
bspc wm -r "TEST-SWAP-B"
|
26
tests/desktop/transfer
Executable file
26
tests/desktop/transfer
Executable file
|
@ -0,0 +1,26 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc wm -a "TEST-TRANSFER-A" 1024x512+0+0
|
||||
bspc wm -a "TEST-TRANSFER-B" 1024x512+0+512
|
||||
|
||||
bspc monitor "TEST-TRANSFER-A" -a source
|
||||
bspc monitor -f "TEST-TRANSFER-A"
|
||||
|
||||
window add 3
|
||||
|
||||
root_rectangle_y=$(bspc query -T -n @/ | jshon -e rectangle -e y)
|
||||
|
||||
bspc desktop "TEST-TRANSFER-A:focused" -m "TEST-TRANSFER-B"
|
||||
|
||||
[ "$(bspc query -D -m "TEST-TRANSFER-A" | wc -l)" -eq 1 ] || fail "Invalid number of desktop in source after transfer."
|
||||
|
||||
bspc desktop "TEST-TRANSFER-B:^2" -f
|
||||
|
||||
[ "$(bspc query -T -n @/ | jshon -e rectangle -e y)" -ne "$root_rectangle_y" ] || fail "Wrong tiled rectangle for root in destination."
|
||||
|
||||
window remove 3
|
||||
|
||||
bspc wm -r "TEST-TRANSFER-A"
|
||||
bspc wm -r "TEST-TRANSFER-B"
|
27
tests/node/flags
Executable file
27
tests/node/flags
Executable file
|
@ -0,0 +1,27 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc monitor -a "test-sticky-a"
|
||||
bspc monitor -a "test-sticky-b"
|
||||
|
||||
bspc desktop -f "test-sticky-a"
|
||||
|
||||
window add 3
|
||||
bspc node -g sticky
|
||||
|
||||
sticky_node_id=$(bspc query -N -n)
|
||||
|
||||
bspc rule -a Test:test -o desktop="test-sticky-b"
|
||||
|
||||
window add
|
||||
|
||||
bspc desktop -f "test-sticky-b"
|
||||
|
||||
bspc query -N -d | grep "$sticky_node_id" > /dev/null || fail "Sticky node is missing in destination."
|
||||
|
||||
window remove 2
|
||||
bspc desktop -f "test-sticky-a"
|
||||
window remove 2
|
||||
|
||||
bspc monitor -r "test-sticky-a" "test-sticky-b"
|
46
tests/node/insertion
Executable file
46
tests/node/insertion
Executable file
|
@ -0,0 +1,46 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc monitor -a "test-insertion"
|
||||
bspc desktop -f "test-insertion"
|
||||
|
||||
# Automatic mode
|
||||
|
||||
window add 2
|
||||
|
||||
split_type_a=$(bspc query -T -n @/ | jshon -e splitType -u)
|
||||
|
||||
window add
|
||||
|
||||
split_type_b=$(bspc query -T -n @/2 | jshon -e splitType -u)
|
||||
|
||||
[ "$split_type_a" = "$split_type_b" ] && fail "Non-vacant node insertion should rotate brother."
|
||||
|
||||
split_type_a=$(bspc query -T -n @/ | jshon -e splitType -u)
|
||||
|
||||
bspc rule -a Test:test -o state=floating
|
||||
window add
|
||||
|
||||
split_type_b=$(bspc query -T -n @/2 | jshon -e splitType -u)
|
||||
|
||||
[ "$split_type_a" = "$split_type_b" ] || fail "Vacant node insertion shouldn't rotate brother."
|
||||
|
||||
window remove
|
||||
|
||||
# Manual mode
|
||||
|
||||
for dir in north west south east ; do
|
||||
child=1
|
||||
split_type=vertical
|
||||
[ "$dir" = "south" -o "$dir" = "east" ] && child=2
|
||||
[ "$dir" = "north" -o "$dir" = "south" ] && split_type=horizontal
|
||||
bspc node -p $dir
|
||||
window add
|
||||
[ "$(bspc query -N -n)" = "$(bspc query -N -n @parent/${child})" ] || fail "Wrong child polarity for ${dir} preselection."
|
||||
[ "$(bspc query -T -n @parent | jshon -e splitType -u)" = "$split_type" ] || fail "Wrong split type for ${dir} preselection."
|
||||
done
|
||||
|
||||
window remove 7
|
||||
|
||||
bspc monitor -r "test-insertion"
|
19
tests/node/removal
Executable file
19
tests/node/removal
Executable file
|
@ -0,0 +1,19 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc monitor -a "test-removal"
|
||||
bspc desktop -f "test-removal"
|
||||
|
||||
window add 3
|
||||
|
||||
next_focus=$(bspc query -N -n);
|
||||
|
||||
bspc node -f @/2/1
|
||||
bspc node @/2 -k
|
||||
|
||||
[ "$(bspc query -N -n)" = "$next_focus" ] || fail "Invalid focus after removal."
|
||||
|
||||
window remove
|
||||
|
||||
bspc monitor -r "test-removal"
|
25
tests/node/swap
Executable file
25
tests/node/swap
Executable file
|
@ -0,0 +1,25 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc monitor -a "test-swap-a" "test-swap-b"
|
||||
bspc desktop -f "test-swap-a"
|
||||
|
||||
window add 5
|
||||
next_focus_b=$(bspc query -N -n @/2/2/1)
|
||||
bspc desktop -f "test-swap-b"
|
||||
window add 3
|
||||
|
||||
bspc node -f @test-swap-a:/2/2/1
|
||||
bspc node -a @test-swap-b:/1
|
||||
|
||||
bspc node @/2 -s @test-swap-b:/1
|
||||
|
||||
[ "$(bspc query -N -n @test-swap-b:)" = "$next_focus_b" ] || fail "Invalid focus after swap."
|
||||
|
||||
window remove 2
|
||||
bspc desktop -f "test-swap-b"
|
||||
window remove 1 2
|
||||
window remove 4
|
||||
|
||||
bspc monitor -r "test-swap-a" "test-swap-b"
|
24
tests/node/transfer
Executable file
24
tests/node/transfer
Executable file
|
@ -0,0 +1,24 @@
|
|||
#! /bin/sh
|
||||
|
||||
. ./prelude
|
||||
|
||||
bspc monitor -a "test-transfer-a" "test-transfer-b"
|
||||
bspc desktop -f "test-transfer-a"
|
||||
|
||||
window add 5
|
||||
|
||||
next_focus_a=$(bspc query -N -n @/1)
|
||||
next_focus_b=$(bspc query -N -n @/2/2/1)
|
||||
|
||||
bspc node -f $next_focus_b
|
||||
bspc node @/2 -d "test-transfer-b"
|
||||
|
||||
[ "$next_focus_a" = "$(bspc query -N -n)" ] || fail "Invalid focus after transfer from source."
|
||||
[ "$next_focus_b" = "$(bspc query -N -n @test-transfer-b:)" ] || fail "Invalid focus after transfer in destination."
|
||||
|
||||
window remove
|
||||
bspc desktop -f "test-transfer-b"
|
||||
window remove 1 2
|
||||
window remove 2
|
||||
|
||||
bspc monitor -r "test-transfer-a" "test-transfer-b"
|
43
tests/prelude
Normal file
43
tests/prelude
Normal file
|
@ -0,0 +1,43 @@
|
|||
#! /bin/sh
|
||||
|
||||
fail() {
|
||||
echo "$@" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
clients_count() {
|
||||
bspc wm -d | jshon -e clientsCount
|
||||
}
|
||||
|
||||
window() {
|
||||
local cmd=$1
|
||||
local iter=${2:-1}
|
||||
local delta=${3:-1}
|
||||
local interval=${4:-0.05}
|
||||
local max_tries=${5:-40}
|
||||
while [ $iter -gt 0 ] ; do
|
||||
local cur=$(clients_count)
|
||||
local trg
|
||||
local tries=0
|
||||
case "$cmd" in
|
||||
add)
|
||||
trg=$((cur + delta))
|
||||
./test_window &
|
||||
;;
|
||||
remove)
|
||||
trg=$((cur - delta))
|
||||
bspc node -c
|
||||
;;
|
||||
*)
|
||||
fail "window: unknown command: ${cmd}."
|
||||
;;
|
||||
esac
|
||||
while [ $cur -ne $trg ] ; do
|
||||
cur=$(clients_count)
|
||||
sleep $interval
|
||||
tries=$((tries + 1))
|
||||
[ $tries -ge $max_tries ] && break
|
||||
done
|
||||
iter=$((iter - 1))
|
||||
done
|
||||
}
|
39
tests/run
Executable file
39
tests/run
Executable file
|
@ -0,0 +1,39 @@
|
|||
#! /bin/sh
|
||||
|
||||
focus_follows_pointer=$(bspc config focus_follows_pointer)
|
||||
initial_polarity=$(bspc config initial_polarity)
|
||||
bspc config initial_polarity first_child
|
||||
bspc config focus_follows_pointer false
|
||||
|
||||
cleanup () {
|
||||
bspc config initial_polarity "$initial_polarity"
|
||||
bspc config focus_follows_pointer "$focus_follows_pointer"
|
||||
}
|
||||
|
||||
abort() {
|
||||
cleanup
|
||||
echo "One test failed." 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Node"
|
||||
echo "-> Insertion"
|
||||
./node/insertion || abort
|
||||
echo "-> Removal"
|
||||
./node/removal || abort
|
||||
echo "-> Transfer"
|
||||
./node/transfer || abort
|
||||
echo "-> Swap"
|
||||
./node/swap || abort
|
||||
echo "-> Flags"
|
||||
./node/flags || abort
|
||||
|
||||
echo "Desktop"
|
||||
echo "-> Transfer"
|
||||
./desktop/transfer || abort
|
||||
echo "-> Swap"
|
||||
./desktop/swap || abort
|
||||
|
||||
cleanup
|
||||
|
||||
echo "All tests passed."
|
105
tests/test_window.c
Normal file
105
tests/test_window.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <xcb/xcb_event.h>
|
||||
#include <xcb/xcb_icccm.h>
|
||||
|
||||
#define TEST_WINDOW_IC "test\0Test"
|
||||
|
||||
bool get_atom(xcb_connection_t *dpy, char *name, xcb_atom_t *atom)
|
||||
{
|
||||
bool ret = true;
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen(name), name), NULL);
|
||||
if (reply != NULL) {
|
||||
*atom = reply->atom;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
free(reply);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void check_request(xcb_connection_t *dpy, xcb_void_cookie_t cookie, char *msg)
|
||||
{
|
||||
xcb_generic_error_t *err = xcb_request_check(dpy, cookie);
|
||||
if (err != NULL) {
|
||||
fprintf(stderr, "%s: error code: %u.\n", msg, err->error_code);
|
||||
xcb_disconnect(dpy);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
xcb_gc_t get_font_gc(xcb_connection_t *dpy, xcb_window_t win, const char *font_name)
|
||||
{
|
||||
xcb_void_cookie_t ck;
|
||||
xcb_font_t font = xcb_generate_id(dpy);
|
||||
ck = xcb_open_font_checked(dpy, font, strlen(font_name), font_name);
|
||||
check_request(dpy, ck, "Can't open font");
|
||||
xcb_gcontext_t gc = xcb_generate_id(dpy);
|
||||
uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND | XCB_GC_FONT;
|
||||
uint32_t values[] = {0xffcccccc, 0xff111111, font};
|
||||
xcb_create_gc(dpy, gc, win, mask, values);
|
||||
xcb_close_font(dpy, font);
|
||||
return gc;
|
||||
}
|
||||
|
||||
void render_text(xcb_connection_t *dpy, xcb_window_t win, int16_t x, int16_t y)
|
||||
{
|
||||
char id[8];
|
||||
xcb_void_cookie_t ck;
|
||||
snprintf(id, sizeof(id), "%07x", win);
|
||||
xcb_gcontext_t gc = get_font_gc(dpy, win, "-*-fixed-medium-*-*-*-18-*-*-*-*-*-*-*");
|
||||
/* Don't work with the _checked ! */
|
||||
ck = xcb_image_text_8_checked(dpy, strlen(id), win, gc, x, y, id);
|
||||
check_request(dpy, ck, "Can't draw text");
|
||||
xcb_free_gc(dpy, gc);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
xcb_connection_t *dpy = xcb_connect(NULL, NULL);
|
||||
if (dpy == NULL) {
|
||||
fprintf(stderr, "Can't connect to X.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
xcb_atom_t WM_PROTOCOLS, WM_DELETE_WINDOW;
|
||||
if (!get_atom(dpy, "WM_PROTOCOLS", &WM_PROTOCOLS) ||
|
||||
!get_atom(dpy, "WM_DELETE_WINDOW", &WM_DELETE_WINDOW)) {
|
||||
fprintf(stderr, "Can't get required atoms.\n");
|
||||
xcb_disconnect(dpy);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
|
||||
if (screen == NULL) {
|
||||
fprintf(stderr, "Can't get current screen.\n");
|
||||
xcb_disconnect(dpy);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
xcb_window_t win = xcb_generate_id(dpy);
|
||||
uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
|
||||
uint32_t values[] = {0xff111111, XCB_EVENT_MASK_EXPOSURE};
|
||||
xcb_create_window(dpy, XCB_COPY_FROM_PARENT, win, screen->root, 0, 0, 320, 240, 2,
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, mask, values);
|
||||
xcb_icccm_set_wm_class(dpy, win, sizeof(TEST_WINDOW_IC), TEST_WINDOW_IC);
|
||||
xcb_map_window(dpy, win);
|
||||
xcb_flush(dpy);
|
||||
xcb_generic_event_t *evt;
|
||||
bool running = true;
|
||||
while (running && (evt = xcb_wait_for_event(dpy)) != NULL) {
|
||||
uint8_t rt = XCB_EVENT_RESPONSE_TYPE(evt);
|
||||
if (rt == XCB_CLIENT_MESSAGE) {
|
||||
xcb_client_message_event_t *cme = (xcb_client_message_event_t *) evt;
|
||||
if (cme->type == WM_PROTOCOLS && cme->data.data32[0] == WM_DELETE_WINDOW) {
|
||||
running = false;
|
||||
}
|
||||
} else if (rt == XCB_EXPOSE) {
|
||||
render_text(dpy, win, 12, 24);
|
||||
}
|
||||
free(evt);
|
||||
}
|
||||
xcb_destroy_window(dpy, win);
|
||||
xcb_disconnect(dpy);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
65
tree.h
65
tree.h
|
@ -27,18 +27,26 @@
|
|||
|
||||
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);
|
||||
presel_t *make_presel(void);
|
||||
void presel_dir(monitor_t *m, desktop_t *d, node_t *n, direction_t dir);
|
||||
void presel_ratio(monitor_t *m, desktop_t *d, node_t *n, double ratio);
|
||||
void cancel_presel(monitor_t *m, desktop_t *d, node_t *n);
|
||||
node_t *find_public(desktop_t *d);
|
||||
node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f);
|
||||
void activate_node(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void transfer_sticky_nodes(monitor_t *m, desktop_t *ds, desktop_t *dd, node_t *n);
|
||||
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, unsigned int border_width);
|
||||
void update_focused(void);
|
||||
void hide_node(node_t *n);
|
||||
void show_node(node_t *n);
|
||||
node_t *make_node(uint32_t id);
|
||||
client_t *make_client(void);
|
||||
void initialize_client(node_t *n);
|
||||
bool is_leaf(node_t *n);
|
||||
bool is_first_child(node_t *n);
|
||||
bool is_second_child(node_t *n);
|
||||
void reset_mode(coordinates_t *loc);
|
||||
unsigned int clients_count_in(node_t *n);
|
||||
node_t *brother_tree(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);
|
||||
|
@ -47,14 +55,18 @@ 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);
|
||||
node_t *nearest_from_tree(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel);
|
||||
node_t *nearest_from_history(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel);
|
||||
node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, client_select_t sel);
|
||||
node_t *nearest_neighbor(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
|
||||
bool is_child(node_t *a, node_t *b);
|
||||
bool is_descendant(node_t *a, node_t *b);
|
||||
bool find_by_id(uint32_t id, coordinates_t *loc);
|
||||
node_t *find_by_id_in(node_t *r, uint32_t id);
|
||||
node_t *nearest_from_tree(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
|
||||
node_t *nearest_from_history(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
|
||||
node_t *nearest_from_distance(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, node_select_t sel);
|
||||
void get_opposite(direction_t src, direction_t *dst);
|
||||
int tiled_area(node_t *n);
|
||||
int tiled_count(desktop_t *d);
|
||||
node_t *find_biggest(monitor_t *m, desktop_t *d, node_t *n, client_select_t sel);
|
||||
unsigned int node_area(monitor_t *m, desktop_t *d, node_t *n);
|
||||
int tiled_count(node_t *n);
|
||||
node_t *find_biggest(monitor_t *m, desktop_t *d, node_t *n, node_select_t sel);
|
||||
void rotate_tree(node_t *n, int deg);
|
||||
void rotate_brother(node_t *n);
|
||||
void unrotate_tree(node_t *n, int rot);
|
||||
|
@ -64,13 +76,28 @@ void equalize_tree(node_t *n);
|
|||
int balance_tree(node_t *n);
|
||||
void unlink_node(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void remove_node(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void destroy_tree(node_t *n);
|
||||
void destroy_tree(monitor_t *m, desktop_t *d, 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(monitor_t *m, 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 set_vacant_state(node_t *n, bool value);
|
||||
void propagate_vacant_state(node_t *n);
|
||||
void update_privacy_level(node_t *n, bool value);
|
||||
node_t *closest_node(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, node_select_t sel);
|
||||
void circulate_leaves(monitor_t *m, desktop_t *d, node_t *n, circulate_dir_t dir);
|
||||
void set_vacant_state(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void propagate_vacant_state(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l);
|
||||
void set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s);
|
||||
void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void neutralize_occluding_windows(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_urgent(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
bool contains(xcb_rectangle_t a, xcb_rectangle_t b);
|
||||
xcb_rectangle_t get_rectangle(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void get_side_handle(monitor_t *m, desktop_t *d, node_t *n, direction_t dir, xcb_point_t *pt);
|
||||
|
||||
unsigned int sticky_count(node_t *n);
|
||||
unsigned int private_count(node_t *n);
|
||||
unsigned int locked_count(node_t *n);
|
||||
|
||||
#endif
|
||||
|
|
53
types.h
53
types.h
|
@ -31,7 +31,7 @@
|
|||
#include "helpers.h"
|
||||
|
||||
#define MISSING_VALUE "N/A"
|
||||
#define MAX_STATE 4
|
||||
#define MAX_WM_STATES 4
|
||||
|
||||
typedef enum {
|
||||
TYPE_HORIZONTAL,
|
||||
|
@ -83,10 +83,10 @@ typedef enum {
|
|||
} history_dir_t;
|
||||
|
||||
typedef enum {
|
||||
DIR_RIGHT,
|
||||
DIR_DOWN,
|
||||
DIR_LEFT,
|
||||
DIR_UP
|
||||
DIR_NORTH,
|
||||
DIR_WEST,
|
||||
DIR_SOUTH,
|
||||
DIR_EAST
|
||||
} direction_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -127,6 +127,10 @@ typedef enum {
|
|||
} child_polarity_t;
|
||||
|
||||
typedef struct {
|
||||
option_bool_t automatic;
|
||||
option_bool_t focused;
|
||||
option_bool_t local;
|
||||
option_bool_t leaf;
|
||||
option_bool_t tiled;
|
||||
option_bool_t pseudo_tiled;
|
||||
option_bool_t floating;
|
||||
|
@ -136,13 +140,10 @@ typedef struct {
|
|||
option_bool_t private;
|
||||
option_bool_t urgent;
|
||||
option_bool_t same_class;
|
||||
option_bool_t automatic;
|
||||
option_bool_t local;
|
||||
option_bool_t focused;
|
||||
option_bool_t below;
|
||||
option_bool_t normal;
|
||||
option_bool_t above;
|
||||
} client_select_t;
|
||||
} node_select_t;
|
||||
|
||||
typedef struct {
|
||||
option_bool_t occupied;
|
||||
|
@ -157,14 +158,10 @@ typedef struct {
|
|||
} monitor_select_t;
|
||||
|
||||
typedef struct {
|
||||
xcb_window_t window;
|
||||
char class_name[3 * SMALEN / 2];
|
||||
char instance_name[3 * SMALEN / 2];
|
||||
unsigned int border_width;
|
||||
bool locked; /* protects window from being closed */
|
||||
bool sticky;
|
||||
bool urgent;
|
||||
bool private;
|
||||
client_state_t state;
|
||||
client_state_t last_state;
|
||||
stack_layer_t layer;
|
||||
|
@ -177,24 +174,33 @@ typedef struct {
|
|||
uint16_t max_width;
|
||||
uint16_t min_height;
|
||||
uint16_t max_height;
|
||||
xcb_atom_t wm_state[MAX_STATE];
|
||||
int num_states;
|
||||
xcb_atom_t wm_state[MAX_WM_STATES];
|
||||
int wm_states_count;
|
||||
} client_t;
|
||||
|
||||
typedef struct presel_t presel_t;
|
||||
struct presel_t {
|
||||
double split_ratio;
|
||||
direction_t split_dir;
|
||||
xcb_window_t feedback;
|
||||
};
|
||||
|
||||
typedef struct node_t node_t;
|
||||
struct node_t {
|
||||
uint32_t id;
|
||||
split_type_t split_type;
|
||||
double split_ratio;
|
||||
split_mode_t split_mode;
|
||||
direction_t split_dir;
|
||||
int birth_rotation;
|
||||
presel_t *presel;
|
||||
xcb_rectangle_t rectangle;
|
||||
bool vacant; /* vacant nodes only hold floating clients */
|
||||
int privacy_level;
|
||||
bool vacant;
|
||||
bool sticky;
|
||||
bool private;
|
||||
bool locked;
|
||||
node_t *first_child;
|
||||
node_t *second_child;
|
||||
node_t *parent;
|
||||
client_t *client; /* NULL except for leaves */
|
||||
client_t *client;
|
||||
};
|
||||
|
||||
typedef struct desktop_t desktop_t;
|
||||
|
@ -223,7 +229,7 @@ struct monitor_t {
|
|||
int right_padding;
|
||||
int bottom_padding;
|
||||
int left_padding;
|
||||
int num_sticky;
|
||||
unsigned int sticky_count;
|
||||
xcb_rectangle_t rectangle;
|
||||
desktop_t *desk;
|
||||
desktop_t *desk_head;
|
||||
|
@ -264,7 +270,8 @@ struct subscriber_list_t {
|
|||
|
||||
typedef struct rule_t rule_t;
|
||||
struct rule_t {
|
||||
char cause[MAXLEN];
|
||||
char class_name[MAXLEN];
|
||||
char instance_name[MAXLEN];
|
||||
char effect[MAXLEN];
|
||||
bool one_shot;
|
||||
rule_t *prev;
|
||||
|
@ -278,9 +285,9 @@ typedef struct {
|
|||
char desktop_desc[MAXLEN];
|
||||
char node_desc[MAXLEN];
|
||||
char split_dir[SMALEN];
|
||||
double split_ratio;
|
||||
stack_layer_t *layer;
|
||||
client_state_t *state;
|
||||
double split_ratio;
|
||||
uint16_t min_width;
|
||||
uint16_t max_width;
|
||||
uint16_t min_height;
|
||||
|
|
622
window.c
622
window.c
|
@ -22,7 +22,9 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "bspwm.h"
|
||||
#include "ewmh.h"
|
||||
|
@ -32,7 +34,6 @@
|
|||
#include "settings.h"
|
||||
#include "stack.h"
|
||||
#include "tree.h"
|
||||
#include "subscribe.h"
|
||||
#include "parse.h"
|
||||
#include "window.h"
|
||||
|
||||
|
@ -47,13 +48,16 @@ void schedule_window(xcb_window_t win)
|
|||
free(wa);
|
||||
}
|
||||
|
||||
if (override_redirect || locate_window(win, &loc))
|
||||
if (override_redirect || locate_window(win, &loc)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* ignore pending windows */
|
||||
for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next)
|
||||
if (pr->win == win)
|
||||
for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
|
||||
if (pr->win == win) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rule_consequence_t *csq = make_rule_conquence();
|
||||
apply_rules(win, csq);
|
||||
|
@ -113,27 +117,33 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
|
|||
if (csq->split_dir[0] != '\0' && f != NULL) {
|
||||
direction_t dir;
|
||||
if (parse_direction(csq->split_dir, &dir)) {
|
||||
f->split_mode = MODE_MANUAL;
|
||||
f->split_dir = dir;
|
||||
presel_dir(m, d, f, dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (csq->split_ratio != 0 && f != NULL) {
|
||||
f->split_ratio = csq->split_ratio;
|
||||
presel_ratio(m, d, f, csq->split_ratio);
|
||||
}
|
||||
|
||||
client_t *c = make_client(win, csq->border ? d->border_width : 0);
|
||||
update_floating_rectangle(c);
|
||||
node_t *n = make_node(win);
|
||||
client_t *c = make_client();
|
||||
c->border_width = csq->border ? d->border_width : 0;
|
||||
n->client = c;
|
||||
initialize_client(n);
|
||||
update_floating_rectangle(n);
|
||||
|
||||
if (c->floating_rectangle.x == 0 && c->floating_rectangle.y == 0) {
|
||||
csq->center = true;
|
||||
}
|
||||
|
||||
c->min_width = csq->min_width;
|
||||
c->max_width = csq->max_width;
|
||||
c->min_height = csq->min_height;
|
||||
c->max_height = csq->max_height;
|
||||
|
||||
monitor_t *mm = monitor_from_client(c);
|
||||
embrace_client(mm, c);
|
||||
translate_client(mm, m, c);
|
||||
adapt_geometry(&mm->rectangle, &m->rectangle, n);
|
||||
|
||||
if (csq->center) {
|
||||
window_center(m, c);
|
||||
|
@ -142,11 +152,10 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
|
|||
snprintf(c->class_name, sizeof(c->class_name), "%s", csq->class_name);
|
||||
snprintf(c->instance_name, sizeof(c->instance_name), "%s", csq->instance_name);
|
||||
|
||||
node_t *n = make_node();
|
||||
n->client = c;
|
||||
f = insert_node(m, d, n, f);
|
||||
clients_count++;
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_MANAGE, "window_manage %s %s 0x%X 0x%X\n", m->name, d->name, win, f!=NULL?f->client->window:0);
|
||||
insert_node(m, d, n, f);
|
||||
put_status(SBSC_MASK_NODE_MANAGE, "node_manage %s %s 0x%X 0x%X\n", m->name, d->name, win, f!=NULL?f->id:0);
|
||||
|
||||
if (f != NULL && f->client != NULL && csq->state != NULL && *(csq->state) == STATE_FLOATING) {
|
||||
c->last_layer = c->layer = f->client->layer;
|
||||
|
@ -174,17 +183,16 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
|
|||
} else if (csq->focus) {
|
||||
activate_node(m, d, n);
|
||||
} else {
|
||||
stack(n, false);
|
||||
stack(d, n, false);
|
||||
}
|
||||
|
||||
uint32_t values[] = {CLIENT_EVENT_MASK | (focus_follows_pointer ? XCB_EVENT_MASK_ENTER_WINDOW : 0)};
|
||||
xcb_change_window_attributes(dpy, c->window, XCB_CW_EVENT_MASK, values);
|
||||
xcb_change_window_attributes(dpy, win, XCB_CW_EVENT_MASK, values);
|
||||
|
||||
if (visible) {
|
||||
if (d == m->desk)
|
||||
window_show(n->client->window);
|
||||
else
|
||||
window_hide(n->client->window);
|
||||
if (d == m->desk) {
|
||||
window_show(n->id);
|
||||
} else {
|
||||
window_hide(n->id);
|
||||
}
|
||||
|
||||
/* the same function is already called in `focus_node` but has no effects on unmapped windows */
|
||||
|
@ -192,9 +200,8 @@ void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd)
|
|||
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT, win, XCB_CURRENT_TIME);
|
||||
}
|
||||
|
||||
num_clients++;
|
||||
ewmh_set_wm_desktop(n, d);
|
||||
ewmh_update_client_list();
|
||||
ewmh_update_client_list(false);
|
||||
free(csq->layer);
|
||||
free(csq->state);
|
||||
}
|
||||
|
@ -203,10 +210,11 @@ void unmanage_window(xcb_window_t win)
|
|||
{
|
||||
coordinates_t loc;
|
||||
if (locate_window(win, &loc)) {
|
||||
put_status(SBSC_MASK_WINDOW_UNMANAGE, "window_unmanage %s %s 0x%X\n", loc.monitor, loc.desktop, win);
|
||||
put_status(SBSC_MASK_NODE_UNMANAGE, "node_unmanage %s %s 0x%X\n", loc.monitor, loc.desktop, win);
|
||||
remove_node(loc.monitor, loc.desktop, loc.node);
|
||||
if (frozen_pointer->window == win)
|
||||
if (frozen_pointer->window == win) {
|
||||
frozen_pointer->action = ACTION_NONE;
|
||||
}
|
||||
arrange(loc.monitor, loc.desktop);
|
||||
} else {
|
||||
for (pending_rule_t *pr = pending_rule_head; pr != NULL; pr = pr->next) {
|
||||
|
@ -218,80 +226,134 @@ void unmanage_window(xcb_window_t win)
|
|||
}
|
||||
}
|
||||
|
||||
void window_draw_border(node_t *n, bool focused_window, bool focused_monitor)
|
||||
void initialize_presel_feedback(node_t *n)
|
||||
{
|
||||
if (n == NULL || n->client->border_width < 1) {
|
||||
if (n == NULL || n->presel == NULL || n->presel->feedback != XCB_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
xcb_window_t win = n->client->window;
|
||||
uint32_t border_color_pxl = get_border_color(n->client, focused_window, focused_monitor);
|
||||
xcb_window_t win = xcb_generate_id(dpy);
|
||||
xcb_create_window(dpy, XCB_COPY_FROM_PARENT, win, root, 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||
XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL, (uint32_t []) {get_color_pixel(presel_feedback_color)});
|
||||
|
||||
if (n->split_mode == MODE_AUTOMATIC) {
|
||||
xcb_change_window_attributes(dpy, win, XCB_CW_BORDER_PIXEL, &border_color_pxl);
|
||||
} else {
|
||||
unsigned int border_width = n->client->border_width;
|
||||
uint32_t presel_border_color_pxl;
|
||||
get_color(presel_border_color, win, &presel_border_color_pxl);
|
||||
|
||||
xcb_rectangle_t actual_rectangle = get_rectangle(NULL, n->client);
|
||||
|
||||
uint16_t width = actual_rectangle.width;
|
||||
uint16_t height = actual_rectangle.height;
|
||||
|
||||
uint16_t full_width = width + 2 * border_width;
|
||||
uint16_t full_height = height + 2 * border_width;
|
||||
|
||||
xcb_rectangle_t border_rectangles[] =
|
||||
{
|
||||
{ width, 0, 2 * border_width, height + 2 * border_width },
|
||||
{ 0, height, width + 2 * border_width, 2 * border_width }
|
||||
};
|
||||
|
||||
xcb_rectangle_t *presel_rectangles;
|
||||
|
||||
uint8_t win_depth = root_depth;
|
||||
xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL);
|
||||
if (geo != NULL)
|
||||
win_depth = geo->depth;
|
||||
free(geo);
|
||||
|
||||
xcb_pixmap_t pixmap = xcb_generate_id(dpy);
|
||||
xcb_create_pixmap(dpy, win_depth, pixmap, win, full_width, full_height);
|
||||
|
||||
xcb_gcontext_t gc = xcb_generate_id(dpy);
|
||||
xcb_create_gc(dpy, gc, pixmap, 0, NULL);
|
||||
|
||||
xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &border_color_pxl);
|
||||
xcb_poly_fill_rectangle(dpy, pixmap, gc, LENGTH(border_rectangles), border_rectangles);
|
||||
|
||||
uint16_t fence = (int16_t) (n->split_ratio * ((n->split_dir == DIR_UP || n->split_dir == DIR_DOWN) ? height : width));
|
||||
presel_rectangles = malloc(2 * sizeof(xcb_rectangle_t));
|
||||
switch (n->split_dir) {
|
||||
case DIR_UP:
|
||||
presel_rectangles[0] = (xcb_rectangle_t) {width, 0, 2 * border_width, fence};
|
||||
presel_rectangles[1] = (xcb_rectangle_t) {0, height + border_width, full_width, border_width};
|
||||
break;
|
||||
case DIR_DOWN:
|
||||
presel_rectangles[0] = (xcb_rectangle_t) {width, fence + 1, 2 * border_width, height + border_width - (fence + 1)};
|
||||
presel_rectangles[1] = (xcb_rectangle_t) {0, height, full_width, border_width};
|
||||
break;
|
||||
case DIR_LEFT:
|
||||
presel_rectangles[0] = (xcb_rectangle_t) {0, height, fence, 2 * border_width};
|
||||
presel_rectangles[1] = (xcb_rectangle_t) {width + border_width, 0, border_width, full_height};
|
||||
break;
|
||||
case DIR_RIGHT:
|
||||
presel_rectangles[0] = (xcb_rectangle_t) {fence + 1, height, width + border_width - (fence + 1), 2 * border_width};
|
||||
presel_rectangles[1] = (xcb_rectangle_t) {width, 0, border_width, full_height};
|
||||
break;
|
||||
}
|
||||
xcb_change_gc(dpy, gc, XCB_GC_FOREGROUND, &presel_border_color_pxl);
|
||||
xcb_poly_fill_rectangle(dpy, pixmap, gc, 2, presel_rectangles);
|
||||
xcb_change_window_attributes(dpy, win, XCB_CW_BORDER_PIXMAP, &pixmap);
|
||||
free(presel_rectangles);
|
||||
xcb_free_gc(dpy, gc);
|
||||
xcb_free_pixmap(dpy, pixmap);
|
||||
xcb_icccm_set_wm_class(dpy, win, sizeof(PRESEL_FEEDBACK_IC), PRESEL_FEEDBACK_IC);
|
||||
stacking_list_t *s = stack_tail;
|
||||
while (s != NULL && !IS_TILED(s->node->client)) {
|
||||
s = s->prev;
|
||||
}
|
||||
if (s != NULL) {
|
||||
window_above(win, s->node->id);
|
||||
}
|
||||
n->presel->feedback = win;
|
||||
}
|
||||
|
||||
void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n)
|
||||
{
|
||||
if (n == NULL || n->presel == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool exists = (n->presel->feedback != XCB_NONE);
|
||||
if (!exists) {
|
||||
initialize_presel_feedback(n);
|
||||
}
|
||||
|
||||
presel_t *p = n->presel;
|
||||
xcb_rectangle_t rect = n->rectangle;
|
||||
rect.x = rect.y = 0;
|
||||
rect.width -= d->window_gap;
|
||||
rect.height -= d->window_gap;
|
||||
xcb_rectangle_t presel_rect = rect;
|
||||
|
||||
switch (p->split_dir) {
|
||||
case DIR_NORTH:
|
||||
presel_rect.height = p->split_ratio * rect.height;
|
||||
break;
|
||||
case DIR_EAST:
|
||||
presel_rect.width = (1 - p->split_ratio) * rect.width;
|
||||
presel_rect.x = rect.width - presel_rect.width;
|
||||
break;
|
||||
case DIR_SOUTH:
|
||||
presel_rect.height = (1 - p->split_ratio) * rect.height;
|
||||
presel_rect.y = rect.height - presel_rect.height;
|
||||
break;
|
||||
case DIR_WEST:
|
||||
presel_rect.width = p->split_ratio * rect.width;
|
||||
break;
|
||||
}
|
||||
|
||||
window_move_resize(p->feedback, n->rectangle.x + presel_rect.x, n->rectangle.y + presel_rect.y,
|
||||
presel_rect.width, presel_rect.height);
|
||||
|
||||
if (!exists && m->desk == d) {
|
||||
window_show(p->feedback);
|
||||
}
|
||||
}
|
||||
|
||||
void refresh_presel_feebacks_in(node_t *n, desktop_t *d, monitor_t *m)
|
||||
{
|
||||
if (n == NULL) {
|
||||
return;
|
||||
} else {
|
||||
if (n->presel != NULL) {
|
||||
draw_presel_feedback(m, d, n);
|
||||
}
|
||||
refresh_presel_feebacks_in(n->first_child, d, m);
|
||||
refresh_presel_feebacks_in(n->second_child, d, m);
|
||||
}
|
||||
}
|
||||
|
||||
void update_colors(void)
|
||||
{
|
||||
for (monitor_t *m = mon_head; m != NULL; m = m->next) {
|
||||
for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
|
||||
update_colors_in(d->root, d, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_colors_in(node_t *n, desktop_t *d, monitor_t *m)
|
||||
{
|
||||
if (n == NULL) {
|
||||
return;
|
||||
} else {
|
||||
if (n->presel != NULL) {
|
||||
uint32_t pxl = get_color_pixel(presel_feedback_color);
|
||||
xcb_change_window_attributes(dpy, n->presel->feedback, XCB_CW_BACK_PIXEL, &pxl);
|
||||
if (d == m->desk) {
|
||||
/* hack to induce back pixel refresh */
|
||||
window_hide(n->presel->feedback);
|
||||
window_show(n->presel->feedback);
|
||||
}
|
||||
}
|
||||
if (n == d->focus) {
|
||||
draw_border(n, true, (m == mon));
|
||||
} else if (n->client != NULL) {
|
||||
draw_border(n, false, (m == mon));
|
||||
} else {
|
||||
update_colors_in(n->first_child, d, m);
|
||||
update_colors_in(n->second_child, d, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw_border(node_t *n, bool focused_node, bool focused_monitor)
|
||||
{
|
||||
if (n == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t border_color_pxl = get_border_color(focused_node, focused_monitor);
|
||||
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
|
||||
if (f->client->border_width > 0) {
|
||||
window_draw_border(f->id, border_color_pxl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void window_draw_border(xcb_window_t win, uint32_t border_color_pxl)
|
||||
{
|
||||
xcb_change_window_attributes(dpy, win, XCB_CW_BORDER_PIXEL, &border_color_pxl);
|
||||
}
|
||||
|
||||
pointer_state_t *make_pointer_state(void)
|
||||
|
@ -306,67 +368,22 @@ pointer_state_t *make_pointer_state(void)
|
|||
return p;
|
||||
}
|
||||
|
||||
/* Returns true if a contains b */
|
||||
bool contains(xcb_rectangle_t a, xcb_rectangle_t b)
|
||||
{
|
||||
return (a.x <= b.x && (a.x + a.width) >= (b.x + b.width) &&
|
||||
a.y <= b.y && (a.y + a.height) >= (b.y + b.height));
|
||||
}
|
||||
|
||||
xcb_rectangle_t get_rectangle(monitor_t *m, client_t *c)
|
||||
{
|
||||
switch (c->state) {
|
||||
case STATE_TILED:
|
||||
return c->tiled_rectangle;
|
||||
break;
|
||||
case STATE_PSEUDO_TILED:
|
||||
case STATE_FLOATING:
|
||||
return c->floating_rectangle;
|
||||
break;
|
||||
case STATE_FULLSCREEN:
|
||||
default:
|
||||
return m != NULL ? m->rectangle : (xcb_rectangle_t) {0, 0, screen_width, screen_height};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt)
|
||||
{
|
||||
xcb_rectangle_t rect = get_rectangle(NULL, c);
|
||||
|
||||
switch (dir) {
|
||||
case DIR_RIGHT:
|
||||
pt->x = rect.x + rect.width;
|
||||
pt->y = rect.y + (rect.height / 2);
|
||||
break;
|
||||
case DIR_DOWN:
|
||||
pt->x = rect.x + (rect.width / 2);
|
||||
pt->y = rect.y + rect.height;
|
||||
break;
|
||||
case DIR_LEFT:
|
||||
pt->x = rect.x;
|
||||
pt->y = rect.y + (rect.height / 2);
|
||||
break;
|
||||
case DIR_UP:
|
||||
pt->x = rect.x + (rect.width / 2);
|
||||
pt->y = rect.y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void adopt_orphans(void)
|
||||
{
|
||||
xcb_query_tree_reply_t *qtr = xcb_query_tree_reply(dpy, xcb_query_tree(dpy, root), NULL);
|
||||
if (qtr == NULL)
|
||||
if (qtr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
int len = xcb_query_tree_children_length(qtr);
|
||||
xcb_window_t *wins = xcb_query_tree_children(qtr);
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
uint32_t idx;
|
||||
xcb_window_t win = wins[i];
|
||||
if (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), &idx, NULL) == 1)
|
||||
if (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), &idx, NULL) == 1) {
|
||||
schedule_window(win);
|
||||
}
|
||||
}
|
||||
|
||||
free(qtr);
|
||||
|
@ -374,274 +391,75 @@ void adopt_orphans(void)
|
|||
|
||||
void window_close(node_t *n)
|
||||
{
|
||||
if (n == NULL || n->client->locked)
|
||||
if (n == NULL) {
|
||||
return;
|
||||
|
||||
send_client_message(n->client->window, ewmh->WM_PROTOCOLS, WM_DELETE_WINDOW);
|
||||
} else if (n->client != NULL) {
|
||||
send_client_message(n->id, ewmh->WM_PROTOCOLS, WM_DELETE_WINDOW);
|
||||
} else {
|
||||
window_close(n->first_child);
|
||||
window_close(n->second_child);
|
||||
}
|
||||
}
|
||||
|
||||
void window_kill(monitor_t *m, desktop_t *d, node_t *n)
|
||||
{
|
||||
if (n == NULL)
|
||||
if (n == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
xcb_window_t win = n->client->window;
|
||||
for (node_t *f = first_extrema(n); f != NULL; f = next_leaf(f, n)) {
|
||||
xcb_kill_client(dpy, f->id);
|
||||
}
|
||||
|
||||
xcb_kill_client(dpy, win);
|
||||
remove_node(m, d, n);
|
||||
}
|
||||
|
||||
void set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l)
|
||||
uint32_t get_border_color(bool focused_node, bool focused_monitor)
|
||||
{
|
||||
if (n == NULL || n->client->layer == l) {
|
||||
return;
|
||||
}
|
||||
|
||||
client_t *c = n->client;
|
||||
|
||||
c->last_layer = c->layer;
|
||||
c->layer = l;
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_LAYER, "window_layer %s %s 0x%X %s\n", m->name, d->name, c->window, LAYER_STR(l));
|
||||
|
||||
if (d->focus == n) {
|
||||
neutralize_obscuring_windows(m, d, n);
|
||||
}
|
||||
|
||||
stack(n, (d->focus == n));
|
||||
}
|
||||
|
||||
void set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s)
|
||||
{
|
||||
if (n == NULL || n->client->state == s) {
|
||||
return;
|
||||
}
|
||||
|
||||
client_t *c = n->client;
|
||||
|
||||
c->last_state = c->state;
|
||||
c->state = s;
|
||||
|
||||
switch (c->last_state) {
|
||||
case STATE_TILED:
|
||||
case STATE_PSEUDO_TILED:
|
||||
break;
|
||||
case STATE_FLOATING:
|
||||
set_floating(m, d, n, false);
|
||||
break;
|
||||
case STATE_FULLSCREEN:
|
||||
set_fullscreen(m, d, n, false);
|
||||
break;
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_STATE, "window_state %s %s 0x%X %s off\n", m->name, d->name, c->window, STATE_STR(c->last_state));
|
||||
|
||||
switch (c->state) {
|
||||
case STATE_TILED:
|
||||
case STATE_PSEUDO_TILED:
|
||||
break;
|
||||
case STATE_FLOATING:
|
||||
set_floating(m, d, n, true);
|
||||
break;
|
||||
case STATE_FULLSCREEN:
|
||||
set_fullscreen(m, d, n, true);
|
||||
break;
|
||||
}
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_STATE, "window_state %s %s 0x%X %s on\n", m->name, d->name, c->window, STATE_STR(c->state));
|
||||
}
|
||||
|
||||
void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value)
|
||||
{
|
||||
if (n == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
n->split_mode = MODE_AUTOMATIC;
|
||||
set_vacant_state(n, value);
|
||||
|
||||
if (!value && d->focus == n) {
|
||||
neutralize_obscuring_windows(m, d, n);
|
||||
}
|
||||
|
||||
stack(n, (d->focus == n));
|
||||
}
|
||||
|
||||
void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value)
|
||||
{
|
||||
if (n == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
client_t *c = n->client;
|
||||
|
||||
n->split_mode = MODE_AUTOMATIC;
|
||||
set_vacant_state(n, value);
|
||||
|
||||
if (value) {
|
||||
ewmh_wm_state_add(c, ewmh->_NET_WM_STATE_FULLSCREEN);
|
||||
c->last_layer = c->layer;
|
||||
c->layer = LAYER_ABOVE;
|
||||
if (focused_monitor && focused_node) {
|
||||
return get_color_pixel(focused_border_color);
|
||||
} else if (focused_node) {
|
||||
return get_color_pixel(active_border_color);
|
||||
} else {
|
||||
ewmh_wm_state_remove(c, ewmh->_NET_WM_STATE_FULLSCREEN);
|
||||
c->layer = c->last_layer;
|
||||
if (d->focus == n) {
|
||||
neutralize_obscuring_windows(m, d, n);
|
||||
}
|
||||
}
|
||||
|
||||
stack(n, (d->focus == n));
|
||||
}
|
||||
|
||||
void neutralize_obscuring_windows(monitor_t *m, desktop_t *d, node_t *n)
|
||||
{
|
||||
bool dirty = false;
|
||||
for (node_t *a = first_extrema(d->root); a != NULL; a = next_leaf(a, d->root)) {
|
||||
if (a != n) {
|
||||
if (IS_FULLSCREEN(a->client) && stack_cmp(n->client, a->client) < 0) {
|
||||
set_state(m, d, a, a->client->last_state);
|
||||
dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dirty) {
|
||||
arrange(m, d);
|
||||
return get_color_pixel(normal_border_color);
|
||||
}
|
||||
}
|
||||
|
||||
void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
|
||||
void update_floating_rectangle(node_t *n)
|
||||
{
|
||||
if (n == NULL || n->client->locked == value)
|
||||
return;
|
||||
|
||||
client_t *c = n->client;
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_FLAG, "window_flag %s %s 0x%X locked %s\n", m->name, d->name, c->window, ON_OFF_STR(value));
|
||||
xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, n->id), NULL);
|
||||
|
||||
c->locked = value;
|
||||
window_draw_border(n, d->focus == n, m == mon);
|
||||
}
|
||||
|
||||
void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value)
|
||||
{
|
||||
if (n == NULL || n->client->sticky == value)
|
||||
return;
|
||||
|
||||
client_t *c = n->client;
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_FLAG, "window_flag %s %s 0x%X sticky %s\n", m->name, d->name, c->window, ON_OFF_STR(value));
|
||||
|
||||
if (d != m->desk)
|
||||
transfer_node(m, d, n, m, m->desk, m->desk->focus);
|
||||
|
||||
c->sticky = value;
|
||||
if (value) {
|
||||
ewmh_wm_state_add(c, ewmh->_NET_WM_STATE_STICKY);
|
||||
m->num_sticky++;
|
||||
} else {
|
||||
ewmh_wm_state_remove(c, ewmh->_NET_WM_STATE_STICKY);
|
||||
m->num_sticky--;
|
||||
}
|
||||
|
||||
window_draw_border(n, d->focus == n, m == mon);
|
||||
}
|
||||
|
||||
void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value)
|
||||
{
|
||||
if (n == NULL || n->client->private == value)
|
||||
return;
|
||||
|
||||
client_t *c = n->client;
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_FLAG, "window_flag %s %s 0x%X private %s\n", m->name, d->name, c->window, ON_OFF_STR(value));
|
||||
|
||||
c->private = value;
|
||||
update_privacy_level(n, value);
|
||||
window_draw_border(n, d->focus == n, m == mon);
|
||||
}
|
||||
|
||||
void set_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value)
|
||||
{
|
||||
if (value && mon->desk->focus == n)
|
||||
return;
|
||||
n->client->urgent = value;
|
||||
window_draw_border(n, d->focus == n, m == mon);
|
||||
|
||||
put_status(SBSC_MASK_WINDOW_FLAG, "window_flag %s %s 0x%X urgent %s\n", m->name, d->name, n->client->window, ON_OFF_STR(value));
|
||||
put_status(SBSC_MASK_REPORT);
|
||||
}
|
||||
|
||||
uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor)
|
||||
{
|
||||
if (c == NULL)
|
||||
return 0;
|
||||
|
||||
uint32_t pxl = 0;
|
||||
|
||||
if (focused_monitor && focused_window) {
|
||||
if (c->locked)
|
||||
get_color(focused_locked_border_color, c->window, &pxl);
|
||||
else if (c->sticky)
|
||||
get_color(focused_sticky_border_color, c->window, &pxl);
|
||||
else if (c->private)
|
||||
get_color(focused_private_border_color, c->window, &pxl);
|
||||
else
|
||||
get_color(focused_border_color, c->window, &pxl);
|
||||
} else if (focused_window) {
|
||||
if (c->urgent)
|
||||
get_color(urgent_border_color, c->window, &pxl);
|
||||
else if (c->locked)
|
||||
get_color(active_locked_border_color, c->window, &pxl);
|
||||
else if (c->sticky)
|
||||
get_color(active_sticky_border_color, c->window, &pxl);
|
||||
else if (c->private)
|
||||
get_color(active_private_border_color, c->window, &pxl);
|
||||
else
|
||||
get_color(active_border_color, c->window, &pxl);
|
||||
} else {
|
||||
if (c->urgent)
|
||||
get_color(urgent_border_color, c->window, &pxl);
|
||||
else if (c->locked)
|
||||
get_color(normal_locked_border_color, c->window, &pxl);
|
||||
else if (c->sticky)
|
||||
get_color(normal_sticky_border_color, c->window, &pxl);
|
||||
else if (c->private)
|
||||
get_color(normal_private_border_color, c->window, &pxl);
|
||||
else
|
||||
get_color(normal_border_color, c->window, &pxl);
|
||||
}
|
||||
|
||||
return pxl;
|
||||
}
|
||||
|
||||
void update_floating_rectangle(client_t *c)
|
||||
{
|
||||
xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, c->window), NULL);
|
||||
|
||||
if (geo != NULL)
|
||||
if (geo != NULL) {
|
||||
c->floating_rectangle = (xcb_rectangle_t) {geo->x, geo->y, geo->width, geo->height};
|
||||
}
|
||||
|
||||
free(geo);
|
||||
}
|
||||
|
||||
void restrain_floating_width(client_t *c, int *width)
|
||||
{
|
||||
if (*width < 1)
|
||||
if (*width < 1) {
|
||||
*width = 1;
|
||||
if (c->min_width > 0 && *width < c->min_width)
|
||||
}
|
||||
if (c->min_width > 0 && *width < c->min_width) {
|
||||
*width = c->min_width;
|
||||
else if (c->max_width > 0 && *width > c->max_width)
|
||||
} else if (c->max_width > 0 && *width > c->max_width) {
|
||||
*width = c->max_width;
|
||||
}
|
||||
}
|
||||
|
||||
void restrain_floating_height(client_t *c, int *height)
|
||||
{
|
||||
if (*height < 1)
|
||||
if (*height < 1) {
|
||||
*height = 1;
|
||||
if (c->min_height > 0 && *height < c->min_height)
|
||||
}
|
||||
if (c->min_height > 0 && *height < c->min_height) {
|
||||
*height = c->min_height;
|
||||
else if (c->max_height > 0 && *height > c->max_height)
|
||||
} else if (c->max_height > 0 && *height > c->max_height) {
|
||||
*height = c->max_height;
|
||||
}
|
||||
}
|
||||
|
||||
void restrain_floating_size(client_t *c, int *width, int *height)
|
||||
|
@ -657,13 +475,16 @@ void query_pointer(xcb_window_t *win, xcb_point_t *pt)
|
|||
xcb_query_pointer_reply_t *qpr = xcb_query_pointer_reply(dpy, xcb_query_pointer(dpy, root), NULL);
|
||||
|
||||
if (qpr != NULL) {
|
||||
if (win != NULL)
|
||||
if (win != NULL) {
|
||||
*win = qpr->child;
|
||||
if (pt != NULL)
|
||||
}
|
||||
if (pt != NULL) {
|
||||
*pt = (xcb_point_t) {qpr->root_x, qpr->root_y};
|
||||
free(qpr);
|
||||
}
|
||||
}
|
||||
|
||||
free(qpr);
|
||||
|
||||
window_raise(motion_recorder);
|
||||
}
|
||||
|
||||
|
@ -701,22 +522,25 @@ void window_center(monitor_t *m, client_t *c)
|
|||
{
|
||||
xcb_rectangle_t *r = &c->floating_rectangle;
|
||||
xcb_rectangle_t a = m->rectangle;
|
||||
if (r->width >= a.width)
|
||||
if (r->width >= a.width) {
|
||||
r->x = a.x;
|
||||
else
|
||||
} else {
|
||||
r->x = a.x + (a.width - r->width) / 2;
|
||||
if (r->height >= a.height)
|
||||
}
|
||||
if (r->height >= a.height) {
|
||||
r->y = a.y;
|
||||
else
|
||||
} else {
|
||||
r->y = a.y + (a.height - r->height) / 2;
|
||||
}
|
||||
r->x -= c->border_width;
|
||||
r->y -= c->border_width;
|
||||
}
|
||||
|
||||
void window_stack(xcb_window_t w1, xcb_window_t w2, uint32_t mode)
|
||||
{
|
||||
if (w2 == XCB_NONE)
|
||||
if (w2 == XCB_NONE) {
|
||||
return;
|
||||
}
|
||||
uint16_t mask = XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE;
|
||||
uint32_t values[] = {w2, mode};
|
||||
xcb_configure_window(dpy, w1, mask, values);
|
||||
|
@ -743,10 +567,11 @@ void window_set_visibility(xcb_window_t win, bool visible)
|
|||
uint32_t values_off[] = {ROOT_EVENT_MASK & ~XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY};
|
||||
uint32_t values_on[] = {ROOT_EVENT_MASK};
|
||||
xcb_change_window_attributes(dpy, root, XCB_CW_EVENT_MASK, values_off);
|
||||
if (visible)
|
||||
if (visible) {
|
||||
xcb_map_window(dpy, win);
|
||||
else
|
||||
} else {
|
||||
xcb_unmap_window(dpy, win);
|
||||
}
|
||||
xcb_change_window_attributes(dpy, root, XCB_CW_EVENT_MASK, values_on);
|
||||
}
|
||||
|
||||
|
@ -760,18 +585,6 @@ void window_show(xcb_window_t win)
|
|||
window_set_visibility(win, true);
|
||||
}
|
||||
|
||||
void toggle_visibility(void)
|
||||
{
|
||||
visible = !visible;
|
||||
if (!visible)
|
||||
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))
|
||||
window_set_visibility(n->client->window, visible);
|
||||
if (visible)
|
||||
update_input_focus();
|
||||
}
|
||||
|
||||
void enable_motion_recorder(void)
|
||||
{
|
||||
window_raise(motion_recorder);
|
||||
|
@ -801,13 +614,13 @@ void update_input_focus(void)
|
|||
|
||||
void set_input_focus(node_t *n)
|
||||
{
|
||||
if (n == NULL) {
|
||||
if (n == NULL || n->client == NULL) {
|
||||
clear_input_focus();
|
||||
} else {
|
||||
if (n->client->icccm_input) {
|
||||
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_PARENT, n->client->window, XCB_CURRENT_TIME);
|
||||
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_PARENT, n->id, XCB_CURRENT_TIME);
|
||||
} else if (n->client->icccm_focus) {
|
||||
send_client_message(n->client->window, ewmh->WM_PROTOCOLS, WM_TAKE_FOCUS);
|
||||
send_client_message(n->id, ewmh->WM_PROTOCOLS, WM_TAKE_FOCUS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -829,10 +642,11 @@ void center_pointer(xcb_rectangle_t r)
|
|||
void get_atom(char *name, xcb_atom_t *atom)
|
||||
{
|
||||
xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen(name), name), NULL);
|
||||
if (reply != NULL)
|
||||
if (reply != NULL) {
|
||||
*atom = reply->atom;
|
||||
else
|
||||
} else {
|
||||
*atom = XCB_NONE;
|
||||
}
|
||||
free(reply);
|
||||
}
|
||||
|
||||
|
@ -843,9 +657,11 @@ 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)
|
||||
{
|
||||
for (uint32_t i = 0; i < protocols->atoms_len; i++)
|
||||
if (protocols->atoms[i] == atom)
|
||||
for (uint32_t i = 0; i < protocols->atoms_len; i++) {
|
||||
if (protocols->atoms[i] == atom) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
25
window.h
25
window.h
|
@ -34,25 +34,19 @@
|
|||
void schedule_window(xcb_window_t win);
|
||||
void manage_window(xcb_window_t win, rule_consequence_t *csq, int fd);
|
||||
void unmanage_window(xcb_window_t win);
|
||||
void window_draw_border(node_t *n, bool focused_window, bool focused_monitor);
|
||||
void initialize_presel_feedback(node_t *n);
|
||||
void draw_presel_feedback(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void refresh_presel_feebacks_in(node_t *n, desktop_t *d, monitor_t *m);
|
||||
void update_colors(void);
|
||||
void update_colors_in(node_t *n, desktop_t *d, monitor_t *m);
|
||||
void draw_border(node_t *n, bool focused_node, bool focused_monitor);
|
||||
void window_draw_border(xcb_window_t win, uint32_t border_color_pxl);
|
||||
pointer_state_t *make_pointer_state(void);
|
||||
bool contains(xcb_rectangle_t a, xcb_rectangle_t b);
|
||||
xcb_rectangle_t get_rectangle(monitor_t *m, client_t *c);
|
||||
void get_side_handle(client_t *c, direction_t dir, xcb_point_t *pt);
|
||||
void adopt_orphans(void);
|
||||
void window_close(node_t *n);
|
||||
void window_kill(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void set_layer(monitor_t *m, desktop_t *d, node_t *n, stack_layer_t l);
|
||||
void set_state(monitor_t *m, desktop_t *d, node_t *n, client_state_t s);
|
||||
void set_floating(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_fullscreen(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void neutralize_obscuring_windows(monitor_t *m, desktop_t *d, node_t *n);
|
||||
void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_sticky(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_private(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
void set_urgency(monitor_t *m, desktop_t *d, node_t *n, bool value);
|
||||
uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor);
|
||||
void update_floating_rectangle(client_t *c);
|
||||
uint32_t get_border_color(bool focused_node, bool focused_monitor);
|
||||
void update_floating_rectangle(node_t *n);
|
||||
void restrain_floating_width(client_t *c, int *width);
|
||||
void restrain_floating_height(client_t *c, int *height);
|
||||
void restrain_floating_size(client_t *c, int *width, int *height);
|
||||
|
@ -70,7 +64,6 @@ 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);
|
||||
|
|
Loading…
Add table
Reference in a new issue