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'; |