From: Bastien Dejean Date: Fri, 31 Aug 2018 09:33:00 +0000 (+0200) Subject: Add new setting: automatic_scheme X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=385f73e576d4e5fdb09e5f6e77293503e01adf88;p=bspwm.git Add new setting: automatic_scheme Fixes #764. --- diff --git a/README.md b/README.md index a4e586b..a5d0cd5 100644 --- a/README.md +++ b/README.md @@ -51,49 +51,7 @@ When *bspwm* receives a new window, it inserts it into a window tree at the spec The insertion mode tells *bspwm* how it should alter the tree in order to insert new windows on a given insertion point. -By default the insertion point is the focused window and its default insertion mode is *automatic*. - -### Automatic Mode - -The *automatic* mode, as opposed to the *manual* mode, doesn't require any user choice: the new window will *take the space* of the insertion point. - -For example, let's consider the following scenario: - -``` - a a a - / \ / \ / \ - 1 b ---> 1 c ---> 1 d - / \ / \ / \ - 2 3 4 b 5 c - ^ ^ / \ ^ / \ - 3 2 b 4 - / \ - 3 2 - - +-----------------------+ +-----------------------+ +-----------------------+ - | | | | | | | | | - | | 2 | | | 4 | | | 5 | - | | ^ | | | ^ | | | ^ | - | 1 |-----------| | 1 |-----------| | 1 |-----------| - | | | | | | | | | 3 | | - | | 3 | | | 3 | 2 | | |-----| 4 | - | | | | | | | | | 2 | | - +-----------------------+ +-----------------------+ +-----------------------+ - - X Y Z -``` - -In state *X*, the insertion point, *2* is in automatic mode. - -When we add a new window, *4*, the whole tree rooted at *b* is reattached, as the second child of a new internal node, *c*. - -The splitting parameters of *b* (type: *horizontal*, ratio: *½*) are copied to *c* and *b* is rotated by 90° clockwise. - -The tiling rectangle of *4* in state *Y* is equal to the tiling rectangle of *2* in state *X*. - -Then the insertion of *5*, with *4* as insertion point, leads to *Z*. - -The automatic mode generates window spirals that rotate clockwise (resp. anti-clockwise) if the insertion point is the first (resp. second) child of its parent. +By default the insertion point is the focused window and its insertion mode is *automatic*. ### Manual Mode @@ -103,7 +61,7 @@ The *DIR* argument allows to specify how the insertion point should be split (ho After doing so the insertion point goes into *manual* mode. -For example, let's consider the following scenario: +Let's consider the following scenario: ``` a a a @@ -138,6 +96,86 @@ Finally we send another message: *node -p west* and add window *5*. The ratio of the preselection (that ends up being the ratio of the split of the new internal node) can be changed with the *node -o|--presel-ratio* message. +### Automatic Mode + +The *automatic* mode, as opposed to the *manual* mode, doesn't require any user choice. The way the new window is inserted is determined by the value of the automatic scheme and the initial polarity settings. + +#### Longest side + +When the value of the automatic scheme is `longest_side`, the window will be attached as if the insertion point was in manual mode and the split direction was choosen based on the dimensions of the tiling rectangle and the initial polarity. + +Let's consider the following scenario, where the initial polarity is set to `second_child`: + +``` + 1 a a + ^ / \ / \ + ---> 1 2 ---> 1 b + ^ / \ + 2 3 + ^ + + +-----------------------+ +-----------------------+ +-----------------------+ + | | | | | | | | + | | | | | | | 2 | + | | | | | | | | + | 1 | | 1 | 2 | | 1 |-----------| + | ^ | | | ^ | | | | + | | | | | | | 3 | + | | | | | | | ^ | + +-----------------------+ +-----------------------+ +-----------------------+ + + X Y Z +``` + +In state *X*, a new window is added. + +Since *1* is wide, it gets split vertically and *2* is added as *a*'s second child given the initial polarity. + +This leads to *Y* where we insert window *3*. *2* is tall and is therefore split horizontally. *3* is once again added as *b*'s second child. + +#### Spiral + +When the value of the automatic scheme is `spiral`, the window will *take the space* of the insertion point. + +Let's dive into the details with the following scenario: + +``` + a a a + / \ / \ / \ + 1 b ---> 1 c ---> 1 d + / \ / \ / \ + 2 3 4 b 5 c + ^ ^ / \ ^ / \ + 3 2 b 4 + / \ + 3 2 + + +-----------------------+ +-----------------------+ +-----------------------+ + | | | | | | | | | + | | 2 | | | 4 | | | 5 | + | | ^ | | | ^ | | | ^ | + | 1 |-----------| | 1 |-----------| | 1 |-----------| + | | | | | | | | | 3 | | + | | 3 | | | 3 | 2 | | |-----| 4 | + | | | | | | | | | 2 | | + +-----------------------+ +-----------------------+ +-----------------------+ + + X Y Z +``` + +In state *X*, the insertion point, *2* is in automatic mode. + +When we add a new window, *4*, the whole tree rooted at *b* is reattached, as the second child of a new internal node, *c*. + +The splitting parameters of *b* (type: *horizontal*, ratio: *½*) are copied to *c* and *b* is rotated by 90° clockwise. + +The tiling rectangle of *4* in state *Y* is equal to the tiling rectangle of *2* in state *X*. + +Then the insertion of *5*, with *4* as insertion point, leads to *Z*. + +The *spiral* automatic scheme generates window spirals that rotate clockwise (resp. anti-clockwise) if the insertion point is the first (resp. second) child of its parent. + + ## Supported protocols and standards - The RandR and Xinerama protocols. diff --git a/contrib/bash_completion b/contrib/bash_completion index 35c1f29..ab57d02 100644 --- a/contrib/bash_completion +++ b/contrib/bash_completion @@ -1,7 +1,7 @@ _bspc() { local commands='node desktop monitor query rule wm subscribe config quit' - local settings='external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio initial_polarity directional_focus_tightness borderless_monocle gapless_monocle single_monocle pointer_motion_interval pointer_modifier pointer_action1 pointer_action2 pointer_action3 click_to_focus swallow_first_click focus_follows_pointer pointer_follows_focus pointer_follows_monitor mapping_events_count ignore_ewmh_focus ignore_ewmh_fullscreen center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors' + local settings='external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio automatic_scheme initial_polarity directional_focus_tightness borderless_monocle gapless_monocle single_monocle pointer_motion_interval pointer_modifier pointer_action1 pointer_action2 pointer_action3 click_to_focus swallow_first_click focus_follows_pointer pointer_follows_focus pointer_follows_monitor mapping_events_count ignore_ewmh_focus ignore_ewmh_fullscreen center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors' COMPREPLY=() diff --git a/contrib/fish_completion b/contrib/fish_completion index 940ad07..a79c483 100644 --- a/contrib/fish_completion +++ b/contrib/fish_completion @@ -11,4 +11,4 @@ function __fish_bspc_using_command end complete -f -c bspc -n '__fish_bspc_needs_command' -a 'node desktop monitor query rule wm subscribe config quit' -complete -f -c bspc -n '__fish_bspc_using_command config' -a 'external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio initial_polarity directional_focus_tightness borderless_monocle gapless_monocle single_monocle pointer_motion_interval pointer_modifier pointer_action1 pointer_action2 pointer_action3 click_to_focus swallow_first_click focus_follows_pointer pointer_follows_focus pointer_follows_monitor mapping_events_count ignore_ewmh_focus ignore_ewmh_fullscreen center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors' +complete -f -c bspc -n '__fish_bspc_using_command config' -a 'external_rules_command status_prefix normal_border_color active_border_color focused_border_color presel_feedback_color border_width window_gap top_padding right_padding bottom_padding left_padding split_ratio automatic_scheme initial_polarity directional_focus_tightness borderless_monocle gapless_monocle single_monocle pointer_motion_interval pointer_modifier pointer_action1 pointer_action2 pointer_action3 click_to_focus swallow_first_click focus_follows_pointer pointer_follows_focus pointer_follows_monitor mapping_events_count ignore_ewmh_focus ignore_ewmh_fullscreen center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors' diff --git a/contrib/zsh_completion b/contrib/zsh_completion index 5b663f7..3f94bfd 100644 --- a/contrib/zsh_completion +++ b/contrib/zsh_completion @@ -318,7 +318,7 @@ _bspc() { look_bool=(borderless_monocle gapless_monocle) look=({normal,active,focused}_border_color {top,right,bottom,left}_padding presel_feedback_color border_width window_gap) behaviour_bool=(single_monocle ignore_ewmh_focus center_pseudo_tiled honor_size_hints remove_disabled_monitors remove_unplugged_monitors merge_overlapping_monitors) - behaviour=(mapping_events_count ignore_ewmh_fullscreen external_rules_command split_ratio initial_polarity directional_focus_tightness status_prefix) + behaviour=(mapping_events_count ignore_ewmh_fullscreen external_rules_command split_ratio automatic_scheme initial_polarity directional_focus_tightness status_prefix) input_bool=(swallow_first_click focus_follows_pointer pointer_follows_{focus,monitor}) input=(click_to_focus pointer_motion_interval pointer_modifier pointer_action{1,2,3}) if [[ "$CURRENT" == (2|3) ]];then diff --git a/doc/bspwm.1 b/doc/bspwm.1 index f545bd1..0b59b74 100644 --- a/doc/bspwm.1 +++ b/doc/bspwm.1 @@ -2,12 +2,12 @@ .\" Title: bspwm .\" Author: [see the "Author" section] .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 08/28/2018 +.\" Date: 08/31/2018 .\" Manual: Bspwm Manual -.\" Source: Bspwm 0.9.5-10-g336bc86 +.\" Source: Bspwm 0.9.5-14-g56ad57c .\" Language: English .\" -.TH "BSPWM" "1" "08/28/2018" "Bspwm 0\&.9\&.5\-10\-g336bc86" "Bspwm Manual" +.TH "BSPWM" "1" "08/31/2018" "Bspwm 0\&.9\&.5\-14\-g56ad57c" "Bspwm Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -1151,6 +1151,13 @@ External command used to retrieve rule consequences\&. The command will receive command)\&. .RE .PP +\fIautomatic_scheme\fR +.RS 4 +The insertion scheme used when the insertion point is in automatic mode\&. Accept the following values: +\fBlongest_side\fR, +\fBspiral\fR\&. +.RE +.PP \fIinitial_polarity\fR .RS 4 On which child should a new window be attached when adding a window on a single window tree in automatic mode\&. Accept the following values: diff --git a/doc/bspwm.1.asciidoc b/doc/bspwm.1.asciidoc index 70f1919..29a455b 100644 --- a/doc/bspwm.1.asciidoc +++ b/doc/bspwm.1.asciidoc @@ -677,6 +677,9 @@ Global Settings 'external_rules_command':: External command used to retrieve rule consequences. The command will receive the following arguments: window ID, class name, instance name, and intermediate consequences. The output of that command must have the following format: *key1=value1 key2=value2 ...* (the valid key/value pairs are given in the description of the 'rule' command). +'automatic_scheme':: + The insertion scheme used when the insertion point is in automatic mode. Accept the following values: *longest_side*, *spiral*. + 'initial_polarity':: On which child should a new window be attached when adding a window on a single window tree in automatic mode. Accept the following values: *first_child*, *second_child*. diff --git a/examples/external_rules/pseudo_automatic_mode/README.md b/examples/external_rules/pseudo_automatic_mode/README.md deleted file mode 100644 index 26284fc..0000000 --- a/examples/external_rules/pseudo_automatic_mode/README.md +++ /dev/null @@ -1 +0,0 @@ -`wattr` belongs to [wmutils](https://github.com/wmutils/core). diff --git a/examples/external_rules/pseudo_automatic_mode/external_rules b/examples/external_rules/pseudo_automatic_mode/external_rules deleted file mode 100755 index b8fe0e6..0000000 --- a/examples/external_rules/pseudo_automatic_mode/external_rules +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/sh - -fwid=$(bspc query -N -n focused.automatic) - -if [ -n "$fwid" ] ; then - wattr wh $fwid | { - read width height - if [ $width -gt $height ] ; then - echo "split_dir=west" - else - echo "split_dir=south" - fi - echo "split_ratio=0.5" - } -fi diff --git a/src/helpers.h b/src/helpers.h index 771bbdc..8b933be 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -47,6 +47,7 @@ #define LAYOUT_STR(A) ((A) == LAYOUT_TILED ? "tiled" : "monocle") #define LAYOUT_CHR(A) ((A) == LAYOUT_TILED ? 'T' : 'M') #define CHILD_POL_STR(A) ((A) == FIRST_CHILD ? "first_child" : "second_child") +#define AUTO_SCM_STR(A) ((A) == SCHEME_LONGEST_SIDE ? "longest_side" : "spiral") #define TIGHTNESS_STR(A) ((A) == TIGHTNESS_HIGH ? "high" : "low") #define SPLIT_TYPE_STR(A) ((A) == TYPE_HORIZONTAL ? "horizontal" : "vertical") #define SPLIT_MODE_STR(A) ((A) == MODE_AUTOMATIC ? "automatic" : "manual") diff --git a/src/messages.c b/src/messages.c index 0ed0866..e12b382 100644 --- a/src/messages.c +++ b/src/messages.c @@ -1555,6 +1555,14 @@ void set_setting(coordinates_t loc, char *name, char *value, FILE *rsp) fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value); return; } + } else if (streq("automatic_scheme", name)) { + automatic_scheme_t a; + if (parse_automatic_scheme(value, &a)) { + automatic_scheme = a; + } else { + fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value); + return; + } } else if (streq("mapping_events_count", name)) { if (sscanf(value, "%" SCNi8, &mapping_events_count) != 1) { fail(rsp, "config: %s: Invalid value: '%s'.\n", name, value); @@ -1731,6 +1739,8 @@ void get_setting(coordinates_t loc, char *name, FILE* rsp) fprintf(rsp, "%s", status_prefix); } else if (streq("initial_polarity", name)) { fprintf(rsp, "%s", CHILD_POL_STR(initial_polarity)); + } else if (streq("automatic_scheme", name)) { + fprintf(rsp, "%s", AUTO_SCM_STR(automatic_scheme)); } else if (streq("mapping_events_count", name)) { fprintf(rsp, "%" PRIi8, mapping_events_count); } else if (streq("directional_focus_tightness", name)) { diff --git a/src/parse.c b/src/parse.c index f7dc1d8..886f944 100644 --- a/src/parse.c +++ b/src/parse.c @@ -267,6 +267,18 @@ bool parse_child_polarity(char *s, child_polarity_t *p) return false; } +bool parse_automatic_scheme(char *s, automatic_scheme_t *a) +{ + if (streq("longest_side", s)) { + *a = SCHEME_LONGEST_SIDE; + return true; + } else if (streq("spiral", s)) { + *a = SCHEME_SPIRAL; + return true; + } + return false; +} + bool parse_state_transition(char *s, state_transition_t *m) { if (streq("none", s)) { diff --git a/src/parse.h b/src/parse.h index 370c08f..89ba6e1 100644 --- a/src/parse.h +++ b/src/parse.h @@ -25,6 +25,7 @@ bool parse_modifier_mask(char *s, uint16_t *m); bool parse_button_index(char *s, int8_t *b); bool parse_pointer_action(char *s, pointer_action_t *a); bool parse_child_polarity(char *s, child_polarity_t *p); +bool parse_automatic_scheme(char *s, automatic_scheme_t *a); bool parse_state_transition(char *s, state_transition_t *m); bool parse_tightness(char *s, tightness_t *t); bool parse_degree(char *s, int *d); diff --git a/src/settings.c b/src/settings.c index f8390b8..923d9ac 100644 --- a/src/settings.c +++ b/src/settings.c @@ -56,15 +56,16 @@ void load_settings(void) window_gap = WINDOW_GAP; border_width = BORDER_WIDTH; split_ratio = SPLIT_RATIO; - initial_polarity = FIRST_CHILD; + initial_polarity = SECOND_CHILD; + automatic_scheme = SCHEME_LONGEST_SIDE; directional_focus_tightness = TIGHTNESS_HIGH; + pointer_modifier = POINTER_MODIFIER; pointer_motion_interval = POINTER_MOTION_INTERVAL; - mapping_events_count = MAPPING_EVENTS_COUNT; - pointer_actions[0] = ACTION_MOVE; pointer_actions[1] = ACTION_RESIZE_SIDE; pointer_actions[2] = ACTION_RESIZE_CORNER; + mapping_events_count = MAPPING_EVENTS_COUNT; borderless_monocle = BORDERLESS_MONOCLE; gapless_monocle = GAPLESS_MONOCLE; diff --git a/src/settings.h b/src/settings.h index 4c15644..c4dcd27 100644 --- a/src/settings.h +++ b/src/settings.h @@ -41,6 +41,7 @@ #define WINDOW_GAP 6 #define BORDER_WIDTH 1 #define SPLIT_RATIO 0.5 +#define AUTOMATIC_SCHEME SCHEME_LONGEST_SIDE #define BORDERLESS_MONOCLE false #define GAPLESS_MONOCLE false @@ -75,9 +76,10 @@ padding_t padding; int window_gap; unsigned int border_width; double split_ratio; - child_polarity_t initial_polarity; +automatic_scheme_t automatic_scheme; tightness_t directional_focus_tightness; + uint16_t pointer_modifier; uint32_t pointer_motion_interval; pointer_action_t pointer_actions[3]; diff --git a/src/tree.c b/src/tree.c index 2e262dd..9518c2e 100644 --- a/src/tree.c +++ b/src/tree.c @@ -331,7 +331,7 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f) } n->parent = c; if (f->presel == NULL) { - if (p == NULL || (f->client != NULL && IS_TILED(f->client) && tiled_count(d->root, true) == 1)) { + if (p == NULL || automatic_scheme == SCHEME_LONGEST_SIDE || (f->client != NULL && IS_TILED(f->client) && tiled_count(d->root, true) == 1)) { if (p != NULL) { if (is_first_child(f)) { p->first_child = c; @@ -350,7 +350,7 @@ node_t *insert_node(monitor_t *m, desktop_t *d, node_t *n, node_t *f) c->first_child = f; c->second_child = n; } - if (m->rectangle.width > m->rectangle.height) { + if (f->rectangle.width > f->rectangle.height) { c->split_type = TYPE_VERTICAL; } else { c->split_type = TYPE_HORIZONTAL; diff --git a/src/types.h b/src/types.h index 2b43a35..1aebc77 100644 --- a/src/types.h +++ b/src/types.h @@ -44,6 +44,11 @@ typedef enum { MODE_MANUAL } split_mode_t; +typedef enum { + SCHEME_LONGEST_SIDE, + SCHEME_SPIRAL +} automatic_scheme_t; + typedef enum { STATE_TILED, STATE_PSEUDO_TILED, diff --git a/tests/run b/tests/run index 90cca7c..1b3babc 100755 --- a/tests/run +++ b/tests/run @@ -2,10 +2,13 @@ focus_follows_pointer=$(bspc config focus_follows_pointer) initial_polarity=$(bspc config initial_polarity) +automatic_scheme=$(bspc config automatic_scheme) +bspc config automatic_scheme spiral bspc config initial_polarity first_child bspc config focus_follows_pointer false cleanup () { + bspc config automatic_scheme "$automatic_scheme" bspc config initial_polarity "$initial_polarity" bspc config focus_follows_pointer "$focus_follows_pointer" }