MANPREFIX = $(PREFIX)/share/man
CPLPREFIX = $(PREFIX)/share/bash-completion/completions
-WM_SRC = bspwm.c events.c messages.c ewmh.c settings.c helpers.c tree.c types.c rules.c window.c
+WM_SRC = bspwm.c helpers.c settings.c types.c tree.c events.c window.c messages.c query.c restore.c rules.c ewmh.c
WM_OBJ = $(WM_SRC:.c=.o)
CL_SRC = bspc.c helpers.c
CL_OBJ = $(CL_SRC:.c=.o)
*bspwm* [*-h*|*-v*|*-s* 'PANEL_FIFO'|*-p* 'PANEL_PREFIX']
-*bspc* 'MESSAGE' ['ARGUMENTS'] ['OPTIONS']
+*bspc* 'COMMAND' ['ARGUMENTS']
Description
-----------
It is controlled and configured via *bspc*.
+
+Options
+-------
+
+*-h*::
+ Print the synopsis and exit.
+
+*-v*::
+ Print the version and exit.
+
+*-s* 'PANEL_FIFO'::
+ Write the internal state to the given FIFO.
+
+*-p* 'PANEL_PREFIX'::
+ Start every line written to the 'PANEL_FIFO' with the given prefix.
+
+
Configuration
-------------
Splitting Modes
---------------
+New windows are inserted in the tree as close as possible to the focused window.
+
There is only two splitting modes: 'automatic' and 'manual'.
-The default mode is 'automatic'. The 'manual' mode is entered by sending a *presel* message.
+The default mode is 'automatic'. The 'manual' mode is entered by sending a *preselection* message.
Example: insertion of a new node (number 4) into the given tree in 'automatic' mode:
+-------------------------+ +-------------------------+
----
-Same departure, but the mode is 'manual', and a *presel* 'up' message was sent beforehand:
+Same departure, but the mode is 'manual', and a *window --presel up* message was sent beforehand:
----
b b
Each desktop contains at most one tree.
-Messages
+
+Definitions
+-----------
+
+----
+WINDOW_SEL := (CYCLE|DIR|biggest|focused|last)[.WINDOW_CLASS] | <window_id>
+DESKTOP_SEL := (CYCLE|focused|last)[.DESKTOP_CLASS] | <desktop_name>
+MONITOR_SEL := (CYCLE|DIR|focused|last)[.DESKTOP_CLASS] | <monitor_name>
+
+DESKTOP_CLASS := [occupied|free]
+WINDOW_CLASS := [floating|tiled][.][like|unlike]
+
+DIR := left|right|up|down
+CYCLE := next|prev
+ROTATE := 90|270|180
+FLIP := horizontal|vertical
+----
+
+Commands
--------
+Window
+~~~~~~
-*get* 'SETTING'::
- Return the value of the given setting.
+General Syntax
+^^^^^^^^^^^^^^
-*set* 'SETTING' 'VALUE'::
- Set the value of the given setting.
+window ['WINDOW_SEL'] 'OPTIONS'
-*list* ['DESKTOP_NAME']::
- Output the internal representation of the window tree.
+Options
+^^^^^^^
+*-f*, *--focus* ['WINDOW_SEL']::
+ Focus the selected or given window.
-*list_desktops* [*--quiet*]::
- Perform a dump of each desktop for the current monitor.
+*-d*, *--to-desktop* 'DESKTOP_SEL'::
+ Send the selected window to the given desktop.
-*list_monitors* [*--quiet*]::
- Perform a dump of each monitor.
+*-m*, *--to-monitor* 'MONITOR_SEL'::
+ Send the selected window to the given monitor.
-*list_history*::
- Return the node focus history of each desktop.
+*-w*, *--to-window* 'WINDOW_SEL'::
+ Transplant the selected window to the given window.
-*list_windows*::
- Return the list of managed windows (i.e. their identifiers).
+*-s*, *--swap* 'WINDOW_SEL'::
+ Swap the selected window with the given window.
-*list_rules*::
- Return the list of rules.
+*-p*, *--presel* 'DIR'|cancel::
+ Preselect the splitting area of the selected window (or cancel the preselection).
-*presel* 'left'|'right'|'up'|'down' ['SPLIT_RATIO']::
- Switch to manual mode and select the splitting direction.
+*-r*, *--ratio* 'RATIO'::
+ Set the splitting ratio of the selected window.
-*cancel* [*--all*]::
- Switch to automatic mode.
+*-e*, *--edge* 'DIR' 'RATIO'|pull|push::
+ Set the splitting ratio (or pull, or push) the edge located in the given direction in relation to the selected window.
-*ratio* 'VALUE'::
- Set the splitting ratio of the focused window.
+*-t*, *--toggle* floating|fullscreen|locked[=on|off]::
+ Set or toggle the given state for the selected window.
-*pad* 'MONITOR_NAME' ['TOP_PADDING' ['RIGHT_PADDING' ['BOTTOM_PADDING' ['LEFT_PADDING']]]]::
- Set the padding of the given monitor.
+*-c*, *--close*::
+ Close the selected window.
-*focus* 'left'|'right'|'up'|'down'::
- Focus the neighbor window situated in the given direction.
+*-k*, *--kill*::
+ Kill the selected window.
-*shift* 'left'|'right'|'up'|'down'::
- Exchange the current window with the given neighbor.
+Desktop
+~~~~~~~
-*swap* [*--keep-focus*]::
- Swap the focused window with the last focused window.
+General Syntax
+^^^^^^^^^^^^^^
-*push* 'left'|'right'|'up'|'down'::
- Push the fence located in the given direction.
+desktop ['DESKTOP_SEL'] 'OPTIONS'
-*pull* 'left'|'right'|'up'|'down'::
- Pull the fence located in the given direction.
+Options
+^^^^^^^
+*-f*, *--focus* ['DESKTOP_SEL']::
+ Focus the selected or given desktop.
-*fence_ratio* 'left'|'right'|'up'|'down' 'RATIO'::
- Set the splitting ratio of the fence located in the given direction.
+*-m*, *--to-monitor* 'MONITOR_SEL'::
+ Send the selected desktop to the given monitor.
-*cycle* 'next'|'prev' [*--skip-floating*|*--skip-tiled*|*--skip-class-equal*|*--skip-class-differ*]::
- Focus the next or previous window matching the given constraints.
+*-l*, *--layout* 'CYCLE'|monocle|tiled::
+ Set or cycle the layout of the selected desktop.
-*nearest* 'older'|'newer' [*--skip-floating*|*--skip-tiled*|*--skip-class-equal*|*--skip-class-differ*]::
- Focus the nearest window matching the given constraints.
+*-n*, *--rename* <new_name>::
+ Rename the selected desktop.
-*biggest*::
- Return the ID of the biggest tiled window.
+*-r*, *--remove*::
+ Remove the selected desktop.
-*circulate* 'forward'|'backward'::
- Circulate the leaves in the given direction.
+*-c*, *--cancel-presel*::
+ Cancel the preselection of all the windows of the selected desktop.
-*grab_pointer* 'focus'|'move'|'resize_side'|'resize_corner'::
- Begin the specified pointer action.
+*-F*, *--flip* 'FLIP'::
+ Flip the tree of the selected desktop.
-*track_pointer* 'ROOT_X' 'ROOT_Y'::
- Pass the pointer root coordinates for the current pointer action.
+*-R*, *--rotate* 'ROTATE'::
+ Rotate the tree of the selected desktop.
-*toggle_fullscreen*::
- Toggle the fullscreen state of the current window.
+*-B*, *--balance*::
+ Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area.
-*toggle_floating*::
- Toggle the floating state of the current window.
+*-C*, *--circulate* forward|backward::
+ Circulate the leaves of the tree of the selected desktop.
-*toggle_locked*::
- Toggle the locked state of the current window (locked windows will not respond to the *close* message).
+Monitor
+~~~~~~~
-*toggle_visibility*::
- Toggle the visibility of all the managed windows.
+General Syntax
+^^^^^^^^^^^^^^
-*close*::
- Close the focused window.
+monitor ['MONITOR_SEL'] 'OPTIONS'
-*kill*::
- Kill the focused window.
+Options
+^^^^^^^
+*-f*, *--focus* ['MONITOR_SEL']::
+ Focus the selected or given monitor.
-*send_to* 'DESKTOP_NAME' [*--follow*]::
- Send the focused window to the given desktop.
+*-a*, *--add-desktops* <name>...::
+ Create desktops with the given names in the selected monitor.
-*drop_to* 'next'|'prev' [*--follow*]::
- Send the focused window to the next or previous desktop.
+*-r*, *--remove-desktops* <name>...::
+ Remove desktops with the given names.
-*send_to_monitor* 'MONITOR_NAME' [*--follow*]::
- Send the focused window to the given monitor.
+*-p*, *--pad* <top> <right> <bottom> <left>::
+ Set the padding of the selected monitor.
-*drop_to_monitor* 'next'|'prev' [*--follow*]::
- Send the focused window to the next or previous monitor.
+*-n*, *--rename* <new_name>::
+ Rename the selected monitor.
-*use* 'DESKTOP_NAME'::
- Select the given desktop.
+Query
+~~~~~
-*use_monitor* 'MONITOR_NAME'::
- Select the given monitor.
+General Syntax
+^^^^^^^^^^^^^^
-*focus_monitor* 'left'|'right'|'up'|'down'::
- Focus the nearest monitor in the given direction.
+query 'OPTIONS'
-*alternate*::
- Alternate between the current and the last focused window.
+Options
+^^^^^^^
+*-W*, *--windows*::
+ List matching windows.
-*alternate_desktop*::
- Alternate between the current and the last focused desktop.
+*-D*, *--desktops*::
+ List matching desktops.
-*alternate_monitor*::
- Alternate between the current and the last focused monitor.
+*-M*, *--monitors*::
+ List matching monitors.
-*add* 'DESKTOP_NAME' ...::
- Make new desktops with the given names.
+*-T*, *--tree*::
+ Print tree rooted at query.
-*add_in* 'MONITOR_NAME' 'DESKTOP_NAME' ...::
- Make new desktops with the given names in the given monitor.
+*-H*, *--history*::
+ Print the history as it relates to the query.
-*rename_monitor* 'CURRENT_NAME' 'NEW_NAME'::
- Rename the monitor named 'CURRENT_NAME' to 'NEW_NAME'.
+[*-m*,*--monitor* ['MONITOR_SEL']] | [*-d*,*--desktop* ['DESKTOP_SEL']] | [*-w*, *--window* ['WINDOW_SEL']]::
+ Constrain matches to the selected monitor, desktop or window.
-*rename* 'CURRENT_NAME' 'NEW_NAME'::
- Rename the desktop named 'CURRENT_NAME' to 'NEW_NAME'.
+Restore
+~~~~~~~
-*remove_desktop* 'DESKTOP_NAME' ...::
- Remove the given desktops.
+General Syntax
+^^^^^^^^^^^^^^
-*send_desktop_to* 'MONITOR_NAME' [*--follow*]::
- Send the current desktop to the given monitor.
+restore 'OPTIONS'
+
+Options
+^^^^^^^
+
+*-T*, *--tree* <file_path>::
+ Load the desktop trees from the given file.
+
+*-H*, *--history* <file_path>::
+ Load the focus history from the given file.
+
+Control
+~~~~~~~
+
+General Syntax
+^^^^^^^^^^^^^^
+
+control 'OPTIONS'
+
+Options
+^^^^^^^
+
+*--adopt-orphans* <file_path>::
+ Manage all the unmanaged windows remaining from a previous session.
+
+*--put-status* <file_path>::
+ Write the current internal state to the panel FIFO.
+
+*--toggle-visibility*::
+ Toggle the visibility of all the managed windows.
+
+Pointer
+~~~~~~~
+
+General Syntax
+^^^^^^^^^^^^^^
+
+pointer 'OPTIONS'
+
+Options
+^^^^^^^
+
+*-t*, *--track* <x> <y>::
+ Pass the pointer root coordinates for the current pointer action.
-*cycle_monitor* 'next'|'prev'::
- Select the next or previous monitor.
+*-g*, *--grab* focus|move|resize_side|resize_corner::
+ Perform the given pointer action.
-*cycle_desktop* 'next'|'prev' [*--skip-free*|*--skip-occupied*]::
- Select the next or previous desktop.
+Rule
+~~~~
-*layout* 'monocle'|'tiled' ['DESKTOP_NAME' ...]::
- Set the layout of the given desktops (current if none given).
+General Syntax
+^^^^^^^^^^^^^^
-*cycle_layout*::
- Cycle the layout of the current desktop.
+rule 'OPTIONS'
-*rotate* 'clockwise'|'counter_clockwise'|'full_cycle'::
- Rotate the window tree.
+Options
+^^^^^^^
-*flip* 'horizontal'|'vertical'::
- Flip the window tree.
+*-a*, *--add* <pattern> [-d 'DESKTOP_SEL'] [--floating] [--follow]::
+ Create a new rule (<pattern> must match the class or instance name).
-*balance*::
- Adjust the split ratios so that all windows occupy the same area.
+*-r*, *--rm* <rule_uid>...::
+ Remove the rules with the given UIDs.
-*rule* 'PATTERN' ['DESKTOP_NAME'] ['floating'] ['follow']::
- Create a new rule ('PATTERN' must match the class or instance name).
+*-l*, *--list* [<pattern>]::
+ List the rules.
-*remove_rule* 'UID' ...::
- Remove the rules with the given 'UIDs'.
+Config
+~~~~~~
-*put_status*::
- Output the current state to the panel fifo.
+General Syntax
+^^^^^^^^^^^^^^
-*adopt_orphans*::
- Manage all the unmanaged windows remaining from a previous session.
+config <key> [<value>]::
+ Get or set the value of <key>.
-*restore_layout* 'FILE_PATH'::
- Restore the layout of each desktop from the content of 'FILE_PATH'.
+Quit
+~~~~
-*restore_history* 'FILE_PATH'::
- Restore the history of each desktop from the content of 'FILE_PATH'.
+General Syntax
+^^^^^^^^^^^^^^
-*quit* ['EXIT_STATUS']::
- Quit.
+quit [<status>]::
+ Quit with an optional exit status.
Settings
--------
* Configured and controlled through messages.
* Multiple monitors support (via 'RandR').
* EWMH support (*tint2* works).
-* Automatic and manual modes.
+* Hybrid tiling.
Contributors
------------
events.o: events.c bspwm.h events.h ewmh.h helpers.h rules.h settings.h tree.h types.h window.h
ewmh.o: ewmh.c bspwm.h ewmh.h helpers.h settings.h tree.h types.h
helpers.o: helpers.c bspwm.h helpers.h types.h
-messages.o: messages.c bspwm.h common.h events.h ewmh.h helpers.h messages.h rules.h settings.h tree.h types.h window.h
+messages.o: messages.c bspwm.h common.h events.h ewmh.h helpers.h messages.h query.h restore.h rules.h settings.h tree.h types.h window.h
+query.o: query.c bspwm.h helpers.h query.h tree.h types.h
+restore.o: restore.c bspwm.h ewmh.h helpers.h restore.h settings.h tree.h types.h
rules.o: rules.c bspwm.h ewmh.h helpers.h rules.h types.h
settings.o: settings.c bspwm.h common.h helpers.h settings.h types.h
tree.o: tree.c bspwm.h ewmh.h helpers.h settings.h tree.h types.h window.h
_bspc()
{
- local messages='get set list list_desktops list_monitors list_windows list_rules list_history presel cancel ratio pad focus shift swap push pull fence_ratio cycle nearest biggest circulate grab_pointer track_pointer toggle_fullscreen toggle_floating toggle_locked toggle_visibility close kill send_to drop_to send_to_monitor drop_to_monitor use use_monitor focus_monitor alternate alternate_desktop alternate_monitor add add_in rename_monitor rename remove_desktop send_desktop_to cycle_monitor cycle_desktop layout cycle_layout rotate flip balance rule remove_rule put_status adopt_orphans restore_layout restore_history quit'
+ local messages='window desktop monitor query pointer rule restore control config quit'
local settings='focused_border_color active_border_color normal_border_color presel_border_color focused_locked_border_color active_locked_border_color normal_locked_border_color urgent_border_color border_width window_gap split_ratio top_padding right_padding bottom_padding left_padding wm_name borderless_monocle gapless_monocle focus_follows_pointer pointer_follows_monitor monitor_focus_fallback adaptative_raise apply_shadow_property auto_alternate auto_cancel focus_by_distance history_aware_focus'
else
local second_word=${COMP_WORDS[1]}
case $second_word in
- set|get)
+ config)
if [[ $COMP_CWORD -eq 2 ]] ; then
COMPREPLY=( $(compgen -W "$settings" -- "$current_word") )
fi
{
int sock_fd;
struct sockaddr_un sock_address;
- size_t msglen = 0;
char msg[BUFSIZ];
char rsp[BUFSIZ];
err("No arguments given.\n");
char *sock_path = getenv(SOCKET_ENV_VAR);
- if (sock_path == NULL || strlen(sock_path) == 0)
- warn("The environment variable '%s' is not set or empty, we will use: '%s'.\n", SOCKET_ENV_VAR, DEFAULT_SOCKET_PATH);
- else if (sizeof(sock_address.sun_path) <= strlen(sock_path))
- err("The string can't fit in the socket address: '%s'.\n", sock_path);
+ if (sock_path != NULL && sizeof(sock_address.sun_path) <= strlen(sock_path))
+ err("The socket path can't fit into the socket address.\n");
sock_address.sun_family = AF_UNIX;
strncpy(sock_address.sun_path, (sock_path == NULL ? DEFAULT_SOCKET_PATH : sock_path), sizeof(sock_address.sun_path));
sock_address.sun_path[sizeof(sock_address.sun_path) - 1] = 0;
- for (int offset = 0, len = sizeof(msg), n = 0; --argc && ++argv && len > 0; offset += n, len -= n)
- n = snprintf(msg + offset, len, "%s ", *argv);
+ argc--, argv++;
+ int msg_len = 0;
- msglen = strlen(msg);
- if (msg[msglen - 1] == ' ')
- msg[--msglen] = '\0';
+ for (int offset = 0, rem = sizeof(msg), n = 0; argc > 0 && rem > 0; offset += n, msg_len = offset, rem -= n, argc--, argv++) {
+ n = snprintf(msg + offset, rem, "%s%c", *argv, 0);
+ msg_len += n;
+ }
- sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (sock_fd == -1)
+ if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
err("Failed to create the socket.\n");
if (connect(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1)
err("Failed to connect to the socket.\n");
- if (send(sock_fd, msg, msglen, 0) == -1)
+ if (send(sock_fd, msg, msg_len, 0) == -1)
err("Failed to send the data.\n");
+ int ret = EXIT_SUCCESS;
+
int n = recv(sock_fd, rsp, sizeof(rsp), 0);
if (n == -1) {
err("Failed to get the response.\n");
} else if (n > 0) {
- rsp[n] = '\0';
- printf("%s\n", rsp);
+ if (n == 1 && rsp[0] == MESSAGE_FAILURE) {
+ ret = EXIT_FAILURE;
+ } else {
+ rsp[n] = '\0';
+ printf("%s\n", rsp);
+ }
}
if (sock_fd)
close(sock_fd);
- return EXIT_SUCCESS;
+ return ret;
}
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
#include <xcb/xcb.h>
#include <xcb/xcb_event.h>
#include <xcb/xcb_ewmh.h>
#include "tree.h"
#include "ewmh.h"
-void quit(void)
-{
- running = false;
-}
-
-void cleanup(void)
-{
- while (mon_head != NULL)
- remove_monitor(mon_head);
- while (rule_head != NULL)
- remove_rule(rule_head);
- free(frozen_pointer);
-}
-
-void register_events(void)
-{
- uint32_t values[] = {ROOT_EVENT_MASK};
- xcb_generic_error_t *e = xcb_request_check(dpy, xcb_change_window_attributes_checked(dpy, root, XCB_CW_EVENT_MASK, values));
- if (e != NULL) {
- xcb_disconnect(dpy);
- err("Another window manager is already running.\n");
- }
-}
-
-bool import_monitors(void)
-{
- PUTS("import monitors");
- xcb_randr_get_screen_resources_current_reply_t *sres = xcb_randr_get_screen_resources_current_reply(dpy, xcb_randr_get_screen_resources_current(dpy, root), NULL);
- if (sres == NULL)
- return false;
-
- int len = xcb_randr_get_screen_resources_current_outputs_length(sres);
- xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres);
-
- xcb_randr_get_output_info_cookie_t cookies[len];
- for (int i = 0; i < len; i++)
- cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
-
- for (monitor_t *m = mon_head; m != NULL; m = m->next)
- m->wired = false;
-
- monitor_t *mm = NULL;
- unsigned int num = 0;
-
- 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);
- if (info != NULL && info->crtc != XCB_NONE) {
-
- xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL);
- if (cir != NULL) {
- 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) {
- mm->rectangle = 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))
- fit_monitor(mm, n->client);
- arrange(mm, mm->desk);
- mm->wired = true;
- PRINTF("update monitor %s (0x%X)\n", mm->name, mm->id);
- } else {
- mm = add_monitor(&rect);
- char *name = (char *)xcb_randr_get_output_info_name(info);
- size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info));
- strncpy(mm->name, name, name_len);
- mm->name[name_len] = '\0';
- mm->id = outputs[i];
- add_desktop(mm, make_desktop(NULL));
- PRINTF("add monitor %s (0x%X)\n", mm->name, mm->id);
- }
- num++;
- }
- free(cir);
- }
- free(info);
- }
-
- monitor_t *m = mon_head;
- while (m != NULL) {
- monitor_t *next = m->next;
- if (!m->wired) {
- PRINTF("remove monitor %s (0x%X)\n", m->name, m->id);
- merge_monitors(m, mm);
- remove_monitor(m);
- }
- m = next;
- }
-
- free(sres);
- update_motion_recorder();
- return (num_monitors > 0);
-}
-
-void init(void)
-{
- num_monitors = num_desktops = num_clients = 0;
- monitor_uid = desktop_uid = client_uid = rule_uid = 0;
- mon = last_mon = mon_head = mon_tail = NULL;
- rule_head = rule_tail = NULL;
- status_fifo = NULL;
- randr_base = 0;
- visible = true;
- exit_status = 0;
-}
-
-void setup(void)
-{
- init();
- ewmh_init();
- screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
- 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;
-
- uint32_t mask = XCB_CW_EVENT_MASK;
- uint32_t values[] = {XCB_EVENT_MASK_POINTER_MOTION};
- motion_recorder = xcb_generate_id(dpy);
- xcb_create_window(dpy, XCB_COPY_FROM_PARENT, motion_recorder, root, 0, 0, screen_width, screen_height, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, mask, values);
-
- xcb_atom_t net_atoms[] = {ewmh->_NET_SUPPORTED,
- ewmh->_NET_DESKTOP_NAMES,
- ewmh->_NET_NUMBER_OF_DESKTOPS,
- ewmh->_NET_CURRENT_DESKTOP,
- ewmh->_NET_CLIENT_LIST,
- ewmh->_NET_ACTIVE_WINDOW,
- ewmh->_NET_WM_DESKTOP,
- ewmh->_NET_WM_STATE,
- ewmh->_NET_WM_STATE_FULLSCREEN,
- ewmh->_NET_WM_STATE_DEMANDS_ATTENTION,
- ewmh->_NET_WM_WINDOW_TYPE,
- ewmh->_NET_WM_WINDOW_TYPE_DOCK,
- ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION,
- ewmh->_NET_WM_WINDOW_TYPE_DIALOG,
- ewmh->_NET_WM_WINDOW_TYPE_UTILITY,
- ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR};
-
- xcb_ewmh_set_supported(ewmh, default_screen, LENGTH(net_atoms), net_atoms);
-
- xcb_intern_atom_reply_t *iar = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen("_COMPTON_SHADOW"), "_COMPTON_SHADOW"), NULL);
-
- if (iar != NULL) {
- compton_shadow = iar->atom;
- free(iar);
- }
-
- const xcb_query_extension_reply_t *qep = xcb_get_extension_data(dpy, &xcb_randr_id);
- if (qep->present && import_monitors()) {
- randr = true;
- randr_base = qep->first_event;
- xcb_randr_select_input(dpy, root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
- } else {
- randr = false;
- warn("Couldn't retrieve monitors via RandR.\n");
- xcb_rectangle_t rect = (xcb_rectangle_t) {0, 0, screen_width, screen_height};
- monitor_t *m = add_monitor(&rect);
- add_desktop(m, make_desktop(NULL));
- }
-
- ewmh_update_number_of_desktops();
- ewmh_update_desktop_names();
- ewmh_update_current_desktop();
- frozen_pointer = make_pointer_state();
-}
-
int main(int argc, char *argv[])
{
fd_set descriptors;
status_prefix = NULL;
int sock_fd, ret_fd, dpy_fd, sel, n;
struct sockaddr_un sock_address;
- size_t rsplen = 0;
+ size_t rsp_len = 0;
char msg[BUFSIZ] = {0};
char rsp[BUFSIZ] = {0};
xcb_generic_event_t *event;
ret_fd = accept(sock_fd, NULL, 0);
if (ret_fd > 0 && (n = recv(ret_fd, msg, sizeof(msg), 0)) > 0) {
msg[n] = '\0';
- process_message(msg, rsp);
- rsplen = strlen(rsp);
- if (rsp[rsplen - 1] == '\n')
- rsp[--rsplen] = '\0';
- send(ret_fd, rsp, rsplen, 0);
+ if (handle_message(msg, n, rsp)) {
+ rsp_len = strlen(rsp);
+ if (rsp[rsp_len - 1] == '\n')
+ rsp[--rsp_len] = '\0';
+ } else {
+ rsp[0] = MESSAGE_FAILURE;
+ rsp_len = 1;
+ }
+ send(ret_fd, rsp, rsp_len, 0);
close(ret_fd);
rsp[0] = '\0';
}
xcb_disconnect(dpy);
return exit_status;
}
+
+void init(void)
+{
+ num_monitors = num_desktops = num_clients = 0;
+ monitor_uid = desktop_uid = rule_uid = 0;
+ mon = last_mon = mon_head = mon_tail = NULL;
+ rule_head = rule_tail = NULL;
+ status_fifo = NULL;
+ randr_base = 0;
+ visible = true;
+ exit_status = 0;
+}
+
+void setup(void)
+{
+ init();
+ ewmh_init();
+ screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
+ 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;
+
+ uint32_t mask = XCB_CW_EVENT_MASK;
+ uint32_t values[] = {XCB_EVENT_MASK_POINTER_MOTION};
+ motion_recorder = xcb_generate_id(dpy);
+ xcb_create_window(dpy, XCB_COPY_FROM_PARENT, motion_recorder, root, 0, 0, screen_width, screen_height, 0, XCB_WINDOW_CLASS_INPUT_ONLY, XCB_COPY_FROM_PARENT, mask, values);
+
+ xcb_atom_t net_atoms[] = {ewmh->_NET_SUPPORTED,
+ ewmh->_NET_DESKTOP_NAMES,
+ ewmh->_NET_NUMBER_OF_DESKTOPS,
+ ewmh->_NET_CURRENT_DESKTOP,
+ ewmh->_NET_CLIENT_LIST,
+ ewmh->_NET_ACTIVE_WINDOW,
+ ewmh->_NET_WM_DESKTOP,
+ ewmh->_NET_WM_STATE,
+ ewmh->_NET_WM_STATE_FULLSCREEN,
+ ewmh->_NET_WM_STATE_DEMANDS_ATTENTION,
+ ewmh->_NET_WM_WINDOW_TYPE,
+ ewmh->_NET_WM_WINDOW_TYPE_DOCK,
+ ewmh->_NET_WM_WINDOW_TYPE_NOTIFICATION,
+ ewmh->_NET_WM_WINDOW_TYPE_DIALOG,
+ ewmh->_NET_WM_WINDOW_TYPE_UTILITY,
+ ewmh->_NET_WM_WINDOW_TYPE_TOOLBAR};
+
+ xcb_ewmh_set_supported(ewmh, default_screen, LENGTH(net_atoms), net_atoms);
+
+ xcb_intern_atom_reply_t *iar = xcb_intern_atom_reply(dpy, xcb_intern_atom(dpy, 0, strlen("_COMPTON_SHADOW"), "_COMPTON_SHADOW"), NULL);
+
+ if (iar != NULL) {
+ compton_shadow = iar->atom;
+ free(iar);
+ }
+
+ const xcb_query_extension_reply_t *qep = xcb_get_extension_data(dpy, &xcb_randr_id);
+ if (qep->present && import_monitors()) {
+ randr = true;
+ randr_base = qep->first_event;
+ xcb_randr_select_input(dpy, root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE);
+ } else {
+ randr = false;
+ warn("Couldn't retrieve monitors via RandR.\n");
+ xcb_rectangle_t rect = (xcb_rectangle_t) {0, 0, screen_width, screen_height};
+ monitor_t *m = add_monitor(&rect);
+ add_desktop(m, make_desktop(NULL));
+ }
+
+ ewmh_update_number_of_desktops();
+ ewmh_update_desktop_names();
+ ewmh_update_current_desktop();
+ frozen_pointer = make_pointer_state();
+}
+
+void register_events(void)
+{
+ uint32_t values[] = {ROOT_EVENT_MASK};
+ xcb_generic_error_t *e = xcb_request_check(dpy, xcb_change_window_attributes_checked(dpy, root, XCB_CW_EVENT_MASK, values));
+ if (e != NULL) {
+ xcb_disconnect(dpy);
+ err("Another window manager is already running.\n");
+ }
+}
+
+bool import_monitors(void)
+{
+ PUTS("import monitors");
+ xcb_randr_get_screen_resources_current_reply_t *sres = xcb_randr_get_screen_resources_current_reply(dpy, xcb_randr_get_screen_resources_current(dpy, root), NULL);
+ if (sres == NULL)
+ return false;
+
+ int len = xcb_randr_get_screen_resources_current_outputs_length(sres);
+ xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(sres);
+
+ xcb_randr_get_output_info_cookie_t cookies[len];
+ for (int i = 0; i < len; i++)
+ cookies[i] = xcb_randr_get_output_info(dpy, outputs[i], XCB_CURRENT_TIME);
+
+ for (monitor_t *m = mon_head; m != NULL; m = m->next)
+ m->wired = false;
+
+ monitor_t *mm = NULL;
+ unsigned int num = 0;
+
+ 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);
+ if (info != NULL && info->crtc != XCB_NONE) {
+
+ xcb_randr_get_crtc_info_reply_t *cir = xcb_randr_get_crtc_info_reply(dpy, xcb_randr_get_crtc_info(dpy, info->crtc, XCB_CURRENT_TIME), NULL);
+ if (cir != NULL) {
+ 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) {
+ mm->rectangle = 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))
+ fit_monitor(mm, n->client);
+ arrange(mm, mm->desk);
+ mm->wired = true;
+ PRINTF("update monitor %s (0x%X)\n", mm->name, mm->id);
+ } else {
+ mm = add_monitor(&rect);
+ char *name = (char *)xcb_randr_get_output_info_name(info);
+ size_t name_len = MIN(sizeof(mm->name), (size_t)xcb_randr_get_output_info_name_length(info));
+ strncpy(mm->name, name, name_len);
+ mm->name[name_len] = '\0';
+ mm->id = outputs[i];
+ add_desktop(mm, make_desktop(NULL));
+ PRINTF("add monitor %s (0x%X)\n", mm->name, mm->id);
+ }
+ num++;
+ }
+ free(cir);
+ }
+ free(info);
+ }
+
+ monitor_t *m = mon_head;
+ while (m != NULL) {
+ monitor_t *next = m->next;
+ if (!m->wired) {
+ PRINTF("remove monitor %s (0x%X)\n", m->name, m->id);
+ merge_monitors(m, mm);
+ remove_monitor(m);
+ }
+ m = next;
+ }
+
+ free(sres);
+ update_motion_recorder();
+ return (num_monitors > 0);
+}
+
+void quit(void)
+{
+ running = false;
+}
+
+void cleanup(void)
+{
+ while (mon_head != NULL)
+ remove_monitor(mon_head);
+ while (rule_head != NULL)
+ remove_rule(rule_head);
+ free(frozen_pointer);
+}
+
+void put_status(void)
+{
+ if (status_fifo == NULL)
+ return;
+ if (status_prefix != NULL)
+ fprintf(status_fifo, "%s", status_prefix);
+ bool urgent = false;
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+ fprintf(status_fifo, "%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))
+ urgent |= n->client->urgent;
+ fprintf(status_fifo, "%c%s:", m->desk == d ? (urgent ? 'U' : 'D') : (d->root == NULL ? 'E' : (urgent ? 'u' : 'd')), d->name);
+ }
+ }
+ if (mon != NULL && mon->desk != NULL)
+ fprintf(status_fifo, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
+ fprintf(status_fifo, "\n");
+ fflush(status_fifo);
+}
unsigned int num_monitors;
unsigned int monitor_uid;
unsigned int desktop_uid;
-unsigned int client_uid;
unsigned int rule_uid;
xcb_screen_t *screen;
xcb_window_t root;
bool import_monitors(void);
void init(void);
void setup(void);
+void put_status(void);
void cleanup(void);
void quit(void);
#define DEFAULT_SOCKET_PATH "/tmp/bspwm-socket"
#define SOCKET_ENV_VAR "BSPWM_SOCKET"
+#define MESSAGE_FAILURE '\x18'
#endif
- Externalize rules?
-- Use macros in `messages.c`.
.\" Title: bspwm
.\" Author: [see the "Author" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 07/05/2013
+.\" Date: 07/12/2013
.\" Manual: Bspwm Manual
.\" Source: Bspwm 0.7
.\" Language: English
.\"
-.TH "BSPWM" "1" "07/05/2013" "Bspwm 0\&.7" "Bspwm Manual"
+.TH "BSPWM" "1" "07/12/2013" "Bspwm 0\&.7" "Bspwm Manual"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.sp
\fBbspwm\fR [\fB\-h\fR|\fB\-v\fR|\fB\-s\fR \fIPANEL_FIFO\fR|\fB\-p\fR \fIPANEL_PREFIX\fR]
.sp
-\fBbspc\fR \fIMESSAGE\fR [\fIARGUMENTS\fR] [\fIOPTIONS\fR]
+\fBbspc\fR \fICOMMAND\fR [\fIARGUMENTS\fR]
.SH "DESCRIPTION"
.sp
\fBbspwm\fR is a tiling window manager that represents windows as the leaves of a full binary tree\&.
.sp
It is controlled and configured via \fBbspc\fR\&.
+.SH "OPTIONS"
+.PP
+\fB\-h\fR
+.RS 4
+Print the synopsis and exit\&.
+.RE
+.PP
+\fB\-v\fR
+.RS 4
+Print the version and exit\&.
+.RE
+.PP
+\fB\-s\fR \fIPANEL_FIFO\fR
+.RS 4
+Write the internal state to the given FIFO\&.
+.RE
+.PP
+\fB\-p\fR \fIPANEL_PREFIX\fR
+.RS 4
+Start every line written to the
+\fIPANEL_FIFO\fR
+with the given prefix\&.
+.RE
.SH "CONFIGURATION"
.sp
\fBbspwm\fR have only two sources of informations: the X events it receives and the messages it reads on a dedicated socket\&.
Example configuration files can be found in the \fBexamples\fR directory\&.
.SH "SPLITTING MODES"
.sp
+New windows are inserted in the tree as close as possible to the focused window\&.
+.sp
There is only two splitting modes: \fIautomatic\fR and \fImanual\fR\&.
.sp
-The default mode is \fIautomatic\fR\&. The \fImanual\fR mode is entered by sending a \fBpresel\fR message\&.
+The default mode is \fIautomatic\fR\&. The \fImanual\fR mode is entered by sending a \fBpreselection\fR message\&.
.sp
Example: insertion of a new node (number 4) into the given tree in \fIautomatic\fR mode:
.sp
.RE
.\}
.sp
-Same departure, but the mode is \fImanual\fR, and a \fBpresel\fR \fIup\fR message was sent beforehand:
+Same departure, but the mode is \fImanual\fR, and a \fBwindow \-\-presel up\fR message was sent beforehand:
.sp
.if n \{\
.RS 4
Each monitor contains at least one desktop\&.
.sp
Each desktop contains at most one tree\&.
-.SH "MESSAGES"
-.PP
-\fBget\fR \fISETTING\fR
+.SH "DEFINITIONS"
+.sp
+.if n \{\
.RS 4
-Return the value of the given setting\&.
+.\}
+.nf
+WINDOW_SEL := (CYCLE|DIR|biggest|focused|last)[\&.WINDOW_CLASS] | <window_id>
+DESKTOP_SEL := (CYCLE|focused|last)[\&.DESKTOP_CLASS] | <desktop_name>
+MONITOR_SEL := (CYCLE|DIR|focused|last)[\&.DESKTOP_CLASS] | <monitor_name>
+
+DESKTOP_CLASS := [occupied|free]
+WINDOW_CLASS := [floating|tiled][\&.][like|unlike]
+
+DIR := left|right|up|down
+CYCLE := next|prev
+ROTATE := 90|270|180
+FLIP := horizontal|vertical
+.fi
+.if n \{\
.RE
-.PP
-\fBset\fR \fISETTING\fR \fIVALUE\fR
+.\}
+.SH "COMMANDS"
+.SS "Window"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Set the value of the given setting\&.
+.sp
+window [\fIWINDOW_SEL\fR] \fIOPTIONS\fR
.RE
-.PP
-\fBlist\fR [\fIDESKTOP_NAME\fR]
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
.RS 4
-Output the internal representation of the window tree\&.
-.RE
.PP
-\fBlist_desktops\fR [\fB\-\-quiet\fR]
+\fB\-f\fR, \fB\-\-focus\fR [\fIWINDOW_SEL\fR]
.RS 4
-Perform a dump of each desktop for the current monitor\&.
+Focus the selected or given window\&.
.RE
.PP
-\fBlist_monitors\fR [\fB\-\-quiet\fR]
+\fB\-d\fR, \fB\-\-to\-desktop\fR \fIDESKTOP_SEL\fR
.RS 4
-Perform a dump of each monitor\&.
+Send the selected window to the given desktop\&.
.RE
.PP
-\fBlist_history\fR
+\fB\-m\fR, \fB\-\-to\-monitor\fR \fIMONITOR_SEL\fR
.RS 4
-Return the node focus history of each desktop\&.
+Send the selected window to the given monitor\&.
.RE
.PP
-\fBlist_windows\fR
+\fB\-w\fR, \fB\-\-to\-window\fR \fIWINDOW_SEL\fR
.RS 4
-Return the list of managed windows (i\&.e\&. their identifiers)\&.
+Transplant the selected window to the given window\&.
.RE
.PP
-\fBlist_rules\fR
+\fB\-s\fR, \fB\-\-swap\fR \fIWINDOW_SEL\fR
.RS 4
-Return the list of rules\&.
+Swap the selected window with the given window\&.
.RE
.PP
-\fBpresel\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR [\fISPLIT_RATIO\fR]
+\fB\-p\fR, \fB\-\-presel\fR \fIDIR\fR|cancel
.RS 4
-Switch to manual mode and select the splitting direction\&.
+Preselect the splitting area of the selected window (or cancel the preselection)\&.
.RE
.PP
-\fBcancel\fR [\fB\-\-all\fR]
+\fB\-r\fR, \fB\-\-ratio\fR \fIRATIO\fR
.RS 4
-Switch to automatic mode\&.
+Set the splitting ratio of the selected window\&.
.RE
.PP
-\fBratio\fR \fIVALUE\fR
+\fB\-e\fR, \fB\-\-edge\fR \fIDIR\fR \fIRATIO\fR|pull|push
.RS 4
-Set the splitting ratio of the focused window\&.
+Set the splitting ratio (or pull, or push) the edge located in the given direction in relation to the selected window\&.
.RE
.PP
-\fBpad\fR \fIMONITOR_NAME\fR [\fITOP_PADDING\fR [\fIRIGHT_PADDING\fR [\fIBOTTOM_PADDING\fR [\fILEFT_PADDING\fR]]]]
+\fB\-t\fR, \fB\-\-toggle\fR floating|fullscreen|locked[=on|off]
.RS 4
-Set the padding of the given monitor\&.
+Set or toggle the given state for the selected window\&.
.RE
.PP
-\fBfocus\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR
+\fB\-c\fR, \fB\-\-close\fR
.RS 4
-Focus the neighbor window situated in the given direction\&.
+Close the selected window\&.
.RE
.PP
-\fBshift\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR
+\fB\-k\fR, \fB\-\-kill\fR
.RS 4
-Exchange the current window with the given neighbor\&.
+Kill the selected window\&.
.RE
-.PP
-\fBswap\fR [\fB\-\-keep\-focus\fR]
-.RS 4
-Swap the focused window with the last focused window\&.
.RE
-.PP
-\fBpush\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR
+.SS "Desktop"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Push the fence located in the given direction\&.
+.sp
+desktop [\fIDESKTOP_SEL\fR] \fIOPTIONS\fR
.RE
-.PP
-\fBpull\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
.RS 4
-Pull the fence located in the given direction\&.
-.RE
.PP
-\fBfence_ratio\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR \fIRATIO\fR
+\fB\-f\fR, \fB\-\-focus\fR [\fIDESKTOP_SEL\fR]
.RS 4
-Set the splitting ratio of the fence located in the given direction\&.
+Focus the selected or given desktop\&.
.RE
.PP
-\fBcycle\fR \fInext\fR|\fIprev\fR [\fB\-\-skip\-floating\fR|\fB\-\-skip\-tiled\fR|\fB\-\-skip\-class\-equal\fR|\fB\-\-skip\-class\-differ\fR]
+\fB\-m\fR, \fB\-\-to\-monitor\fR \fIMONITOR_SEL\fR
.RS 4
-Focus the next or previous window matching the given constraints\&.
+Send the selected desktop to the given monitor\&.
.RE
.PP
-\fBnearest\fR \fIolder\fR|\fInewer\fR [\fB\-\-skip\-floating\fR|\fB\-\-skip\-tiled\fR|\fB\-\-skip\-class\-equal\fR|\fB\-\-skip\-class\-differ\fR]
+\fB\-l\fR, \fB\-\-layout\fR \fICYCLE\fR|monocle|tiled
.RS 4
-Focus the nearest window matching the given constraints\&.
+Set or cycle the layout of the selected desktop\&.
.RE
.PP
-\fBbiggest\fR
+\fB\-n\fR, \fB\-\-rename\fR <new_name>
.RS 4
-Return the ID of the biggest tiled window\&.
+Rename the selected desktop\&.
.RE
.PP
-\fBcirculate\fR \fIforward\fR|\fIbackward\fR
+\fB\-r\fR, \fB\-\-remove\fR
.RS 4
-Circulate the leaves in the given direction\&.
+Remove the selected desktop\&.
.RE
.PP
-\fBgrab_pointer\fR \fIfocus\fR|\fImove\fR|\fIresize_side\fR|\fIresize_corner\fR
+\fB\-c\fR, \fB\-\-cancel\-presel\fR
.RS 4
-Begin the specified pointer action\&.
+Cancel the preselection of all the windows of the selected desktop\&.
.RE
.PP
-\fBtrack_pointer\fR \fIROOT_X\fR \fIROOT_Y\fR
+\fB\-F\fR, \fB\-\-flip\fR \fIFLIP\fR
.RS 4
-Pass the pointer root coordinates for the current pointer action\&.
+Flip the tree of the selected desktop\&.
.RE
.PP
-\fBtoggle_fullscreen\fR
+\fB\-R\fR, \fB\-\-rotate\fR \fIROTATE\fR
.RS 4
-Toggle the fullscreen state of the current window\&.
+Rotate the tree of the selected desktop\&.
.RE
.PP
-\fBtoggle_floating\fR
+\fB\-B\fR, \fB\-\-balance\fR
.RS 4
-Toggle the floating state of the current window\&.
+Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area\&.
.RE
.PP
-\fBtoggle_locked\fR
+\fB\-C\fR, \fB\-\-circulate\fR forward|backward
.RS 4
-Toggle the locked state of the current window (locked windows will not respond to the
-\fBclose\fR
-message)\&.
+Circulate the leaves of the tree of the selected desktop\&.
.RE
-.PP
-\fBtoggle_visibility\fR
-.RS 4
-Toggle the visibility of all the managed windows\&.
.RE
-.PP
-\fBclose\fR
+.SS "Monitor"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Close the focused window\&.
+.sp
+monitor [\fIMONITOR_SEL\fR] \fIOPTIONS\fR
.RE
-.PP
-\fBkill\fR
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
.RS 4
-Kill the focused window\&.
-.RE
.PP
-\fBsend_to\fR \fIDESKTOP_NAME\fR [\fB\-\-follow\fR]
+\fB\-f\fR, \fB\-\-focus\fR [\fIMONITOR_SEL\fR]
.RS 4
-Send the focused window to the given desktop\&.
+Focus the selected or given monitor\&.
.RE
.PP
-\fBdrop_to\fR \fInext\fR|\fIprev\fR [\fB\-\-follow\fR]
+\fB\-a\fR, \fB\-\-add\-desktops\fR <name>\&...
.RS 4
-Send the focused window to the next or previous desktop\&.
+Create desktops with the given names in the selected monitor\&.
.RE
.PP
-\fBsend_to_monitor\fR \fIMONITOR_NAME\fR [\fB\-\-follow\fR]
+\fB\-r\fR, \fB\-\-remove\-desktops\fR <name>\&...
.RS 4
-Send the focused window to the given monitor\&.
+Remove desktops with the given names\&.
.RE
.PP
-\fBdrop_to_monitor\fR \fInext\fR|\fIprev\fR [\fB\-\-follow\fR]
+\fB\-p\fR, \fB\-\-pad\fR <top> <right> <bottom> <left>
.RS 4
-Send the focused window to the next or previous monitor\&.
+Set the padding of the selected monitor\&.
.RE
.PP
-\fBuse\fR \fIDESKTOP_NAME\fR
+\fB\-n\fR, \fB\-\-rename\fR <new_name>
.RS 4
-Select the given desktop\&.
+Rename the selected monitor\&.
.RE
-.PP
-\fBuse_monitor\fR \fIMONITOR_NAME\fR
-.RS 4
-Select the given monitor\&.
.RE
-.PP
-\fBfocus_monitor\fR \fIleft\fR|\fIright\fR|\fIup\fR|\fIdown\fR
+.SS "Query"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Focus the nearest monitor in the given direction\&.
+.sp
+query \fIOPTIONS\fR
.RE
-.PP
-\fBalternate\fR
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
.RS 4
-Alternate between the current and the last focused window\&.
-.RE
.PP
-\fBalternate_desktop\fR
+\fB\-W\fR, \fB\-\-windows\fR
.RS 4
-Alternate between the current and the last focused desktop\&.
+List matching windows\&.
.RE
.PP
-\fBalternate_monitor\fR
+\fB\-D\fR, \fB\-\-desktops\fR
.RS 4
-Alternate between the current and the last focused monitor\&.
+List matching desktops\&.
.RE
.PP
-\fBadd\fR \fIDESKTOP_NAME\fR \&...
+\fB\-M\fR, \fB\-\-monitors\fR
.RS 4
-Make new desktops with the given names\&.
+List matching monitors\&.
.RE
.PP
-\fBadd_in\fR \fIMONITOR_NAME\fR \fIDESKTOP_NAME\fR \&...
+\fB\-T\fR, \fB\-\-tree\fR
.RS 4
-Make new desktops with the given names in the given monitor\&.
+Print tree rooted at query\&.
.RE
.PP
-\fBrename_monitor\fR \fICURRENT_NAME\fR \fINEW_NAME\fR
+\fB\-H\fR, \fB\-\-history\fR
.RS 4
-Rename the monitor named
-\fICURRENT_NAME\fR
-to
-\fINEW_NAME\fR\&.
+Print the history as it relates to the query\&.
.RE
.PP
-\fBrename\fR \fICURRENT_NAME\fR \fINEW_NAME\fR
+[\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
-Rename the desktop named
-\fICURRENT_NAME\fR
-to
-\fINEW_NAME\fR\&.
+Constrain matches to the selected monitor, desktop or window\&.
.RE
-.PP
-\fBremove_desktop\fR \fIDESKTOP_NAME\fR \&...
+.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
-Remove the given desktops\&.
+.sp
+restore \fIOPTIONS\fR
.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
+.RS 4
.PP
-\fBsend_desktop_to\fR \fIMONITOR_NAME\fR [\fB\-\-follow\fR]
+\fB\-T\fR, \fB\-\-tree\fR <file_path>
.RS 4
-Send the current desktop to the given monitor\&.
+Load the desktop trees from the given file\&.
.RE
.PP
-\fBcycle_monitor\fR \fInext\fR|\fIprev\fR
+\fB\-H\fR, \fB\-\-history\fR <file_path>
.RS 4
-Select the next or previous monitor\&.
+Load the focus history from the given file\&.
.RE
-.PP
-\fBcycle_desktop\fR \fInext\fR|\fIprev\fR [\fB\-\-skip\-free\fR|\fB\-\-skip\-occupied\fR]
+.RE
+.SS "Control"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Select the next or previous desktop\&.
+.sp
+control \fIOPTIONS\fR
.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
+.RS 4
.PP
-\fBlayout\fR \fImonocle\fR|\fItiled\fR [\fIDESKTOP_NAME\fR \&...]
+\fB\-\-adopt\-orphans\fR <file_path>
.RS 4
-Set the layout of the given desktops (current if none given)\&.
+Manage all the unmanaged windows remaining from a previous session\&.
.RE
.PP
-\fBcycle_layout\fR
+\fB\-\-put\-status\fR <file_path>
.RS 4
-Cycle the layout of the current desktop\&.
+Write the current internal state to the panel FIFO\&.
.RE
.PP
-\fBrotate\fR \fIclockwise\fR|\fIcounter_clockwise\fR|\fIfull_cycle\fR
+\fB\-\-toggle\-visibility\fR
.RS 4
-Rotate the window tree\&.
+Toggle the visibility of all the managed windows\&.
.RE
-.PP
-\fBflip\fR \fIhorizontal\fR|\fIvertical\fR
+.RE
+.SS "Pointer"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Flip the window tree\&.
+.sp
+pointer \fIOPTIONS\fR
.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
+.RS 4
.PP
-\fBbalance\fR
+\fB\-t\fR, \fB\-\-track\fR <x> <y>
.RS 4
-Adjust the split ratios so that all windows occupy the same area\&.
+Pass the pointer root coordinates for the current pointer action\&.
.RE
.PP
-\fBrule\fR \fIPATTERN\fR [\fIDESKTOP_NAME\fR] [\fIfloating\fR] [\fIfollow\fR]
+\fB\-g\fR, \fB\-\-grab\fR focus|move|resize_side|resize_corner
.RS 4
-Create a new rule (\fIPATTERN\fR
-must match the class or instance name)\&.
+Perform the given pointer action\&.
.RE
-.PP
-\fBremove_rule\fR \fIUID\fR \&...
+.RE
+.SS "Rule"
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBGeneral Syntax\fR
.RS 4
-Remove the rules with the given
-\fIUIDs\fR\&.
+.sp
+rule \fIOPTIONS\fR
.RE
+.sp
+.it 1 an-trap
+.nr an-no-space-flag 1
+.nr an-break-flag 1
+.br
+.ps +1
+\fBOptions\fR
+.RS 4
.PP
-\fBput_status\fR
+\fB\-a\fR, \fB\-\-add\fR <pattern> [\-d \fIDESKTOP_SEL\fR] [\-\-floating] [\-\-follow]
.RS 4
-Output the current state to the panel fifo\&.
+Create a new rule (<pattern> must match the class or instance name)\&.
.RE
.PP
-\fBadopt_orphans\fR
+\fB\-r\fR, \fB\-\-rm\fR <rule_uid>\&...
.RS 4
-Manage all the unmanaged windows remaining from a previous session\&.
+Remove the rules with the given UIDs\&.
.RE
.PP
-\fBrestore_layout\fR \fIFILE_PATH\fR
+\fB\-l\fR, \fB\-\-list\fR [<pattern>]
.RS 4
-Restore the layout of each desktop from the content of
-\fIFILE_PATH\fR\&.
+List the rules\&.
+.RE
.RE
+.SS "Config"
+.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
-\fBrestore_history\fR \fIFILE_PATH\fR
+config <key> [<value>]
.RS 4
-Restore the history of each desktop from the content of
-\fIFILE_PATH\fR\&.
+Get or set the value of <key>\&.
+.RE
.RE
+.SS "Quit"
+.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
-\fBquit\fR [\fIEXIT_STATUS\fR]
+quit [<status>]
.RS 4
-Quit\&.
+Quit with an optional exit status\&.
+.RE
.RE
.SH "SETTINGS"
.sp
.sp -1
.IP \(bu 2.3
.\}
-Automatic and manual modes\&.
+Hybrid tiling\&.
.RE
.SH "CONTRIBUTORS"
.sp
*bspwm* [*-h*|*-v*|*-s* 'PANEL_FIFO'|*-p* 'PANEL_PREFIX']
-*bspc* 'MESSAGE' ['ARGUMENTS'] ['OPTIONS']
+*bspc* 'COMMAND' ['ARGUMENTS']
Description
-----------
It is controlled and configured via *bspc*.
+
+Options
+-------
+
+*-h*::
+ Print the synopsis and exit.
+
+*-v*::
+ Print the version and exit.
+
+*-s* 'PANEL_FIFO'::
+ Write the internal state to the given FIFO.
+
+*-p* 'PANEL_PREFIX'::
+ Start every line written to the 'PANEL_FIFO' with the given prefix.
+
+
Configuration
-------------
Splitting Modes
---------------
+New windows are inserted in the tree as close as possible to the focused window.
+
There is only two splitting modes: 'automatic' and 'manual'.
-The default mode is 'automatic'. The 'manual' mode is entered by sending a *presel* message.
+The default mode is 'automatic'. The 'manual' mode is entered by sending a *preselection* message.
Example: insertion of a new node (number 4) into the given tree in 'automatic' mode:
+-------------------------+ +-------------------------+
----
-Same departure, but the mode is 'manual', and a *presel* 'up' message was sent beforehand:
+Same departure, but the mode is 'manual', and a *window --presel up* message was sent beforehand:
----
b b
Each desktop contains at most one tree.
-Messages
+
+Definitions
+-----------
+
+----
+WINDOW_SEL := (CYCLE|DIR|biggest|focused|last)[.WINDOW_CLASS] | <window_id>
+DESKTOP_SEL := (CYCLE|focused|last)[.DESKTOP_CLASS] | <desktop_name>
+MONITOR_SEL := (CYCLE|DIR|focused|last)[.DESKTOP_CLASS] | <monitor_name>
+
+DESKTOP_CLASS := [occupied|free]
+WINDOW_CLASS := [floating|tiled][.][like|unlike]
+
+DIR := left|right|up|down
+CYCLE := next|prev
+ROTATE := 90|270|180
+FLIP := horizontal|vertical
+----
+
+Commands
--------
+Window
+~~~~~~
-*get* 'SETTING'::
- Return the value of the given setting.
+General Syntax
+^^^^^^^^^^^^^^
-*set* 'SETTING' 'VALUE'::
- Set the value of the given setting.
+window ['WINDOW_SEL'] 'OPTIONS'
-*list* ['DESKTOP_NAME']::
- Output the internal representation of the window tree.
+Options
+^^^^^^^
+*-f*, *--focus* ['WINDOW_SEL']::
+ Focus the selected or given window.
-*list_desktops* [*--quiet*]::
- Perform a dump of each desktop for the current monitor.
+*-d*, *--to-desktop* 'DESKTOP_SEL'::
+ Send the selected window to the given desktop.
-*list_monitors* [*--quiet*]::
- Perform a dump of each monitor.
+*-m*, *--to-monitor* 'MONITOR_SEL'::
+ Send the selected window to the given monitor.
-*list_history*::
- Return the node focus history of each desktop.
+*-w*, *--to-window* 'WINDOW_SEL'::
+ Transplant the selected window to the given window.
-*list_windows*::
- Return the list of managed windows (i.e. their identifiers).
+*-s*, *--swap* 'WINDOW_SEL'::
+ Swap the selected window with the given window.
-*list_rules*::
- Return the list of rules.
+*-p*, *--presel* 'DIR'|cancel::
+ Preselect the splitting area of the selected window (or cancel the preselection).
-*presel* 'left'|'right'|'up'|'down' ['SPLIT_RATIO']::
- Switch to manual mode and select the splitting direction.
+*-r*, *--ratio* 'RATIO'::
+ Set the splitting ratio of the selected window.
-*cancel* [*--all*]::
- Switch to automatic mode.
+*-e*, *--edge* 'DIR' 'RATIO'|pull|push::
+ Set the splitting ratio (or pull, or push) the edge located in the given direction in relation to the selected window.
-*ratio* 'VALUE'::
- Set the splitting ratio of the focused window.
+*-t*, *--toggle* floating|fullscreen|locked[=on|off]::
+ Set or toggle the given state for the selected window.
-*pad* 'MONITOR_NAME' ['TOP_PADDING' ['RIGHT_PADDING' ['BOTTOM_PADDING' ['LEFT_PADDING']]]]::
- Set the padding of the given monitor.
+*-c*, *--close*::
+ Close the selected window.
-*focus* 'left'|'right'|'up'|'down'::
- Focus the neighbor window situated in the given direction.
+*-k*, *--kill*::
+ Kill the selected window.
-*shift* 'left'|'right'|'up'|'down'::
- Exchange the current window with the given neighbor.
+Desktop
+~~~~~~~
-*swap* [*--keep-focus*]::
- Swap the focused window with the last focused window.
+General Syntax
+^^^^^^^^^^^^^^
-*push* 'left'|'right'|'up'|'down'::
- Push the fence located in the given direction.
+desktop ['DESKTOP_SEL'] 'OPTIONS'
-*pull* 'left'|'right'|'up'|'down'::
- Pull the fence located in the given direction.
+Options
+^^^^^^^
+*-f*, *--focus* ['DESKTOP_SEL']::
+ Focus the selected or given desktop.
-*fence_ratio* 'left'|'right'|'up'|'down' 'RATIO'::
- Set the splitting ratio of the fence located in the given direction.
+*-m*, *--to-monitor* 'MONITOR_SEL'::
+ Send the selected desktop to the given monitor.
-*cycle* 'next'|'prev' [*--skip-floating*|*--skip-tiled*|*--skip-class-equal*|*--skip-class-differ*]::
- Focus the next or previous window matching the given constraints.
+*-l*, *--layout* 'CYCLE'|monocle|tiled::
+ Set or cycle the layout of the selected desktop.
-*nearest* 'older'|'newer' [*--skip-floating*|*--skip-tiled*|*--skip-class-equal*|*--skip-class-differ*]::
- Focus the nearest window matching the given constraints.
+*-n*, *--rename* <new_name>::
+ Rename the selected desktop.
-*biggest*::
- Return the ID of the biggest tiled window.
+*-r*, *--remove*::
+ Remove the selected desktop.
-*circulate* 'forward'|'backward'::
- Circulate the leaves in the given direction.
+*-c*, *--cancel-presel*::
+ Cancel the preselection of all the windows of the selected desktop.
-*grab_pointer* 'focus'|'move'|'resize_side'|'resize_corner'::
- Begin the specified pointer action.
+*-F*, *--flip* 'FLIP'::
+ Flip the tree of the selected desktop.
-*track_pointer* 'ROOT_X' 'ROOT_Y'::
- Pass the pointer root coordinates for the current pointer action.
+*-R*, *--rotate* 'ROTATE'::
+ Rotate the tree of the selected desktop.
-*toggle_fullscreen*::
- Toggle the fullscreen state of the current window.
+*-B*, *--balance*::
+ Adjust the split ratios of the tree of the selected desktop so that all windows occupy the same area.
-*toggle_floating*::
- Toggle the floating state of the current window.
+*-C*, *--circulate* forward|backward::
+ Circulate the leaves of the tree of the selected desktop.
-*toggle_locked*::
- Toggle the locked state of the current window (locked windows will not respond to the *close* message).
+Monitor
+~~~~~~~
-*toggle_visibility*::
- Toggle the visibility of all the managed windows.
+General Syntax
+^^^^^^^^^^^^^^
-*close*::
- Close the focused window.
+monitor ['MONITOR_SEL'] 'OPTIONS'
-*kill*::
- Kill the focused window.
+Options
+^^^^^^^
+*-f*, *--focus* ['MONITOR_SEL']::
+ Focus the selected or given monitor.
-*send_to* 'DESKTOP_NAME' [*--follow*]::
- Send the focused window to the given desktop.
+*-a*, *--add-desktops* <name>...::
+ Create desktops with the given names in the selected monitor.
-*drop_to* 'next'|'prev' [*--follow*]::
- Send the focused window to the next or previous desktop.
+*-r*, *--remove-desktops* <name>...::
+ Remove desktops with the given names.
-*send_to_monitor* 'MONITOR_NAME' [*--follow*]::
- Send the focused window to the given monitor.
+*-p*, *--pad* <top> <right> <bottom> <left>::
+ Set the padding of the selected monitor.
-*drop_to_monitor* 'next'|'prev' [*--follow*]::
- Send the focused window to the next or previous monitor.
+*-n*, *--rename* <new_name>::
+ Rename the selected monitor.
-*use* 'DESKTOP_NAME'::
- Select the given desktop.
+Query
+~~~~~
-*use_monitor* 'MONITOR_NAME'::
- Select the given monitor.
+General Syntax
+^^^^^^^^^^^^^^
-*focus_monitor* 'left'|'right'|'up'|'down'::
- Focus the nearest monitor in the given direction.
+query 'OPTIONS'
-*alternate*::
- Alternate between the current and the last focused window.
+Options
+^^^^^^^
+*-W*, *--windows*::
+ List matching windows.
-*alternate_desktop*::
- Alternate between the current and the last focused desktop.
+*-D*, *--desktops*::
+ List matching desktops.
-*alternate_monitor*::
- Alternate between the current and the last focused monitor.
+*-M*, *--monitors*::
+ List matching monitors.
-*add* 'DESKTOP_NAME' ...::
- Make new desktops with the given names.
+*-T*, *--tree*::
+ Print tree rooted at query.
-*add_in* 'MONITOR_NAME' 'DESKTOP_NAME' ...::
- Make new desktops with the given names in the given monitor.
+*-H*, *--history*::
+ Print the history as it relates to the query.
-*rename_monitor* 'CURRENT_NAME' 'NEW_NAME'::
- Rename the monitor named 'CURRENT_NAME' to 'NEW_NAME'.
+[*-m*,*--monitor* ['MONITOR_SEL']] | [*-d*,*--desktop* ['DESKTOP_SEL']] | [*-w*, *--window* ['WINDOW_SEL']]::
+ Constrain matches to the selected monitor, desktop or window.
-*rename* 'CURRENT_NAME' 'NEW_NAME'::
- Rename the desktop named 'CURRENT_NAME' to 'NEW_NAME'.
+Restore
+~~~~~~~
-*remove_desktop* 'DESKTOP_NAME' ...::
- Remove the given desktops.
+General Syntax
+^^^^^^^^^^^^^^
-*send_desktop_to* 'MONITOR_NAME' [*--follow*]::
- Send the current desktop to the given monitor.
+restore 'OPTIONS'
+
+Options
+^^^^^^^
+
+*-T*, *--tree* <file_path>::
+ Load the desktop trees from the given file.
+
+*-H*, *--history* <file_path>::
+ Load the focus history from the given file.
+
+Control
+~~~~~~~
+
+General Syntax
+^^^^^^^^^^^^^^
+
+control 'OPTIONS'
+
+Options
+^^^^^^^
+
+*--adopt-orphans* <file_path>::
+ Manage all the unmanaged windows remaining from a previous session.
+
+*--put-status* <file_path>::
+ Write the current internal state to the panel FIFO.
+
+*--toggle-visibility*::
+ Toggle the visibility of all the managed windows.
+
+Pointer
+~~~~~~~
+
+General Syntax
+^^^^^^^^^^^^^^
+
+pointer 'OPTIONS'
+
+Options
+^^^^^^^
+
+*-t*, *--track* <x> <y>::
+ Pass the pointer root coordinates for the current pointer action.
-*cycle_monitor* 'next'|'prev'::
- Select the next or previous monitor.
+*-g*, *--grab* focus|move|resize_side|resize_corner::
+ Perform the given pointer action.
-*cycle_desktop* 'next'|'prev' [*--skip-free*|*--skip-occupied*]::
- Select the next or previous desktop.
+Rule
+~~~~
-*layout* 'monocle'|'tiled' ['DESKTOP_NAME' ...]::
- Set the layout of the given desktops (current if none given).
+General Syntax
+^^^^^^^^^^^^^^
-*cycle_layout*::
- Cycle the layout of the current desktop.
+rule 'OPTIONS'
-*rotate* 'clockwise'|'counter_clockwise'|'full_cycle'::
- Rotate the window tree.
+Options
+^^^^^^^
-*flip* 'horizontal'|'vertical'::
- Flip the window tree.
+*-a*, *--add* <pattern> [-d 'DESKTOP_SEL'] [--floating] [--follow]::
+ Create a new rule (<pattern> must match the class or instance name).
-*balance*::
- Adjust the split ratios so that all windows occupy the same area.
+*-r*, *--rm* <rule_uid>...::
+ Remove the rules with the given UIDs.
-*rule* 'PATTERN' ['DESKTOP_NAME'] ['floating'] ['follow']::
- Create a new rule ('PATTERN' must match the class or instance name).
+*-l*, *--list* [<pattern>]::
+ List the rules.
-*remove_rule* 'UID' ...::
- Remove the rules with the given 'UIDs'.
+Config
+~~~~~~
-*put_status*::
- Output the current state to the panel fifo.
+General Syntax
+^^^^^^^^^^^^^^
-*adopt_orphans*::
- Manage all the unmanaged windows remaining from a previous session.
+config <key> [<value>]::
+ Get or set the value of <key>.
-*restore_layout* 'FILE_PATH'::
- Restore the layout of each desktop from the content of 'FILE_PATH'.
+Quit
+~~~~
-*restore_history* 'FILE_PATH'::
- Restore the history of each desktop from the content of 'FILE_PATH'.
+General Syntax
+^^^^^^^^^^^^^^
-*quit* ['EXIT_STATUS']::
- Quit.
+quit [<status>]::
+ Quit with an optional exit status.
Settings
--------
* Configured and controlled through messages.
* Multiple monitors support (via 'RandR').
* EWMH support (*tint2* works).
-* Automatic and manual modes.
+* Hybrid tiling.
Contributors
------------
#include "window.h"
#include "events.h"
#include "tree.h"
+#include "query.h"
#include "rules.h"
#include "ewmh.h"
PRINTF("configure request %X\n", e->window);
- window_location_t loc;
+ coordinates_t loc;
bool is_managed = locate_window(e->window, &loc);
if (!is_managed || is_floating(loc.node->client)) {
PRINTF("destroy notify %X\n", e->window);
- window_location_t loc;
+ coordinates_t loc;
if (locate_window(e->window, &loc)) {
remove_node(loc.desktop, loc.node);
arrange(loc.monitor, loc.desktop);
PRINTF("unmap notify %X\n", e->window);
- window_location_t loc;
+ coordinates_t loc;
if (locate_window(e->window, &loc)) {
remove_node(loc.desktop, loc.node);
arrange(loc.monitor, loc.desktop);
if (e->atom != XCB_ATOM_WM_HINTS)
return;
- window_location_t loc;
+ coordinates_t loc;
if (locate_window(e->window, &loc)
&& xcb_icccm_get_wm_hints_reply(dpy, xcb_icccm_get_wm_hints(dpy, e->window), &hints, NULL) == 1)
set_urgency(loc.monitor, loc.desktop, loc.node, xcb_icccm_wm_hints_get_urgency(&hints));
PRINTF("client message %X %u\n", e->window, e->type);
if (e->type == ewmh->_NET_CURRENT_DESKTOP) {
- desktop_location_t loc;
+ coordinates_t loc;
if (ewmh_locate_desktop(e->data.data32[0], &loc))
focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
return;
}
- window_location_t loc;
+ coordinates_t loc;
if (!locate_window(e->window, &loc))
return;
if (loc.node == mon->desk->focus)
return;
if (loc.desktop->focus->client->fullscreen && loc.desktop->focus != loc.node) {
- toggle_fullscreen(loc.desktop, loc.desktop->focus);
+ set_fullscreen(loc.desktop, loc.desktop->focus, false);
arrange(loc.monitor, loc.desktop);
}
focus_node(loc.monitor, loc.desktop, loc.node);
} else if (e->type == ewmh->_NET_WM_DESKTOP) {
- desktop_location_t dloc;
+ coordinates_t dloc;
if (ewmh_locate_desktop(e->data.data32[0], &dloc))
transfer_node(loc.monitor, loc.desktop, dloc.monitor, dloc.desktop, loc.node);
}
void handle_state(monitor_t *m, desktop_t *d, node_t *n, xcb_atom_t state, unsigned int action)
{
if (state == ewmh->_NET_WM_STATE_FULLSCREEN) {
- bool fs = n->client->fullscreen;
- if (action == XCB_EWMH_WM_STATE_TOGGLE
- || (fs && action == XCB_EWMH_WM_STATE_REMOVE)
- || (!fs && action == XCB_EWMH_WM_STATE_ADD)) {
- toggle_fullscreen(d, n);
- arrange(m, d);
- }
+ if (action == XCB_EWMH_WM_STATE_ADD)
+ set_fullscreen(d, n, true);
+ else if (action == XCB_EWMH_WM_STATE_REMOVE)
+ set_fullscreen(d, n, false);
+ else if (action == XCB_EWMH_WM_STATE_TOGGLE)
+ set_fullscreen(d, n, !n->client->fullscreen);
+ arrange(m, d);
} else if (state == ewmh->_NET_WM_STATE_DEMANDS_ATTENTION) {
if (action == XCB_EWMH_WM_STATE_ADD)
set_urgency(m, d, n, true);
if (win == XCB_NONE)
return;
- window_location_t loc;
+ coordinates_t loc;
if (locate_window(win, &loc)) {
client_t *c = NULL;
frozen_pointer->position = pos;
query_pointer(&pwin, NULL);
if (pwin == win)
return;
- window_location_t loc;
+ coordinates_t loc;
bool is_managed = (pwin == XCB_NONE ? false : locate_window(pwin, &loc));
if (is_managed && is_tiled(loc.node->client) && loc.monitor == m) {
swap_nodes(n, loc.node, true);
return 0;
}
-bool ewmh_locate_desktop(uint32_t i, desktop_location_t *loc)
+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--)
if (i == 0) {
loc->monitor = m;
loc->desktop = d;
+ loc->node = NULL;
return true;
}
-
return false;
}
void ewmh_update_active_window(void);
void ewmh_update_number_of_desktops(void);
uint32_t ewmh_get_desktop_index(desktop_t *);
-bool ewmh_locate_desktop(uint32_t, desktop_location_t *);
+bool ewmh_locate_desktop(uint32_t, coordinates_t *);
void ewmh_update_current_desktop(void);
void ewmh_set_wm_desktop(node_t *, desktop_t *);
void ewmh_update_desktop_names(void);
FIRST_DESK=1
REMAINING_DESKS="$(seq 2 9) 0"
-bspc rename Desktop01 $FIRST_DESK
-bspc add $REMAINING_DESKS
+bspc desktop Desktop01 -n $FIRST_DESK
+bspc monitor -a $REMAINING_DESKS
-bspc rule Gimp Eight floating
+bspc rule -a Gimp -d Eight --floating
-bspc set split_ratio 0.52
-bspc set border_width 2
-bspc set window_gap 12
-bspc set borderless_monocle true
-bspc set gapless_monocle true
-bspc set focus_by_distance true
+bspc config split_ratio 0.52
+bspc config border_width 2
+bspc config window_gap 12
+bspc config borderless_monocle true
+bspc config gapless_monocle true
+bspc config focus_by_distance true
bspc quit
super + w
- bspc close
+ bspc window -c
super + t
- bspc cycle_layout
+ bspc desktop -l next
super + b
- bspc balance
+ bspc desktop -B
super + {s,f}
- bspc toggle_{floating,fullscreen}
+ bspc window -t {floating,fullscreen}
super + {grave,Tab}
- bspc {alternate,alternate_desktop}
+ bspc {window,desktop} -f last
super + apostrophe
- bspc swap
+ bspc window -s last
super + m
- cur=$(xdo id); \
- wid=$(bspc biggest); \
- [ -n "$wid" -a "$cur" != "$wid" ] && \
- xdo activate $wid && bspc swap
+ bspc window -s biggest
super + {_,shift + }{h,j,k,l}
- bspc {focus,shift} {left,down,up,right}
+ bspc window -{f,s} {left,down,up,right}
-super + {c,shift + c}
- bspc cycle {next,prev}
+super + {_,shift + }c
+ bspc window -f {next,prev}
super + {comma,period}
- bspc circulate {backward,forward}
+ bspc desktop -C {backward,forward}
super + bracket{left,right}
- bspc cycle_desktop {prev,next}
+ bspc desktop -f {prev,next}
super + ctrl + {h,j,k,l}
- bspc presel {left,down,up,right}
+ bspc window -p {left,down,up,right}
super + ctrl + {_,shift + }space
- bspc cancel{_, --all }
+ bspc {window -p cancel,desktop -c}
super + alt + {h,j,k,l}
- bspc push {left,down,up,right}
+ bspc window -e {left,down,up,right} push
super + alt + shift + {h,j,k,l}
- bspc pull {right,up,down,left}
+ bspc window -e {right,up,down,left} pull
super + ctrl + {1-9}
- bspc ratio 0.{1-9}
+ bspc window -r 0.{1-9}
super + {_,shift + }{1-9,0}
- bspc {use,send_to} {1-9,0}
+ bspc {desktop -f,window -d} {1-9,0}
:button1
- bspc grab_pointer focus
+ bspc pointer -g focus
super + button{1-3}
- bspc grab_pointer {move,resize_side,resize_corner}
+ bspc pointer -g {move,resize_side,resize_corner}
super + !button{1-3}
- bspc track_pointer %i %i
+ bspc pointer -t %i %i
#
# wm independent hotkeys
exit(EXIT_FAILURE);
}
-uint32_t get_color(char *col)
+bool get_color(char *col, uint32_t *pxl)
{
xcb_colormap_t map = screen->default_colormap;
- uint32_t pxl = 0;
if (col[0] == '#') {
unsigned int red, green, blue;
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;
+ *pxl = reply->pixel;
free(reply);
+ return true;
}
}
} 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;
+ *pxl = reply->pixel;
free(reply);
+ return true;
}
}
-
- return pxl;
+ return false;
}
double distance(xcb_point_t a, xcb_point_t b)
#include <xcb/xcb.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stdbool.h>
#include <stdint.h>
#define LENGTH(x) (sizeof(x) / sizeof(*x))
#define XCB_CONFIG_WINDOW_X_Y XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y
#define XCB_CONFIG_WINDOW_WIDTH_HEIGHT XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT
#define XCB_CONFIG_WINDOW_X_Y_WIDTH_HEIGHT XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT
-#define MAXLEN 256
+
+#define MAXLEN 256
+#define INIT_CAP 8
#define REMLEN(x) (BUFSIZ - strlen(x) - 1)
+#define streq(s1, s2) (strcmp((s1), (s2)) == 0)
#ifdef DEBUG
# define PUTS(x) puts(x)
void warn(char *, ...);
__attribute__((noreturn))
void err(char *, ...);
-uint32_t get_color(char *);
+bool get_color(char *, uint32_t *);
double distance(xcb_point_t, xcb_point_t);
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include "settings.h"
#include "messages.h"
+#include "query.h"
+#include "restore.h"
#include "common.h"
#include "types.h"
#include "bspwm.h"
#include "tree.h"
#include "rules.h"
-void process_message(char *msg, char *rsp)
+bool cmd_window(char **args, int num)
{
- char *cmd = strtok(msg, TOK_SEP);
-
- if (cmd == NULL)
- return;
-
- if (strcmp(cmd, "get") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- get_setting(name, rsp);
- } else if (strcmp(cmd, "set") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- char *value = strtok(NULL, TOK_SEP);
- set_setting(name, value, rsp);
- } else if (strcmp(cmd, "list") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- desktop_location_t loc;
- if (locate_desktop(name, &loc))
- list(loc.desktop, loc.desktop->root, rsp, 0);
- } else {
- list(mon->desk, mon->desk->root, rsp, 0);
- }
- } else if (strcmp(cmd, "list_monitors") == 0) {
- char *arg = strtok(NULL, TOK_SEP);
- list_option_t opt;
- if (parse_list_option(arg, &opt))
- list_monitors(opt, rsp);
- } else if (strcmp(cmd, "list_desktops") == 0) {
- char *arg = strtok(NULL, TOK_SEP);
- list_option_t opt;
- if (parse_list_option(arg, &opt))
- list_desktops(mon, opt, 0, rsp);
- } else if (strcmp(cmd, "list_windows") == 0) {
- list_windows(rsp);
- } else if (strcmp(cmd, "list_history") == 0) {
- list_history(rsp);
- } else if (strcmp(cmd, "list_rules") == 0) {
- list_rules(rsp);
- } else if (strcmp(cmd, "close") == 0) {
- window_close(mon->desk->focus);
- } else if (strcmp(cmd, "kill") == 0) {
- window_kill(mon, mon->desk, mon->desk->focus);
- } else if (strcmp(cmd, "rotate") == 0) {
- char *deg = strtok(NULL, TOK_SEP);
- if (deg != NULL) {
- rotate_t r;
- if (parse_rotate(deg, &r))
- rotate_tree(mon->desk->root, r);
- }
- arrange(mon, mon->desk);
- } else if (strcmp(cmd, "flip") == 0) {
- char *flp = strtok(NULL, TOK_SEP);
- if (flp != NULL) {
- flip_t f;
- if (parse_flip(flp, &f))
- flip_tree(mon->desk->root, f);
- }
- arrange(mon, mon->desk);
- } else if (strcmp(cmd, "balance") == 0) {
- balance_tree(mon->desk->root);
- arrange(mon, mon->desk);
- } else if (strcmp(cmd, "grab_pointer") == 0) {
- char *pac = strtok(NULL, TOK_SEP);
- if (pac != NULL) {
- pointer_action_t a;
- if (parse_pointer_action(pac, &a))
- grab_pointer(a);
- }
- } else if (strcmp(cmd, "track_pointer") == 0) {
- char *arg1 = strtok(NULL, TOK_SEP);
- char *arg2 = strtok(NULL, TOK_SEP);
- if (arg1 == NULL || arg2 == NULL)
- return;
- int root_x, root_y;
- if (sscanf(arg1, "%i", &root_x) == 1 && sscanf(arg2, "%i", &root_y) == 1)
- track_pointer(root_x, root_y);
- } else if (strcmp(cmd, "layout") == 0) {
- char *lyt = strtok(NULL, TOK_SEP);
- if (lyt != NULL) {
- layout_t l;
- if (parse_layout(lyt, &l)) {
- char *name = strtok(NULL, TOK_SEP);
- if (name == NULL) {
- change_layout(mon, mon->desk, l);
- } else {
- desktop_location_t loc;
- do {
- if (locate_desktop(name, &loc))
- change_layout(loc.monitor, loc.desktop, l);
- } while ((name = strtok(NULL, TOK_SEP)) != NULL);
- }
- }
- }
- } else if (strcmp(cmd, "cycle_layout") == 0) {
- if (mon->desk->layout == LAYOUT_MONOCLE)
- change_layout(mon, mon->desk, LAYOUT_TILED);
+ coordinates_t ref = {mon, mon->desk, mon->desk->focus};
+ coordinates_t trg = ref;
+
+ if (*args[0] != OPT_CHR) {
+ if (node_from_desc(*args, &ref, &trg))
+ num--, args++;
else
- change_layout(mon, mon->desk, LAYOUT_MONOCLE);
- } else if (strcmp(cmd, "shift") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- direction_t d;
- if (parse_direction(dir, &d)) {
- node_t *n = nearest_neighbor(mon->desk, mon->desk->focus, d);
- if (n != NULL) {
- swap_nodes(mon->desk->focus, n, true);
- arrange(mon, mon->desk);
- } else if (monitor_focus_fallback) {
- monitor_t *m = nearest_monitor(d);
- if (m != NULL) {
- transfer_node(mon, mon->desk, m, m->desk, mon->desk->focus);
- focus_node(m, m->desk, m->desk->focus);
- }
- }
+ return false;
+ }
+
+ if (trg.node == NULL)
+ return false;
+
+ bool dirty = false;
+
+ while (num > 0) {
+ if (streq("-f", *args) || streq("--focus", *args)) {
+ coordinates_t dst = trg;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!node_from_desc(*args, &trg, &dst))
+ return false;
}
- }
- } else if (strcmp(cmd, "toggle_fullscreen") == 0) {
- toggle_fullscreen(mon->desk, mon->desk->focus);
- arrange(mon, mon->desk);
- } else if (strcmp(cmd, "toggle_floating") == 0) {
- toggle_floating(mon->desk, mon->desk->focus);
- arrange(mon, mon->desk);
- } else if (strcmp(cmd, "toggle_locked") == 0) {
- toggle_locked(mon, mon->desk, mon->desk->focus);
- } else if (strcmp(cmd, "toggle_visibility") == 0) {
- toggle_visibility();
- } else if (strcmp(cmd, "pad") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- monitor_t *m = find_monitor(name);
- if (m != NULL) {
- char args[BUFSIZ] = {0}, *s;
- while ((s = strtok(NULL, TOK_SEP)) != NULL) {
- strncat(args, s, REMLEN(args));
- strncat(args, TOK_SEP, REMLEN(args));
- }
- if (strlen(args) > 0) {
- sscanf(args, "%i %i %i %i", &m->top_padding, &m->right_padding, &m->bottom_padding, &m->left_padding);
- arrange(m, m->desk);
- } else {
- snprintf(rsp, BUFSIZ, "%i %i %i %i\n", m->top_padding, m->right_padding, m->bottom_padding, m->left_padding);
- }
+ focus_node(dst.monitor, dst.desktop, dst.node);
+ } else if (streq("-d", *args) || streq("--to-desktop", *args)) {
+ num--, args++;
+ coordinates_t dst;
+ if (desktop_from_desc(*args, &trg, &dst)) {
+ transfer_node(trg.monitor, trg.desktop, dst.monitor, dst.desktop, trg.node);
+ trg.monitor = dst.monitor;
+ trg.desktop = dst.desktop;
+ } else {
+ return false;
}
- }
- } else if (strcmp(cmd, "ratio") == 0) {
- char *value;
- if (mon->desk->focus != NULL && (value = strtok(NULL, TOK_SEP)) != NULL &&
- sscanf(value, "%lf", &mon->desk->focus->split_ratio) == 1)
- window_draw_border(mon->desk->focus, true, true);
- } else if (strcmp(cmd, "cancel") == 0) {
- if (mon->desk->focus == NULL)
- return;
- char *opt = strtok(NULL, TOK_SEP);
- cancel_option_t o;
- if (parse_cancel_option(opt, &o))
- reset_mode(mon->desk, mon->desk->focus, o);
- } else if (strcmp(cmd, "presel") == 0) {
- if (mon->desk->focus == NULL || !is_tiled(mon->desk->focus->client) || mon->desk->layout != LAYOUT_TILED)
- return;
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- direction_t d;
- if (parse_direction(dir, &d)) {
- char *rat = strtok(NULL, TOK_SEP);
- double r = mon->desk->focus->split_ratio;
- if (rat != NULL)
- sscanf(rat, "%lf", &r);
- if (auto_cancel && mon->desk->focus->split_mode == MODE_MANUAL
- && d == mon->desk->focus->split_dir
- && r == mon->desk->focus->split_ratio) {
- reset_mode(mon->desk, mon->desk->focus, CANCEL_OPTION_FOCUSED);
+ } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ coordinates_t dst;
+ if (monitor_from_desc(*args, &trg, &dst)) {
+ transfer_node(trg.monitor, trg.desktop, dst.monitor, dst.monitor->desk, trg.node);
+ trg.monitor = dst.monitor;
+ trg.desktop = dst.monitor->desk;
+ } else {
+ return false;
+ }
+ } else if (streq("-w", *args) || streq("--to-window", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ coordinates_t dst;
+ if (node_from_desc(*args, &trg, &dst))
+ transplant_node(trg.monitor, trg.desktop, trg.node, dst.node);
+ else
+ return false;
+ dirty = true;
+ } else if (streq("-s", *args) || streq("--swap", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ coordinates_t dst;
+ if (node_from_desc(*args, &trg, &dst))
+ swap_nodes(trg.node, dst.node, true);
+ else
+ return false;
+ dirty = true;
+ } else if (streq("-t", *args) || streq("--toggle", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ char *key = strtok(*args, EQL_TOK);
+ char *val = strtok(NULL, EQL_TOK);
+ state_alter_t a = ALTER_NONE;
+ bool b;
+ if (val == NULL) {
+ a = ALTER_TOGGLE;
+ } else {
+ if (parse_bool(val, &b))
+ a = ALTER_SET;
+ else
+ return false;
+ }
+ if (streq("fullscreen", key)) {
+ set_fullscreen(trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->fullscreen));
+ dirty = true;
+ } else if (streq("floating", key)) {
+ set_floating(trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->floating));
+ dirty = true;
+ } else if (streq("locked", key)) {
+ set_locked(trg.monitor, trg.desktop, trg.node, (a == ALTER_SET ? b : !trg.node->client->locked));
+ }
+ } else if (streq("-p", *args) || streq("--presel", *args)) {
+ num--, args++;
+ if (num < 1 || !is_tiled(trg.node->client)
+ || trg.desktop->layout != LAYOUT_TILED)
+ return false;
+ if (streq("cancel", *args)) {
+ reset_mode(&trg);
+ } else {
+ direction_t dir;
+ if (parse_direction(*args, &dir)) {
+ double rat = trg.node->split_ratio;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (sscanf(*args, "%lf", &rat) != 1)
+ return false;
+ }
+ if (auto_cancel && trg.node->split_mode == MODE_MANUAL
+ && dir == trg.node->split_dir
+ && rat == trg.node->split_ratio) {
+ reset_mode(&trg);
+ } else {
+ trg.node->split_mode = MODE_MANUAL;
+ trg.node->split_dir = dir;
+ trg.node->split_ratio = rat;
+ }
+ window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
} else {
- mon->desk->focus->split_mode = MODE_MANUAL;
- mon->desk->focus->split_dir = d;
- mon->desk->focus->split_ratio = r;
+ return false;
}
- window_draw_border(mon->desk->focus, true, true);
}
- }
- } else if (strcmp(cmd, "push") == 0 || strcmp(cmd, "pull") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- fence_move_t m;
- direction_t d;
- if (parse_fence_move(cmd, &m) && parse_direction(dir, &d)) {
- move_fence(mon->desk->focus, d, m);
- arrange(mon, mon->desk);
- }
- }
- } else if (strcmp(cmd, "fence_ratio") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- direction_t d;
- node_t *n;
- if (parse_direction(dir, &d) && (n = find_fence(mon->desk->focus, d)) != NULL) {
- char *value = strtok(NULL, TOK_SEP);
- if (value != NULL && sscanf(value, "%lf", &n->split_ratio) == 1)
- arrange(mon, mon->desk);
+ } else if (streq("-e", *args) || streq("--edge", *args)) {
+ num--, args++;
+ if (num < 2)
+ return false;
+ direction_t dir;
+ if (!parse_direction(*args, &dir))
+ return false;
+ num--, args++;
+ fence_move_t fmo;
+ if (parse_fence_move(*args, &fmo)) {
+ move_fence(trg.node, dir, fmo);
+ } else {
+ node_t *n = find_fence(trg.node, dir);
+ if (n == NULL || sscanf(*args, "%lf", &n->split_ratio) != 1)
+ return false;
}
+ dirty = true;
+ } else if (streq("-r", *args) || streq("--ratio", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ if (sscanf(*args, "%lf", &trg.node->split_ratio) == 1)
+ window_draw_border(trg.node, trg.desktop->focus == trg.node, mon == trg.monitor);
+ else
+ return false;
+ } else if (streq("-c", *args) || streq("--close", *args)) {
+ if (num > 1)
+ return false;
+ window_close(trg.node);
+ } else if (streq("-k", *args) || streq("--kill", *args)) {
+ if (num > 1)
+ return false;
+ window_kill(trg.desktop, trg.node);
+ dirty = true;
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "drop_to_monitor") == 0) {
- if (mon->desk->focus == NULL)
- return;
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- cycle_dir_t d;
- if (parse_cycle_direction(dir, &d)) {
- monitor_t *m;
- if (d == CYCLE_NEXT)
- m = ((mon->next == NULL ? mon_head : mon->next));
- else
- m = ((mon->prev == NULL ? mon_tail : mon->prev));
- transfer_node(mon, mon->desk, m, m->desk, mon->desk->focus);
- char *opt = strtok(NULL, TOK_SEP);
- send_option_t o;
- if (parse_send_option(opt, &o) && o == SEND_OPTION_FOLLOW)
- focus_node(m, m->desk, m->desk->focus);
+ num--, args++;
+ }
+
+ if (dirty)
+ arrange(trg.monitor, trg.desktop);
+
+ return true;
+}
+
+bool cmd_desktop(char **args, int num)
+{
+ coordinates_t ref = {mon, mon->desk, NULL};
+ coordinates_t trg = ref;
+
+ if (*args[0] != OPT_CHR) {
+ if (desktop_from_desc(*args, &ref, &trg))
+ num--, args++;
+ else
+ return false;
+ }
+
+ bool dirty = false;
+
+ while (num > 0) {
+ if (streq("-f", *args) || streq("--focus", *args)) {
+ coordinates_t dst = trg;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!desktop_from_desc(*args, &trg, &dst))
+ return false;
}
- }
- } else if (strcmp(cmd, "send_to_monitor") == 0) {
- if (mon->desk->focus == NULL)
- return;
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- monitor_t *m = find_monitor(name);
- if (m != NULL && m != mon) {
- transfer_node(mon, mon->desk, m, m->desk, mon->desk->focus);
- char *opt = strtok(NULL, TOK_SEP);
- send_option_t o;
- if (parse_send_option(opt, &o) && o == SEND_OPTION_FOLLOW)
- focus_node(m, m->desk, m->desk->focus);
+ if (auto_alternate && dst.desktop == dst.monitor->desk && dst.monitor->last_desk != NULL)
+ dst.desktop = dst.monitor->last_desk;
+ focus_node(dst.monitor, dst.desktop, dst.desktop->focus);
+ } else if (streq("-m", *args) || streq("--to-monitor", *args)) {
+ num--, args++;
+ if (num < 1 || trg.monitor->desk_head == trg.monitor->desk_tail)
+ return false;
+ coordinates_t dst;
+ if (monitor_from_desc(*args, &trg, &dst)) {
+ transfer_desktop(trg.monitor, dst.monitor, dst.desktop);
+ trg.monitor = dst.monitor;
+ update_current();
+ } else {
+ return false;
}
- }
- } else if (strcmp(cmd, "drop_to") == 0) {
- if (mon->desk->focus == NULL)
- return;
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- cycle_dir_t c;
- if (parse_cycle_direction(dir, &c)) {
- desktop_t *d;
- if (c == CYCLE_NEXT)
- d = ((mon->desk->next == NULL ? mon->desk_head : mon->desk->next));
- else
- d = ((mon->desk->prev == NULL ? mon->desk_tail : mon->desk->prev));
- transfer_node(mon, mon->desk, mon, d, mon->desk->focus);
- char *opt = strtok(NULL, TOK_SEP);
- send_option_t o;
- if (parse_send_option(opt, &o) && o == SEND_OPTION_FOLLOW)
- focus_node(mon, d, d->focus);
+ } else if (streq("-l", *args) || streq("--layout", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ layout_t lyt;
+ cycle_dir_t cyc;
+ if (parse_cycle_direction(*args, &cyc))
+ change_layout(trg.monitor, trg.desktop, (trg.desktop->layout + 1) % 2);
+ else if (parse_layout(*args, &lyt))
+ change_layout(trg.monitor, trg.desktop, lyt);
+ else
+ return false;
+ } else if (streq("-n", *args) || streq("--rename", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ strncpy(trg.desktop->name, *args, sizeof(trg.desktop->name));
+ ewmh_update_desktop_names();
+ put_status();
+ } else if (streq("-r", *args) || streq("--rm", *args)) {
+ if (trg.desktop->root == NULL
+ && trg.monitor->desk_head != trg.monitor->desk_tail) {
+ remove_desktop(trg.monitor, trg.desktop);
+ desktop_show(trg.monitor->desk);
+ update_current();
+ return true;
+ } else {
+ return false;
}
- }
- } else if (strcmp(cmd, "send_to") == 0) {
- if (mon->desk->focus == NULL)
- return;
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- desktop_location_t loc;
- if (locate_desktop(name, &loc)) {
- transfer_node(mon, mon->desk, loc.monitor, loc.desktop, mon->desk->focus);
- char *opt = strtok(NULL, TOK_SEP);
- send_option_t o;
- if (parse_send_option(opt, &o) && o == SEND_OPTION_FOLLOW)
- focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
+ } else if (streq("-c", *args) || streq("--cancel-presel", *args)) {
+ reset_mode(&trg);
+ } else if (streq("-F", *args) || streq("--flip", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ flip_t flp;
+ if (parse_flip(*args, &flp)) {
+ flip_tree(trg.desktop->root, flp);
+ dirty = true;
}
- }
- } else if (strcmp(cmd, "rename_monitor") == 0) {
- char *cur_name = strtok(NULL, TOK_SEP);
- if (cur_name != NULL) {
- monitor_t *m = find_monitor(cur_name);
- if (m != NULL) {
- char *new_name = strtok(NULL, TOK_SEP);
- if (new_name != NULL) {
- strncpy(m->name, new_name, sizeof(m->name));
- put_status();
- }
+ } else if (streq("-R", *args) || streq("--rotate", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ int rot = atoi(*args);
+ while (rot < 0)
+ rot += 360;
+ while (rot > 359)
+ rot -= 360;
+ if ((rot % 90) != 0) {
+ return false;
+ } else {
+ rotate_tree(trg.desktop->root, rot);
+ dirty = true;
}
- }
- } else if (strcmp(cmd, "rename") == 0) {
- char *cur_name = strtok(NULL, TOK_SEP);
- if (cur_name != NULL) {
- desktop_location_t loc;
- if (locate_desktop(cur_name, &loc)) {
- char *new_name = strtok(NULL, TOK_SEP);
- if (new_name != NULL) {
- strncpy(loc.desktop->name, new_name, sizeof(loc.desktop->name));
- ewmh_update_desktop_names();
- put_status();
- }
+ } else if (streq("-B", *args) || streq("--balance", *args)) {
+ balance_tree(trg.desktop->root);
+ dirty = true;
+ } else if (streq("-C", *args) || streq("--circulate", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ circulate_dir_t cir;
+ if (parse_circulate_direction(*args, &cir)) {
+ circulate_leaves(trg.monitor, trg.desktop, cir);
+ dirty = true;
+ } else {
+ return false;
}
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "use_monitor") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- monitor_t *m = find_monitor(name);
- if (m != NULL) {
- if (auto_alternate && m == mon && last_mon != NULL)
- m = last_mon;
- focus_node(m, m->desk, m->desk->focus);
+ num--, args++;
+ }
+
+ if (dirty)
+ arrange(trg.monitor, trg.desktop);
+
+ return true;
+}
+
+bool cmd_monitor(char **args, int num)
+{
+ coordinates_t ref = {mon, NULL, NULL};
+ coordinates_t trg = ref;
+
+ if (*args[0] != OPT_CHR) {
+ if (monitor_from_desc(*args, &ref, &trg))
+ num--, args++;
+ else
+ return false;
+ }
+
+ while (num > 0) {
+ if (streq("-f", *args) || streq("--focus", *args)) {
+ coordinates_t dst = trg;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!desktop_from_desc(*args, &trg, &dst))
+ return false;
}
- }
- } else if (strcmp(cmd, "focus_monitor") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- direction_t d;
- if (parse_direction(dir, &d)) {
- monitor_t *m = nearest_monitor(d);
- if (m != NULL)
- focus_node(m, m->desk, m->desk->focus);
+ if (auto_alternate && dst.monitor == mon && last_mon != NULL)
+ dst.monitor = last_mon;
+ focus_node(dst.monitor, dst.monitor->desk, dst.monitor->desk->focus);
+ } else if (streq("-a", *args) || streq("--add-desktops", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ while (num > 0) {
+ add_desktop(trg.monitor, make_desktop(*args));
+ num--, args++;
}
- }
- } else if (strcmp(cmd, "use") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- desktop_location_t loc;
- if (locate_desktop(name, &loc)) {
- if (auto_alternate && loc.desktop == mon->desk && mon->last_desk != NULL)
- focus_node(mon, mon->last_desk, mon->last_desk->focus);
- else
- focus_node(loc.monitor, loc.desktop, loc.desktop->focus);
+ } else if (streq("-r", *args) || streq("--remove-desktops", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ while (num > 0) {
+ coordinates_t dst;
+ if (locate_desktop(*args, &dst) && dst.monitor->desk_head != dst.monitor->desk_tail) {
+ remove_desktop(dst.monitor, dst.desktop);
+ desktop_show(dst.monitor->desk);
+ }
+ num--, args++;
}
+ } else if (streq("-p", *args) || streq("--pad", *args)) {
+ num--, args++;
+ if (num < 4)
+ return false;
+ char values[MAXLEN];
+ snprintf(values, sizeof(values), "%s %s %s %s", args[0], args[1], args[2], args[3]);
+ if (sscanf(values, "%i %i %i %i", &trg.monitor->top_padding, &trg.monitor->right_padding, &trg.monitor->bottom_padding, &trg.monitor->left_padding) == 4)
+ for (desktop_t *d = trg.monitor->desk_head; d != NULL; d = d->next)
+ arrange(trg.monitor, d);
+ else
+ return false;
+ } else if (streq("-n", *args) || streq("--rename", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ strncpy(trg.monitor->name, *args, sizeof(trg.monitor->name));
+ put_status();
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "cycle_monitor") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- cycle_dir_t d;
- if (parse_cycle_direction(dir, &d))
- cycle_monitor(d);
- }
- } else if (strcmp(cmd, "cycle_desktop") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- cycle_dir_t d;
- if (parse_cycle_direction(dir, &d)) {
- skip_desktop_t k;
- char *skip = strtok(NULL, TOK_SEP);
- if (parse_skip_desktop(skip, &k))
- cycle_desktop(mon, mon->desk, d, k);
+ num--, args++;
+ }
+
+ return true;
+}
+
+bool cmd_query(char **args, int num, char *rsp) {
+ coordinates_t ref = {mon, mon->desk, mon->desk->focus};
+ coordinates_t trg = {NULL, NULL, NULL};
+ domain_t dom = DOMAIN_TREE;
+ int d = 0, t = 0;
+
+ while (num > 0) {
+ if (streq("-T", *args) || streq("--tree", *args)) {
+ dom = DOMAIN_TREE, d++;
+ } else if (streq("-M", *args) || streq("--monitors", *args)) {
+ dom = DOMAIN_MONITOR, d++;
+ } else if (streq("-D", *args) || streq("--desktops", *args)) {
+ dom = DOMAIN_DESKTOP, d++;
+ } else if (streq("-W", *args) || streq("--windows", *args)) {
+ dom = DOMAIN_WINDOW, d++;
+ } else if (streq("-H", *args) || streq("--history", *args)) {
+ dom = DOMAIN_HISTORY, d++;
+ } else if (streq("-m", *args) || streq("--monitor", *args)) {
+ trg.monitor = ref.monitor;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!monitor_from_desc(*args, &ref, &trg))
+ return false;
}
- }
- } else if (strcmp(cmd, "cycle") == 0) {
- if (mon->desk->focus != NULL && mon->desk->focus->client->fullscreen)
- return;
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- cycle_dir_t d;
- if (parse_cycle_direction(dir, &d)) {
- skip_client_t k;
- char *skip = strtok(NULL, TOK_SEP);
- if (parse_skip_client(skip, &k))
- cycle_leaf(mon, mon->desk, mon->desk->focus, d, k);
+ t++;
+ } else if (streq("-d", *args) || streq("--desktop", *args)) {
+ trg.monitor = ref.monitor;
+ trg.desktop = ref.desktop;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!desktop_from_desc(*args, &ref, &trg))
+ return false;
}
- }
- } else if (strcmp(cmd, "nearest") == 0) {
- if (mon->desk->focus != NULL && mon->desk->focus->client->fullscreen)
- return;
- char *arg = strtok(NULL, TOK_SEP);
- if (arg != NULL) {
- nearest_arg_t a;
- if (parse_nearest_argument(arg, &a)) {
- skip_client_t k;
- char *skip = strtok(NULL, TOK_SEP);
- if (parse_skip_client(skip, &k))
- nearest_leaf(mon, mon->desk, mon->desk->focus, a, k);
+ t++;
+ } else if (streq("-w", *args) || streq("--window", *args)) {
+ trg = ref;
+ if (num > 1 && *(args + 1)[0] != OPT_CHR) {
+ num--, args++;
+ if (!node_from_desc(*args, &ref, &trg))
+ return false;
}
+ t++;
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "biggest") == 0) {
- node_t *n = find_biggest(mon->desk);
- if (n != NULL)
- snprintf(rsp, BUFSIZ, "0x%X", n->client->window);
- } else if (strcmp(cmd, "circulate") == 0) {
- if (mon->desk->layout == LAYOUT_MONOCLE
- || (mon->desk->focus != NULL && !is_tiled(mon->desk->focus->client)))
- return;
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- circulate_dir_t d;
- if (parse_circulate_direction(dir, &d))
- circulate_leaves(mon, mon->desk, d);
- }
- arrange(mon, mon->desk);
- } else if (strcmp(cmd, "rule") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
+ num--, args++;
+ }
+
+ if (d != 1 || t > 1)
+ return false;
+
+ if (dom == DOMAIN_HISTORY)
+ query_history(trg, rsp);
+ else if (dom == DOMAIN_WINDOW)
+ query_windows(trg, rsp);
+ else
+ query_monitors(trg, dom, rsp);
+
+ return true;
+}
+
+bool cmd_rule(char **args, int num, char *rsp) {
+ while (num > 0) {
+ if (streq("-a", *args) || streq("--add", *args)) {
+ num--, args++;
+ if (num < 2)
+ return false;
rule_t *rule = make_rule();
- strncpy(rule->cause.name, name, sizeof(rule->cause.name));
- char *arg = strtok(NULL, TOK_SEP);
- while (arg != NULL) {
- if (strcmp(arg, "floating") == 0) {
+ strncpy(rule->cause.name, *args, sizeof(rule->cause.name));
+ num--, args++;
+ while (num > 0) {
+ if (streq("--floating", *args)) {
rule->effect.floating = true;
- } else if (strcmp(arg, "follow") == 0) {
+ } else if (streq("--follow", *args)) {
rule->effect.follow = true;
- } else {
- desktop_location_t loc;
- if (locate_desktop(arg, &loc)) {
- rule->effect.monitor = loc.monitor;
- rule->effect.desktop = loc.desktop;
+ } else if (streq("-d", *args) || streq("--desktop", *args)) {
+ num--, args++;
+ if (num < 1) {
+ free(rule);
+ return false;
}
+ strncpy(rule->effect.desc, *args, sizeof(rule->effect.desc));
+ } else {
+ free(rule);
+ return false;
}
- arg = strtok(NULL, TOK_SEP);
+ num--, args++;
}
add_rule(rule);
+ } else if (streq("-r", *args) || streq("--rm", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ unsigned int uid;
+ while (num > 0) {
+ if (sscanf(*args, "%X", &uid) == 1)
+ remove_rule_by_uid(uid);
+ else
+ return false;
+ num--, args++;
+ }
+ } else if (streq("-l", *args) || streq("--list", *args)) {
+ num--, args++;
+ list_rules(num > 0 ? *args : NULL, rsp);
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "remove_rule") == 0) {
- char *arg;
- unsigned int uid;
- while ((arg = strtok(NULL, TOK_SEP)) != NULL)
- if (sscanf(arg, "%X", &uid) > 0)
- remove_rule_by_uid(uid);
- } else if (strcmp(cmd, "swap") == 0) {
- char *opt = strtok(NULL, TOK_SEP);
- swap_option_t o;
- if (!parse_swap_option(opt, &o))
- return;
- node_t *last_focus = history_get(mon->desk->history, 1);
- swap_nodes(mon->desk->focus, last_focus, true);
- arrange(mon, mon->desk);
- if (o == SWAP_OPTION_SWAP_FOCUS)
- focus_node(mon, mon->desk, last_focus);
- } else if (strcmp(cmd, "alternate") == 0) {
- focus_node(mon, mon->desk, history_get(mon->desk->history, 1));
- } else if (strcmp(cmd, "alternate_desktop") == 0) {
- if (mon->last_desk != NULL)
- focus_node(mon, mon->last_desk, mon->last_desk->focus);
- } else if (strcmp(cmd, "alternate_monitor") == 0) {
- if (last_mon != NULL)
- focus_node(last_mon, last_mon->desk, last_mon->desk->focus);
- } else if (strcmp(cmd, "add_in") == 0) {
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- monitor_t *m = find_monitor(name);
- if (m != NULL)
- for (name = strtok(NULL, TOK_SEP); name != NULL; name = strtok(NULL, TOK_SEP))
- add_desktop(m, make_desktop(name));
+ num--, args++;
+ }
+
+ return true;
+}
+
+bool cmd_pointer(char **args, int num) {
+ while (num > 0) {
+ if (streq("-t", *args) || streq("--track", *args)) {
+ num--, args++;
+ if (num < 2)
+ return false;
+ int x, y;
+ if (sscanf(*args, "%i", &x) == 1 && sscanf(*(args + 1), "%i", &y) == 1)
+ track_pointer(x, y);
+ else
+ return false;
+ } else if (streq("-g", *args) || streq("--grab", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ pointer_action_t pac;
+ if (parse_pointer_action(*args, &pac))
+ grab_pointer(pac);
+ else
+ return false;
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "add") == 0) {
- for (char *name = strtok(NULL, TOK_SEP); name != NULL; name = strtok(NULL, TOK_SEP))
- add_desktop(mon, make_desktop(name));
- } else if (strcmp(cmd, "remove_desktop") == 0) {
- for (char *name = strtok(NULL, TOK_SEP); name != NULL; name = strtok(NULL, TOK_SEP)) {
- desktop_location_t loc;
- if (locate_desktop(name, &loc)) {
- if (loc.desktop->root == NULL && loc.monitor->desk_head != loc.monitor->desk_tail) {
- remove_desktop(loc.monitor, loc.desktop);
- desktop_show(loc.monitor->desk);
- }
- }
+ num--, args++;
+ }
+
+ return true;
+}
+
+bool cmd_restore(char **args, int num) {
+ while (num > 0) {
+ if (streq("-T", *args) || streq("--tree", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ restore_tree(*args);
+ } else if (streq("-H", *args) || streq("--history", *args)) {
+ num--, args++;
+ if (num < 1)
+ return false;
+ restore_history(*args);
+ } else {
+ return false;
}
- update_current();
- } else if (strcmp(cmd, "send_desktop_to") == 0) {
- if (mon->desk_head == mon->desk_tail)
- return;
- char *name = strtok(NULL, TOK_SEP);
- if (name != NULL) {
- monitor_t *m = find_monitor(name);
- if (m != NULL && m != mon) {
- char *opt = strtok(NULL, TOK_SEP);
- send_option_t o;
- if (!parse_send_option(opt, &o))
- return;
- desktop_t *d = mon->desk;
- transfer_desktop(mon, m, d);
- if (o == SEND_OPTION_FOLLOW)
- focus_node(m, d, d->focus);
- else if (o == SEND_OPTION_DONT_FOLLOW)
- update_current();
- }
+ num--, args++;
+ }
+
+ return true;
+}
+
+bool cmd_control(char **args, int num) {
+ while (num > 0) {
+ if (streq("--adopt-orphans", *args)) {
+ adopt_orphans();
+ } else if (streq("--put-status", *args)) {
+ put_status();
+ } else if (streq("--toggle-visibility", *args)) {
+ toggle_visibility();
+ } else {
+ return false;
}
- } else if (strcmp(cmd, "focus") == 0) {
- char *dir = strtok(NULL, TOK_SEP);
- if (dir != NULL) {
- direction_t d;
- if (parse_direction(dir, &d)) {
- node_t *n = nearest_neighbor(mon->desk, mon->desk->focus, d);
- if (n != NULL) {
- focus_node(mon, mon->desk, n);
- } else if (monitor_focus_fallback) {
- monitor_t *m = nearest_monitor(d);
- if (m != NULL)
- focus_node(m, m->desk, m->desk->focus);
- }
+ num--, args++;
+ }
+
+ return true;
+}
+
+bool cmd_config(char **args, int num, char *rsp) {
+ if (num == 2)
+ return set_setting(*args, *(args + 1));
+ else if (num == 1)
+ return get_setting(*args, rsp);
+ else
+ return false;
+}
+
+bool cmd_quit(char **args, int num) {
+ if (num > 0 && sscanf(*args, "%i", &exit_status) != 1)
+ return false;
+ quit();
+ return true;
+}
+
+bool handle_message(char *msg, int msg_len, char *rsp)
+{
+ int cap = INIT_CAP;
+ int num = 0;
+ char **args = malloc(cap * sizeof(char *));
+ if (args == NULL)
+ return false;
+
+ for (int i = 0, j = 0; i < msg_len; i++) {
+ if (msg[i] == 0) {
+ args[num++] = msg + j;
+ j = i + 1;
+ }
+ if (num >= cap) {
+ cap *= 2;
+ char **new = realloc(args, cap * sizeof(char *));
+ if (new == NULL) {
+ free(args);
+ return false;
+ } else {
+ args = new;
}
}
- } else if (strcmp(cmd, "put_status") == 0) {
- put_status();
- } else if (strcmp(cmd, "adopt_orphans") == 0) {
- adopt_orphans();
- } else if (strcmp(cmd, "restore_layout") == 0) {
- char *arg = strtok(NULL, TOK_SEP);
- restore_layout(arg);
- } else if (strcmp(cmd, "restore_history") == 0) {
- char *arg = strtok(NULL, TOK_SEP);
- restore_history(arg);
- } else if (strcmp(cmd, "quit") == 0) {
- char *arg = strtok(NULL, TOK_SEP);
- if (arg != NULL)
- sscanf(arg, "%i", &exit_status);
- quit();
- } else {
- snprintf(rsp, BUFSIZ, "unknown command: %s", cmd);
}
+
+ if (num < 1)
+ return false;
+
+ char **args_orig = args;
+ bool ret = process_message(args, num, rsp);
+ free(args_orig);
+ return ret;
}
-void set_setting(char *name, char *value, char *rsp)
+bool process_message(char **args, int num, char *rsp)
{
- if (name == NULL || value == NULL)
- return;
-
- if (strcmp(name, "border_width") == 0) {
- sscanf(value, "%u", &border_width);
- } else if (strcmp(name, "window_gap") == 0) {
- sscanf(value, "%i", &window_gap);
- } else if (strcmp(name, "split_ratio") == 0) {
- sscanf(value, "%lf", &split_ratio);
- } else if (strcmp(name, "left_padding") == 0) {
- sscanf(value, "%i", &mon->left_padding);
- } else if (strcmp(name, "right_padding") == 0) {
- sscanf(value, "%i", &mon->right_padding);
- } else if (strcmp(name, "top_padding") == 0) {
- sscanf(value, "%i", &mon->top_padding);
- } else if (strcmp(name, "bottom_padding") == 0) {
- sscanf(value, "%i", &mon->bottom_padding);
- } else if (strcmp(name, "focused_border_color") == 0) {
- strncpy(focused_border_color, value, sizeof(focused_border_color));
- focused_border_color_pxl = get_color(focused_border_color);
- } else if (strcmp(name, "active_border_color") == 0) {
- strncpy(active_border_color, value, sizeof(active_border_color));
- active_border_color_pxl = get_color(active_border_color);
- } else if (strcmp(name, "normal_border_color") == 0) {
- strncpy(normal_border_color, value, sizeof(normal_border_color));
- normal_border_color_pxl = get_color(normal_border_color);
- } else if (strcmp(name, "presel_border_color") == 0) {
- strncpy(presel_border_color, value, sizeof(presel_border_color));
- presel_border_color_pxl = get_color(presel_border_color);
- } else if (strcmp(name, "focused_locked_border_color") == 0) {
- strncpy(focused_locked_border_color, value, sizeof(focused_locked_border_color));
- focused_locked_border_color_pxl = get_color(focused_locked_border_color);
- } else if (strcmp(name, "active_locked_border_color") == 0) {
- strncpy(active_locked_border_color, value, sizeof(active_locked_border_color));
- active_locked_border_color_pxl = get_color(active_locked_border_color);
- } else if (strcmp(name, "normal_locked_border_color") == 0) {
- strncpy(normal_locked_border_color, value, sizeof(normal_locked_border_color));
- normal_locked_border_color_pxl = get_color(normal_locked_border_color);
- } else if (strcmp(name, "urgent_border_color") == 0) {
- strncpy(urgent_border_color, value, sizeof(urgent_border_color));
- urgent_border_color_pxl = get_color(urgent_border_color);
- } else if (strcmp(name, "borderless_monocle") == 0) {
- bool b;
- if (parse_bool(value, &b))
- borderless_monocle = b;
- } else if (strcmp(name, "gapless_monocle") == 0) {
- bool b;
- if (parse_bool(value, &b))
- gapless_monocle = b;
- } else if (strcmp(name, "focus_follows_pointer") == 0) {
+ if (streq("window", *args)) {
+ return cmd_window(++args, --num);
+ } else if (streq("desktop", *args)) {
+ return cmd_desktop(++args, --num);
+ } else if (streq("monitor", *args)) {
+ return cmd_monitor(++args, --num);
+ } else if (streq("query", *args)) {
+ return cmd_query(++args, --num, rsp);
+ } else if (streq("restore", *args)) {
+ return cmd_restore(++args, --num);
+ } else if (streq("control", *args)) {
+ return cmd_control(++args, --num);
+ } else if (streq("rule", *args)) {
+ return cmd_rule(++args, --num, rsp);
+ } else if (streq("pointer", *args)) {
+ return cmd_pointer(++args, --num);
+ } else if (streq("config", *args)) {
+ return cmd_config(++args, --num, rsp);
+ } else if (streq("quit", *args)) {
+ return cmd_quit(++args, --num);
+ }
+
+ return false;
+}
+
+bool set_setting(char *name, char *value)
+{
+ if (streq("border_width", name)) {
+ if (sscanf(value, "%u", &border_width) != 1)
+ return false;
+ } else if (streq("window_gap", name)) {
+ if (sscanf(value, "%i", &window_gap) != 1)
+ return false;
+ } else if (streq("split_ratio", name)) {
+ if (sscanf(value, "%lf", &split_ratio) != 1)
+ return false;
+ } else if (streq("left_padding", name)) {
+ if (sscanf(value, "%i", &mon->left_padding) != 1)
+ return false;
+ } else if (streq("right_padding", name)) {
+ if (sscanf(value, "%i", &mon->right_padding) != 1)
+ return false;
+ } else if (streq("top_padding", name)) {
+ if (sscanf(value, "%i", &mon->top_padding) != 1)
+ return false;
+ } else if (streq("bottom_padding", name)) {
+ if (sscanf(value, "%i", &mon->bottom_padding) != 1)
+ return false;
+#define SETCOLOR(s) \
+ } else if (streq(#s, name)) { \
+ if (get_color(value, &s ## _pxl)) \
+ strncpy(s, value, sizeof(s)); \
+ else \
+ return false;
+ SETCOLOR(focused_border_color)
+ SETCOLOR(active_border_color)
+ SETCOLOR(normal_border_color)
+ SETCOLOR(presel_border_color)
+ SETCOLOR(focused_locked_border_color)
+ SETCOLOR(active_locked_border_color)
+ SETCOLOR(normal_locked_border_color)
+ SETCOLOR(urgent_border_color)
+#undef SETCOLOR
+ } else if (streq("focus_follows_pointer", name)) {
bool b;
if (parse_bool(value, &b) && b != focus_follows_pointer) {
uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK : CLIENT_EVENT_MASK_FFP)};
else
enable_motion_recorder();
focus_follows_pointer = b;
+ return true;
+ } else {
+ return false;
}
- return;
- } else if (strcmp(name, "pointer_follows_monitor") == 0) {
- bool b;
- if (parse_bool(value, &b))
- pointer_follows_monitor = b;
- return;
- } else if (strcmp(name, "monitor_focus_fallback") == 0) {
- bool b;
- if (parse_bool(value, &b))
- monitor_focus_fallback = b;
- return;
- } else if (strcmp(name, "adaptative_raise") == 0) {
- bool b;
- if (parse_bool(value, &b))
- adaptative_raise = b;
- return;
- } else if (strcmp(name, "apply_shadow_property") == 0) {
- bool b;
- if (parse_bool(value, &b))
- apply_shadow_property = b;
- return;
- } else if (strcmp(name, "auto_alternate") == 0) {
- bool b;
- if (parse_bool(value, &b))
- auto_alternate = b;
- return;
- } else if (strcmp(name, "auto_cancel") == 0) {
- bool b;
- if (parse_bool(value, &b))
- auto_cancel = b;
- return;
- } else if (strcmp(name, "focus_by_distance") == 0) {
- bool b;
- if (parse_bool(value, &b))
- focus_by_distance = b;
- return;
- } else if (strcmp(name, "history_aware_focus") == 0) {
- bool b;
- if (parse_bool(value, &b))
- history_aware_focus = b;
- return;
- } else if (strcmp(name, "wm_name") == 0) {
+#define SETBOOL(s) \
+ } else if (streq(#s, name)) { \
+ if (!parse_bool(value, &s)) \
+ return false;
+ SETBOOL(borderless_monocle)
+ SETBOOL(gapless_monocle)
+ SETBOOL(pointer_follows_monitor)
+ SETBOOL(monitor_focus_fallback)
+ SETBOOL(adaptative_raise)
+ SETBOOL(apply_shadow_property)
+ SETBOOL(auto_alternate)
+ SETBOOL(auto_cancel)
+ SETBOOL(focus_by_distance)
+ SETBOOL(history_aware_focus)
+#undef SETBOOL
+ } else if (streq("wm_name", name)) {
strncpy(wm_name, value, sizeof(wm_name));
ewmh_update_wm_name();
- return;
+ return true;
} else {
- snprintf(rsp, BUFSIZ, "unknown setting: %s", name);
- return;
+ return false;
}
for (monitor_t *m = mon_head; m != NULL; m = m->next)
for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
arrange(m, d);
+
+ return true;
}
-void get_setting(char *name, char* rsp)
+bool get_setting(char *name, char* rsp)
{
- if (name == NULL)
- return;
-
- if (strcmp(name, "border_width") == 0)
+ if (streq("border_width", name))
snprintf(rsp, BUFSIZ, "%u", border_width);
- else if (strcmp(name, "window_gap") == 0)
- snprintf(rsp, BUFSIZ, "%i", window_gap);
- else if (strcmp(name, "split_ratio") == 0)
+ else if (streq("split_ratio", name))
snprintf(rsp, BUFSIZ, "%lf", split_ratio);
- else if (strcmp(name, "left_padding") == 0)
+ else if (streq("window_gap", name))
+ snprintf(rsp, BUFSIZ, "%i", window_gap);
+ else if (streq("left_padding", name))
snprintf(rsp, BUFSIZ, "%i", mon->left_padding);
- else if (strcmp(name, "right_padding") == 0)
+ else if (streq("right_padding", name))
snprintf(rsp, BUFSIZ, "%i", mon->right_padding);
- else if (strcmp(name, "top_padding") == 0)
+ else if (streq("top_padding", name))
snprintf(rsp, BUFSIZ, "%i", mon->top_padding);
- else if (strcmp(name, "bottom_padding") == 0)
+ else if (streq("bottom_padding", name))
snprintf(rsp, BUFSIZ, "%i", mon->bottom_padding);
- else if (strcmp(name, "focused_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", focused_border_color, focused_border_color_pxl);
- else if (strcmp(name, "active_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", active_border_color, active_border_color_pxl);
- else if (strcmp(name, "normal_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", normal_border_color, normal_border_color_pxl);
- else if (strcmp(name, "presel_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", presel_border_color, presel_border_color_pxl);
- else if (strcmp(name, "focused_locked_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", focused_locked_border_color, focused_locked_border_color_pxl);
- else if (strcmp(name, "active_locked_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", active_locked_border_color, active_locked_border_color_pxl);
- else if (strcmp(name, "normal_locked_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", normal_locked_border_color, normal_locked_border_color_pxl);
- else if (strcmp(name, "urgent_border_color") == 0)
- snprintf(rsp, BUFSIZ, "%s (%06X)", urgent_border_color, urgent_border_color_pxl);
- else if (strcmp(name, "borderless_monocle") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(borderless_monocle));
- else if (strcmp(name, "gapless_monocle") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(gapless_monocle));
- else if (strcmp(name, "focus_follows_pointer") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(focus_follows_pointer));
- else if (strcmp(name, "pointer_follows_monitor") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(pointer_follows_monitor));
- else if (strcmp(name, "monitor_focus_fallback") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(monitor_focus_fallback));
- else if (strcmp(name, "adaptative_raise") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(adaptative_raise));
- else if (strcmp(name, "apply_shadow_property") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(apply_shadow_property));
- else if (strcmp(name, "auto_alternate") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(auto_alternate));
- else if (strcmp(name, "auto_cancel") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(auto_cancel));
- else if (strcmp(name, "focus_by_distance") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(focus_by_distance));
- else if (strcmp(name, "history_aware_focus") == 0)
- snprintf(rsp, BUFSIZ, "%s", BOOLSTR(history_aware_focus));
- else if (strcmp(name, "wm_name") == 0)
+#define GETCOLOR(s) \
+ else if (streq(#s, name)) \
+ snprintf(rsp, BUFSIZ, "%s (%06X)", s, s##_pxl);
+ GETCOLOR(focused_border_color)
+ GETCOLOR(active_border_color)
+ GETCOLOR(normal_border_color)
+ GETCOLOR(presel_border_color)
+ GETCOLOR(focused_locked_border_color)
+ GETCOLOR(active_locked_border_color)
+ GETCOLOR(normal_locked_border_color)
+ GETCOLOR(urgent_border_color)
+#undef GETCOLOR
+#define GETBOOL(s) \
+ else if (streq(#s, name)) \
+ snprintf(rsp, BUFSIZ, "%s", BOOLSTR(s));
+ GETBOOL(borderless_monocle)
+ GETBOOL(gapless_monocle)
+ GETBOOL(focus_follows_pointer)
+ GETBOOL(pointer_follows_monitor)
+ GETBOOL(monitor_focus_fallback)
+ GETBOOL(adaptative_raise)
+ GETBOOL(apply_shadow_property)
+ GETBOOL(auto_alternate)
+ GETBOOL(auto_cancel)
+ GETBOOL(focus_by_distance)
+ GETBOOL(history_aware_focus)
+#undef GETBOOL
+ else if (streq("wm_name", name))
snprintf(rsp, BUFSIZ, "%s", wm_name);
else
- snprintf(rsp, BUFSIZ, "unknown setting: %s", name);
+ return false;
+ return true;
}
bool parse_bool(char *value, bool *b)
{
- if (strcmp(value, "true") == 0) {
+ if (streq("true", value) || streq("on", value)) {
*b = true;
return true;
- } else if (strcmp(value, "false") == 0) {
+ } else if (streq("false", value) || streq("off", value)) {
*b = false;
return true;
}
bool parse_layout(char *s, layout_t *l)
{
- if (strcmp(s, "monocle") == 0) {
+ if (streq("monocle", s)) {
*l = LAYOUT_MONOCLE;
return true;
- } else if (strcmp(s, "tiled") == 0) {
+ } else if (streq("tiled", s)) {
*l = LAYOUT_TILED;
return true;
}
bool parse_direction(char *s, direction_t *d)
{
- if (strcmp(s, "up") == 0) {
- *d = DIR_UP;
+ if (streq("right", s)) {
+ *d = DIR_RIGHT;
return true;
- } else if (strcmp(s, "down") == 0) {
+ } else if (streq("down", s)) {
*d = DIR_DOWN;
return true;
- } else if (strcmp(s, "left") == 0) {
+ } else if (streq("left", s)) {
*d = DIR_LEFT;
return true;
- } else if (strcmp(s, "right") == 0) {
- *d = DIR_RIGHT;
- return true;
- }
- return false;
-}
-
-bool parse_nearest_argument(char *s, nearest_arg_t *a)
-{
- if (strcmp(s, "older") == 0) {
- *a = NEAREST_OLDER;
- return true;
- } else if (strcmp(s, "newer") == 0) {
- *a = NEAREST_NEWER;
+ } else if (streq("up", s)) {
+ *d = DIR_UP;
return true;
}
return false;
bool parse_cycle_direction(char *s, cycle_dir_t *d)
{
- if (strcmp(s, "prev") == 0) {
- *d = CYCLE_PREV;
- return true;
- } else if (strcmp(s, "next") == 0) {
+ if (streq("next", s)) {
*d = CYCLE_NEXT;
return true;
+ } else if (streq("prev", s)) {
+ *d = CYCLE_PREV;
+ return true;
}
return false;
}
bool parse_circulate_direction(char *s, circulate_dir_t *d)
{
- if (strcmp(s, "forward") == 0) {
+ if (streq("forward", s)) {
*d = CIRCULATE_FORWARD;
return true;
- } else if (strcmp(s, "backward") == 0) {
+ } else if (streq("backward", s)) {
*d = CIRCULATE_BACKWARD;
return true;
}
return false;
}
-bool parse_skip_client(char *s, skip_client_t *k)
-{
- if (s == NULL) {
- *k = CLIENT_SKIP_NONE;
- return true;
- } else if (strcmp(s, "--skip-floating") == 0) {
- *k = CLIENT_SKIP_FLOATING;
- return true;
- } else if (strcmp(s, "--skip-tiled") == 0) {
- *k = CLIENT_SKIP_TILED;
- return true;
- } else if (strcmp(s, "--skip-class-equal") == 0) {
- *k = CLIENT_SKIP_CLASS_EQUAL;
- return true;
- } else if (strcmp(s, "--skip-class-differ") == 0) {
- *k = CLIENT_SKIP_CLASS_DIFFER;
- return true;
- }
- return false;
-}
-
-bool parse_skip_desktop(char *s, skip_desktop_t *k)
-{
- if (s == NULL) {
- *k = DESKTOP_SKIP_NONE;
- return true;
- } else if (strcmp(s, "--skip-free") == 0) {
- *k = DESKTOP_SKIP_FREE;
- return true;
- } else if (strcmp(s, "--skip-occupied") == 0) {
- *k = DESKTOP_SKIP_OCCUPIED;
- return true;
- }
- return false;
-}
-
-bool parse_list_option(char *s, list_option_t *o)
-{
- if (s == NULL) {
- *o = LIST_OPTION_VERBOSE;
- return true;
- } else if (strcmp(s, "--quiet") == 0) {
- *o = LIST_OPTION_QUIET;
- return true;
- }
- return false;
-}
-
-bool parse_send_option(char *s, send_option_t *o)
-{
- if (s == NULL) {
- *o = SEND_OPTION_DONT_FOLLOW;
- return true;
- } else if (strcmp(s, "--follow") == 0) {
- *o = SEND_OPTION_FOLLOW;
- return true;
- }
- return false;
-}
-
-bool parse_swap_option(char *s, swap_option_t *o)
-{
- if (s == NULL) {
- *o = SWAP_OPTION_SWAP_FOCUS;
- return true;
- } else if (strcmp(s, "--keep-focus") == 0) {
- *o = SWAP_OPTION_KEEP_FOCUS;
- return true;
- }
- return false;
-}
-
-bool parse_cancel_option(char *s, cancel_option_t *o)
-{
- if (s == NULL) {
- *o = CANCEL_OPTION_FOCUSED;
- return true;
- } else if (strcmp(s, "--all") == 0) {
- *o = CANCEL_OPTION_ALL;
- return true;
- }
- return false;
-}
-
-bool parse_rotate(char *s, rotate_t *r)
-{
- if (strcmp(s, "clockwise") == 0) {
- *r = ROTATE_CLOCKWISE;
- return true;
- } else if (strcmp(s, "counter_clockwise") == 0) {
- *r = ROTATE_COUNTER_CLOCKWISE;
- return true;
- } else if (strcmp(s, "full_cycle") == 0) {
- *r = ROTATE_FULL_CYCLE;
- return true;
- }
- return false;
-}
-
bool parse_flip(char *s, flip_t *f)
{
- if (strcmp(s, "horizontal") == 0) {
+ if (streq("horizontal", s)) {
*f = FLIP_HORIZONTAL;
return true;
- } else if (strcmp(s, "vertical") == 0) {
+ } else if (streq("vertical", s)) {
*f = FLIP_VERTICAL;
return true;
}
bool parse_fence_move(char *s, fence_move_t *m)
{
- if (strcmp(s, "push") == 0) {
+ if (streq("push", s)) {
*m = MOVE_PUSH;
return true;
- } else if (strcmp(s, "pull") == 0) {
+ } else if (streq("pull", s)) {
*m = MOVE_PULL;
return true;
}
bool parse_pointer_action(char *s, pointer_action_t *a)
{
- if (strcmp(s, "move") == 0) {
+ if (streq("move", s)) {
*a = ACTION_MOVE;
return true;
- } else if (strcmp(s, "resize_corner") == 0) {
+ } else if (streq("resize_corner", s)) {
*a = ACTION_RESIZE_CORNER;
return true;
- } else if (strcmp(s, "resize_side") == 0) {
+ } else if (streq("resize_side", s)) {
*a = ACTION_RESIZE_SIDE;
return true;
- } else if (strcmp(s, "focus") == 0) {
+ } else if (streq("focus", s)) {
*a = ACTION_FOCUS;
return true;
}
return false;
}
+
+bool parse_window_id(char *s, long int *i)
+{
+ char *end;
+ errno = 0;
+ long int ret = strtol(s, &end, 0);
+ if (errno != 0 || *end != '\0')
+ return false;
+ else
+ *i = ret;
+ return true;
+}
#include "types.h"
-#define TOK_SEP " "
+#define OPT_CHR '-'
+#define CAT_CHR '.'
+#define EQL_TOK "="
-void process_message(char*, char*);
-void get_setting(char*, char*);
-void set_setting(char*, char*, char*);
+bool handle_message(char *, int, char *);
+bool process_message(char **, int, char *);
+bool cmd_window(char **, int);
+bool cmd_desktop(char **, int);
+bool cmd_monitor(char **, int);
+bool cmd_query(char **, int, char *);
+bool cmd_rule(char **, int, char *);
+bool cmd_pointer(char **, int);
+bool cmd_control(char **, int);
+bool cmd_restore(char **, int);
+bool cmd_config(char **, int, char *);
+bool cmd_quit(char **, int);
+bool get_setting(char *, char *);
+bool set_setting(char *, char *);
bool parse_bool(char *, bool *);
bool parse_layout(char *, layout_t *);
bool parse_direction(char *, direction_t *);
-bool parse_nearest_argument(char *, nearest_arg_t *);
bool parse_cycle_direction(char *, cycle_dir_t *);
bool parse_circulate_direction(char *, circulate_dir_t *);
-bool parse_list_option(char *, list_option_t *);
-bool parse_send_option(char *, send_option_t *);
-bool parse_swap_option(char *, swap_option_t *);
-bool parse_cancel_option(char *, cancel_option_t *);
-bool parse_skip_client(char *, skip_client_t *);
-bool parse_skip_desktop(char *, skip_desktop_t *);
-bool parse_rotate(char *, rotate_t *);
bool parse_flip(char *, flip_t *);
bool parse_fence_move(char *, fence_move_t *);
bool parse_pointer_action(char *, pointer_action_t *);
+bool parse_window_id(char *, long int *);
#endif
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "bspwm.h"
+#include "tree.h"
+#include "settings.h"
+#include "messages.h"
+#include "query.h"
+
+void query_monitors(coordinates_t loc, domain_t dom, char *rsp)
+{
+ char line[MAXLEN];
+ for (monitor_t *m = mon_head; m != NULL; m = m->next) {
+ if (loc.monitor != NULL && m != loc.monitor)
+ continue;
+ if (dom != DOMAIN_DESKTOP) {
+ if (dom == DOMAIN_MONITOR) {
+ snprintf(line, sizeof(line), "%s\n", m->name);
+ strncat(rsp, line, REMLEN(rsp));
+ continue;
+ } else {
+ snprintf(line, sizeof(line), "%s %ux%u%+i%+i", m->name, m->rectangle.width, m->rectangle.height, m->rectangle.x, m->rectangle.y);
+ strncat(rsp, line, REMLEN(rsp));
+ if (m == mon)
+ strncat(rsp, " #", REMLEN(rsp));
+ else if (m == last_mon)
+ strncat(rsp, " ~", REMLEN(rsp));
+ strncat(rsp, "\n", REMLEN(rsp));
+ }
+ }
+ query_desktops(m, dom, loc, (dom == DOMAIN_DESKTOP ? 0 : 1), rsp);
+ }
+}
+
+void query_desktops(monitor_t *m, domain_t dom, coordinates_t loc, unsigned int depth, char *rsp)
+{
+ char line[MAXLEN];
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
+ if (loc.desktop != NULL && d != loc.desktop)
+ continue;
+ for (unsigned int i = 0; i < depth; i++)
+ strncat(rsp, " ", REMLEN(rsp));
+ if (dom == DOMAIN_DESKTOP) {
+ snprintf(line, sizeof(line), "%s\n", d->name);
+ strncat(rsp, line, REMLEN(rsp));
+ continue;
+ } else {
+ snprintf(line, sizeof(line), "%s %c", d->name, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
+ strncat(rsp, line, REMLEN(rsp));
+ if (d == m->desk)
+ strncat(rsp, " @", REMLEN(rsp));
+ else if (d == m->last_desk)
+ strncat(rsp, " ~", REMLEN(rsp));
+ strncat(rsp, "\n", REMLEN(rsp));
+ }
+ query_tree(d, d->root, rsp, depth + 1);
+ }
+}
+
+void query_tree(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
+{
+ if (n == NULL)
+ return;
+
+ char line[MAXLEN];
+
+ for (unsigned int i = 0; i < depth; i++)
+ strncat(rsp, " ", REMLEN(rsp));
+
+ if (is_leaf(n)) {
+ client_t *c = n->client;
+ snprintf(line, sizeof(line), "%c %s %X %u %ux%u%+i%+i %c%c%c%c%c", (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), c->class_name, c->window, c->border_width, c->floating_rectangle.width, c->floating_rectangle.height, c->floating_rectangle.x, c->floating_rectangle.y, (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'));
+ } else {
+ snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == 90 ? 'a' : (n->birth_rotation == 270 ? 'c' : 'm')), n->split_ratio);
+ }
+
+ strncat(rsp, line, REMLEN(rsp));
+
+ if (n == d->focus)
+ strncat(rsp, " *", REMLEN(rsp));
+ strncat(rsp, "\n", REMLEN(rsp));
+
+ query_tree(d, n->first_child, rsp, depth + 1);
+ query_tree(d, n->second_child, rsp, depth + 1);
+}
+
+void query_history(coordinates_t loc, char *rsp)
+{
+ char line[MAXLEN];
+ 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;
+ snprintf(line, sizeof(line), "%s\n", d->name);
+ strncat(rsp, line, REMLEN(rsp));
+ for (node_list_t *a = d->history->tail; a != NULL; a = a->prev) {
+ snprintf(line, sizeof(line), " %X\n", a->node->client->window);
+ strncat(rsp, line, REMLEN(rsp));
+ }
+ }
+ }
+}
+
+void query_windows(coordinates_t loc, char *rsp)
+{
+ char line[MAXLEN];
+
+ 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;
+ snprintf(line, sizeof(line), "0x%X\n", n->client->window);
+ strncat(rsp, line, REMLEN(rsp));
+ }
+ }
+ }
+}
+
+bool node_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+{
+ client_select_t sel;
+ sel.type = CLIENT_TYPE_ALL;
+ sel.class = CLIENT_CLASS_ALL;
+ char *tok;
+ while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
+ tok[0] = '\0';
+ tok++;
+ if (streq("tiled", tok)) {
+ sel.type = CLIENT_TYPE_TILED;
+ } else if (streq("floating", tok)) {
+ sel.type = CLIENT_TYPE_FLOATING;
+ } else if (streq("like", tok)) {
+ sel.class = CLIENT_CLASS_EQUAL;
+ } else if (streq("unlike", tok)) {
+ sel.class = CLIENT_CLASS_DIFFER;
+ }
+ }
+
+ dst->monitor = ref->monitor;
+ dst->desktop = ref->desktop;
+ dst->node = NULL;
+
+ direction_t dir;
+ cycle_dir_t cyc;
+ if (parse_direction(desc, &dir)) {
+ dst->node = nearest_neighbor(dst->desktop, ref->node, dir);
+ if (dst->node == NULL && monitor_focus_fallback) {
+ if (monitor_from_desc(desc, ref, dst)) {
+ dst->desktop = dst->monitor->desk;
+ dst->node = dst->monitor->desk->focus;
+ return true;
+ }
+ }
+ } else if (parse_cycle_direction(desc, &cyc)) {
+ dst->node = closest_node(ref->desktop, ref->node, cyc, sel);
+ } else if (streq("last", desc)) {
+ dst->node = history_get(ref->desktop->history, 1);
+ } else if (streq("biggest", desc)) {
+ dst->node = find_biggest(ref->desktop);
+ } else if (streq("focused", desc)) {
+ dst->monitor = mon;
+ dst->desktop = mon->desk;
+ dst->node = mon->desk->focus;
+ } else {
+ long int wid;
+ if (parse_window_id(desc, &wid))
+ locate_window(wid, dst);
+ }
+
+ return (dst->node != NULL);
+}
+
+bool desktop_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+{
+ desktop_select_t sel;
+ sel = DESKTOP_ALL;
+ char *tok;
+ while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
+ tok[0] = '\0';
+ tok++;
+ if (streq("free", tok)) {
+ sel = DESKTOP_FREE;
+ } else if (streq("occupied", tok)) {
+ sel = DESKTOP_OCCUPIED;
+ }
+ }
+
+ dst->desktop = NULL;
+
+ cycle_dir_t cyc;
+ if (parse_cycle_direction(desc, &cyc)) {
+ dst->monitor = ref->monitor;
+ dst->desktop = closest_desktop(ref->monitor, ref->desktop, cyc, sel);
+ } else if (streq("last", desc)) {
+ dst->monitor = mon;
+ dst->desktop = mon->last_desk;
+ } else if (streq("focused", desc)) {
+ dst->monitor = mon;
+ dst->desktop = mon->desk;
+ } else {
+ locate_desktop(desc, dst);
+ }
+
+ return (dst->desktop != NULL);
+}
+
+bool monitor_from_desc(char *desc, coordinates_t *ref, coordinates_t *dst)
+{
+ desktop_select_t sel;
+ sel = DESKTOP_ALL;
+ char *tok;
+ while ((tok = strrchr(desc, CAT_CHR)) != NULL) {
+ tok[0] = '\0';
+ tok++;
+ if (streq("free", tok)) {
+ sel = DESKTOP_FREE;
+ } else if (streq("occupied", tok)) {
+ sel = DESKTOP_OCCUPIED;
+ }
+ }
+
+ dst->monitor = NULL;
+
+ direction_t dir;
+ cycle_dir_t cyc;
+ if (parse_direction(desc, &dir)) {
+ dst->monitor = nearest_monitor(ref->monitor, dir);
+ } else if (parse_cycle_direction(desc, &cyc)) {
+ dst->monitor = closest_monitor(ref->monitor, cyc, sel);
+ } else if (streq("last", desc)) {
+ dst->monitor = last_mon;
+ } else if (streq("focused", desc)) {
+ dst->monitor = mon;
+ } else {
+ locate_monitor(desc, dst);
+ }
+
+ return (dst->monitor != NULL);
+}
+
+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) {
+ 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)
+ 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)
+ if (streq(m->name, name)) {
+ loc->monitor = m;
+ return true;
+ }
+ return false;
+}
--- /dev/null
+#ifndef _QUERY_H
+#define _QUERY_H
+
+typedef enum {
+ DOMAIN_MONITOR,
+ DOMAIN_DESKTOP,
+ DOMAIN_WINDOW,
+ DOMAIN_TREE,
+ DOMAIN_HISTORY
+} domain_t;
+
+void query_monitors(coordinates_t, domain_t, char *);
+void query_desktops(monitor_t *, domain_t, coordinates_t, unsigned int, char *);
+void query_tree(desktop_t *, node_t *, char *, unsigned int);
+void query_history(coordinates_t, char *);
+void query_windows(coordinates_t, char *);
+bool locate_window(xcb_window_t, coordinates_t *);
+bool locate_desktop(char *, coordinates_t *);
+bool locate_monitor(char *, coordinates_t *);
+bool node_from_desc(char *, coordinates_t *, coordinates_t *);
+bool desktop_from_desc(char *, coordinates_t *, coordinates_t *);
+bool monitor_from_desc(char *, coordinates_t *, coordinates_t *);
+
+#endif
--- /dev/null
+#include <ctype.h>
+#include <string.h>
+#include "types.h"
+#include "tree.h"
+#include "settings.h"
+#include "ewmh.h"
+#include "bspwm.h"
+#include "query.h"
+#include "restore.h"
+
+void restore_tree(char *file_path)
+{
+ if (file_path == NULL)
+ return;
+
+ FILE *snapshot = fopen(file_path, "r");
+ if (snapshot == NULL) {
+ warn("Restore: can't open file\n");
+ return;
+ }
+
+ PUTS("restore tree");
+
+ char line[MAXLEN];
+ monitor_t *m = NULL;
+ desktop_t *d = NULL;
+ node_t *n = NULL;
+ num_clients = 0;
+ unsigned int level, last_level = 0;
+ bool aborted = false;
+
+ while (!aborted && fgets(line, sizeof(line), snapshot) != NULL) {
+ unsigned int len = strlen(line);
+ level = 0;
+ while (level < strlen(line) && isspace(line[level]))
+ level++;
+ if (level == 0) {
+ if (m == NULL)
+ m = mon_head;
+ else
+ m = m->next;
+ if (len >= 2)
+ switch (line[len - 2]) {
+ case '#':
+ mon = m;
+ break;
+ case '~':
+ last_mon = m;
+ break;
+ }
+ } else if (level == 2) {
+ if (d == NULL)
+ d = m->desk_head;
+ else
+ d = d->next;
+ int i = len - 1;
+ while (i > 0 && !isupper(line[i]))
+ i--;
+ if (line[i] == 'M')
+ d->layout = LAYOUT_MONOCLE;
+ else if (line[i] == 'T')
+ d->layout = LAYOUT_TILED;
+ if (len >= 2)
+ switch (line[len - 2]) {
+ case '@':
+ m->desk = d;
+ break;
+ case '~':
+ m->last_desk = d;
+ break;
+ }
+ } else {
+ node_t *birth = make_node();
+ if (level == 4) {
+ empty_desktop(d);
+ d->root = birth;
+ } else {
+ if (level > last_level) {
+ n->first_child = birth;
+ } else {
+ do {
+ n = n->parent;
+ } while (n != NULL && n->second_child != NULL);
+ if (n == NULL) {
+ warn("Restore: file is malformed\n");
+ aborted = true;
+ }
+ n->second_child = birth;
+ }
+ birth->parent = n;
+ }
+ n = birth;
+
+ char br;
+ if (isupper(line[level])) {
+ char st;
+ sscanf(line + level, "%c %c %lf", &st, &br, &n->split_ratio);
+ if (st == 'H')
+ n->split_type = TYPE_HORIZONTAL;
+ else if (st == 'V')
+ n->split_type = TYPE_VERTICAL;
+ } else {
+ client_t *c = make_client(XCB_NONE);
+ num_clients++;
+ char floating, transient, fullscreen, urgent, locked;
+ sscanf(line + level, "%c %s %X %u %hux%hu%hi%hi %c%c%c%c%c", &br, c->class_name, &c->window, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &floating, &transient, &fullscreen, &urgent, &locked);
+ c->floating = (floating == '-' ? false : true);
+ c->transient = (transient == '-' ? false : true);
+ c->fullscreen = (fullscreen == '-' ? false : true);
+ c->urgent = (urgent == '-' ? false : true);
+ c->locked = (locked == '-' ? false : true);
+ n->client = c;
+ if (len >= 2 && line[len - 2] == '*')
+ d->focus = n;
+ }
+ if (br == 'a')
+ n->birth_rotation = 90;
+ else if (br == 'c')
+ n->birth_rotation = 270;
+ else if (br == 'm')
+ n->birth_rotation = 0;
+ }
+ last_level = level;
+ }
+
+ fclose(snapshot);
+
+ if (!aborted) {
+ for (monitor_t *m = mon_head; m != NULL; m = m->next)
+ for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
+ for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
+ uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
+ xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
+ if (n->client->floating) {
+ n->vacant = true;
+ update_vacant_state(n->parent);
+ }
+ }
+ ewmh_update_current_desktop();
+ }
+}
+
+void restore_history(char *file_path)
+{
+ if (file_path == NULL)
+ return;
+
+ FILE *snapshot = fopen(file_path, "r");
+ if (snapshot == NULL) {
+ warn("Restore history: can't open file\n");
+ return;
+ }
+
+ PUTS("restore history");
+
+ char line[MAXLEN];
+ desktop_t *d = NULL;
+ unsigned int level;
+
+ while (fgets(line, sizeof(line), snapshot) != NULL) {
+ unsigned int i = strlen(line) - 1;
+ while (i > 0 && isspace(line[i]))
+ line[i--] = '\0';
+ level = 0;
+ while (level < strlen(line) && isspace(line[level]))
+ level++;
+ if (level == 0) {
+ coordinates_t loc;
+ if (locate_desktop(line + level, &loc))
+ d = loc.desktop;
+ } else if (d != NULL) {
+ xcb_window_t win;
+ if (sscanf(line + level, "%X", &win) == 1) {
+ coordinates_t loc;
+ if (locate_window(win, &loc))
+ history_add(d->history, loc.node);
+ }
+ }
+ }
+
+ fclose(snapshot);
+}
--- /dev/null
+#ifndef _RESTORE_H
+#define _RESTORE_H
+
+void restore_tree(char *);
+void restore_history(char *);
+
+#endif
#include "bspwm.h"
#include "ewmh.h"
#include "rules.h"
+#include "query.h"
void add_rule(rule_t *r)
{
remove_rule(find_rule(uid));
}
-void prune_rules(desktop_t *d)
-{
- rule_t *r = rule_head;
- while (r != NULL) {
- rule_t *next = r->next;
- if (r->effect.desktop == d)
- remove_rule(r);
- r = next;
- }
-}
-
rule_t *find_rule(unsigned int uid)
{
for (rule_t *r = rule_head; r != NULL; r = r->next)
{
xcb_icccm_get_wm_class_reply_t reply;
if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &reply, NULL) == 1
- && (strcmp(reply.class_name, r->cause.name) == 0
- || strcmp(reply.instance_name, r->cause.name) == 0)) {
+ && (streq(reply.class_name, r->cause.name)
+ || streq(reply.instance_name, r->cause.name))) {
xcb_icccm_get_wm_class_reply_wipe(&reply);
return true;
}
*floating = true;
if (efc.follow)
*follow = true;
- if (efc.monitor != NULL && efc.desktop != NULL) {
- *m = efc.monitor;
- *d = efc.desktop;
+ if (efc.desc[0] != '\0') {
+ coordinates_t ref = {*m, *d, NULL};
+ coordinates_t loc;
+ if (desktop_from_desc(efc.desc, &ref, &loc)) {
+ *m = loc.monitor;
+ *d = loc.desktop;
+ }
}
}
rule = rule->next;
}
}
-void list_rules(char *rsp)
+void list_rules(char *pattern, char *rsp)
{
char line[MAXLEN];
for (rule_t *r = rule_head; r != NULL; r = r->next) {
- snprintf(line, sizeof(line), "%2X %s %s %s %s\n", r->uid, r->cause.name, (r->effect.desktop != NULL ? r->effect.desktop->name : "\b"), (r->effect.floating ? "floating" : "\b"), (r->effect.follow ? "follow" : "\b"));
+ if (pattern != NULL && !streq(pattern, r->cause.name))
+ continue;
+ snprintf(line, sizeof(line), "%2X %s", r->uid, r->cause.name);
strncat(rsp, line, REMLEN(rsp));
+ if (r->effect.floating)
+ strncat(rsp, " --floating", REMLEN(rsp));
+ if (r->effect.follow)
+ strncat(rsp, " --follow", REMLEN(rsp));
+ if (r->effect.desc[0] != '\0') {
+ snprintf(line, sizeof(line), " -d %s", r->effect.desc);
+ strncat(rsp, line, REMLEN(rsp));
+ }
+ strncat(rsp, "\n", REMLEN(rsp));
}
}
rule_t *find_rule(unsigned int);
bool is_match(rule_t *, xcb_window_t);
void handle_rules(xcb_window_t, monitor_t **, desktop_t **, bool *, bool *, bool *, bool *, bool *, bool *);
-void list_rules(char *);
+void list_rules(char *, char *);
#endif
strncpy(normal_locked_border_color, NORMAL_LOCKED_BORDER_COLOR, sizeof(normal_locked_border_color));
strncpy(urgent_border_color, URGENT_BORDER_COLOR, sizeof(urgent_border_color));
- normal_border_color_pxl = get_color(normal_border_color);
- focused_border_color_pxl = get_color(active_border_color);
- active_border_color_pxl = get_color(active_border_color);
- presel_border_color_pxl = get_color(presel_border_color);
- focused_locked_border_color_pxl = get_color(active_locked_border_color);
- active_locked_border_color_pxl = get_color(active_locked_border_color);
- normal_locked_border_color_pxl = get_color(normal_locked_border_color);
- urgent_border_color_pxl = get_color(urgent_border_color);
+ get_color(normal_border_color, &normal_border_color_pxl);
+ get_color(active_border_color, &focused_border_color_pxl);
+ get_color(active_border_color, &active_border_color_pxl);
+ get_color(presel_border_color, &presel_border_color_pxl);
+ get_color(active_locked_border_color, &focused_locked_border_color_pxl);
+ get_color(active_locked_border_color, &active_locked_border_color_pxl);
+ get_color(normal_locked_border_color, &normal_locked_border_color_pxl);
+ get_color(urgent_border_color, &urgent_border_color_pxl);
strncpy(wm_name, WM_NAME, sizeof(wm_name));
-#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <limits.h>
#include <math.h>
+#include <limits.h>
#include <float.h>
-#include <xcb/xcb.h>
-#include <xcb/xcb_event.h>
#include "settings.h"
#include "helpers.h"
#include "window.h"
void change_split_ratio(node_t *n, value_change_t chg)
{
- n->split_ratio = pow(n->split_ratio, (chg == CHANGE_INCREASE ? INC_EXP : DEC_EXP));
+ n->split_ratio = pow(n->split_ratio,
+ (chg == CHANGE_INCREASE ? (1 / GROWTH_FACTOR) : GROWTH_FACTOR));
}
void change_layout(monitor_t *m, desktop_t *d, layout_t l)
put_status();
}
-void reset_mode(desktop_t *d, node_t *n, cancel_option_t c)
+void reset_mode(coordinates_t *loc)
{
- if (c == CANCEL_OPTION_FOCUSED) {
- n->split_mode = MODE_AUTOMATIC;
- window_draw_border(mon->desk->focus, d->focus == n, true);
- } else if (c == CANCEL_OPTION_ALL) {
- for (node_t *a = first_extrema(d->root); a != NULL; a = next_leaf(a, d->root)) {
+ if (loc->node != NULL) {
+ loc->node->split_mode = MODE_AUTOMATIC;
+ window_draw_border(loc->node, loc->desktop->focus == loc->node, mon == loc->monitor);
+ } else if (loc->desktop != NULL) {
+ for (node_t *a = first_extrema(loc->desktop->root); a != NULL; a = next_leaf(a, loc->desktop->root)) {
a->split_mode = MODE_AUTOMATIC;
- window_draw_border(a, d->focus == a, true);
+ window_draw_border(a, loc->desktop->focus == a, mon == loc->monitor);
}
}
}
return second_extrema(p->parent->first_child);
}
-bool is_adjacent(node_t *a, node_t *r)
+/* bool is_adjacent(node_t *a, node_t *r) */
+/* { */
+/* node_t *f = r->parent; */
+/* node_t *p = a; */
+/* bool first_child = is_first_child(r); */
+/* while (p != r) { */
+/* if (p->parent->split_type == f->split_type && is_first_child(p) == first_child) */
+/* return false; */
+/* p = p->parent; */
+/* } */
+/* return true; */
+/* } */
+
+/* Returns true if *b* is adjacent to *a* in the direction *dir* */
+bool is_adjacent(node_t *a, node_t *b, direction_t dir)
{
- node_t *f = r->parent;
- node_t *p = a;
- bool first_child = is_first_child(r);
- while (p != r) {
- if (p->parent->split_type == f->split_type && is_first_child(p) == first_child)
- return false;
- p = p->parent;
+ switch (dir) {
+ case DIR_RIGHT:
+ return (a->rectangle.x + a->rectangle.width) == b->rectangle.x;
+ break;
+ case DIR_DOWN:
+ return (a->rectangle.y + a->rectangle.height) == b->rectangle.y;
+ break;
+ case DIR_LEFT:
+ return (b->rectangle.x + b->rectangle.width) == a->rectangle.x;
+ break;
+ case DIR_UP:
+ return (b->rectangle.y + b->rectangle.height) == a->rectangle.y;
+ break;
}
- return true;
+ return false;
}
node_t *find_fence(node_t *n, direction_t dir)
int min_rank = INT_MAX;
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
- if (!is_tiled(a->client) || !is_adjacent(a, target) || a == n)
+ if (a->vacant || !is_adjacent(n, a, dir) || a == n)
continue;
int rank = history_rank(f, a);
if (rank >= 0 && rank < min_rank) {
for (node_t *a = first_extrema(target); a != NULL; a = next_leaf(a, target)) {
if (is_tiled(a->client) != is_tiled(n->client)
- || (is_tiled(a->client) && !is_adjacent(a, target))
+ || (is_tiled(a->client) && !is_adjacent(n, a, dir))
|| a == n)
continue;
get_side_handle(a->client, dir2, &pt2);
change_split_ratio(fence, CHANGE_DECREASE);
}
-void rotate_tree(node_t *n, rotate_t rot)
+void rotate_tree(node_t *n, int rot)
{
- if (n == NULL || is_leaf(n) || rot == ROTATE_IDENTITY)
+ if (n == NULL || is_leaf(n) || rot == 0)
return;
node_t *tmp;
- if ((rot == ROTATE_CLOCKWISE && n->split_type == TYPE_HORIZONTAL)
- || (rot == ROTATE_COUNTER_CLOCKWISE && n->split_type == TYPE_VERTICAL)
- || rot == ROTATE_FULL_CYCLE) {
+ if ((rot == 90 && n->split_type == TYPE_HORIZONTAL)
+ || (rot == 270 && n->split_type == TYPE_VERTICAL)
+ || rot == 180) {
tmp = n->first_child;
n->first_child = n->second_child;
n->second_child = tmp;
n->split_ratio = 1.0 - n->split_ratio;
}
- if (rot != ROTATE_FULL_CYCLE) {
+ if (rot != 180) {
if (n->split_type == TYPE_HORIZONTAL)
n->split_type = TYPE_VERTICAL;
else if (n->split_type == TYPE_VERTICAL)
rotate_tree(n->parent->first_child, n->birth_rotation);
}
-void unrotate_tree(node_t *n, rotate_t rot)
+void unrotate_tree(node_t *n, int rot)
{
- switch(rot) {
- case ROTATE_CLOCKWISE:
- rotate_tree(n, ROTATE_COUNTER_CLOCKWISE);
- break;
- case ROTATE_COUNTER_CLOCKWISE:
- rotate_tree(n, ROTATE_CLOCKWISE);
- break;
- case ROTATE_IDENTITY:
- case ROTATE_FULL_CYCLE:
- break;
- }
+ if (rot == 0)
+ return;
+ rotate_tree(n, 360 - rot);
}
void unrotate_brother(node_t *n)
flip_tree(n->second_child, flp);
}
-void list_history(char *rsp)
-{
- char line[MAXLEN];
- for (monitor_t *m = mon_head; m != NULL; m = m->next)
- for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
- snprintf(line, sizeof(line), "%s\n", d->name);
- strncat(rsp, line, REMLEN(rsp));
- for (node_list_t *a = d->history->tail; a != NULL; a = a->prev) {
- snprintf(line, sizeof(line), " %X\n", a->node->client->window);
- strncat(rsp, line, REMLEN(rsp));
- }
- }
-}
-
int balance_tree(node_t *n)
{
if (n == NULL || n->vacant) {
fence = rect.width * n->split_ratio;
first_rect = (xcb_rectangle_t) {rect.x, rect.y, fence, rect.height};
second_rect = (xcb_rectangle_t) {rect.x + fence, rect.y, rect.width - fence, rect.height};
-
} else if (n->split_type == TYPE_HORIZONTAL) {
fence = rect.height * n->split_ratio;
first_rect = (xcb_rectangle_t) {rect.x, rect.y, rect.width, fence};
c->split_type = p->split_type;
c->split_ratio = p->split_ratio;
p->parent = c;
- rotate_t rot;
+ int rot;
if (is_first_child(f)) {
c->first_child = n;
c->second_child = p;
- rot = ROTATE_CLOCKWISE;
+ rot = 90;
} else {
c->first_child = p;
c->second_child = n;
- rot = ROTATE_COUNTER_CLOCKWISE;
+ rot = 270;
}
if (!is_floating(n->client))
rotate_tree(p, rot);
c->split_ratio = f->split_ratio;
c->parent = p;
f->parent = c;
- f->birth_rotation = ROTATE_IDENTITY;
+ f->birth_rotation = 0;
switch (f->split_dir) {
case DIR_LEFT:
c->split_type = TYPE_VERTICAL;
node_t *pn2 = n2->parent;
bool n1_first_child = is_first_child(n1);
bool n2_first_child = is_first_child(n2);
- rotate_t br1 = n1->birth_rotation;
- rotate_t br2 = n2->birth_rotation;
+ int br1 = n1->birth_rotation;
+ int br2 = n2->birth_rotation;
if (pn1 != NULL) {
if (n1_first_child)
put_status();
}
-monitor_t *nearest_monitor(direction_t dir)
+monitor_t *nearest_monitor(monitor_t *m, direction_t dir)
{
int dmin = INT_MAX;
monitor_t *nearest = NULL;
- xcb_rectangle_t rect = mon->rectangle;
- for (monitor_t *m = mon_head; m != NULL; m = m->next) {
- if (m == mon)
+ xcb_rectangle_t rect = m->rectangle;
+ for (monitor_t *f = mon_head; f != NULL; f = f->next) {
+ if (f == m)
continue;
- xcb_rectangle_t r = m->rectangle;
+ 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) ||
ABS((r.y + r.height / 2) - (rect.y + rect.height / 2));
if (d < dmin) {
dmin = d;
- nearest = m;
+ nearest = f;
}
}
}
put_status();
}
-void cycle_monitor(cycle_dir_t dir)
+monitor_t *closest_monitor(monitor_t *m, cycle_dir_t dir, desktop_select_t sel)
{
- monitor_t *m = NULL;
- if (dir == CYCLE_NEXT)
- m = (mon->next == NULL ? mon_head : mon->next);
- else if (dir == CYCLE_PREV)
- m = (mon->prev == NULL ? mon_tail : mon->prev);
- focus_node(m, m->desk, m->desk->focus);
+ monitor_t *f = (dir == CYCLE_PREV ? m->prev : m->next);
+ if (f == NULL)
+ f = (dir == CYCLE_PREV ? mon_tail : mon_head);
+
+ while (f != m) {
+ if (sel == DESKTOP_ALL
+ || (sel == DESKTOP_FREE && f->desk->root == NULL)
+ || (sel == DESKTOP_OCCUPIED && f->desk->root != NULL)) {
+ return f;
+ }
+ f = (dir == CYCLE_PREV ? m->prev : m->next);
+ if (f == NULL)
+ f = (dir == CYCLE_PREV ? mon_tail : mon_head);
+ }
+
+ return NULL;
}
-void cycle_desktop(monitor_t *m, desktop_t *d, cycle_dir_t dir, skip_desktop_t skip)
+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)
f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
while (f != d) {
- if (skip == DESKTOP_SKIP_NONE
- || (skip == DESKTOP_SKIP_FREE && f->root != NULL)
- || (skip == DESKTOP_SKIP_OCCUPIED && f->root == NULL)) {
- focus_node(m, f, f->focus);
- return;
+ if (sel == DESKTOP_ALL
+ || (sel == DESKTOP_FREE && f->root == NULL)
+ || (sel == DESKTOP_OCCUPIED && f->root != NULL)) {
+ return f;
}
f = (dir == CYCLE_PREV ? f->prev : f->next);
if (f == NULL)
f = (dir == CYCLE_PREV ? m->desk_tail : m->desk_head);
}
+
+ return NULL;
}
-void cycle_leaf(monitor_t *m, desktop_t *d, node_t *n, cycle_dir_t dir, skip_client_t skip)
+node_t *closest_node(desktop_t *d, node_t *n, cycle_dir_t dir, client_select_t sel)
{
if (n == NULL)
- return;
-
- PUTS("cycle leaf");
+ return NULL;
node_t *f = (dir == CYCLE_PREV ? prev_leaf(n, d->root) : next_leaf(n, d->root));
if (f == NULL)
while (f != n) {
bool tiled = is_tiled(f->client);
- if (skip == CLIENT_SKIP_NONE || (skip == CLIENT_SKIP_TILED && !tiled) || (skip == CLIENT_SKIP_FLOATING && tiled)
- || (skip == CLIENT_SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0)
- || (skip == CLIENT_SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0)) {
- focus_node(m, d, f);
- return;
+ if ((sel.type == CLIENT_TYPE_ALL
+ || (tiled && sel.type == CLIENT_TYPE_TILED)
+ || (!tiled && sel.type == CLIENT_TYPE_FLOATING)) &&
+ (sel.class == CLIENT_CLASS_ALL
+ || (sel.class == CLIENT_CLASS_EQUAL
+ && streq(f->client->class_name, n->client->class_name))
+ || (sel.class == CLIENT_CLASS_DIFFER
+ && !streq(f->client->class_name, n->client->class_name)))) {
+ return f;
}
f = (dir == CYCLE_PREV ? prev_leaf(f, d->root) : next_leaf(f, d->root));
if (f == NULL)
f = (dir == CYCLE_PREV ? second_extrema(d->root) : first_extrema(d->root));
}
-}
-
-void nearest_leaf(monitor_t *m, desktop_t *d, node_t *n, nearest_arg_t dir, skip_client_t skip)
-{
- if (n == NULL)
- return;
-
- PUTS("nearest leaf");
-
- node_t *x = NULL;
-
- for (node_t *f = first_extrema(d->root); f != NULL; f = next_leaf(f, d->root))
- if (skip == CLIENT_SKIP_NONE || (skip == CLIENT_SKIP_TILED && !is_tiled(f->client)) || (skip == CLIENT_SKIP_FLOATING && is_tiled(f->client))
- || (skip == CLIENT_SKIP_CLASS_DIFFER && strcmp(f->client->class_name, n->client->class_name) == 0)
- || (skip == CLIENT_SKIP_CLASS_EQUAL && strcmp(f->client->class_name, n->client->class_name) != 0))
- if ((dir == NEAREST_OLDER
- && (f->client->uid < n->client->uid)
- && (x == NULL || f->client->uid > x->client->uid))
- || (dir == NEAREST_NEWER
- && (f->client->uid > n->client->uid)
- && (x == NULL || f->client->uid < x->client->uid)))
- x = f;
-
- focus_node(m, d, x);
+ return NULL;
}
void circulate_leaves(monitor_t *m, desktop_t *d, circulate_dir_t dir)
crect.y -= mrect.height;
c->floating_rectangle = crect;
}
-
-void put_status(void)
-{
- if (status_fifo == NULL)
- return;
- if (status_prefix != NULL)
- fprintf(status_fifo, "%s", status_prefix);
- bool urgent = false;
- for (monitor_t *m = mon_head; m != NULL; m = m->next) {
- fprintf(status_fifo, "%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))
- urgent |= n->client->urgent;
- fprintf(status_fifo, "%c%s:", m->desk == d ? (urgent ? 'U' : 'D') : (d->root == NULL ? 'E' : (urgent ? 'u' : 'd')), d->name);
- }
- }
- if (mon != NULL && mon->desk != NULL)
- fprintf(status_fifo, "L%s", (mon->desk->layout == LAYOUT_TILED ? "tiled" : "monocle"));
- fprintf(status_fifo, "\n");
- fflush(status_fifo);
-}
-
-void list_monitors(list_option_t opt, char *rsp)
-{
- char line[MAXLEN];
- for (monitor_t *m = mon_head; m != NULL; m = m->next) {
- snprintf(line, sizeof(line), "%s %ux%u%+i%+i", m->name, m->rectangle.width, m->rectangle.height, m->rectangle.x, m->rectangle.y);
- strncat(rsp, line, REMLEN(rsp));
- if (m == mon)
- strncat(rsp, " #\n", REMLEN(rsp));
- else if (m == last_mon)
- strncat(rsp, " ~\n", REMLEN(rsp));
- else
- strncat(rsp, "\n", REMLEN(rsp));
- if (opt == LIST_OPTION_VERBOSE)
- list_desktops(m, opt, 1, rsp);
- }
-}
-
-void list_desktops(monitor_t *m, list_option_t opt, unsigned int depth, char *rsp)
-{
- char line[MAXLEN];
- for (desktop_t *d = m->desk_head; d != NULL; d = d->next) {
- for (unsigned int i = 0; i < depth; i++)
- strncat(rsp, " ", REMLEN(rsp));
- snprintf(line, sizeof(line), "%s %c", d->name, (d->layout == LAYOUT_TILED ? 'T' : 'M'));
- strncat(rsp, line, REMLEN(rsp));
- if (d == m->desk)
- strncat(rsp, " @\n", REMLEN(rsp));
- else if (d == m->last_desk)
- strncat(rsp, " ~\n", REMLEN(rsp));
- else
- strncat(rsp, "\n", REMLEN(rsp));
- if (opt == LIST_OPTION_VERBOSE)
- list(d, d->root, rsp, depth + 1);
- }
-}
-
-void list(desktop_t *d, node_t *n, char *rsp, unsigned int depth)
-{
- if (n == NULL)
- return;
-
- char line[MAXLEN];
-
- for (unsigned int i = 0; i < depth; i++)
- strncat(rsp, " ", REMLEN(rsp));
-
- if (is_leaf(n)) {
- client_t *c = n->client;
- snprintf(line, sizeof(line), "%c %s %X %u %u %ux%u%+i%+i %c%c%c%c%c", (n->birth_rotation == ROTATE_CLOCKWISE ? 'a' : (n->birth_rotation == ROTATE_COUNTER_CLOCKWISE ? 'c' : 'm')), c->class_name, c->window, c->uid, c->border_width, c->floating_rectangle.width, c->floating_rectangle.height, c->floating_rectangle.x, c->floating_rectangle.y, (c->floating ? 'f' : '-'), (c->transient ? 't' : '-'), (c->fullscreen ? 'F' : '-'), (c->urgent ? 'u' : '-'), (c->locked ? 'l' : '-'));
- } else {
- snprintf(line, sizeof(line), "%c %c %.2f", (n->split_type == TYPE_HORIZONTAL ? 'H' : 'V'), (n->birth_rotation == ROTATE_CLOCKWISE ? 'a' : (n->birth_rotation == ROTATE_COUNTER_CLOCKWISE ? 'c' : 'm')), n->split_ratio);
- }
-
- strncat(rsp, line, REMLEN(rsp));
-
- if (n == d->focus)
- strncat(rsp, " *\n", REMLEN(rsp));
- else
- strncat(rsp, "\n", REMLEN(rsp));
-
- list(d, n->first_child, rsp, depth + 1);
- list(d, n->second_child, rsp, depth + 1);
-}
-
-void restore_layout(char *file_path)
-{
- if (file_path == NULL)
- return;
-
- FILE *snapshot = fopen(file_path, "r");
- if (snapshot == NULL) {
- warn("restore: can't open file\n");
- return;
- }
-
- PUTS("restore layout");
-
- char line[MAXLEN];
- monitor_t *m = NULL;
- desktop_t *d = NULL;
- node_t *n = NULL;
- num_clients = 0;
- unsigned int level, last_level = 0, max_uid = 0;
- bool aborted = false;
-
- while (!aborted && fgets(line, sizeof(line), snapshot) != NULL) {
- unsigned int len = strlen(line);
- level = 0;
- while (level < strlen(line) && isspace(line[level]))
- level++;
- if (level == 0) {
- if (m == NULL)
- m = mon_head;
- else
- m = m->next;
- if (len >= 2)
- switch (line[len - 2]) {
- case '#':
- mon = m;
- break;
- case '~':
- last_mon = m;
- break;
- }
- } else if (level == 2) {
- if (d == NULL)
- d = m->desk_head;
- else
- d = d->next;
- int i = len - 1;
- while (i > 0 && !isupper(line[i]))
- i--;
- if (line[i] == 'M')
- d->layout = LAYOUT_MONOCLE;
- else if (line[i] == 'T')
- d->layout = LAYOUT_TILED;
- if (len >= 2)
- switch (line[len - 2]) {
- case '@':
- m->desk = d;
- break;
- case '~':
- m->last_desk = d;
- break;
- }
- } else {
- node_t *birth = make_node();
- if (level == 4) {
- empty_desktop(d);
- d->root = birth;
- } else {
- if (level > last_level) {
- n->first_child = birth;
- } else {
- do {
- n = n->parent;
- } while (n != NULL && n->second_child != NULL);
- if (n == NULL) {
- warn("restore: file is malformed\n");
- aborted = true;
- }
- n->second_child = birth;
- }
- birth->parent = n;
- }
- n = birth;
-
- char br;
- if (isupper(line[level])) {
- char st;
- sscanf(line + level, "%c %c %lf", &st, &br, &n->split_ratio);
- if (st == 'H')
- n->split_type = TYPE_HORIZONTAL;
- else if (st == 'V')
- n->split_type = TYPE_VERTICAL;
- } else {
- client_t *c = make_client(XCB_NONE);
- num_clients++;
- char floating, transient, fullscreen, urgent, locked;
- sscanf(line + level, "%c %s %X %u %u %hux%hu%hi%hi %c%c%c%c%c", &br, c->class_name, &c->window, &c->uid, &c->border_width, &c->floating_rectangle.width, &c->floating_rectangle.height, &c->floating_rectangle.x, &c->floating_rectangle.y, &floating, &transient, &fullscreen, &urgent, &locked);
- c->floating = (floating == '-' ? false : true);
- c->transient = (transient == '-' ? false : true);
- c->fullscreen = (fullscreen == '-' ? false : true);
- c->urgent = (urgent == '-' ? false : true);
- c->locked = (locked == '-' ? false : true);
- if (c->uid > max_uid)
- max_uid = c->uid;
- n->client = c;
- if (len >= 2 && line[len - 2] == '*')
- d->focus = n;
- }
- if (br == 'a')
- n->birth_rotation = ROTATE_CLOCKWISE;
- else if (br == 'c')
- n->birth_rotation = ROTATE_COUNTER_CLOCKWISE;
- else if (br == 'm')
- n->birth_rotation = ROTATE_IDENTITY;
- }
- last_level = level;
- }
-
- fclose(snapshot);
-
- if (!aborted) {
- client_uid = max_uid + 1;
- for (monitor_t *m = mon_head; m != NULL; m = m->next)
- for (desktop_t *d = m->desk_head; d != NULL; d = d->next)
- for (node_t *n = first_extrema(d->root); n != NULL; n = next_leaf(n, d->root)) {
- uint32_t values[] = {(focus_follows_pointer ? CLIENT_EVENT_MASK_FFP : CLIENT_EVENT_MASK)};
- xcb_change_window_attributes(dpy, n->client->window, XCB_CW_EVENT_MASK, values);
- if (n->client->floating) {
- n->vacant = true;
- update_vacant_state(n->parent);
- }
- }
- ewmh_update_current_desktop();
- }
-}
-
-void restore_history(char *file_path)
-{
- if (file_path == NULL)
- return;
-
- FILE *snapshot = fopen(file_path, "r");
- if (snapshot == NULL) {
- warn("restore history: can't open file\n");
- return;
- }
-
- PUTS("restore history");
-
- char line[MAXLEN];
- desktop_t *d = NULL;
- unsigned int level;
-
- while (fgets(line, sizeof(line), snapshot) != NULL) {
- unsigned int i = strlen(line) - 1;
- while (i > 0 && isspace(line[i]))
- line[i--] = '\0';
- level = 0;
- while (level < strlen(line) && isspace(line[level]))
- level++;
- if (level == 0) {
- desktop_location_t loc;
- if (locate_desktop(line + level, &loc))
- d = loc.desktop;
- } else if (d != NULL) {
- xcb_window_t win;
- if (sscanf(line + level, "%X", &win) == 1) {
- window_location_t loc;
- if (locate_window(win, &loc))
- history_add(d->history, loc.node);
- }
- }
- }
-
- fclose(snapshot);
-}
#ifndef _TREE_H
#define _TREE_H
-#define INC_EXP 0.9
-#define DEC_EXP 1.1
+#define GROWTH_FACTOR 1.1
+void arrange(monitor_t *, desktop_t *);
+void apply_layout(monitor_t *, desktop_t *, node_t *, xcb_rectangle_t, xcb_rectangle_t);
+void focus_node(monitor_t *, desktop_t *, node_t *);
+void insert_node(monitor_t *, desktop_t *, node_t *, node_t *);
+void unlink_node(desktop_t *, node_t *);
+void remove_node(desktop_t *, node_t *);
+void swap_nodes(node_t *, node_t *, bool);
+void pseudo_focus(desktop_t *, node_t *);
+void update_current(void);
+node_t *find_fence(node_t *, direction_t);
+node_t *nearest_neighbor(desktop_t *, node_t *, direction_t);
+node_t *nearest_from_tree(node_t *, direction_t);
+node_t *nearest_from_distance(desktop_t *, node_t *, direction_t);
+node_t *nearest_from_history(focus_history_t *, node_t *, direction_t);
+node_t *find_biggest(desktop_t *);
bool is_leaf(node_t *);
bool is_tiled(client_t *);
bool is_floating(client_t *);
bool is_second_child(node_t *);
void change_split_ratio(node_t *, value_change_t);
void change_layout(monitor_t *, desktop_t *, layout_t);
-void reset_mode(desktop_t *, node_t *, cancel_option_t);
+void reset_mode(coordinates_t *);
node_t *first_extrema(node_t *);
node_t *second_extrema(node_t *);
node_t *next_leaf(node_t *, node_t *);
node_t *prev_leaf(node_t *, node_t *);
-bool is_adjacent(node_t *, node_t *);
-node_t *find_fence(node_t *, direction_t);
-node_t *nearest_neighbor(desktop_t *, node_t *, direction_t);
-node_t *nearest_from_tree(node_t *, direction_t);
-node_t *nearest_from_distance(desktop_t *, node_t *, direction_t);
-node_t *nearest_from_history(focus_history_t *, node_t *, direction_t);
+bool is_adjacent(node_t *, node_t *, direction_t);
void get_opposite(direction_t, direction_t *);
int tiled_area(node_t *);
-node_t *find_biggest(desktop_t *);
void move_fence(node_t *, direction_t, fence_move_t);
-void rotate_tree(node_t *, rotate_t);
+void rotate_tree(node_t *, int);
void rotate_brother(node_t *);
-void unrotate_tree(node_t *, rotate_t);
+void unrotate_tree(node_t *, int);
void unrotate_brother(node_t *);
void flip_tree(node_t *, flip_t);
int balance_tree(node_t *);
-void arrange(monitor_t *, desktop_t *);
-void apply_layout(monitor_t *, desktop_t *, node_t *, xcb_rectangle_t, xcb_rectangle_t);
-void insert_node(monitor_t *, desktop_t *, node_t *, node_t *);
-void pseudo_focus(desktop_t *, node_t *);
-void focus_node(monitor_t *, desktop_t *, node_t *);
-void update_current(void);
-void unlink_node(desktop_t *, node_t *);
-void remove_node(desktop_t *, node_t *);
void destroy_tree(node_t *);
-void swap_nodes(node_t *, node_t *, bool);
void fit_monitor(monitor_t *, client_t *);
void transfer_node(monitor_t *, desktop_t *, monitor_t *, desktop_t *, node_t *);
void transplant_node(monitor_t *, desktop_t *, node_t *, node_t *);
void select_monitor(monitor_t *);
-monitor_t *nearest_monitor(direction_t);
void select_desktop(monitor_t *, desktop_t *);
-void cycle_monitor(cycle_dir_t);
-void cycle_desktop(monitor_t *, desktop_t *, cycle_dir_t, skip_desktop_t);
-void cycle_leaf(monitor_t *, desktop_t *, node_t *, cycle_dir_t, skip_client_t);
-void nearest_leaf(monitor_t *, desktop_t *, node_t *, nearest_arg_t, skip_client_t);
+monitor_t *nearest_monitor(monitor_t *, direction_t);
+node_t *closest_node(desktop_t *, node_t *, cycle_dir_t, client_select_t);
+desktop_t *closest_desktop(monitor_t *, desktop_t *, cycle_dir_t, desktop_select_t);
+monitor_t *closest_monitor(monitor_t *, cycle_dir_t, desktop_select_t);
void circulate_leaves(monitor_t *, desktop_t *, circulate_dir_t);
void update_vacant_state(node_t *);
-void put_status(void);
-void list_history(char *);
-void list_monitors(list_option_t, char *);
-void list_desktops(monitor_t *, list_option_t, unsigned int, char *);
-void list(desktop_t *, node_t *, char *, unsigned int);
-void restore_layout(char *);
-void restore_history(char *);
#endif
n->split_ratio = split_ratio;
n->split_mode = MODE_AUTOMATIC;
n->split_type = TYPE_VERTICAL;
- n->birth_rotation = ROTATE_IDENTITY;
+ n->birth_rotation = 0;
n->client = NULL;
n->vacant = false;
return n;
monitor_t *find_monitor(char *name)
{
for (monitor_t *m = mon_head; m != NULL; m = m->next)
- if (strcmp(m->name, name) == 0)
+ if (streq(m->name, name))
return m;
return NULL;
}
void transfer_desktop(monitor_t *ms, monitor_t *md, desktop_t *d)
{
+ if (ms == md)
+ return;
desktop_t *dd = ms->desk;
unlink_desktop(ms, d);
insert_desktop(md, d);
{
PRINTF("remove desktop %s\n", d->name);
- prune_rules(d);
unlink_desktop(m, d);
empty_desktop(d);
free(d);
{
client_t *c = malloc(sizeof(client_t));
strncpy(c->class_name, MISSING_VALUE, sizeof(c->class_name));
- c->uid = ++client_uid;
c->border_width = border_width;
c->window = win;
c->floating = c->transient = c->fullscreen = c->locked = c->urgent = false;
r->uid = ++rule_uid;
r->effect.floating = false;
r->effect.follow = false;
- r->effect.monitor = NULL;
- r->effect.desktop = NULL;
+ r->effect.desc[0] = '\0';
r->prev = NULL;
r->next = NULL;
return r;
} value_change_t;
typedef enum {
- LIST_OPTION_VERBOSE,
- LIST_OPTION_QUIET
-} list_option_t;
+ CLIENT_TYPE_ALL,
+ CLIENT_TYPE_FLOATING,
+ CLIENT_TYPE_TILED
+} client_type_t;
typedef enum {
- SEND_OPTION_FOLLOW,
- SEND_OPTION_DONT_FOLLOW
-} send_option_t;
+ CLIENT_CLASS_ALL,
+ CLIENT_CLASS_EQUAL,
+ CLIENT_CLASS_DIFFER
+} client_class_t;
-typedef enum {
- SWAP_OPTION_KEEP_FOCUS,
- SWAP_OPTION_SWAP_FOCUS
-} swap_option_t;
-
-typedef enum {
- CANCEL_OPTION_FOCUSED,
- CANCEL_OPTION_ALL
-} cancel_option_t;
+typedef struct {
+ client_type_t type;
+ client_class_t class;
+} client_select_t;
typedef enum {
- CLIENT_SKIP_NONE,
- CLIENT_SKIP_FLOATING,
- CLIENT_SKIP_TILED,
- CLIENT_SKIP_CLASS_EQUAL,
- CLIENT_SKIP_CLASS_DIFFER
-} skip_client_t;
+ ALTER_NONE,
+ ALTER_TOGGLE,
+ ALTER_SET
+} state_alter_t;
typedef enum {
- DESKTOP_SKIP_NONE,
- DESKTOP_SKIP_FREE,
- DESKTOP_SKIP_OCCUPIED
-} skip_desktop_t;
+ DESKTOP_ALL,
+ DESKTOP_FREE,
+ DESKTOP_OCCUPIED
+} desktop_select_t;
typedef enum {
CYCLE_NEXT,
CYCLE_PREV
} cycle_dir_t;
-typedef enum {
- NEAREST_OLDER,
- NEAREST_NEWER
-} nearest_arg_t;
-
typedef enum {
CIRCULATE_FORWARD,
CIRCULATE_BACKWARD
} circulate_dir_t;
-typedef enum {
- ROTATE_IDENTITY,
- ROTATE_CLOCKWISE,
- ROTATE_COUNTER_CLOCKWISE,
- ROTATE_FULL_CYCLE
-} rotate_t;
-
typedef enum {
FLIP_HORIZONTAL,
FLIP_VERTICAL
} flip_t;
typedef enum {
- DIR_LEFT,
DIR_RIGHT,
- DIR_UP,
- DIR_DOWN
+ DIR_DOWN,
+ DIR_LEFT,
+ DIR_UP
} direction_t;
typedef enum {
CORNER_TOP_LEFT,
CORNER_TOP_RIGHT,
- CORNER_BOTTOM_LEFT,
- CORNER_BOTTOM_RIGHT
+ CORNER_BOTTOM_RIGHT,
+ CORNER_BOTTOM_LEFT
} corner_t;
typedef enum {
typedef struct {
xcb_window_t window;
- unsigned int uid;
char class_name[MAXLEN];
unsigned int border_width;
bool floating;
double split_ratio;
split_mode_t split_mode;
direction_t split_dir;
- rotate_t birth_rotation;
+ int birth_rotation;
xcb_rectangle_t rectangle;
bool vacant; /* vacant nodes only hold floating clients */
node_t *first_child;
monitor_t *next;
};
+typedef struct {
+ monitor_t *monitor;
+ desktop_t *desktop;
+ node_t *node;
+} coordinates_t;
+
typedef struct {
char name[MAXLEN];
} rule_cause_t;
typedef struct {
bool floating;
bool follow;
- monitor_t *monitor;
- desktop_t *desktop;
+ char desc[MAXLEN];
} rule_effect_t;
typedef struct rule_t rule_t;
rule_t *next;
};
-typedef struct {
- node_t *node;
- desktop_t *desktop;
- monitor_t *monitor;
-} window_location_t;
-
-typedef struct {
- desktop_t *desktop;
- monitor_t *monitor;
-} desktop_location_t;
-
typedef struct {
xcb_point_t position;
pointer_action_t action;
#include "settings.h"
#include "ewmh.h"
#include "rules.h"
+#include "query.h"
#include "window.h"
void center(xcb_rectangle_t a, xcb_rectangle_t *b)
return false;
}
-bool locate_window(xcb_window_t win, window_location_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) {
- loc->monitor = m;
- loc->desktop = d;
- loc->node = n;
- return true;
- }
- return false;
-}
-
-bool locate_desktop(char *name, desktop_location_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)
- if (strcmp(d->name, name) == 0) {
- loc->monitor = m;
- loc->desktop = d;
- return true;
- }
- return false;
-}
-
bool is_inside(monitor_t *m, xcb_point_t pt)
{
xcb_rectangle_t r = m->rectangle;
void manage_window(monitor_t *m, desktop_t *d, xcb_window_t win)
{
- window_location_t loc;
+ coordinates_t loc;
xcb_get_window_attributes_reply_t *wa = xcb_get_window_attributes_reply(dpy, xcb_get_window_attributes(dpy, win), NULL);
uint8_t override_redirect = 0;
disable_shadow(c->window);
if (floating)
- toggle_floating(d, n);
+ set_floating(d, n, true);
if (d->focus != NULL && d->focus->client->fullscreen)
- toggle_fullscreen(d, d->focus);
+ set_fullscreen(d, d->focus, false);
if (fullscreen)
- toggle_fullscreen(d, n);
+ set_fullscreen(d, n, true);
if (is_tiled(c))
window_lower(c->window);
xcb_window_t win = wins[i];
window_hide(win);
if (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), &idx, NULL) == 1) {
- desktop_location_t loc;
+ coordinates_t loc;
if (ewmh_locate_desktop(idx, &loc))
manage_window(loc.monitor, loc.desktop, win);
else
xcb_send_event(dpy, false, win, XCB_EVENT_MASK_NO_EVENT, (char *) &e);
}
-void window_kill(monitor_t *m, desktop_t *d, node_t *n)
+void window_kill(desktop_t *d, node_t *n)
{
if (n == NULL)
return;
xcb_kill_client(dpy, win);
remove_node(d, n);
- arrange(m, d);
}
-void toggle_fullscreen(desktop_t *d, node_t *n)
+void set_fullscreen(desktop_t *d, node_t *n, bool value)
{
- if (n == NULL)
+ if (n == NULL || n->client->fullscreen == value)
return;
client_t *c = n->client;
- PRINTF("toggle fullscreen %X\n", c->window);
+ PRINTF("fullscreen %X: %s\n", c->window, BOOLSTR(value));
- if (c->fullscreen) {
- c->fullscreen = false;
- xcb_atom_t values[] = {XCB_NONE};
- xcb_ewmh_set_wm_state(ewmh, c->window, LENGTH(values), values);
- stack(d, n);
- } else {
+ if (value) {
c->fullscreen = true;
xcb_atom_t values[] = {ewmh->_NET_WM_STATE_FULLSCREEN};
xcb_ewmh_set_wm_state(ewmh, c->window, LENGTH(values), values);
window_raise(c->window);
+ } else {
+ c->fullscreen = false;
+ xcb_atom_t values[] = {XCB_NONE};
+ xcb_ewmh_set_wm_state(ewmh, c->window, LENGTH(values), values);
+ stack(d, n);
}
}
-void toggle_floating(desktop_t *d, node_t *n)
+void set_floating(desktop_t *d, node_t *n, bool value)
{
- if (n == NULL || n->client->transient || n->client->fullscreen)
+ if (n == NULL || n->client->transient || n->client->fullscreen || n->client->floating == value)
return;
- PRINTF("toggle floating %X\n", n->client->window);
+ PRINTF("floating %X: %s\n", n->client->window, BOOLSTR(value));
n->split_mode = MODE_AUTOMATIC;
client_t *c = n->client;
- c->floating = !c->floating;
- n->vacant = !n->vacant;
+ c->floating = n->vacant = value;
update_vacant_state(n->parent);
- if (c->floating) {
+ if (value) {
enable_shadow(c->window);
unrotate_brother(n);
} else {
stack(d, n);
}
-void toggle_locked(monitor_t *m, desktop_t *d, node_t *n)
+void set_locked(monitor_t *m, desktop_t *d, node_t *n, bool value)
{
- if (n == NULL)
+ if (n == NULL || n->client->locked == value)
return;
client_t *c = n->client;
- PRINTF("toggle locked %X\n", c->window);
+ PRINTF("set locked %X: %s\n", c->window, BOOLSTR(value));
- c->locked = !c->locked;
+ c->locked = value;
window_draw_border(n, d->focus == n, m == mon);
}
set_shadow(win, 0);
}
-void list_windows(char *rsp)
-{
- char line[MAXLEN];
-
- 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)) {
- snprintf(line, sizeof(line), "0x%X\n", n->client->window);
- strncat(rsp, line, REMLEN(rsp));
- }
-}
-
uint32_t get_border_color(client_t *c, bool focused_window, bool focused_monitor)
{
if (c == NULL)
void window_focus(xcb_window_t win)
{
- window_location_t loc;
+ coordinates_t loc;
if (locate_window(win, &loc)) {
if (loc.node == mon->desk->focus)
return;
void toggle_visibility(void)
{
- if (visible)
- clear_input_focus();
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);
void center(xcb_rectangle_t, xcb_rectangle_t *);
bool contains(xcb_rectangle_t, xcb_rectangle_t);
bool might_cover(desktop_t *, node_t *);
-bool locate_window(xcb_window_t, window_location_t *);
-bool locate_desktop(char *, desktop_location_t *);
bool is_inside(monitor_t *, xcb_point_t);
xcb_rectangle_t get_rectangle(client_t *);
void get_side_handle(client_t *, direction_t, xcb_point_t *);
uint32_t get_border_color(client_t *, bool, bool);
void update_floating_rectangle(client_t *);
void query_pointer(xcb_window_t *, xcb_point_t *);
-void list_windows(char *);
void window_close(node_t *);
-void window_kill(monitor_t *, desktop_t *, node_t *);
-void toggle_fullscreen(desktop_t *, node_t *);
-void toggle_floating(desktop_t *, node_t *);
-void toggle_locked(monitor_t *, desktop_t *, node_t *);
+void window_kill(desktop_t *, node_t *);
+void set_fullscreen(desktop_t *, node_t *, bool);
+void set_floating(desktop_t *, node_t *, bool);
+void set_locked(monitor_t *, desktop_t *, node_t *, bool);
void set_urgency(monitor_t *, desktop_t *, node_t *, bool);
void set_shadow(xcb_window_t, uint32_t);
void enable_shadow(xcb_window_t);