From 55d400b17d786cb60ce2af5229c18177d74aa0ba Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 16 Oct 2022 17:42:17 +0200 Subject: [PATCH] make tiling drag configurable fixes https://github.com/i3/i3/issues/5155 --- docs/userguide | 24 ++++++++++++++++++++++++ etc/config | 4 ++++ etc/config.keycodes | 4 ++++ include/config_directives.h | 1 + include/configuration.h | 3 +++ include/tiling_drag.h | 10 ++++++++++ parser-specs/config.spec | 13 +++++++++++++ release-notes/changes/1-tiling-drag | 1 + src/click.c | 11 ++++++++--- src/config.c | 2 ++ src/config_directives.c | 14 ++++++++++++++ testcases/t/201-config-parser.t | 1 + 12 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 release-notes/changes/1-tiling-drag diff --git a/docs/userguide b/docs/userguide index 7b233844..b8f75b37 100644 --- a/docs/userguide +++ b/docs/userguide @@ -196,6 +196,7 @@ provided by the i3 https://github.com/i3/i3/blob/next/etc/config.keycodes[defaul Floating windows are always on top of tiling windows. +[[tiling_drag]] === Moving tiling containers with the mouse Since i3 4.21, it's possible to drag tiling containers using the mouse. The @@ -1402,6 +1403,29 @@ fullscreen toggle bindsym Mod1+F fullscreen toggle ------------------- +[[config_tiling_drag]] +=== Tiling drag + +You can configure how to initiate the tiling drag feature (see <>). + +*Syntax*: +-------------------------------- +tiling_drag off +tiling_drag modifier|titlebar [modifier|titlebar] +-------------------------------- + +*Examples*: +-------------------------------- +# Only initiate a tiling drag when the modifier is held: +tiling_drag modifier + +# Initiate a tiling drag on either titlebar click or held modifier: +tiling_drag modifier titlebar + +# Disable tiling drag altogether +tiling_drag off +-------------------------------- + == Configuring i3bar The bar at the bottom of your monitor is drawn by a separate process called diff --git a/etc/config b/etc/config index 51902f08..40076ca9 100644 --- a/etc/config +++ b/etc/config @@ -49,6 +49,10 @@ set $right semicolon # use Mouse+Mod1 to drag floating windows to their wanted position floating_modifier Mod1 +# move tiling windows via drag & drop by left-clicking into the title bar, +# or left-clicking anywhere into the window while holding the floating modifier. +tiling_drag modifier titlebar + # start a terminal bindsym Mod1+Return exec i3-sensible-terminal diff --git a/etc/config.keycodes b/etc/config.keycodes index 11a7d46f..7bc5d60a 100644 --- a/etc/config.keycodes +++ b/etc/config.keycodes @@ -43,6 +43,10 @@ bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOU # Use Mouse+$mod to drag floating windows to their wanted position floating_modifier $mod +# move tiling windows via drag & drop by left-clicking into the title bar, +# or left-clicking anywhere into the window while holding the floating modifier. +tiling_drag modifier titlebar + # start a terminal bindcode $mod+36 exec i3-sensible-terminal diff --git a/include/config_directives.h b/include/config_directives.h index e0057097..015154d5 100644 --- a/include/config_directives.h +++ b/include/config_directives.h @@ -65,6 +65,7 @@ CFGFUN(assign, const char *workspace, bool is_number); CFGFUN(no_focus); CFGFUN(ipc_socket, const char *path); CFGFUN(ipc_kill_timeout, const long timeout_ms); +CFGFUN(tiling_drag, const char *value); CFGFUN(restart_state, const char *path); CFGFUN(popup_during_fullscreen, const char *value); CFGFUN(color, const char *colorclass, const char *border, const char *background, const char *text, const char *indicator, const char *child_border); diff --git a/include/configuration.h b/include/configuration.h index 843e156f..63d504de 100644 --- a/include/configuration.h +++ b/include/configuration.h @@ -14,6 +14,7 @@ #include "queue.h" #include "i3.h" +#include "tiling_drag.h" typedef struct IncludedFile IncludedFile; typedef struct Config Config; @@ -265,6 +266,8 @@ struct Config { /* The number of currently parsed barconfigs */ int number_barconfigs; + + tiling_drag_t tiling_drag; }; /** diff --git a/include/tiling_drag.h b/include/tiling_drag.h index ac9679b2..d78744c9 100644 --- a/include/tiling_drag.h +++ b/include/tiling_drag.h @@ -9,6 +9,16 @@ */ #pragma once +/** + * Tiling drag initiation modes. + */ +typedef enum { + TILING_DRAG_OFF = 0, + TILING_DRAG_MODIFIER = 1, + TILING_DRAG_TITLEBAR = 2, + TILING_DRAG_MODIFIER_OR_TITLEBAR = 3 +} tiling_drag_t; + /** * Initiates a mouse drag operation on a tiled window. * diff --git a/parser-specs/config.spec b/parser-specs/config.spec index 617ed130..dfe8008d 100644 --- a/parser-specs/config.spec +++ b/parser-specs/config.spec @@ -53,6 +53,7 @@ state INITIAL: 'ipc_kill_timeout' -> IPC_KILL_TIMEOUT 'restart_state' -> RESTART_STATE 'popup_during_fullscreen' -> POPUP_DURING_FULLSCREEN + 'tiling_drag' -> TILING_DRAG exectype = 'exec_always', 'exec' -> EXEC colorclass = 'client.background' -> COLOR_SINGLE @@ -330,6 +331,18 @@ state POPUP_DURING_FULLSCREEN: value = 'ignore', 'leave_fullscreen', 'smart' -> call cfg_popup_during_fullscreen($value) +state TILING_DRAG_MODE: + value = 'modifier', 'titlebar' + -> + end + -> call cfg_tiling_drag($value) + +state TILING_DRAG: + off = '0', 'no', 'false', 'off', 'disable', 'inactive' + -> call cfg_tiling_drag($off) + value = 'modifier', 'titlebar' + -> TILING_DRAG_MODE + # client.background state COLOR_SINGLE: color = word diff --git a/release-notes/changes/1-tiling-drag b/release-notes/changes/1-tiling-drag new file mode 100644 index 00000000..bc16308b --- /dev/null +++ b/release-notes/changes/1-tiling-drag @@ -0,0 +1 @@ +tiling drag is now configurable, and defaults to “modifier” for existing configs diff --git a/src/click.c b/src/click.c index 5b0cc2e8..6f1cb5c2 100644 --- a/src/click.c +++ b/src/click.c @@ -228,7 +228,9 @@ static void route_click(Con *con, xcb_button_press_event_t *event, const bool mo } /* 2: floating modifier pressed, initiate a drag */ - if (mod_pressed && event->detail == XCB_BUTTON_INDEX_1 && !floatingcon) { + if (mod_pressed && is_left_click && !floatingcon && + (config.tiling_drag == TILING_DRAG_MODIFIER || + config.tiling_drag == TILING_DRAG_MODIFIER_OR_TITLEBAR)) { const bool use_threshold = !mod_pressed; tiling_drag(con, event, use_threshold); allow_replay_pointer(event->time); @@ -305,8 +307,11 @@ static void route_click(Con *con, xcb_button_press_event_t *event, const bool mo return; } - /* 8: floating modifier pressed, initiate a drag */ - if ((mod_pressed || dest == CLICK_DECORATION) && event->detail == XCB_BUTTON_INDEX_1) { + /* 8: floating modifier pressed, or click in titlebar, initiate a drag */ + if (is_left_click && + ((config.tiling_drag == TILING_DRAG_TITLEBAR && dest == CLICK_DECORATION) || + (config.tiling_drag == TILING_DRAG_MODIFIER_OR_TITLEBAR && + (mod_pressed || dest == CLICK_DECORATION)))) { allow_replay_pointer(event->time); const bool use_threshold = !mod_pressed; tiling_drag(con, event, use_threshold); diff --git a/src/config.c b/src/config.c index f3fd9476..236d682b 100644 --- a/src/config.c +++ b/src/config.c @@ -222,6 +222,8 @@ bool load_configuration(const char *override_configpath, config_load_t load_type config.focus_wrapping = FOCUS_WRAPPING_ON; + config.tiling_drag = TILING_DRAG_MODIFIER; + FREE(current_configpath); current_configpath = get_config_path(override_configpath, true); if (current_configpath == NULL) { diff --git a/src/config_directives.c b/src/config_directives.c index a611da27..39fe7410 100644 --- a/src/config_directives.c +++ b/src/config_directives.c @@ -560,6 +560,20 @@ CFGFUN(ipc_kill_timeout, const long timeout_ms) { ipc_set_kill_timeout(timeout_ms / 1000.0); } +CFGFUN(tiling_drag, const char *value) { + if (strcmp(value, "modifier") == 0) { + config.tiling_drag = TILING_DRAG_MODIFIER; + } else if (strcmp(value, "titlebar") == 0) { + config.tiling_drag = TILING_DRAG_TITLEBAR; + } else if (strcmp(value, "modifier,titlebar") == 0 || + strcmp(value, "titlebar,modifier") == 0) { + /* Switch the above to strtok() or similar if we ever grow more options */ + config.tiling_drag = TILING_DRAG_MODIFIER_OR_TITLEBAR; + } else { + config.tiling_drag = TILING_DRAG_OFF; + } +} + /******************************************************************************* * Bar configuration (i3bar) ******************************************************************************/ diff --git a/testcases/t/201-config-parser.t b/testcases/t/201-config-parser.t index 3a21a8a0..11efdf84 100644 --- a/testcases/t/201-config-parser.t +++ b/testcases/t/201-config-parser.t @@ -549,6 +549,7 @@ my $expected_all_tokens = "ERROR: CONFIG: Expected one of these tokens: , ' ipc_kill_timeout restart_state popup_during_fullscreen + tiling_drag exec_always exec client.background