From d78fd8d91fa714dec5288322098dec6410927f9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Tue, 2 May 2017 09:08:42 +0200 Subject: [PATCH] Introduce --exclude-titlebar flag for mouse bindings. (#2703) This introduces the flag --exclude-titlebar for mouse bindings which allows bindings like bindsym --whole-window --border --exclude-titlebar button3 focus fixes #2347 --- docs/userguide | 9 ++++++--- include/bindings.h | 3 ++- include/config_directives.h | 4 ++-- include/data.h | 4 ++++ parser-specs/config.spec | 12 ++++++++++-- src/bindings.c | 4 +++- src/click.c | 2 +- src/config_directives.c | 8 ++++---- testcases/t/201-config-parser.t | 20 ++++++++++++-------- 9 files changed, 44 insertions(+), 22 deletions(-) diff --git a/docs/userguide b/docs/userguide index 4946a1ba..d2ad7d41 100644 --- a/docs/userguide +++ b/docs/userguide @@ -412,9 +412,9 @@ button in the scope of the clicked container (see <>). You can configure mouse bindings in a similar way to key bindings. *Syntax*: -------------------------------------------------------------------------------- -bindsym [--release] [--border] [--whole-window] [+]button command -------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------- +bindsym [--release] [--border] [--whole-window] [--exclude-titlebar] [+]button command +---------------------------------------------------------------------------------------------------- By default, the binding will only run when you click on the titlebar of the window. If the +--release+ flag is given, it will run when the mouse button @@ -424,6 +424,9 @@ If the +--whole-window+ flag is given, the binding will also run when any part of the window is clicked, with the exception of the border. To have a bind run when the border is clicked, specify the +--border+ flag. +If the +--exclude-titlebar+ flag is given, the titlebar will not be considered +for the keybinding. + *Examples*: -------------------------------- # The middle button over a titlebar kills the window diff --git a/include/bindings.h b/include/bindings.h index 0fcc4df4..df3c32a5 100644 --- a/include/bindings.h +++ b/include/bindings.h @@ -27,7 +27,8 @@ extern const char *DEFAULT_BINDING_MODE; */ Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *border, const char *whole_window, - const char *command, const char *mode, bool pango_markup); + const char *exclude_titlebar, const char *command, const char *mode, + bool pango_markup); /** * Grab the bound keys (tell X to send us keypress events for those keycodes) diff --git a/include/config_directives.h b/include/config_directives.h index 0bf52168..f35666f3 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -67,10 +67,10 @@ CFGFUN(color_single, const char *colorclass, const char *color); CFGFUN(floating_modifier, const char *modifiers); CFGFUN(new_window, const char *windowtype, const char *border, const long width); CFGFUN(workspace, const char *workspace, const char *output); -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command); +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command); CFGFUN(enter_mode, const char *pango_markup, const char *mode); -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command); +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command); CFGFUN(bar_font, const char *font); CFGFUN(bar_separator_symbol, const char *separator); diff --git a/include/data.h b/include/data.h index 3d67e315..69a79ade 100644 --- a/include/data.h +++ b/include/data.h @@ -298,6 +298,10 @@ struct Binding { * title bar (default). */ bool whole_window; + /** If this is true for a mouse binding, the binding should only be + * executed if the button press was not on the titlebar. */ + bool exclude_titlebar; + /** Keycode to bind */ uint32_t keycode; diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 19e2d21a..53828221 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -321,6 +321,8 @@ state BINDING: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', 'Group1', 'Group2', 'Group3', 'Group4', '$mod' -> '+' @@ -335,8 +337,10 @@ state BINDCOMMAND: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> command = string - -> call cfg_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command) + -> call cfg_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $exclude_titlebar, $command) ################################################################################ # Mode configuration @@ -376,6 +380,8 @@ state MODE_BINDING: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> modifiers = 'Mod1', 'Mod2', 'Mod3', 'Mod4', 'Mod5', 'Shift', 'Control', 'Ctrl', 'Mode_switch', 'Group1', 'Group2', 'Group3', 'Group4', '$mod' -> '+' @@ -390,8 +396,10 @@ state MODE_BINDCOMMAND: -> whole_window = '--whole-window' -> + exclude_titlebar = '--exclude-titlebar' + -> command = string - -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $command); MODE + -> call cfg_mode_binding($bindtype, $modifiers, $key, $release, $border, $whole_window, $exclude_titlebar, $command); MODE ################################################################################ # Bar configuration (i3bar) diff --git a/src/bindings.c b/src/bindings.c index bfec27e1..36bcc5d1 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -56,12 +56,14 @@ static struct Mode *mode_from_name(const char *name, bool pango_markup) { */ Binding *configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *border, const char *whole_window, - const char *command, const char *modename, bool pango_markup) { + const char *exclude_titlebar, const char *command, const char *modename, + bool pango_markup) { Binding *new_binding = scalloc(1, sizeof(Binding)); DLOG("Binding %p bindtype %s, modifiers %s, input code %s, release %s\n", new_binding, bindtype, modifiers, input_code, release); new_binding->release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS); new_binding->border = (border != NULL); new_binding->whole_window = (whole_window != NULL); + new_binding->exclude_titlebar = (exclude_titlebar != NULL); if (strcmp(bindtype, "bindsym") == 0) { new_binding->input_type = (strncasecmp(input_code, "button", (sizeof("button") - 1)) == 0 ? B_MOUSE diff --git a/src/click.c b/src/click.c index e989b88d..e5cdc8b2 100644 --- a/src/click.c +++ b/src/click.c @@ -186,7 +186,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod if (dest == CLICK_DECORATION || dest == CLICK_INSIDE || dest == CLICK_BORDER) { Binding *bind = get_binding_from_xcb_event((xcb_generic_event_t *)event); - if (bind != NULL && (dest == CLICK_DECORATION || + if (bind != NULL && ((dest == CLICK_DECORATION && !bind->exclude_titlebar) || (dest == CLICK_INSIDE && bind->whole_window) || (dest == CLICK_BORDER && bind->border))) { CommandResult *result = run_binding(bind, con); diff --git a/src/config_directives.c b/src/config_directives.c index 879d225e..7ca6e102 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -106,8 +106,8 @@ CFGFUN(font, const char *font) { font_pattern = sstrdup(font); } -CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) { - configure_binding(bindtype, modifiers, key, release, border, whole_window, command, DEFAULT_BINDING_MODE, false); +CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command) { + configure_binding(bindtype, modifiers, key, release, border, whole_window, exclude_titlebar, command, DEFAULT_BINDING_MODE, false); } /******************************************************************************* @@ -117,8 +117,8 @@ CFGFUN(binding, const char *bindtype, const char *modifiers, const char *key, co static char *current_mode; static bool current_mode_pango_markup; -CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *command) { - configure_binding(bindtype, modifiers, key, release, border, whole_window, command, current_mode, current_mode_pango_markup); +CFGFUN(mode_binding, const char *bindtype, const char *modifiers, const char *key, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command) { + configure_binding(bindtype, modifiers, key, release, border, whole_window, exclude_titlebar, command, current_mode, current_mode_pango_markup); } CFGFUN(enter_mode, const char *pango_markup, const char *modename) { diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 1de86c65..159de046 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -49,18 +49,22 @@ mode "meh" { bindsym --release --whole-window button3 nop bindsym --border button3 nop bindsym --release --border button3 nop + bindsym --exclude-titlebar button3 nop + bindsym --whole-window --border --exclude-titlebar button3 nop } EOT my $expected = <<'EOT'; cfg_enter_mode((null), meh) -cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), (null), resize grow) -cfg_mode_binding(bindcode, Mod1, 44, (null), (null), (null), resize shrink) -cfg_mode_binding(bindsym, Mod1, x, --release, (null), (null), exec foo) -cfg_mode_binding(bindsym, (null), button3, (null), (null), --whole-window, nop) -cfg_mode_binding(bindsym, (null), button3, --release, (null), --whole-window, nop) -cfg_mode_binding(bindsym, (null), button3, (null), --border, (null), nop) -cfg_mode_binding(bindsym, (null), button3, --release, --border, (null), nop) +cfg_mode_binding(bindsym, Mod1,Shift, x, (null), (null), (null), (null), resize grow) +cfg_mode_binding(bindcode, Mod1, 44, (null), (null), (null), (null), resize shrink) +cfg_mode_binding(bindsym, Mod1, x, --release, (null), (null), (null), exec foo) +cfg_mode_binding(bindsym, (null), button3, (null), (null), --whole-window, (null), nop) +cfg_mode_binding(bindsym, (null), button3, --release, (null), --whole-window, (null), nop) +cfg_mode_binding(bindsym, (null), button3, (null), --border, (null), (null), nop) +cfg_mode_binding(bindsym, (null), button3, --release, --border, (null), (null), nop) +cfg_mode_binding(bindsym, (null), button3, (null), (null), (null), --exclude-titlebar, nop) +cfg_mode_binding(bindsym, (null), button3, (null), --border, --whole-window, --exclude-titlebar, nop) EOT is(parser_calls($config), @@ -674,7 +678,7 @@ EOT $expected = <<'EOT'; cfg_enter_mode((null), yo) -cfg_mode_binding(bindsym, (null), x, (null), (null), (null), resize shrink left) +cfg_mode_binding(bindsym, (null), x, (null), (null), (null), (null), resize shrink left) ERROR: CONFIG: Expected one of these tokens: , '#', 'set', 'bindsym', 'bindcode', 'bind', '}' ERROR: CONFIG: (in file ) ERROR: CONFIG: Line 1: mode "yo" {