Add configuration option for disabling mouse warping
Patch status: needinfo
Patch by Atte Peltomaki
Long description:
This patch fixes ticket #780 by adding a new configuration option "mouse_warping [yes|no]". When mouse warping is disabled, mouse cursor does not jump to middle of current screen when changing workspaces on multiple monitors. This introduces a "special" cursor state, where focus is in one window and cursor on another. Useful for eg. scrolling a web page with mouse wheel while typing into another window on keyboard.
To apply this patch, use:
curl http://cr.i3wm.org/patch/495/raw.patch | git am
b/include/config.h
| 26 |
@@ -108,6 +108,13 @@ struct Config {
|
| 27 |
* It is not planned to add any different focus models. */ |
| 28 |
bool disable_focus_follows_mouse; |
| 29 |
|
| 30 |
+ /** By default, mouse cursor is placed on middle of current screen/workspace |
| 31 |
+ * when switching workspaces with multiple monitors, along with focus. This |
| 32 |
+ * option disables mouse warping and introduces a new "special" state: keyboard |
| 33 |
+ * focus moves to new workspace, but cursor remains on old workspace and is |
| 34 |
+ * usable, eg. scroll web pages with mouse wheel. */ |
| 35 |
+ bool disable_mouse_warping; |
| 36 |
+ |
| 37 |
/** Remove borders if they are adjacent to the screen edge. |
| 38 |
* This is useful if you are reaching scrollbar on the edge of the |
| 39 |
* screen or do not want to waste a single pixel of displayspace. |
b/include/config_directives.h
| 44 |
@@ -46,6 +46,7 @@ CFGFUN(default_orientation, const char *orientation); |
| 45 |
CFGFUN(workspace_layout, const char *layout); |
| 46 |
CFGFUN(workspace_back_and_forth, const char *value); |
| 47 |
CFGFUN(focus_follows_mouse, const char *value); |
| 48 |
+CFGFUN(mouse_warping, const char *value); |
| 49 |
CFGFUN(force_focus_wrapping, const char *value); |
| 50 |
CFGFUN(force_xinerama, const char *value); |
| 51 |
CFGFUN(fake_outputs, const char *outputs); |
b/parser-specs/config.spec
| 56 |
@@ -32,6 +32,7 @@ state INITIAL: |
| 57 |
'for_window' -> FOR_WINDOW |
| 58 |
'assign' -> ASSIGN |
| 59 |
'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE |
| 60 |
+ 'mouse_warping' -> MOUSE_WARPING |
| 61 |
'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING |
| 62 |
'force_xinerama', 'force-xinerama' -> FORCE_XINERAMA |
| 63 |
'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH |
| 64 |
@@ -172,6 +173,11 @@ state FOCUS_FOLLOWS_MOUSE: |
| 65 |
value = word |
| 66 |
-> call cfg_focus_follows_mouse($value) |
| 67 |
|
| 68 |
+# mouse_warping bool |
| 69 |
+state MOUSE_WARPING: |
| 70 |
+ value = word |
| 71 |
+ -> call cfg_mouse_warping($value) |
| 72 |
+ |
| 73 |
# force_focus_wrapping |
| 74 |
state FORCE_FOCUS_WRAPPING: |
| 75 |
value = word |
b/src/config_directives.c
| 80 |
@@ -299,6 +299,10 @@ CFGFUN(focus_follows_mouse, const char *value) {
|
| 81 |
config.disable_focus_follows_mouse = !eval_boolstr(value); |
| 82 |
} |
| 83 |
|
| 84 |
+CFGFUN(mouse_warping, const char *value) {
|
| 85 |
+ config.disable_mouse_warping = !eval_boolstr(value); |
| 86 |
+} |
| 87 |
+ |
| 88 |
CFGFUN(force_xinerama, const char *value) {
|
| 89 |
config.force_xinerama = eval_boolstr(value); |
| 90 |
} |
b/src/x.c
| 95 |
@@ -1127,7 +1127,7 @@ void x_set_i3_atoms(void) {
|
| 96 |
*/ |
| 97 |
void x_set_warp_to(Rect *rect) |
| 98 |
{
|
| 99 |
- if (!config.disable_focus_follows_mouse) |
| 100 |
+ if (!config.disable_focus_follows_mouse && !config.disable_mouse_warping) |
| 101 |
warp_to = rect; |
| 102 |
} |
| 103 |
|
b/testcases/t/201-config-parser.t
| 108 |
@@ -310,6 +310,24 @@ is(parser_calls($config), |
| 109 |
'focus_follows_mouse ok'); |
| 110 |
|
| 111 |
################################################################################ |
| 112 |
+# mouse_warping |
| 113 |
+################################################################################ |
| 114 |
+ |
| 115 |
+$config = <<'EOT'; |
| 116 |
+mouse_warping yes |
| 117 |
+mouse_warping no |
| 118 |
+EOT |
| 119 |
+ |
| 120 |
+$expected = <<'EOT'; |
| 121 |
+cfg_mouse_warping(yes) |
| 122 |
+cfg_mouse_warping(no) |
| 123 |
+EOT |
| 124 |
+ |
| 125 |
+is(parser_calls($config), |
| 126 |
+ $expected, |
| 127 |
+ 'mouse_warping ok'); |
| 128 |
+ |
| 129 |
+################################################################################ |
| 130 |
# force_display_urgency_hint |
| 131 |
################################################################################ |
| 132 |
|
| 133 |
@@ -413,7 +431,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 |
| 134 |
EOT |
| 135 |
|
| 136 |
my $expected_all_tokens = <<'EOT'; |
| 137 |
-ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent' |
| 138 |
+ERROR: CONFIG: Expected one of these tokens: <end>, '#', 'set', 'bindsym', 'bindcode', 'bind', 'bar', 'font', 'mode', 'floating_minimum_size', 'floating_maximum_size', 'floating_modifier', 'default_orientation', 'workspace_layout', 'new_window', 'new_float', 'hide_edge_borders', 'for_window', 'assign', 'focus_follows_mouse', 'mouse_warping', 'force_focus_wrapping', 'force_xinerama', 'force-xinerama', 'workspace_auto_back_and_forth', 'fake_outputs', 'fake-outputs', 'force_display_urgency_hint', 'workspace', 'ipc_socket', 'ipc-socket', 'restart_state', 'popup_during_fullscreen', 'exec_always', 'exec', 'client.background', 'client.focused_inactive', 'client.focused', 'client.unfocused', 'client.urgent' |
| 139 |
EOT |
| 140 |
|
| 141 |
my $expected_end = <<'EOT'; |