diff options
-rw-r--r-- | common/util.c | 16 | ||||
-rw-r--r-- | include/sway/config.h | 23 | ||||
-rw-r--r-- | include/sway/input/cursor.h | 6 | ||||
-rw-r--r-- | include/util.h | 8 | ||||
-rw-r--r-- | sway/commands/bind.c | 168 | ||||
-rw-r--r-- | sway/commands/focus_follows_mouse.c | 4 | ||||
-rw-r--r-- | sway/commands/focus_wrapping.c | 12 | ||||
-rw-r--r-- | sway/commands/force_focus_wrapping.c | 8 | ||||
-rw-r--r-- | sway/commands/fullscreen.c | 14 | ||||
-rw-r--r-- | sway/commands/input/drag_lock.c | 9 | ||||
-rw-r--r-- | sway/commands/input/dwt.c | 9 | ||||
-rw-r--r-- | sway/commands/input/left_handed.c | 11 | ||||
-rw-r--r-- | sway/commands/input/middle_emulation.c | 9 | ||||
-rw-r--r-- | sway/commands/input/natural_scroll.c | 11 | ||||
-rw-r--r-- | sway/commands/input/tap.c | 9 | ||||
-rw-r--r-- | sway/commands/output/dpms.c | 8 | ||||
-rw-r--r-- | sway/commands/show_marks.c | 10 | ||||
-rw-r--r-- | sway/commands/urgent.c | 10 | ||||
-rw-r--r-- | sway/config.c | 7 | ||||
-rw-r--r-- | sway/input/cursor.c | 108 | ||||
-rw-r--r-- | sway/input/keyboard.c | 42 | ||||
-rw-r--r-- | sway/tree/workspace.c | 159 |
22 files changed, 423 insertions, 238 deletions
diff --git a/common/util.c b/common/util.c index e8a88772..467aa4b5 100644 --- a/common/util.c +++ b/common/util.c | |||
@@ -123,6 +123,22 @@ uint32_t parse_color(const char *color) { | |||
123 | return res; | 123 | return res; |
124 | } | 124 | } |
125 | 125 | ||
126 | bool parse_boolean(const char *boolean, bool current) { | ||
127 | if (strcasecmp(boolean, "1") == 0 | ||
128 | || strcasecmp(boolean, "yes") == 0 | ||
129 | || strcasecmp(boolean, "on") == 0 | ||
130 | || strcasecmp(boolean, "true") == 0 | ||
131 | || strcasecmp(boolean, "enable") == 0 | ||
132 | || strcasecmp(boolean, "enabled") == 0 | ||
133 | || strcasecmp(boolean, "active") == 0) { | ||
134 | return true; | ||
135 | } else if (strcasecmp(boolean, "toggle") == 0) { | ||
136 | return !current; | ||
137 | } | ||
138 | // All other values are false to match i3 | ||
139 | return false; | ||
140 | } | ||
141 | |||
126 | char* resolve_path(const char* path) { | 142 | char* resolve_path(const char* path) { |
127 | struct stat sb; | 143 | struct stat sb; |
128 | ssize_t r; | 144 | ssize_t r; |
diff --git a/include/sway/config.h b/include/sway/config.h index 9d2e1bf9..032f4196 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -21,14 +21,28 @@ struct sway_variable { | |||
21 | char *value; | 21 | char *value; |
22 | }; | 22 | }; |
23 | 23 | ||
24 | |||
25 | enum binding_input_type { | ||
26 | BINDING_KEYCODE, | ||
27 | BINDING_KEYSYM, | ||
28 | BINDING_MOUSE, | ||
29 | }; | ||
30 | |||
31 | enum binding_flags { | ||
32 | BINDING_RELEASE=1, | ||
33 | BINDING_LOCKED=2, // keyboard only | ||
34 | BINDING_BORDER=4, // mouse only; trigger on container border | ||
35 | BINDING_CONTENTS=8, // mouse only; trigger on container contents | ||
36 | BINDING_TITLEBAR=16 // mouse only; trigger on container titlebar | ||
37 | }; | ||
38 | |||
24 | /** | 39 | /** |
25 | * A key binding and an associated command. | 40 | * A key binding and an associated command. |
26 | */ | 41 | */ |
27 | struct sway_binding { | 42 | struct sway_binding { |
43 | enum binding_input_type type; | ||
28 | int order; | 44 | int order; |
29 | bool release; | 45 | uint32_t flags; |
30 | bool locked; | ||
31 | bool bindcode; | ||
32 | list_t *keys; // sorted in ascending order | 46 | list_t *keys; // sorted in ascending order |
33 | uint32_t modifiers; | 47 | uint32_t modifiers; |
34 | char *command; | 48 | char *command; |
@@ -49,6 +63,7 @@ struct sway_mode { | |||
49 | char *name; | 63 | char *name; |
50 | list_t *keysym_bindings; | 64 | list_t *keysym_bindings; |
51 | list_t *keycode_bindings; | 65 | list_t *keycode_bindings; |
66 | list_t *mouse_bindings; | ||
52 | bool pango; | 67 | bool pango; |
53 | }; | 68 | }; |
54 | 69 | ||
@@ -471,6 +486,8 @@ void free_sway_binding(struct sway_binding *sb); | |||
471 | 486 | ||
472 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); | 487 | struct sway_binding *sway_binding_dup(struct sway_binding *sb); |
473 | 488 | ||
489 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); | ||
490 | |||
474 | void load_swaybars(); | 491 | void load_swaybars(); |
475 | 492 | ||
476 | void invoke_swaybar(struct bar_config *bar); | 493 | void invoke_swaybar(struct bar_config *bar); |
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index b0a3a7c5..7ec45120 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h | |||
@@ -3,6 +3,8 @@ | |||
3 | #include <stdint.h> | 3 | #include <stdint.h> |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | 5 | ||
6 | #define SWAY_CURSOR_PRESSED_BUTTONS_CAP 32 | ||
7 | |||
6 | struct sway_cursor { | 8 | struct sway_cursor { |
7 | struct sway_seat *seat; | 9 | struct sway_seat *seat; |
8 | struct wlr_cursor *cursor; | 10 | struct wlr_cursor *cursor; |
@@ -29,6 +31,10 @@ struct sway_cursor { | |||
29 | uint32_t tool_buttons; | 31 | uint32_t tool_buttons; |
30 | 32 | ||
31 | struct wl_listener request_set_cursor; | 33 | struct wl_listener request_set_cursor; |
34 | |||
35 | // Mouse binding state | ||
36 | uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP]; | ||
37 | size_t pressed_button_count; | ||
32 | }; | 38 | }; |
33 | 39 | ||
34 | void sway_cursor_destroy(struct sway_cursor *cursor); | 40 | void sway_cursor_destroy(struct sway_cursor *cursor); |
diff --git a/include/util.h b/include/util.h index f68deae8..bda941ce 100644 --- a/include/util.h +++ b/include/util.h | |||
@@ -51,6 +51,14 @@ pid_t get_parent_pid(pid_t pid); | |||
51 | uint32_t parse_color(const char *color); | 51 | uint32_t parse_color(const char *color); |
52 | 52 | ||
53 | /** | 53 | /** |
54 | * Given a string that represents a boolean, return the boolean value. This | ||
55 | * function also takes in the current boolean value to support toggling. If | ||
56 | * toggling is not desired, pass in true for current so that toggling values | ||
57 | * get parsed as not true. | ||
58 | */ | ||
59 | bool parse_boolean(const char *boolean, bool current); | ||
60 | |||
61 | /** | ||
54 | * Given a path string, recurseively resolves any symlinks to their targets | 62 | * Given a path string, recurseively resolves any symlinks to their targets |
55 | * (which may be a file, directory) and returns the result. | 63 | * (which may be a file, directory) and returns the result. |
56 | * argument is returned. Caller must free the returned buffer. | 64 | * argument is returned. Caller must free the returned buffer. |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 83e9e432..133fd089 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -34,11 +34,14 @@ void free_sway_binding(struct sway_binding *binding) { | |||
34 | */ | 34 | */ |
35 | static bool binding_key_compare(struct sway_binding *binding_a, | 35 | static bool binding_key_compare(struct sway_binding *binding_a, |
36 | struct sway_binding *binding_b) { | 36 | struct sway_binding *binding_b) { |
37 | if (binding_a->release != binding_b->release) { | 37 | if (binding_a->type != binding_b->type) { |
38 | return false; | 38 | return false; |
39 | } | 39 | } |
40 | 40 | ||
41 | if (binding_a->bindcode != binding_b->bindcode) { | 41 | uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER |
42 | | BINDING_CONTENTS | BINDING_TITLEBAR; | ||
43 | if ((binding_a->flags & conflict_generating_flags) != | ||
44 | (binding_b->flags & conflict_generating_flags)) { | ||
42 | return false; | 45 | return false; |
43 | } | 46 | } |
44 | 47 | ||
@@ -69,6 +72,66 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) { | |||
69 | return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); | 72 | return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); |
70 | } | 73 | } |
71 | 74 | ||
75 | |||
76 | /** | ||
77 | * From a keycode, bindcode, or bindsym name and the most likely binding type, | ||
78 | * identify the appropriate numeric value corresponding to the key. Return NULL | ||
79 | * and set *key_val if successful, otherwise return a specific error. Change | ||
80 | * the value of *type if the initial type guess was incorrect and if this | ||
81 | * was the first identified key. | ||
82 | */ | ||
83 | static struct cmd_results *identify_key(const char* name, bool first_key, | ||
84 | uint32_t* key_val, enum binding_input_type* type) { | ||
85 | if (*type == BINDING_KEYCODE) { | ||
86 | // check for keycode | ||
87 | xkb_keycode_t keycode = strtol(name, NULL, 10); | ||
88 | if (!xkb_keycode_is_legal_ext(keycode)) { | ||
89 | return cmd_results_new(CMD_INVALID, "bindcode", | ||
90 | "Invalid keycode '%s'", name); | ||
91 | } | ||
92 | *key_val = keycode; | ||
93 | } else { | ||
94 | // check for keysym | ||
95 | xkb_keysym_t keysym = xkb_keysym_from_name(name, | ||
96 | XKB_KEYSYM_CASE_INSENSITIVE); | ||
97 | |||
98 | // Check for mouse binding | ||
99 | uint32_t button = 0; | ||
100 | if (strncasecmp(name, "button", strlen("button")) == 0 && | ||
101 | strlen(name) == strlen("button0")) { | ||
102 | button = name[strlen("button")] - '1' + BTN_LEFT; | ||
103 | } | ||
104 | |||
105 | if (*type == BINDING_KEYSYM) { | ||
106 | if (button) { | ||
107 | if (first_key) { | ||
108 | *type = BINDING_MOUSE; | ||
109 | *key_val = button; | ||
110 | } else { | ||
111 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
112 | "Mixed button '%s' into key sequence", name); | ||
113 | } | ||
114 | } else if (keysym) { | ||
115 | *key_val = keysym; | ||
116 | } else { | ||
117 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
118 | "Unknown key '%s'", name); | ||
119 | } | ||
120 | } else { | ||
121 | if (button) { | ||
122 | *key_val = button; | ||
123 | } else if (keysym) { | ||
124 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
125 | "Mixed keysym '%s' into button sequence", name); | ||
126 | } else { | ||
127 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
128 | "Unknown button '%s'", name); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | return NULL; | ||
133 | } | ||
134 | |||
72 | static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | 135 | static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, |
73 | bool bindcode) { | 136 | bool bindcode) { |
74 | const char *bindtype = bindcode ? "bindcode" : "bindsym"; | 137 | const char *bindtype = bindcode ? "bindcode" : "bindsym"; |
@@ -85,22 +148,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
85 | } | 148 | } |
86 | binding->keys = create_list(); | 149 | binding->keys = create_list(); |
87 | binding->modifiers = 0; | 150 | binding->modifiers = 0; |
88 | binding->release = false; | 151 | binding->flags = 0; |
89 | binding->locked = false; | 152 | binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM; |
90 | binding->bindcode = bindcode; | 153 | |
154 | bool exclude_titlebar = false; | ||
91 | 155 | ||
92 | // Handle --release and --locked | 156 | // Handle --release and --locked |
93 | while (argc > 0) { | 157 | while (argc > 0) { |
94 | if (strcmp("--release", argv[0]) == 0) { | 158 | if (strcmp("--release", argv[0]) == 0) { |
95 | binding->release = true; | 159 | binding->flags |= BINDING_RELEASE; |
96 | } else if (strcmp("--locked", argv[0]) == 0) { | 160 | } else if (strcmp("--locked", argv[0]) == 0) { |
97 | binding->locked = true; | 161 | binding->flags |= BINDING_LOCKED; |
162 | } else if (strcmp("--whole-window", argv[0]) == 0) { | ||
163 | binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR; | ||
164 | } else if (strcmp("--border", argv[0]) == 0) { | ||
165 | binding->flags |= BINDING_BORDER; | ||
166 | } else if (strcmp("--exclude-titlebar", argv[0]) == 0) { | ||
167 | exclude_titlebar = true; | ||
98 | } else { | 168 | } else { |
99 | break; | 169 | break; |
100 | } | 170 | } |
101 | argv++; | 171 | argv++; |
102 | argc--; | 172 | argc--; |
103 | } | 173 | } |
174 | if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR) | ||
175 | || exclude_titlebar) { | ||
176 | binding->type = BINDING_MOUSE; | ||
177 | } | ||
178 | |||
104 | if (argc < 2) { | 179 | if (argc < 2) { |
105 | free_sway_binding(binding); | 180 | free_sway_binding(binding); |
106 | return cmd_results_new(CMD_FAILURE, bindtype, | 181 | return cmd_results_new(CMD_FAILURE, bindtype, |
@@ -119,64 +194,47 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
119 | continue; | 194 | continue; |
120 | } | 195 | } |
121 | 196 | ||
122 | xkb_keycode_t keycode; | 197 | // Identify the key and possibly change binding->type |
123 | xkb_keysym_t keysym; | 198 | uint32_t key_val = 0; |
124 | if (bindcode) { | 199 | error = identify_key(split->items[i], binding->keys->length == 0, |
125 | // parse keycode | 200 | &key_val, &binding->type); |
126 | keycode = (int)strtol(split->items[i], NULL, 10); | 201 | if (error) { |
127 | if (!xkb_keycode_is_legal_ext(keycode)) { | 202 | free_sway_binding(binding); |
128 | error = | 203 | list_free(split); |
129 | cmd_results_new(CMD_INVALID, "bindcode", | 204 | return error; |
130 | "Invalid keycode '%s'", (char *)split->items[i]); | ||
131 | free_sway_binding(binding); | ||
132 | list_free(split); | ||
133 | return error; | ||
134 | } | ||
135 | } else { | ||
136 | // Check for xkb key | ||
137 | keysym = xkb_keysym_from_name(split->items[i], | ||
138 | XKB_KEYSYM_CASE_INSENSITIVE); | ||
139 | |||
140 | // Check for mouse binding | ||
141 | if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && | ||
142 | strlen(split->items[i]) == strlen("button0")) { | ||
143 | keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; | ||
144 | } | ||
145 | if (!keysym) { | ||
146 | struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", | ||
147 | "Unknown key '%s'", (char *)split->items[i]); | ||
148 | free_sway_binding(binding); | ||
149 | free_flat_list(split); | ||
150 | return ret; | ||
151 | } | ||
152 | } | 205 | } |
206 | |||
153 | uint32_t *key = calloc(1, sizeof(uint32_t)); | 207 | uint32_t *key = calloc(1, sizeof(uint32_t)); |
154 | if (!key) { | 208 | if (!key) { |
155 | free_sway_binding(binding); | 209 | free_sway_binding(binding); |
156 | free_flat_list(split); | 210 | free_flat_list(split); |
157 | return cmd_results_new(CMD_FAILURE, bindtype, | 211 | return cmd_results_new(CMD_FAILURE, bindtype, |
158 | "Unable to allocate binding"); | 212 | "Unable to allocate binding key"); |
159 | } | 213 | } |
160 | 214 | *key = key_val; | |
161 | if (bindcode) { | ||
162 | *key = (uint32_t)keycode; | ||
163 | } else { | ||
164 | *key = (uint32_t)keysym; | ||
165 | } | ||
166 | |||
167 | list_add(binding->keys, key); | 215 | list_add(binding->keys, key); |
168 | } | 216 | } |
169 | free_flat_list(split); | 217 | free_flat_list(split); |
170 | binding->order = binding_order++; | 218 | binding->order = binding_order++; |
171 | 219 | ||
220 | // refine region of interest for mouse binding once we are certain | ||
221 | // that this is one | ||
222 | if (exclude_titlebar) { | ||
223 | binding->flags &= ~BINDING_TITLEBAR; | ||
224 | } else if (binding->type == BINDING_MOUSE) { | ||
225 | binding->flags |= BINDING_TITLEBAR; | ||
226 | } | ||
227 | |||
172 | // sort ascending | 228 | // sort ascending |
173 | list_qsort(binding->keys, key_qsort_cmp); | 229 | list_qsort(binding->keys, key_qsort_cmp); |
174 | 230 | ||
175 | list_t *mode_bindings; | 231 | list_t *mode_bindings; |
176 | if (bindcode) { | 232 | if (binding->type == BINDING_KEYCODE) { |
177 | mode_bindings = config->current_mode->keycode_bindings; | 233 | mode_bindings = config->current_mode->keycode_bindings; |
178 | } else { | 234 | } else if (binding->type == BINDING_KEYSYM) { |
179 | mode_bindings = config->current_mode->keysym_bindings; | 235 | mode_bindings = config->current_mode->keysym_bindings; |
236 | } else { | ||
237 | mode_bindings = config->current_mode->mouse_bindings; | ||
180 | } | 238 | } |
181 | 239 | ||
182 | // overwrite the binding if it already exists | 240 | // overwrite the binding if it already exists |
@@ -209,3 +267,19 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { | |||
209 | struct cmd_results *cmd_bindcode(int argc, char **argv) { | 267 | struct cmd_results *cmd_bindcode(int argc, char **argv) { |
210 | return cmd_bindsym_or_bindcode(argc, argv, true); | 268 | return cmd_bindsym_or_bindcode(argc, argv, true); |
211 | } | 269 | } |
270 | |||
271 | |||
272 | /** | ||
273 | * Execute the command associated to a binding | ||
274 | */ | ||
275 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { | ||
276 | wlr_log(WLR_DEBUG, "running command for binding: %s", | ||
277 | binding->command); | ||
278 | config->handler_context.seat = seat; | ||
279 | struct cmd_results *results = execute_command(binding->command, NULL); | ||
280 | if (results->status != CMD_SUCCESS) { | ||
281 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
282 | binding->command, results->error); | ||
283 | } | ||
284 | free_cmd_results(results); | ||
285 | } | ||
diff --git a/sway/commands/focus_follows_mouse.c b/sway/commands/focus_follows_mouse.c index 661e7852..0b0e334c 100644 --- a/sway/commands/focus_follows_mouse.c +++ b/sway/commands/focus_follows_mouse.c | |||
@@ -1,12 +1,14 @@ | |||
1 | #include <string.h> | 1 | #include <string.h> |
2 | #include <strings.h> | 2 | #include <strings.h> |
3 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
4 | #include "util.h" | ||
4 | 5 | ||
5 | struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { | 6 | struct cmd_results *cmd_focus_follows_mouse(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 7 | struct cmd_results *error = NULL; |
7 | if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { | 8 | if ((error = checkarg(argc, "focus_follows_mouse", EXPECTED_EQUAL_TO, 1))) { |
8 | return error; | 9 | return error; |
9 | } | 10 | } |
10 | config->focus_follows_mouse = !strcasecmp(argv[0], "yes"); | 11 | config->focus_follows_mouse = |
12 | parse_boolean(argv[0], config->focus_follows_mouse); | ||
11 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 13 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
12 | } | 14 | } |
diff --git a/sway/commands/focus_wrapping.c b/sway/commands/focus_wrapping.c index 0a9e0bf2..562ee4f9 100644 --- a/sway/commands/focus_wrapping.c +++ b/sway/commands/focus_wrapping.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <strings.h> | 1 | #include <strings.h> |
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "util.h" | ||
4 | 5 | ||
5 | struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { | 6 | struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { |
6 | struct cmd_results *error = NULL; | 7 | struct cmd_results *error = NULL; |
@@ -8,15 +9,12 @@ struct cmd_results *cmd_focus_wrapping(int argc, char **argv) { | |||
8 | return error; | 9 | return error; |
9 | } | 10 | } |
10 | 11 | ||
11 | if (strcasecmp(argv[0], "no") == 0) { | 12 | if (strcasecmp(argv[0], "force") == 0) { |
12 | config->focus_wrapping = WRAP_NO; | ||
13 | } else if (strcasecmp(argv[0], "yes") == 0) { | ||
14 | config->focus_wrapping = WRAP_YES; | ||
15 | } else if (strcasecmp(argv[0], "force") == 0) { | ||
16 | config->focus_wrapping = WRAP_FORCE; | 13 | config->focus_wrapping = WRAP_FORCE; |
14 | } else if (parse_boolean(argv[0], config->focus_wrapping == WRAP_YES)) { | ||
15 | config->focus_wrapping = WRAP_YES; | ||
17 | } else { | 16 | } else { |
18 | return cmd_results_new(CMD_INVALID, "focus_wrapping", | 17 | config->focus_wrapping = WRAP_NO; |
19 | "Expected 'focus_wrapping yes|no|force'"); | ||
20 | } | 18 | } |
21 | 19 | ||
22 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 20 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/force_focus_wrapping.c b/sway/commands/force_focus_wrapping.c index bc1d067f..0892d9e9 100644 --- a/sway/commands/force_focus_wrapping.c +++ b/sway/commands/force_focus_wrapping.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <strings.h> | 1 | #include <strings.h> |
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "util.h" | ||
4 | 5 | ||
5 | struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { | 6 | struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { |
6 | struct cmd_results *error = | 7 | struct cmd_results *error = |
@@ -9,13 +10,10 @@ struct cmd_results *cmd_force_focus_wrapping(int argc, char **argv) { | |||
9 | return error; | 10 | return error; |
10 | } | 11 | } |
11 | 12 | ||
12 | if (strcasecmp(argv[0], "no") == 0) { | 13 | if (parse_boolean(argv[0], config->focus_wrapping == WRAP_FORCE)) { |
13 | config->focus_wrapping = WRAP_YES; | ||
14 | } else if (strcasecmp(argv[0], "yes") == 0) { | ||
15 | config->focus_wrapping = WRAP_FORCE; | 14 | config->focus_wrapping = WRAP_FORCE; |
16 | } else { | 15 | } else { |
17 | return cmd_results_new(CMD_INVALID, "force_focus_wrapping", | 16 | config->focus_wrapping = WRAP_YES; |
18 | "Expected 'force_focus_wrapping yes|no'"); | ||
19 | } | 17 | } |
20 | 18 | ||
21 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 0b5beaa2..b423fd23 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
7 | #include "sway/tree/layout.h" | 7 | #include "sway/tree/layout.h" |
8 | #include "util.h" | ||
8 | 9 | ||
9 | struct cmd_results *cmd_fullscreen(int argc, char **argv) { | 10 | struct cmd_results *cmd_fullscreen(int argc, char **argv) { |
10 | struct cmd_results *error = NULL; | 11 | struct cmd_results *error = NULL; |
@@ -18,17 +19,10 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
18 | "Only views can fullscreen"); | 19 | "Only views can fullscreen"); |
19 | } | 20 | } |
20 | struct sway_view *view = container->sway_view; | 21 | struct sway_view *view = container->sway_view; |
21 | bool wants_fullscreen; | 22 | bool wants_fullscreen = !view->is_fullscreen; |
22 | 23 | ||
23 | if (argc == 0 || strcmp(argv[0], "toggle") == 0) { | 24 | if (argc) { |
24 | wants_fullscreen = !view->is_fullscreen; | 25 | wants_fullscreen = parse_boolean(argv[0], view->is_fullscreen); |
25 | } else if (strcmp(argv[0], "enable") == 0) { | ||
26 | wants_fullscreen = true; | ||
27 | } else if (strcmp(argv[0], "disable") == 0) { | ||
28 | wants_fullscreen = false; | ||
29 | } else { | ||
30 | return cmd_results_new(CMD_INVALID, "fullscreen", | ||
31 | "Expected 'fullscreen' or 'fullscreen <enable|disable|toggle>'"); | ||
32 | } | 26 | } |
33 | 27 | ||
34 | view_set_fullscreen(view, wants_fullscreen); | 28 | view_set_fullscreen(view, wants_fullscreen); |
diff --git a/sway/commands/input/drag_lock.c b/sway/commands/input/drag_lock.c index 9e32816f..f9ddeef2 100644 --- a/sway/commands/input/drag_lock.c +++ b/sway/commands/input/drag_lock.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,14 +19,10 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | if (parse_boolean(argv[0], true)) { |
22 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; | 23 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; | ||
25 | } else { | 24 | } else { |
26 | free_input_config(new_config); | 25 | new_config->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_DISABLED; |
27 | return cmd_results_new(CMD_INVALID, "drag_lock", | ||
28 | "Expected 'drag_lock <enabled|disabled>'"); | ||
29 | } | 26 | } |
30 | 27 | ||
31 | apply_input_config(new_config); | 28 | apply_input_config(new_config); |
diff --git a/sway/commands/input/dwt.c b/sway/commands/input/dwt.c index 73937507..15134268 100644 --- a/sway/commands/input/dwt.c +++ b/sway/commands/input/dwt.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_dwt(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_dwt(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -17,14 +18,10 @@ struct cmd_results *input_cmd_dwt(int argc, char **argv) { | |||
17 | struct input_config *new_config = | 18 | struct input_config *new_config = |
18 | new_input_config(current_input_config->identifier); | 19 | new_input_config(current_input_config->identifier); |
19 | 20 | ||
20 | if (strcasecmp(argv[0], "enabled") == 0) { | 21 | if (parse_boolean(argv[0], true)) { |
21 | new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; | 22 | new_config->dwt = LIBINPUT_CONFIG_DWT_ENABLED; |
22 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
23 | new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; | ||
24 | } else { | 23 | } else { |
25 | free_input_config(new_config); | 24 | new_config->dwt = LIBINPUT_CONFIG_DWT_DISABLED; |
26 | return cmd_results_new(CMD_INVALID, "dwt", | ||
27 | "Expected 'dwt <enabled|disabled>'"); | ||
28 | } | 25 | } |
29 | 26 | ||
30 | apply_input_config(new_config); | 27 | apply_input_config(new_config); |
diff --git a/sway/commands/input/left_handed.c b/sway/commands/input/left_handed.c index 769ce98c..e770043a 100644 --- a/sway/commands/input/left_handed.c +++ b/sway/commands/input/left_handed.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_left_handed(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_left_handed(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,15 +19,7 @@ struct cmd_results *input_cmd_left_handed(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | new_config->left_handed = parse_boolean(argv[0], true); |
22 | new_config->left_handed = 1; | ||
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->left_handed = 0; | ||
25 | } else { | ||
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "left_handed", | ||
28 | "Expected 'left_handed <enabled|disabled>'"); | ||
29 | } | ||
30 | 23 | ||
31 | apply_input_config(new_config); | 24 | apply_input_config(new_config); |
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/input/middle_emulation.c b/sway/commands/input/middle_emulation.c index 7ca01629..414d4d2b 100644 --- a/sway/commands/input/middle_emulation.c +++ b/sway/commands/input/middle_emulation.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,15 +19,11 @@ struct cmd_results *input_cmd_middle_emulation(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | if (parse_boolean(argv[0], true)) { |
22 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; | 23 | new_config->middle_emulation = LIBINPUT_CONFIG_MIDDLE_EMULATION_ENABLED; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | 24 | } else { |
24 | new_config->middle_emulation = | 25 | new_config->middle_emulation = |
25 | LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; | 26 | LIBINPUT_CONFIG_MIDDLE_EMULATION_DISABLED; |
26 | } else { | ||
27 | free_input_config(new_config); | ||
28 | return cmd_results_new(CMD_INVALID, "middle_emulation", | ||
29 | "Expected 'middle_emulation <enabled|disabled>'"); | ||
30 | } | 27 | } |
31 | 28 | ||
32 | apply_input_config(new_config); | 29 | apply_input_config(new_config); |
diff --git a/sway/commands/input/natural_scroll.c b/sway/commands/input/natural_scroll.c index 55236790..77c3ff00 100644 --- a/sway/commands/input/natural_scroll.c +++ b/sway/commands/input/natural_scroll.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "util.h" | ||
6 | 7 | ||
7 | struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { | 8 | struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { |
8 | struct cmd_results *error = NULL; | 9 | struct cmd_results *error = NULL; |
@@ -18,15 +19,7 @@ struct cmd_results *input_cmd_natural_scroll(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | new_config->natural_scroll = parse_boolean(argv[0], true); |
22 | new_config->natural_scroll = 1; | ||
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->natural_scroll = 0; | ||
25 | } else { | ||
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "natural_scroll", | ||
28 | "Expected 'natural_scroll <enabled|disabled>'"); | ||
29 | } | ||
30 | 23 | ||
31 | apply_input_config(new_config); | 24 | apply_input_config(new_config); |
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 25 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c index a8d1a10c..ac3b8237 100644 --- a/sway/commands/input/tap.c +++ b/sway/commands/input/tap.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/input/input-manager.h" | 5 | #include "sway/input/input-manager.h" |
6 | #include "log.h" | 6 | #include "log.h" |
7 | #include "util.h" | ||
7 | 8 | ||
8 | struct cmd_results *input_cmd_tap(int argc, char **argv) { | 9 | struct cmd_results *input_cmd_tap(int argc, char **argv) { |
9 | struct cmd_results *error = NULL; | 10 | struct cmd_results *error = NULL; |
@@ -18,14 +19,10 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) { | |||
18 | struct input_config *new_config = | 19 | struct input_config *new_config = |
19 | new_input_config(current_input_config->identifier); | 20 | new_input_config(current_input_config->identifier); |
20 | 21 | ||
21 | if (strcasecmp(argv[0], "enabled") == 0) { | 22 | if (parse_boolean(argv[0], true)) { |
22 | new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; | 23 | new_config->tap = LIBINPUT_CONFIG_TAP_ENABLED; |
23 | } else if (strcasecmp(argv[0], "disabled") == 0) { | ||
24 | new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; | ||
25 | } else { | 24 | } else { |
26 | free_input_config(new_config); | 25 | new_config->tap = LIBINPUT_CONFIG_TAP_DISABLED; |
27 | return cmd_results_new(CMD_INVALID, "tap", | ||
28 | "Expected 'tap <enabled|disabled>'"); | ||
29 | } | 26 | } |
30 | 27 | ||
31 | wlr_log(WLR_DEBUG, "apply-tap for device: %s", | 28 | wlr_log(WLR_DEBUG, "apply-tap for device: %s", |
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c index 0959ea6b..3492061e 100644 --- a/sway/commands/output/dpms.c +++ b/sway/commands/output/dpms.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include "sway/commands.h" | 1 | #include "sway/commands.h" |
2 | #include "sway/config.h" | 2 | #include "sway/config.h" |
3 | #include "util.h" | ||
3 | 4 | ||
4 | struct cmd_results *output_cmd_dpms(int argc, char **argv) { | 5 | struct cmd_results *output_cmd_dpms(int argc, char **argv) { |
5 | if (!config->handler_context.output_config) { | 6 | if (!config->handler_context.output_config) { |
@@ -9,13 +10,10 @@ struct cmd_results *output_cmd_dpms(int argc, char **argv) { | |||
9 | return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument."); | 10 | return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument."); |
10 | } | 11 | } |
11 | 12 | ||
12 | if (strcmp(*argv, "on") == 0) { | 13 | if (parse_boolean(argv[0], true)) { |
13 | config->handler_context.output_config->dpms_state = DPMS_ON; | 14 | config->handler_context.output_config->dpms_state = DPMS_ON; |
14 | } else if (strcmp(*argv, "off") == 0) { | ||
15 | config->handler_context.output_config->dpms_state = DPMS_OFF; | ||
16 | } else { | 15 | } else { |
17 | return cmd_results_new(CMD_INVALID, "output", | 16 | config->handler_context.output_config->dpms_state = DPMS_OFF; |
18 | "Invalid dpms state, valid states are on/off."); | ||
19 | } | 17 | } |
20 | 18 | ||
21 | config->handler_context.leftovers.argc = argc - 1; | 19 | config->handler_context.leftovers.argc = argc - 1; |
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index c7fdc538..434a0e27 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include "list.h" | 7 | #include "list.h" |
8 | #include "log.h" | 8 | #include "log.h" |
9 | #include "stringop.h" | 9 | #include "stringop.h" |
10 | #include "util.h" | ||
10 | 11 | ||
11 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { | 12 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { |
12 | if (con->type == C_VIEW) { | 13 | if (con->type == C_VIEW) { |
@@ -20,14 +21,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { | |||
20 | return error; | 21 | return error; |
21 | } | 22 | } |
22 | 23 | ||
23 | if (strcmp(*argv, "yes") == 0) { | 24 | config->show_marks = parse_boolean(argv[0], config->show_marks); |
24 | config->show_marks = true; | ||
25 | } else if (strcmp(*argv, "no") == 0) { | ||
26 | config->show_marks = false; | ||
27 | } else { | ||
28 | return cmd_results_new(CMD_INVALID, "show_marks", | ||
29 | "Expected 'show_marks <yes|no>'"); | ||
30 | } | ||
31 | 25 | ||
32 | if (config->show_marks) { | 26 | if (config->show_marks) { |
33 | container_for_each_descendant_dfs(&root_container, | 27 | container_for_each_descendant_dfs(&root_container, |
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index d199858a..51c497c4 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
7 | #include "sway/tree/layout.h" | 7 | #include "sway/tree/layout.h" |
8 | #include "util.h" | ||
8 | 9 | ||
9 | struct cmd_results *cmd_urgent(int argc, char **argv) { | 10 | struct cmd_results *cmd_urgent(int argc, char **argv) { |
10 | struct cmd_results *error = NULL; | 11 | struct cmd_results *error = NULL; |
@@ -19,17 +20,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { | |||
19 | } | 20 | } |
20 | struct sway_view *view = container->sway_view; | 21 | struct sway_view *view = container->sway_view; |
21 | 22 | ||
22 | if (strcmp(argv[0], "enable") == 0) { | 23 | if (strcmp(argv[0], "allow") == 0) { |
23 | view_set_urgent(view, true); | ||
24 | } else if (strcmp(argv[0], "disable") == 0) { | ||
25 | view_set_urgent(view, false); | ||
26 | } else if (strcmp(argv[0], "allow") == 0) { | ||
27 | view->allow_request_urgent = true; | 24 | view->allow_request_urgent = true; |
28 | } else if (strcmp(argv[0], "deny") == 0) { | 25 | } else if (strcmp(argv[0], "deny") == 0) { |
29 | view->allow_request_urgent = false; | 26 | view->allow_request_urgent = false; |
30 | } else { | 27 | } else { |
31 | return cmd_results_new(CMD_INVALID, "urgent", | 28 | view_set_urgent(view, parse_boolean(argv[0], view_is_urgent(view))); |
32 | "Expected 'urgent <enable|disable|allow|deny>'"); | ||
33 | } | 29 | } |
34 | 30 | ||
35 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/config.c b/sway/config.c index 5f6dd7ad..90dfb9a9 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -56,6 +56,12 @@ static void free_mode(struct sway_mode *mode) { | |||
56 | } | 56 | } |
57 | list_free(mode->keycode_bindings); | 57 | list_free(mode->keycode_bindings); |
58 | } | 58 | } |
59 | if (mode->mouse_bindings) { | ||
60 | for (i = 0; i < mode->mouse_bindings->length; i++) { | ||
61 | free_sway_binding(mode->mouse_bindings->items[i]); | ||
62 | } | ||
63 | list_free(mode->mouse_bindings); | ||
64 | } | ||
59 | free(mode); | 65 | free(mode); |
60 | } | 66 | } |
61 | 67 | ||
@@ -170,6 +176,7 @@ static void config_defaults(struct sway_config *config) { | |||
170 | strcpy(config->current_mode->name, "default"); | 176 | strcpy(config->current_mode->name, "default"); |
171 | if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup; | 177 | if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup; |
172 | if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup; | 178 | if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup; |
179 | if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup; | ||
173 | list_add(config->modes, config->current_mode); | 180 | list_add(config->modes, config->current_mode); |
174 | 181 | ||
175 | config->floating_mod = 0; | 182 | config->floating_mod = 0; |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 65d04cac..27597640 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -460,6 +460,12 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
460 | bool resizing_via_mod = button == BTN_RIGHT && mod_pressed; | 460 | bool resizing_via_mod = button == BTN_RIGHT && mod_pressed; |
461 | if ((resizing_via_border || resizing_via_mod) && | 461 | if ((resizing_via_border || resizing_via_mod) && |
462 | state == WLR_BUTTON_PRESSED) { | 462 | state == WLR_BUTTON_PRESSED) { |
463 | if (edge == WLR_EDGE_NONE) { | ||
464 | edge |= cursor->cursor->x > cont->x + cont->width / 2 ? | ||
465 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | ||
466 | edge |= cursor->cursor->y > cont->y + cont->height / 2 ? | ||
467 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | ||
468 | } | ||
463 | seat_begin_resize(seat, cont, button, edge); | 469 | seat_begin_resize(seat, cont, button, edge); |
464 | return; | 470 | return; |
465 | } | 471 | } |
@@ -469,6 +475,83 @@ static void dispatch_cursor_button_floating(struct sway_cursor *cursor, | |||
469 | seat_pointer_notify_button(seat, time_msec, button, state); | 475 | seat_pointer_notify_button(seat, time_msec, button, state); |
470 | } | 476 | } |
471 | 477 | ||
478 | /** | ||
479 | * Remove a button (and duplicates) to the sorted list of currently pressed buttons | ||
480 | */ | ||
481 | static void state_erase_button(struct sway_cursor *cursor, uint32_t button) { | ||
482 | size_t j = 0; | ||
483 | for (size_t i = 0; i < cursor->pressed_button_count; ++i) { | ||
484 | if (i > j) { | ||
485 | cursor->pressed_buttons[j] = cursor->pressed_buttons[i]; | ||
486 | } | ||
487 | if (cursor->pressed_buttons[i] != button) { | ||
488 | ++j; | ||
489 | } | ||
490 | } | ||
491 | while (cursor->pressed_button_count > j) { | ||
492 | --cursor->pressed_button_count; | ||
493 | cursor->pressed_buttons[cursor->pressed_button_count] = 0; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * Add a button to the sorted list of currently pressed buttons, if there | ||
499 | * is space. | ||
500 | */ | ||
501 | static void state_add_button(struct sway_cursor *cursor, uint32_t button) { | ||
502 | if (cursor->pressed_button_count >= SWAY_CURSOR_PRESSED_BUTTONS_CAP) { | ||
503 | return; | ||
504 | } | ||
505 | size_t i = 0; | ||
506 | while (i < cursor->pressed_button_count && cursor->pressed_buttons[i] < button) { | ||
507 | ++i; | ||
508 | } | ||
509 | size_t j = cursor->pressed_button_count; | ||
510 | while (j > i) { | ||
511 | cursor->pressed_buttons[j] = cursor->pressed_buttons[j - 1]; | ||
512 | --j; | ||
513 | } | ||
514 | cursor->pressed_buttons[i] = button; | ||
515 | cursor->pressed_button_count++; | ||
516 | } | ||
517 | |||
518 | /** | ||
519 | * Return the mouse binding which matches modifier, click location, release, | ||
520 | * and pressed button state, otherwise return null. | ||
521 | */ | ||
522 | static struct sway_binding* get_active_mouse_binding(const struct sway_cursor *cursor, | ||
523 | list_t *bindings, uint32_t modifiers, bool release, bool on_titlebar, | ||
524 | bool on_border, bool on_content) { | ||
525 | uint32_t click_region = (on_titlebar ? BINDING_TITLEBAR : 0) | | ||
526 | (on_border ? BINDING_BORDER : 0) | | ||
527 | (on_content ? BINDING_CONTENTS : 0); | ||
528 | |||
529 | for (int i = 0; i < bindings->length; ++i) { | ||
530 | struct sway_binding *binding = bindings->items[i]; | ||
531 | if (modifiers ^ binding->modifiers || | ||
532 | cursor->pressed_button_count != (size_t)binding->keys->length || | ||
533 | release != (binding->flags & BINDING_RELEASE) || | ||
534 | !(click_region & binding->flags)) { | ||
535 | continue; | ||
536 | } | ||
537 | |||
538 | bool match = true; | ||
539 | for (size_t j = 0; j < cursor->pressed_button_count; j++) { | ||
540 | uint32_t key = *(uint32_t *)binding->keys->items[j]; | ||
541 | if (key != cursor->pressed_buttons[j]) { | ||
542 | match = false; | ||
543 | break; | ||
544 | } | ||
545 | } | ||
546 | if (!match) { | ||
547 | continue; | ||
548 | } | ||
549 | |||
550 | return binding; | ||
551 | } | ||
552 | return NULL; | ||
553 | } | ||
554 | |||
472 | void dispatch_cursor_button(struct sway_cursor *cursor, | 555 | void dispatch_cursor_button(struct sway_cursor *cursor, |
473 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { | 556 | uint32_t time_msec, uint32_t button, enum wlr_button_state state) { |
474 | if (cursor->seat->operation != OP_NONE && | 557 | if (cursor->seat->operation != OP_NONE && |
@@ -485,6 +568,31 @@ void dispatch_cursor_button(struct sway_cursor *cursor, | |||
485 | double sx, sy; | 568 | double sx, sy; |
486 | struct sway_container *cont = container_at_coords(cursor->seat, | 569 | struct sway_container *cont = container_at_coords(cursor->seat, |
487 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); | 570 | cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); |
571 | |||
572 | // Handle mouse bindings | ||
573 | bool on_border = cont && (find_resize_edge(cont, cursor) != WLR_EDGE_NONE); | ||
574 | bool on_contents = !on_border && surface; | ||
575 | bool on_titlebar = !on_border && !surface; | ||
576 | struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(cursor->seat->wlr_seat); | ||
577 | uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; | ||
578 | |||
579 | struct sway_binding *binding = NULL; | ||
580 | if (state == WLR_BUTTON_PRESSED) { | ||
581 | state_add_button(cursor, button); | ||
582 | binding = get_active_mouse_binding(cursor, | ||
583 | config->current_mode->mouse_bindings, modifiers, false, | ||
584 | on_titlebar, on_border, on_contents); | ||
585 | } else { | ||
586 | binding = get_active_mouse_binding(cursor, | ||
587 | config->current_mode->mouse_bindings, modifiers, true, | ||
588 | on_titlebar, on_border, on_contents); | ||
589 | state_erase_button(cursor, button); | ||
590 | } | ||
591 | if (binding) { | ||
592 | seat_execute_command(cursor->seat, binding); | ||
593 | // TODO: do we want to pass on the event? | ||
594 | } | ||
595 | |||
488 | if (surface && wlr_surface_is_layer_surface(surface)) { | 596 | if (surface && wlr_surface_is_layer_surface(surface)) { |
489 | struct wlr_layer_surface *layer = | 597 | struct wlr_layer_surface *layer = |
490 | wlr_layer_surface_from_wlr_surface(surface); | 598 | wlr_layer_surface_from_wlr_surface(surface); |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index ede38519..49241db8 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -3,11 +3,11 @@ | |||
3 | #include <wlr/backend/multi.h> | 3 | #include <wlr/backend/multi.h> |
4 | #include <wlr/backend/session.h> | 4 | #include <wlr/backend/session.h> |
5 | #include <wlr/types/wlr_idle.h> | 5 | #include <wlr/types/wlr_idle.h> |
6 | #include "sway/commands.h" | ||
6 | #include "sway/desktop/transaction.h" | 7 | #include "sway/desktop/transaction.h" |
7 | #include "sway/input/seat.h" | ||
8 | #include "sway/input/keyboard.h" | ||
9 | #include "sway/input/input-manager.h" | 8 | #include "sway/input/input-manager.h" |
10 | #include "sway/commands.h" | 9 | #include "sway/input/keyboard.h" |
10 | #include "sway/input/seat.h" | ||
11 | #include "log.h" | 11 | #include "log.h" |
12 | 12 | ||
13 | /** | 13 | /** |
@@ -88,11 +88,13 @@ static void get_active_binding(const struct sway_shortcut_state *state, | |||
88 | uint32_t modifiers, bool release, bool locked) { | 88 | uint32_t modifiers, bool release, bool locked) { |
89 | for (int i = 0; i < bindings->length; ++i) { | 89 | for (int i = 0; i < bindings->length; ++i) { |
90 | struct sway_binding *binding = bindings->items[i]; | 90 | struct sway_binding *binding = bindings->items[i]; |
91 | bool binding_locked = binding->flags & BINDING_LOCKED; | ||
92 | bool binding_release = binding->flags & BINDING_RELEASE; | ||
91 | 93 | ||
92 | if (modifiers ^ binding->modifiers || | 94 | if (modifiers ^ binding->modifiers || |
93 | state->npressed != (size_t)binding->keys->length || | 95 | state->npressed != (size_t)binding->keys->length || |
94 | locked > binding->locked || | 96 | release != binding_release || |
95 | release != binding->release) { | 97 | locked > binding_locked) { |
96 | continue; | 98 | continue; |
97 | } | 99 | } |
98 | 100 | ||
@@ -119,23 +121,6 @@ static void get_active_binding(const struct sway_shortcut_state *state, | |||
119 | } | 121 | } |
120 | 122 | ||
121 | /** | 123 | /** |
122 | * Execute the command associated to a binding | ||
123 | */ | ||
124 | static void keyboard_execute_command(struct sway_keyboard *keyboard, | ||
125 | struct sway_binding *binding) { | ||
126 | wlr_log(WLR_DEBUG, "running command for binding: %s", | ||
127 | binding->command); | ||
128 | config->handler_context.seat = keyboard->seat_device->sway_seat; | ||
129 | struct cmd_results *results = execute_command(binding->command, NULL); | ||
130 | transaction_commit_dirty(); | ||
131 | if (results->status != CMD_SUCCESS) { | ||
132 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | ||
133 | binding->command, results->error); | ||
134 | } | ||
135 | free_cmd_results(results); | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * Execute a built-in, hardcoded compositor binding. These are triggered from a | 124 | * Execute a built-in, hardcoded compositor binding. These are triggered from a |
140 | * single keysym. | 125 | * single keysym. |
141 | * | 126 | * |
@@ -211,12 +196,13 @@ static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard, | |||
211 | static void handle_keyboard_key(struct wl_listener *listener, void *data) { | 196 | static void handle_keyboard_key(struct wl_listener *listener, void *data) { |
212 | struct sway_keyboard *keyboard = | 197 | struct sway_keyboard *keyboard = |
213 | wl_container_of(listener, keyboard, keyboard_key); | 198 | wl_container_of(listener, keyboard, keyboard_key); |
214 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | 199 | struct sway_seat* seat = keyboard->seat_device->sway_seat; |
200 | struct wlr_seat *wlr_seat = seat->wlr_seat; | ||
215 | struct wlr_input_device *wlr_device = | 201 | struct wlr_input_device *wlr_device = |
216 | keyboard->seat_device->input_device->wlr_device; | 202 | keyboard->seat_device->input_device->wlr_device; |
217 | wlr_idle_notify_activity(keyboard->seat_device->sway_seat->input->server->idle, wlr_seat); | 203 | wlr_idle_notify_activity(seat->input->server->idle, wlr_seat); |
218 | struct wlr_event_keyboard_key *event = data; | 204 | struct wlr_event_keyboard_key *event = data; |
219 | bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; | 205 | bool input_inhibited = seat->exclusive_client != NULL; |
220 | 206 | ||
221 | // Identify new keycode, raw keysym(s), and translated keysym(s) | 207 | // Identify new keycode, raw keysym(s), and translated keysym(s) |
222 | xkb_keycode_t keycode = event->keycode + 8; | 208 | xkb_keycode_t keycode = event->keycode + 8; |
@@ -266,7 +252,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
266 | // Execute stored release binding once no longer active | 252 | // Execute stored release binding once no longer active |
267 | if (keyboard->held_binding && binding_released != keyboard->held_binding && | 253 | if (keyboard->held_binding && binding_released != keyboard->held_binding && |
268 | event->state == WLR_KEY_RELEASED) { | 254 | event->state == WLR_KEY_RELEASED) { |
269 | keyboard_execute_command(keyboard, keyboard->held_binding); | 255 | seat_execute_command(seat, keyboard->held_binding); |
270 | handled = true; | 256 | handled = true; |
271 | } | 257 | } |
272 | if (binding_released != keyboard->held_binding) { | 258 | if (binding_released != keyboard->held_binding) { |
@@ -290,7 +276,7 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
290 | raw_modifiers, false, input_inhibited); | 276 | raw_modifiers, false, input_inhibited); |
291 | 277 | ||
292 | if (binding_pressed) { | 278 | if (binding_pressed) { |
293 | keyboard_execute_command(keyboard, binding_pressed); | 279 | seat_execute_command(seat, binding_pressed); |
294 | handled = true; | 280 | handled = true; |
295 | } | 281 | } |
296 | } | 282 | } |
@@ -312,6 +298,8 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
312 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | 298 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, |
313 | event->keycode, event->state); | 299 | event->keycode, event->state); |
314 | } | 300 | } |
301 | |||
302 | transaction_commit_dirty(); | ||
315 | } | 303 | } |
316 | 304 | ||
317 | static void handle_keyboard_modifiers(struct wl_listener *listener, | 305 | static void handle_keyboard_modifiers(struct wl_listener *listener, |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index b1082e4f..62974cd7 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -108,96 +108,103 @@ static bool workspace_valid_on_output(const char *output_name, | |||
108 | return true; | 108 | return true; |
109 | } | 109 | } |
110 | 110 | ||
111 | char *workspace_next_name(const char *output_name) { | 111 | static void workspace_name_from_binding(const struct sway_binding * binding, |
112 | wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", | 112 | const char* output_name, int *min_order, char **earliest_name) { |
113 | output_name); | 113 | char *cmdlist = strdup(binding->command); |
114 | // Scan all workspace bindings to find the next available workspace name, | 114 | char *dup = cmdlist; |
115 | // if none are found/available then default to a number | 115 | char *name = NULL; |
116 | struct sway_mode *mode = config->current_mode; | 116 | |
117 | 117 | // workspace n | |
118 | // TODO: iterate over keycode bindings too | 118 | char *cmd = argsep(&cmdlist, " "); |
119 | int order = INT_MAX; | 119 | if (cmdlist) { |
120 | char *target = NULL; | 120 | name = argsep(&cmdlist, ",;"); |
121 | for (int i = 0; i < mode->keysym_bindings->length; ++i) { | 121 | } |
122 | struct sway_binding *binding = mode->keysym_bindings->items[i]; | 122 | |
123 | char *cmdlist = strdup(binding->command); | 123 | if (strcmp("workspace", cmd) == 0 && name) { |
124 | char *dup = cmdlist; | 124 | char *_target = strdup(name); |
125 | char *name = NULL; | 125 | _target = do_var_replacement(_target); |
126 | 126 | strip_quotes(_target); | |
127 | // workspace n | 127 | while (isspace(*_target)) { |
128 | char *cmd = argsep(&cmdlist, " "); | 128 | memmove(_target, _target+1, strlen(_target+1)); |
129 | if (cmdlist) { | ||
130 | name = argsep(&cmdlist, ",;"); | ||
131 | } | 129 | } |
130 | wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", | ||
131 | _target); | ||
132 | 132 | ||
133 | if (strcmp("workspace", cmd) == 0 && name) { | 133 | // Make sure that the command references an actual workspace |
134 | char *_target = strdup(name); | 134 | // not a command about workspaces |
135 | _target = do_var_replacement(_target); | 135 | if (strcmp(_target, "next") == 0 || |
136 | strip_quotes(_target); | ||
137 | while (isspace(*_target)) { | ||
138 | memmove(_target, _target+1, strlen(_target+1)); | ||
139 | } | ||
140 | wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", | ||
141 | _target); | ||
142 | |||
143 | // Make sure that the command references an actual workspace | ||
144 | // not a command about workspaces | ||
145 | if (strcmp(_target, "next") == 0 || | ||
146 | strcmp(_target, "prev") == 0 || | 136 | strcmp(_target, "prev") == 0 || |
147 | strcmp(_target, "next_on_output") == 0 || | 137 | strcmp(_target, "next_on_output") == 0 || |
148 | strcmp(_target, "prev_on_output") == 0 || | 138 | strcmp(_target, "prev_on_output") == 0 || |
149 | strcmp(_target, "number") == 0 || | 139 | strcmp(_target, "number") == 0 || |
150 | strcmp(_target, "back_and_forth") == 0 || | 140 | strcmp(_target, "back_and_forth") == 0 || |
151 | strcmp(_target, "current") == 0) | 141 | strcmp(_target, "current") == 0) { |
152 | { | 142 | free(_target); |
153 | free(_target); | 143 | free(dup); |
154 | free(dup); | 144 | return; |
155 | continue; | 145 | } |
156 | } | ||
157 | |||
158 | // If the command is workspace number <name>, isolate the name | ||
159 | if (strncmp(_target, "number ", strlen("number ")) == 0) { | ||
160 | size_t length = strlen(_target) - strlen("number ") + 1; | ||
161 | char *temp = malloc(length); | ||
162 | strncpy(temp, _target + strlen("number "), length - 1); | ||
163 | temp[length - 1] = '\0'; | ||
164 | free(_target); | ||
165 | _target = temp; | ||
166 | wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); | ||
167 | |||
168 | // Make sure the workspace number doesn't already exist | ||
169 | if (workspace_by_number(_target)) { | ||
170 | free(_target); | ||
171 | free(dup); | ||
172 | continue; | ||
173 | } | ||
174 | } | ||
175 | 146 | ||
176 | // Make sure that the workspace doesn't already exist | 147 | // If the command is workspace number <name>, isolate the name |
177 | if (workspace_by_name(_target)) { | 148 | if (strncmp(_target, "number ", strlen("number ")) == 0) { |
149 | size_t length = strlen(_target) - strlen("number ") + 1; | ||
150 | char *temp = malloc(length); | ||
151 | strncpy(temp, _target + strlen("number "), length - 1); | ||
152 | temp[length - 1] = '\0'; | ||
153 | free(_target); | ||
154 | _target = temp; | ||
155 | wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); | ||
156 | |||
157 | // Make sure the workspace number doesn't already exist | ||
158 | if (workspace_by_number(_target)) { | ||
178 | free(_target); | 159 | free(_target); |
179 | free(dup); | 160 | free(dup); |
180 | continue; | 161 | return; |
181 | } | 162 | } |
163 | } | ||
182 | 164 | ||
183 | // make sure that the workspace can appear on the given | 165 | // Make sure that the workspace doesn't already exist |
184 | // output | 166 | if (workspace_by_name(_target)) { |
185 | if (!workspace_valid_on_output(output_name, _target)) { | 167 | free(_target); |
186 | free(_target); | 168 | free(dup); |
187 | free(dup); | 169 | return; |
188 | continue; | 170 | } |
189 | } | ||
190 | 171 | ||
191 | if (binding->order < order) { | 172 | // make sure that the workspace can appear on the given |
192 | order = binding->order; | 173 | // output |
193 | free(target); | 174 | if (!workspace_valid_on_output(output_name, _target)) { |
194 | target = _target; | 175 | free(_target); |
195 | wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); | 176 | free(dup); |
196 | } else { | 177 | return; |
197 | free(_target); | ||
198 | } | ||
199 | } | 178 | } |
200 | free(dup); | 179 | |
180 | if (binding->order < *min_order) { | ||
181 | *min_order = binding->order; | ||
182 | free(*earliest_name); | ||
183 | *earliest_name = _target; | ||
184 | wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); | ||
185 | } else { | ||
186 | free(_target); | ||
187 | } | ||
188 | } | ||
189 | free(dup); | ||
190 | } | ||
191 | |||
192 | char *workspace_next_name(const char *output_name) { | ||
193 | wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", | ||
194 | output_name); | ||
195 | // Scan all workspace bindings to find the next available workspace name, | ||
196 | // if none are found/available then default to a number | ||
197 | struct sway_mode *mode = config->current_mode; | ||
198 | |||
199 | int order = INT_MAX; | ||
200 | char *target = NULL; | ||
201 | for (int i = 0; i < mode->keysym_bindings->length; ++i) { | ||
202 | workspace_name_from_binding(mode->keysym_bindings->items[i], | ||
203 | output_name, &order, &target); | ||
204 | } | ||
205 | for (int i = 0; i < mode->keycode_bindings->length; ++i) { | ||
206 | workspace_name_from_binding(mode->keycode_bindings->items[i], | ||
207 | output_name, &order, &target); | ||
201 | } | 208 | } |
202 | if (target != NULL) { | 209 | if (target != NULL) { |
203 | return target; | 210 | return target; |