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 [output|none]". When mouse warping is disabled, mouse cursor does not jump to middle of current screen when changing workspaces between multiple outputs. 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/550/raw.patch | git am
b/docs/userguide
| 29 |
@@ -810,6 +810,22 @@ focus_follows_mouse <yes|no> |
| 30 |
focus_follows_mouse no |
| 31 |
---------------------- |
| 32 |
|
| 33 |
+=== Focus follows mouse |
| 34 |
+ |
| 35 |
+By default, mouse cursor is warped to center of the destination |
| 36 |
+screen/workspace when switching to a different output (eg. monitor). This |
| 37 |
+option allows disabling mouse cursor warping entirely. |
| 38 |
+ |
| 39 |
+*Syntax*: |
| 40 |
+--------------------------- |
| 41 |
+mouse_warping <output|none> |
| 42 |
+--------------------------- |
| 43 |
+ |
| 44 |
+*Example*: |
| 45 |
+------------------ |
| 46 |
+mouse_warping none |
| 47 |
+------------------ |
| 48 |
+ |
| 49 |
=== Popups during fullscreen mode |
| 50 |
|
| 51 |
When you are in fullscreen mode, some applications still open popup windows |
b/include/config.h
| 56 |
@@ -108,6 +108,11 @@ struct Config {
|
| 57 |
* It is not planned to add any different focus models. */ |
| 58 |
bool disable_focus_follows_mouse; |
| 59 |
|
| 60 |
+ /** By default, mouse cursor is warped to center of the destination |
| 61 |
+ * screen/workspace when switching focus to a different output. |
| 62 |
+ * This option allows disabling mouse cursor warping entirely. */ |
| 63 |
+ bool disable_mouse_warping; |
| 64 |
+ |
| 65 |
/** Remove borders if they are adjacent to the screen edge. |
| 66 |
* This is useful if you are reaching scrollbar on the edge of the |
| 67 |
* screen or do not want to waste a single pixel of displayspace. |
b/include/config_directives.h
| 72 |
@@ -46,6 +46,7 @@ CFGFUN(default_orientation, const char *orientation); |
| 73 |
CFGFUN(workspace_layout, const char *layout); |
| 74 |
CFGFUN(workspace_back_and_forth, const char *value); |
| 75 |
CFGFUN(focus_follows_mouse, const char *value); |
| 76 |
+CFGFUN(mouse_warping, const char *value); |
| 77 |
CFGFUN(force_focus_wrapping, const char *value); |
| 78 |
CFGFUN(force_xinerama, const char *value); |
| 79 |
CFGFUN(fake_outputs, const char *outputs); |
b/parser-specs/config.spec
| 84 |
@@ -32,6 +32,7 @@ state INITIAL: |
| 85 |
'for_window' -> FOR_WINDOW |
| 86 |
'assign' -> ASSIGN |
| 87 |
'focus_follows_mouse' -> FOCUS_FOLLOWS_MOUSE |
| 88 |
+ 'mouse_warping' -> MOUSE_WARPING |
| 89 |
'force_focus_wrapping' -> FORCE_FOCUS_WRAPPING |
| 90 |
'force_xinerama', 'force-xinerama' -> FORCE_XINERAMA |
| 91 |
'workspace_auto_back_and_forth' -> WORKSPACE_BACK_AND_FORTH |
| 92 |
@@ -172,6 +173,11 @@ state FOCUS_FOLLOWS_MOUSE: |
| 93 |
value = word |
| 94 |
-> call cfg_focus_follows_mouse($value) |
| 95 |
|
| 96 |
+# mouse_warping bool |
| 97 |
+state MOUSE_WARPING: |
| 98 |
+ value = word |
| 99 |
+ -> call cfg_mouse_warping($value) |
| 100 |
+ |
| 101 |
# force_focus_wrapping |
| 102 |
state FORCE_FOCUS_WRAPPING: |
| 103 |
value = word |
b/src/config_directives.c
| 108 |
@@ -299,6 +299,13 @@ CFGFUN(focus_follows_mouse, const char *value) {
|
| 109 |
config.disable_focus_follows_mouse = !eval_boolstr(value); |
| 110 |
} |
| 111 |
|
| 112 |
+CFGFUN(mouse_warping, const char *value) {
|
| 113 |
+ if (strcmp(value, "none") == 0) |
| 114 |
+ config.disable_mouse_warping = 1; |
| 115 |
+ else if (strcmp(value, "output") == 0) |
| 116 |
+ config.disable_mouse_warping = 0; |
| 117 |
+} |
| 118 |
+ |
| 119 |
CFGFUN(force_xinerama, const char *value) {
|
| 120 |
config.force_xinerama = eval_boolstr(value); |
| 121 |
} |
b/src/x.c
| 126 |
@@ -1142,7 +1142,7 @@ void x_set_i3_atoms(void) {
|
| 127 |
*/ |
| 128 |
void x_set_warp_to(Rect *rect) |
| 129 |
{
|
| 130 |
- if (!config.disable_focus_follows_mouse) |
| 131 |
+ if (!config.disable_focus_follows_mouse && !config.disable_mouse_warping) |
| 132 |
warp_to = rect; |
| 133 |
} |
| 134 |
|
b/testcases/t/201-config-parser.t
| 139 |
@@ -310,6 +310,24 @@ is(parser_calls($config), |
| 140 |
'focus_follows_mouse ok'); |
| 141 |
|
| 142 |
################################################################################ |
| 143 |
+# mouse_warping |
| 144 |
+################################################################################ |
| 145 |
+ |
| 146 |
+$config = <<'EOT'; |
| 147 |
+mouse_warping output |
| 148 |
+mouse_warping none |
| 149 |
+EOT |
| 150 |
+ |
| 151 |
+$expected = <<'EOT'; |
| 152 |
+cfg_mouse_warping(output) |
| 153 |
+cfg_mouse_warping(none) |
| 154 |
+EOT |
| 155 |
+ |
| 156 |
+is(parser_calls($config), |
| 157 |
+ $expected, |
| 158 |
+ 'mouse_warping ok'); |
| 159 |
+ |
| 160 |
+################################################################################ |
| 161 |
# force_display_urgency_hint |
| 162 |
################################################################################ |
| 163 |
|
| 164 |
@@ -413,7 +431,7 @@ client.focused #4c7899 #285577 #ffffff #2e9ef4 |
| 165 |
EOT |
| 166 |
|
| 167 |
my $expected_all_tokens = <<'EOT'; |
| 168 |
-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' |
| 169 |
+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' |
| 170 |
EOT |
| 171 |
|
| 172 |
my $expected_end = <<'EOT'; |
b/testcases/t/518-mouse-warping.t
| 178 |
@@ -0,0 +1,52 @@ |
| 179 |
+#!/perl |
| 180 |
+# vim:ts=4:sw=4:expandtab |
| 181 |
+# |
| 182 |
+# Please read the following documents before working on tests: |
| 183 |
+# • http://build.i3wm.org/docs/testsuite.html |
| 184 |
+# (or docs/testsuite) |
| 185 |
+# |
| 186 |
+# • http://build.i3wm.org/docs/lib-i3test.html |
| 187 |
+# (alternatively: perldoc ./testcases/lib/i3test.pm) |
| 188 |
+# |
| 189 |
+# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf |
| 190 |
+# (unless you are already familiar with Perl) |
| 191 |
+ |
| 192 |
+use i3test i3_autostart => 0; |
| 193 |
+ |
| 194 |
+# Ensure the pointer is at (0, 0) so that we really start on the first |
| 195 |
+# (the left) workspace. |
| 196 |
+$x->root->warp_pointer(0, 0); |
| 197 |
+ |
| 198 |
+my $config = <<EOT; |
| 199 |
+# i3 config file (v4) |
| 200 |
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1 |
| 201 |
+fake-outputs 1024x768+0+0,1024x768+1024+0 |
| 202 |
+mouse_warping none |
| 203 |
+EOT |
| 204 |
+my $pid = launch_with_config($config); |
| 205 |
+ |
| 206 |
+my $i3 = i3(get_socket_path()); |
| 207 |
+ |
| 208 |
+###################################################### |
| 209 |
+# Open one workspace with one window on both outputs # |
| 210 |
+###################################################### |
| 211 |
+ |
| 212 |
+# Open window on workspace 1, left output |
| 213 |
+is(focused_ws, '1', 'starting with focus on workspace 1'); |
| 214 |
+open_window; |
| 215 |
+ |
| 216 |
+# Open window on workspace 2, right output |
| 217 |
+cmd 'focus output right'; |
| 218 |
+is(focused_ws, '2', 'moved focus to workspace 2'); |
| 219 |
+open_window; |
| 220 |
+ |
| 221 |
+# If mouse_warping is disabled, the pointer has not moved from |
| 222 |
+# position (0, 0) when focus was switched to workspace 2 |
| 223 |
+$x->root->warp_pointer(0, 0); |
| 224 |
+ |
| 225 |
+# Ensure focus is still on workspace 2 |
| 226 |
+is(focused_ws, '2', 'warped mouse cursor to (0, 0), focus still in workspace 2'); |
| 227 |
+ |
| 228 |
+# Exit gracefully |
| 229 |
+exit_gracefully($pid); |
| 230 |
+done_testing; |