diff options
-rw-r--r-- | include/sway/commands.h | 1 | ||||
-rw-r--r-- | include/sway/config.h | 1 | ||||
-rw-r--r-- | include/sway/debug.h | 8 | ||||
-rw-r--r-- | sway/commands/input.c | 1 | ||||
-rw-r--r-- | sway/commands/input/tap_button_map.c | 33 | ||||
-rw-r--r-- | sway/commands/resize.c | 406 | ||||
-rw-r--r-- | sway/config/input.c | 4 | ||||
-rw-r--r-- | sway/desktop/render.c | 4 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 16 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 39 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 39 | ||||
-rw-r--r-- | sway/input/input-manager.c | 6 | ||||
-rw-r--r-- | sway/main.c | 16 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/sway-input.5.scd | 6 | ||||
-rw-r--r-- | swaybar/render.c | 3 | ||||
-rw-r--r-- | swaybg/main.c | 3 |
17 files changed, 453 insertions, 134 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h index 32d6cefd..3ebd0002 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -210,6 +210,7 @@ sway_cmd input_cmd_repeat_rate; | |||
210 | sway_cmd input_cmd_scroll_button; | 210 | sway_cmd input_cmd_scroll_button; |
211 | sway_cmd input_cmd_scroll_method; | 211 | sway_cmd input_cmd_scroll_method; |
212 | sway_cmd input_cmd_tap; | 212 | sway_cmd input_cmd_tap; |
213 | sway_cmd input_cmd_tap_button_map; | ||
213 | sway_cmd input_cmd_xkb_layout; | 214 | sway_cmd input_cmd_xkb_layout; |
214 | sway_cmd input_cmd_xkb_model; | 215 | sway_cmd input_cmd_xkb_model; |
215 | sway_cmd input_cmd_xkb_options; | 216 | sway_cmd input_cmd_xkb_options; |
diff --git a/include/sway/config.h b/include/sway/config.h index 75acd4f2..f660a269 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -79,6 +79,7 @@ struct input_config { | |||
79 | int scroll_method; | 79 | int scroll_method; |
80 | int send_events; | 80 | int send_events; |
81 | int tap; | 81 | int tap; |
82 | int tap_button_map; | ||
82 | 83 | ||
83 | char *xkb_layout; | 84 | char *xkb_layout; |
84 | char *xkb_model; | 85 | char *xkb_model; |
diff --git a/include/sway/debug.h b/include/sway/debug.h index 2430d319..38d4eccd 100644 --- a/include/sway/debug.h +++ b/include/sway/debug.h | |||
@@ -1,7 +1,15 @@ | |||
1 | #ifndef SWAY_DEBUG_H | 1 | #ifndef SWAY_DEBUG_H |
2 | #define SWAY_DEBUG_H | 2 | #define SWAY_DEBUG_H |
3 | 3 | ||
4 | // Tree | ||
4 | extern bool enable_debug_tree; | 5 | extern bool enable_debug_tree; |
5 | void update_debug_tree(); | 6 | void update_debug_tree(); |
6 | 7 | ||
8 | // Damage | ||
9 | extern const char *damage_debug; | ||
10 | |||
11 | // Transactions | ||
12 | extern int txn_timeout_ms; | ||
13 | extern bool txn_debug; | ||
14 | |||
7 | #endif | 15 | #endif |
diff --git a/sway/commands/input.c b/sway/commands/input.c index e7906b0e..5b203ea0 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c | |||
@@ -23,6 +23,7 @@ static struct cmd_handler input_handlers[] = { | |||
23 | { "scroll_button", input_cmd_scroll_button }, | 23 | { "scroll_button", input_cmd_scroll_button }, |
24 | { "scroll_method", input_cmd_scroll_method }, | 24 | { "scroll_method", input_cmd_scroll_method }, |
25 | { "tap", input_cmd_tap }, | 25 | { "tap", input_cmd_tap }, |
26 | { "tap_button_map", input_cmd_tap_button_map }, | ||
26 | { "xkb_layout", input_cmd_xkb_layout }, | 27 | { "xkb_layout", input_cmd_xkb_layout }, |
27 | { "xkb_model", input_cmd_xkb_model }, | 28 | { "xkb_model", input_cmd_xkb_model }, |
28 | { "xkb_options", input_cmd_xkb_options }, | 29 | { "xkb_options", input_cmd_xkb_options }, |
diff --git a/sway/commands/input/tap_button_map.c b/sway/commands/input/tap_button_map.c new file mode 100644 index 00000000..bdbba472 --- /dev/null +++ b/sway/commands/input/tap_button_map.c | |||
@@ -0,0 +1,33 @@ | |||
1 | #include <string.h> | ||
2 | #include <strings.h> | ||
3 | #include "sway/config.h" | ||
4 | #include "sway/commands.h" | ||
5 | #include "sway/input/input-manager.h" | ||
6 | |||
7 | struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) { | ||
8 | struct cmd_results *error = NULL; | ||
9 | if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) { | ||
10 | return error; | ||
11 | } | ||
12 | struct input_config *current_input_config = | ||
13 | config->handler_context.input_config; | ||
14 | if (!current_input_config) { | ||
15 | return cmd_results_new(CMD_FAILURE, "tap_button_map", | ||
16 | "No input device defined."); | ||
17 | } | ||
18 | struct input_config *new_config = | ||
19 | new_input_config(current_input_config->identifier); | ||
20 | |||
21 | if (strcasecmp(argv[0], "lrm") == 0) { | ||
22 | new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; | ||
23 | } else if (strcasecmp(argv[0], "lmr") == 0) { | ||
24 | new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR; | ||
25 | } else { | ||
26 | free_input_config(new_config); | ||
27 | return cmd_results_new(CMD_INVALID, "tap_button_map", | ||
28 | "Expected 'tap_button_map <lrm|lmr>'"); | ||
29 | } | ||
30 | |||
31 | apply_input_config(new_config); | ||
32 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
33 | } | ||
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 5efbd8b0..2cf811d8 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -1,4 +1,5 @@ | |||
1 | #include <errno.h> | 1 | #include <errno.h> |
2 | #include <limits.h> | ||
2 | #include <math.h> | 3 | #include <math.h> |
3 | #include <stdbool.h> | 4 | #include <stdbool.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
@@ -7,6 +8,7 @@ | |||
7 | #include <wlr/util/log.h> | 8 | #include <wlr/util/log.h> |
8 | #include "sway/commands.h" | 9 | #include "sway/commands.h" |
9 | #include "sway/tree/arrange.h" | 10 | #include "sway/tree/arrange.h" |
11 | #include "sway/tree/view.h" | ||
10 | #include "log.h" | 12 | #include "log.h" |
11 | 13 | ||
12 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; | 14 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; |
@@ -21,9 +23,18 @@ enum resize_unit { | |||
21 | enum resize_axis { | 23 | enum resize_axis { |
22 | RESIZE_AXIS_HORIZONTAL, | 24 | RESIZE_AXIS_HORIZONTAL, |
23 | RESIZE_AXIS_VERTICAL, | 25 | RESIZE_AXIS_VERTICAL, |
26 | RESIZE_AXIS_UP, | ||
27 | RESIZE_AXIS_DOWN, | ||
28 | RESIZE_AXIS_LEFT, | ||
29 | RESIZE_AXIS_RIGHT, | ||
24 | RESIZE_AXIS_INVALID, | 30 | RESIZE_AXIS_INVALID, |
25 | }; | 31 | }; |
26 | 32 | ||
33 | struct resize_amount { | ||
34 | int amount; | ||
35 | enum resize_unit unit; | ||
36 | }; | ||
37 | |||
27 | static enum resize_unit parse_resize_unit(const char *unit) { | 38 | static enum resize_unit parse_resize_unit(const char *unit) { |
28 | if (strcasecmp(unit, "px") == 0) { | 39 | if (strcasecmp(unit, "px") == 0) { |
29 | return RESIZE_UNIT_PX; | 40 | return RESIZE_UNIT_PX; |
@@ -37,6 +48,69 @@ static enum resize_unit parse_resize_unit(const char *unit) { | |||
37 | return RESIZE_UNIT_INVALID; | 48 | return RESIZE_UNIT_INVALID; |
38 | } | 49 | } |
39 | 50 | ||
51 | // Parse arguments such as "10", "10px" or "10 px". | ||
52 | // Returns the number of arguments consumed. | ||
53 | static int parse_resize_amount(int argc, char **argv, | ||
54 | struct resize_amount *amount) { | ||
55 | char *err; | ||
56 | amount->amount = (int)strtol(argv[0], &err, 10); | ||
57 | if (*err) { | ||
58 | // e.g. 10px | ||
59 | amount->unit = parse_resize_unit(err); | ||
60 | return 1; | ||
61 | } | ||
62 | if (argc == 1) { | ||
63 | amount->unit = RESIZE_UNIT_DEFAULT; | ||
64 | return 1; | ||
65 | } | ||
66 | // Try the second argument | ||
67 | amount->unit = parse_resize_unit(argv[1]); | ||
68 | if (amount->unit == RESIZE_UNIT_INVALID) { | ||
69 | amount->unit = RESIZE_UNIT_DEFAULT; | ||
70 | return 1; | ||
71 | } | ||
72 | return 2; | ||
73 | } | ||
74 | |||
75 | static void calculate_constraints(int *min_width, int *max_width, | ||
76 | int *min_height, int *max_height) { | ||
77 | struct sway_container *con = config->handler_context.current_container; | ||
78 | |||
79 | if (config->floating_minimum_width == -1) { // no minimum | ||
80 | *min_width = 0; | ||
81 | } else if (config->floating_minimum_width == 0) { // automatic | ||
82 | *min_width = 75; | ||
83 | } else { | ||
84 | *min_width = config->floating_minimum_width; | ||
85 | } | ||
86 | |||
87 | if (config->floating_minimum_height == -1) { // no minimum | ||
88 | *min_height = 0; | ||
89 | } else if (config->floating_minimum_height == 0) { // automatic | ||
90 | *min_height = 50; | ||
91 | } else { | ||
92 | *min_height = config->floating_minimum_height; | ||
93 | } | ||
94 | |||
95 | if (config->floating_maximum_width == -1) { // no maximum | ||
96 | *max_width = INT_MAX; | ||
97 | } else if (config->floating_maximum_width == 0) { // automatic | ||
98 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
99 | *max_width = ws->width; | ||
100 | } else { | ||
101 | *max_width = config->floating_maximum_width; | ||
102 | } | ||
103 | |||
104 | if (config->floating_maximum_height == -1) { // no maximum | ||
105 | *max_height = INT_MAX; | ||
106 | } else if (config->floating_maximum_height == 0) { // automatic | ||
107 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | ||
108 | *max_height = ws->height; | ||
109 | } else { | ||
110 | *max_height = config->floating_maximum_height; | ||
111 | } | ||
112 | } | ||
113 | |||
40 | static enum resize_axis parse_resize_axis(const char *axis) { | 114 | static enum resize_axis parse_resize_axis(const char *axis) { |
41 | if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { | 115 | if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { |
42 | return RESIZE_AXIS_HORIZONTAL; | 116 | return RESIZE_AXIS_HORIZONTAL; |
@@ -44,6 +118,18 @@ static enum resize_axis parse_resize_axis(const char *axis) { | |||
44 | if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { | 118 | if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { |
45 | return RESIZE_AXIS_VERTICAL; | 119 | return RESIZE_AXIS_VERTICAL; |
46 | } | 120 | } |
121 | if (strcasecmp(axis, "up") == 0) { | ||
122 | return RESIZE_AXIS_UP; | ||
123 | } | ||
124 | if (strcasecmp(axis, "down") == 0) { | ||
125 | return RESIZE_AXIS_DOWN; | ||
126 | } | ||
127 | if (strcasecmp(axis, "left") == 0) { | ||
128 | return RESIZE_AXIS_LEFT; | ||
129 | } | ||
130 | if (strcasecmp(axis, "right") == 0) { | ||
131 | return RESIZE_AXIS_RIGHT; | ||
132 | } | ||
47 | return RESIZE_AXIS_INVALID; | 133 | return RESIZE_AXIS_INVALID; |
48 | } | 134 | } |
49 | 135 | ||
@@ -185,102 +271,312 @@ static void resize_tiled(int amount, enum resize_axis axis) { | |||
185 | arrange_and_commit(parent->parent); | 271 | arrange_and_commit(parent->parent); |
186 | } | 272 | } |
187 | 273 | ||
188 | static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { | 274 | /** |
189 | struct sway_container *current = config->handler_context.current_container; | 275 | * Implement `resize <grow|shrink>` for a floating container. |
190 | if (unit == RESIZE_UNIT_DEFAULT) { | 276 | */ |
191 | // Default for tiling; TODO floating should be px | 277 | static struct cmd_results *resize_adjust_floating(enum resize_axis axis, |
192 | unit = RESIZE_UNIT_PPT; | 278 | struct resize_amount *amount) { |
279 | struct sway_container *con = config->handler_context.current_container; | ||
280 | int grow_width = 0, grow_height = 0; | ||
281 | switch (axis) { | ||
282 | case RESIZE_AXIS_HORIZONTAL: | ||
283 | case RESIZE_AXIS_LEFT: | ||
284 | case RESIZE_AXIS_RIGHT: | ||
285 | grow_width = amount->amount; | ||
286 | break; | ||
287 | case RESIZE_AXIS_VERTICAL: | ||
288 | case RESIZE_AXIS_UP: | ||
289 | case RESIZE_AXIS_DOWN: | ||
290 | grow_height = amount->amount; | ||
291 | break; | ||
292 | case RESIZE_AXIS_INVALID: | ||
293 | return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction"); | ||
294 | } | ||
295 | // Make sure we're not adjusting beyond floating min/max size | ||
296 | int min_width, max_width, min_height, max_height; | ||
297 | calculate_constraints(&min_width, &max_width, &min_height, &max_height); | ||
298 | if (con->width + grow_width < min_width) { | ||
299 | grow_width = min_width - con->width; | ||
300 | } else if (con->width + grow_width > max_width) { | ||
301 | grow_width = max_width - con->width; | ||
193 | } | 302 | } |
303 | if (con->height + grow_height < min_height) { | ||
304 | grow_height = min_height - con->height; | ||
305 | } else if (con->height + grow_height > max_height) { | ||
306 | grow_height = max_height - con->height; | ||
307 | } | ||
308 | int grow_x = 0, grow_y = 0; | ||
309 | switch (axis) { | ||
310 | case RESIZE_AXIS_HORIZONTAL: | ||
311 | grow_x = -grow_width / 2; | ||
312 | break; | ||
313 | case RESIZE_AXIS_VERTICAL: | ||
314 | grow_y = -grow_height / 2; | ||
315 | break; | ||
316 | case RESIZE_AXIS_UP: | ||
317 | grow_y = -grow_height; | ||
318 | break; | ||
319 | case RESIZE_AXIS_LEFT: | ||
320 | grow_x = -grow_width; | ||
321 | break; | ||
322 | case RESIZE_AXIS_DOWN: | ||
323 | case RESIZE_AXIS_RIGHT: | ||
324 | break; | ||
325 | case RESIZE_AXIS_INVALID: | ||
326 | return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction"); | ||
327 | } | ||
328 | con->x += grow_x; | ||
329 | con->y += grow_y; | ||
330 | con->width += grow_width; | ||
331 | con->height += grow_height; | ||
332 | |||
333 | if (con->type == C_VIEW) { | ||
334 | struct sway_view *view = con->sway_view; | ||
335 | view->x += grow_x; | ||
336 | view->y += grow_y; | ||
337 | view->width += grow_width; | ||
338 | view->height += grow_height; | ||
339 | } | ||
340 | |||
341 | arrange_and_commit(con); | ||
342 | |||
343 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
344 | } | ||
194 | 345 | ||
195 | if (unit == RESIZE_UNIT_PPT) { | 346 | /** |
196 | float pct = amount / 100.0f; | 347 | * Implement `resize <grow|shrink>` for a tiled container. |
348 | */ | ||
349 | static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, | ||
350 | struct resize_amount *amount) { | ||
351 | struct sway_container *current = config->handler_context.current_container; | ||
352 | |||
353 | if (amount->unit == RESIZE_UNIT_DEFAULT) { | ||
354 | amount->unit = RESIZE_UNIT_PPT; | ||
355 | } | ||
356 | if (amount->unit == RESIZE_UNIT_PPT) { | ||
357 | float pct = amount->amount / 100.0f; | ||
358 | // TODO: Make left/right/up/down resize in that direction? | ||
197 | switch (axis) { | 359 | switch (axis) { |
360 | case RESIZE_AXIS_LEFT: | ||
361 | case RESIZE_AXIS_RIGHT: | ||
198 | case RESIZE_AXIS_HORIZONTAL: | 362 | case RESIZE_AXIS_HORIZONTAL: |
199 | amount = (float)current->width * pct; | 363 | amount->amount = (float)current->width * pct; |
200 | break; | 364 | break; |
365 | case RESIZE_AXIS_UP: | ||
366 | case RESIZE_AXIS_DOWN: | ||
201 | case RESIZE_AXIS_VERTICAL: | 367 | case RESIZE_AXIS_VERTICAL: |
202 | amount = (float)current->height * pct; | 368 | amount->amount = (float)current->height * pct; |
203 | break; | 369 | break; |
204 | default: | 370 | case RESIZE_AXIS_INVALID: |
205 | sway_assert(0, "invalid resize axis"); | 371 | return cmd_results_new(CMD_INVALID, "resize", |
206 | return; | 372 | "Invalid resize axis/direction"); |
207 | } | 373 | } |
208 | } | 374 | } |
209 | 375 | ||
210 | return resize_tiled(amount, axis); | 376 | resize_tiled(amount->amount, axis); |
377 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
211 | } | 378 | } |
212 | 379 | ||
213 | struct cmd_results *cmd_resize(int argc, char **argv) { | 380 | /** |
214 | struct sway_container *current = config->handler_context.current_container; | 381 | * Implement `resize set` for a tiled container. |
215 | if (!current) { | 382 | */ |
216 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); | 383 | static struct cmd_results *resize_set_tiled(struct sway_container *con, |
217 | } | 384 | struct resize_amount *width, struct resize_amount *height) { |
218 | if (current->type != C_VIEW && current->type != C_CONTAINER) { | 385 | return cmd_results_new(CMD_INVALID, "resize", |
219 | return cmd_results_new(CMD_INVALID, "resize", | 386 | "'resize set' is not implemented for tiled views"); |
220 | "Can only resize views/containers"); | 387 | } |
388 | |||
389 | /** | ||
390 | * Implement `resize set` for a floating container. | ||
391 | */ | ||
392 | static struct cmd_results *resize_set_floating(struct sway_container *con, | ||
393 | struct resize_amount *width, struct resize_amount *height) { | ||
394 | int min_width, max_width, min_height, max_height; | ||
395 | calculate_constraints(&min_width, &max_width, &min_height, &max_height); | ||
396 | width->amount = fmax(min_width, fmin(width->amount, max_width)); | ||
397 | height->amount = fmax(min_height, fmin(height->amount, max_height)); | ||
398 | int grow_width = width->amount - con->width; | ||
399 | int grow_height = height->amount - con->height; | ||
400 | con->x -= grow_width / 2; | ||
401 | con->y -= grow_height / 2; | ||
402 | con->width = width->amount; | ||
403 | con->height = height->amount; | ||
404 | |||
405 | if (con->type == C_VIEW) { | ||
406 | struct sway_view *view = con->sway_view; | ||
407 | view->x -= grow_width / 2; | ||
408 | view->y -= grow_height / 2; | ||
409 | view->width += grow_width; | ||
410 | view->height += grow_height; | ||
221 | } | 411 | } |
222 | 412 | ||
413 | arrange_and_commit(con); | ||
414 | |||
415 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
416 | } | ||
417 | |||
418 | /** | ||
419 | * resize set <args> | ||
420 | * | ||
421 | * args: <width> [px|ppt] <height> [px|ppt] | ||
422 | */ | ||
423 | static struct cmd_results *cmd_resize_set(int argc, char **argv) { | ||
223 | struct cmd_results *error; | 424 | struct cmd_results *error; |
224 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { | 425 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { |
225 | return error; | 426 | return error; |
226 | } | 427 | } |
227 | 428 | const char *usage = "Expected 'resize set <width> <height>'"; | |
228 | if (strcasecmp(argv[0], "set") == 0) { | 429 | |
229 | // TODO | 430 | // Width |
230 | //return cmd_resize_set(argc - 1, &argv[1]); | 431 | struct resize_amount width; |
231 | return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented"); | 432 | int num_consumed_args = parse_resize_amount(argc, argv, &width); |
433 | argc -= num_consumed_args; | ||
434 | argv += num_consumed_args; | ||
435 | if (width.unit == RESIZE_UNIT_INVALID) { | ||
436 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
437 | } | ||
438 | if (!argc) { | ||
439 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
232 | } | 440 | } |
233 | 441 | ||
234 | // TODO: resize grow|shrink left|right|up|down | 442 | // Height |
443 | struct resize_amount height; | ||
444 | num_consumed_args = parse_resize_amount(argc, argv, &height); | ||
445 | argc -= num_consumed_args; | ||
446 | argv += num_consumed_args; | ||
447 | if (height.unit == RESIZE_UNIT_INVALID) { | ||
448 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
449 | } | ||
235 | 450 | ||
236 | const char *usage = "Expected 'resize <shrink|grow> " | 451 | // If 0, don't resize that dimension |
237 | "<width|height> [<amount>] [px|ppt]'"; | 452 | struct sway_container *con = config->handler_context.current_container; |
453 | if (width.amount <= 0) { | ||
454 | width.amount = con->width; | ||
455 | } | ||
456 | if (height.amount <= 0) { | ||
457 | height.amount = con->height; | ||
458 | } | ||
238 | 459 | ||
239 | int multiplier = 0; | 460 | if (container_is_floating(con)) { |
240 | if (strcasecmp(*argv, "grow") == 0) { | 461 | return resize_set_floating(con, &width, &height); |
241 | multiplier = 1; | ||
242 | } else if (strcasecmp(*argv, "shrink") == 0) { | ||
243 | multiplier = -1; | ||
244 | } else { | ||
245 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
246 | } | 462 | } |
247 | --argc; ++argv; | 463 | return resize_set_tiled(con, &width, &height); |
464 | } | ||
248 | 465 | ||
466 | /** | ||
467 | * resize <grow|shrink> <args> | ||
468 | * | ||
469 | * args: <direction> | ||
470 | * args: <direction> <amount> <unit> | ||
471 | * args: <direction> <amount> <unit> or <amount> <other_unit> | ||
472 | */ | ||
473 | static struct cmd_results *cmd_resize_adjust(int argc, char **argv, | ||
474 | int multiplier) { | ||
475 | const char *usage = "Expected 'resize grow|shrink <direction> " | ||
476 | "[<amount> px|ppt [or <amount> px|ppt]]'"; | ||
249 | enum resize_axis axis = parse_resize_axis(*argv); | 477 | enum resize_axis axis = parse_resize_axis(*argv); |
250 | if (axis == RESIZE_AXIS_INVALID) { | 478 | if (axis == RESIZE_AXIS_INVALID) { |
251 | return cmd_results_new(CMD_INVALID, "resize", usage); | 479 | return cmd_results_new(CMD_INVALID, "resize", usage); |
252 | } | 480 | } |
253 | --argc; ++argv; | 481 | --argc; ++argv; |
254 | 482 | ||
255 | int amount = 10; // Default amount | 483 | // First amount |
256 | enum resize_unit unit = RESIZE_UNIT_DEFAULT; | 484 | struct resize_amount first_amount; |
257 | |||
258 | if (argc) { | 485 | if (argc) { |
259 | char *err; | 486 | int num_consumed_args = parse_resize_amount(argc, argv, &first_amount); |
260 | amount = (int)strtol(*argv, &err, 10); | 487 | argc -= num_consumed_args; |
261 | if (*err) { | 488 | argv += num_consumed_args; |
262 | // e.g. `resize grow width 10px` | 489 | if (first_amount.unit == RESIZE_UNIT_INVALID) { |
263 | unit = parse_resize_unit(err); | 490 | return cmd_results_new(CMD_INVALID, "resize", usage); |
264 | if (unit == RESIZE_UNIT_INVALID) { | ||
265 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
266 | } | ||
267 | } | 491 | } |
268 | --argc; ++argv; | 492 | } else { |
493 | first_amount.amount = 10; | ||
494 | first_amount.unit = RESIZE_UNIT_DEFAULT; | ||
269 | } | 495 | } |
270 | 496 | ||
497 | // "or" | ||
271 | if (argc) { | 498 | if (argc) { |
272 | unit = parse_resize_unit(*argv); | 499 | if (strcmp(*argv, "or") != 0) { |
273 | if (unit == RESIZE_UNIT_INVALID) { | ||
274 | return cmd_results_new(CMD_INVALID, "resize", usage); | 500 | return cmd_results_new(CMD_INVALID, "resize", usage); |
275 | } | 501 | } |
276 | --argc; ++argv; | 502 | --argc; ++argv; |
277 | } | 503 | } |
278 | 504 | ||
505 | // Second amount | ||
506 | struct resize_amount second_amount; | ||
279 | if (argc) { | 507 | if (argc) { |
280 | // Provied too many args, the bastard | 508 | int num_consumed_args = parse_resize_amount(argc, argv, &second_amount); |
281 | return cmd_results_new(CMD_INVALID, "resize", usage); | 509 | argc -= num_consumed_args; |
510 | argv += num_consumed_args; | ||
511 | if (second_amount.unit == RESIZE_UNIT_INVALID) { | ||
512 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
513 | } | ||
514 | } else { | ||
515 | second_amount.unit = RESIZE_UNIT_INVALID; | ||
282 | } | 516 | } |
283 | 517 | ||
284 | resize(amount * multiplier, axis, unit); | 518 | first_amount.amount *= multiplier; |
285 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 519 | second_amount.amount *= multiplier; |
520 | |||
521 | struct sway_container *con = config->handler_context.current_container; | ||
522 | if (container_is_floating(con)) { | ||
523 | // Floating containers can only resize in px. Choose an amount which | ||
524 | // uses px, with fallback to an amount that specified no unit. | ||
525 | if (first_amount.unit == RESIZE_UNIT_PX) { | ||
526 | return resize_adjust_floating(axis, &first_amount); | ||
527 | } else if (second_amount.unit == RESIZE_UNIT_PX) { | ||
528 | return resize_adjust_floating(axis, &second_amount); | ||
529 | } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) { | ||
530 | return resize_adjust_floating(axis, &first_amount); | ||
531 | } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) { | ||
532 | return resize_adjust_floating(axis, &second_amount); | ||
533 | } else { | ||
534 | return cmd_results_new(CMD_INVALID, "resize", | ||
535 | "Floating containers cannot use ppt measurements"); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | // For tiling, prefer ppt -> default -> px | ||
540 | if (first_amount.unit == RESIZE_UNIT_PPT) { | ||
541 | return resize_adjust_tiled(axis, &first_amount); | ||
542 | } else if (second_amount.unit == RESIZE_UNIT_PPT) { | ||
543 | return resize_adjust_tiled(axis, &second_amount); | ||
544 | } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) { | ||
545 | return resize_adjust_tiled(axis, &first_amount); | ||
546 | } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) { | ||
547 | return resize_adjust_tiled(axis, &second_amount); | ||
548 | } else { | ||
549 | return resize_adjust_tiled(axis, &first_amount); | ||
550 | } | ||
551 | } | ||
552 | |||
553 | struct cmd_results *cmd_resize(int argc, char **argv) { | ||
554 | struct sway_container *current = config->handler_context.current_container; | ||
555 | if (!current) { | ||
556 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); | ||
557 | } | ||
558 | if (current->type != C_VIEW && current->type != C_CONTAINER) { | ||
559 | return cmd_results_new(CMD_INVALID, "resize", | ||
560 | "Can only resize views/containers"); | ||
561 | } | ||
562 | |||
563 | struct cmd_results *error; | ||
564 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { | ||
565 | return error; | ||
566 | } | ||
567 | |||
568 | if (strcasecmp(argv[0], "set") == 0) { | ||
569 | return cmd_resize_set(argc - 1, &argv[1]); | ||
570 | } | ||
571 | if (strcasecmp(argv[0], "grow") == 0) { | ||
572 | return cmd_resize_adjust(argc - 1, &argv[1], 1); | ||
573 | } | ||
574 | if (strcasecmp(argv[0], "shrink") == 0) { | ||
575 | return cmd_resize_adjust(argc - 1, &argv[1], -1); | ||
576 | } | ||
577 | |||
578 | const char *usage = "Expected 'resize <shrink|grow> " | ||
579 | "<width|height|up|down|left|right> [<amount>] [px|ppt]'"; | ||
580 | |||
581 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
286 | } | 582 | } |
diff --git a/sway/config/input.c b/sway/config/input.c index cbd7d5f0..8d687a6d 100644 --- a/sway/config/input.c +++ b/sway/config/input.c | |||
@@ -19,6 +19,7 @@ struct input_config *new_input_config(const char* identifier) { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | input->tap = INT_MIN; | 21 | input->tap = INT_MIN; |
22 | input->tap_button_map = INT_MIN; | ||
22 | input->drag_lock = INT_MIN; | 23 | input->drag_lock = INT_MIN; |
23 | input->dwt = INT_MIN; | 24 | input->dwt = INT_MIN; |
24 | input->send_events = INT_MIN; | 25 | input->send_events = INT_MIN; |
@@ -80,6 +81,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { | |||
80 | if (src->tap != INT_MIN) { | 81 | if (src->tap != INT_MIN) { |
81 | dst->tap = src->tap; | 82 | dst->tap = src->tap; |
82 | } | 83 | } |
84 | if (src->tap_button_map != INT_MIN) { | ||
85 | dst->tap_button_map = src->tap_button_map; | ||
86 | } | ||
83 | if (src->xkb_layout) { | 87 | if (src->xkb_layout) { |
84 | free(dst->xkb_layout); | 88 | free(dst->xkb_layout); |
85 | dst->xkb_layout = strdup(src->xkb_layout); | 89 | dst->xkb_layout = strdup(src->xkb_layout); |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index b370f8a2..4bfc573b 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <wlr/util/region.h> | 15 | #include <wlr/util/region.h> |
16 | #include "log.h" | 16 | #include "log.h" |
17 | #include "sway/config.h" | 17 | #include "sway/config.h" |
18 | #include "sway/debug.h" | ||
18 | #include "sway/input/input-manager.h" | 19 | #include "sway/input/input-manager.h" |
19 | #include "sway/input/seat.h" | 20 | #include "sway/input/seat.h" |
20 | #include "sway/layers.h" | 21 | #include "sway/layers.h" |
@@ -786,6 +787,8 @@ static void render_floating(struct sway_output *soutput, | |||
786 | } | 787 | } |
787 | } | 788 | } |
788 | 789 | ||
790 | const char *damage_debug = NULL; | ||
791 | |||
789 | void output_render(struct sway_output *output, struct timespec *when, | 792 | void output_render(struct sway_output *output, struct timespec *when, |
790 | pixman_region32_t *damage) { | 793 | pixman_region32_t *damage) { |
791 | struct wlr_output *wlr_output = output->wlr_output; | 794 | struct wlr_output *wlr_output = output->wlr_output; |
@@ -805,7 +808,6 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
805 | goto renderer_end; | 808 | goto renderer_end; |
806 | } | 809 | } |
807 | 810 | ||
808 | const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); | ||
809 | if (damage_debug != NULL) { | 811 | if (damage_debug != NULL) { |
810 | if (strcmp(damage_debug, "highlight") == 0) { | 812 | if (strcmp(damage_debug, "highlight") == 0) { |
811 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | 813 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 2b3f87c3..5e42fde5 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -19,14 +19,14 @@ | |||
19 | * How long we should wait for views to respond to the configure before giving | 19 | * How long we should wait for views to respond to the configure before giving |
20 | * up and applying the transaction anyway. | 20 | * up and applying the transaction anyway. |
21 | */ | 21 | */ |
22 | #define TIMEOUT_MS 200 | 22 | int txn_timeout_ms = 200; |
23 | 23 | ||
24 | /** | 24 | /** |
25 | * If enabled, sway will always wait for the transaction timeout before | 25 | * If enabled, sway will always wait for the transaction timeout before |
26 | * applying it, rather than applying it when the views are ready. This allows us | 26 | * applying it, rather than applying it when the views are ready. This allows us |
27 | * to observe the rendered state while a transaction is in progress. | 27 | * to observe the rendered state while a transaction is in progress. |
28 | */ | 28 | */ |
29 | #define TRANSACTION_DEBUG false | 29 | bool txn_debug = false; |
30 | 30 | ||
31 | struct sway_transaction { | 31 | struct sway_transaction { |
32 | struct wl_event_source *timer; | 32 | struct wl_event_source *timer; |
@@ -330,7 +330,7 @@ void transaction_commit(struct sway_transaction *transaction) { | |||
330 | // Set up a timer which the views must respond within | 330 | // Set up a timer which the views must respond within |
331 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, | 331 | transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, |
332 | handle_timeout, transaction); | 332 | handle_timeout, transaction); |
333 | wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); | 333 | wl_event_source_timer_update(transaction->timer, txn_timeout_ms); |
334 | } | 334 | } |
335 | 335 | ||
336 | // The debug tree shows the pending/live tree. Here is a good place to | 336 | // The debug tree shows the pending/live tree. Here is a good place to |
@@ -361,11 +361,11 @@ static void set_instruction_ready( | |||
361 | // If all views are ready, apply the transaction. | 361 | // If all views are ready, apply the transaction. |
362 | // If the transaction has timed out then its num_waiting will be 0 already. | 362 | // If the transaction has timed out then its num_waiting will be 0 already. |
363 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { | 363 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { |
364 | #if !TRANSACTION_DEBUG | 364 | if (!txn_debug) { |
365 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); | 365 | wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); |
366 | wl_event_source_timer_update(transaction->timer, 0); | 366 | wl_event_source_timer_update(transaction->timer, 0); |
367 | transaction_progress_queue(); | 367 | transaction_progress_queue(); |
368 | #endif | 368 | } |
369 | } | 369 | } |
370 | } | 370 | } |
371 | 371 | ||
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 17b7b750..fbeeb2e3 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -46,47 +46,18 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { | |||
46 | } | 46 | } |
47 | 47 | ||
48 | static void popup_unconstrain(struct sway_xdg_popup *popup) { | 48 | static void popup_unconstrain(struct sway_xdg_popup *popup) { |
49 | // get the output of the popup's positioner anchor point and convert it to | ||
50 | // the toplevel parent's coordinate system and then pass it to | ||
51 | // wlr_xdg_popup_unconstrain_from_box | ||
52 | |||
53 | struct sway_view *view = popup->child.view; | 49 | struct sway_view *view = popup->child.view; |
54 | struct wlr_output_layout *output_layout = | ||
55 | root_container.sway_root->output_layout; | ||
56 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; | 50 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; |
57 | 51 | ||
58 | int anchor_lx, anchor_ly; | 52 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
59 | wlr_xdg_popup_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); | ||
60 | |||
61 | int popup_lx, popup_ly; | ||
62 | wlr_xdg_popup_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, | ||
63 | wlr_popup->geometry.y, &popup_lx, &popup_ly); | ||
64 | popup_lx += view->x; | ||
65 | popup_ly += view->y; | ||
66 | |||
67 | anchor_lx += popup_lx; | ||
68 | anchor_ly += popup_ly; | ||
69 | |||
70 | double dest_x = 0, dest_y = 0; | ||
71 | wlr_output_layout_closest_point(output_layout, NULL, anchor_lx, anchor_ly, | ||
72 | &dest_x, &dest_y); | ||
73 | |||
74 | struct wlr_output *output = | ||
75 | wlr_output_layout_output_at(output_layout, dest_x, dest_y); | ||
76 | if (output == NULL) { | ||
77 | return; | ||
78 | } | ||
79 | |||
80 | int width = 0, height = 0; | ||
81 | wlr_output_effective_resolution(output, &width, &height); | ||
82 | 53 | ||
83 | // the output box expressed in the coordinate system of the toplevel parent | 54 | // the output box expressed in the coordinate system of the toplevel parent |
84 | // of the popup | 55 | // of the popup |
85 | struct wlr_box output_toplevel_sx_box = { | 56 | struct wlr_box output_toplevel_sx_box = { |
86 | .x = output->lx - view->x, | 57 | .x = output->x - view->x, |
87 | .y = output->ly - view->y, | 58 | .y = output->y - view->y, |
88 | .width = width, | 59 | .width = output->width, |
89 | .height = height | 60 | .height = output->height, |
90 | }; | 61 | }; |
91 | 62 | ||
92 | wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); | 63 | wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 43e58918..88d9bb94 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -45,47 +45,18 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { | 47 | static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { |
48 | // get the output of the popup's positioner anchor point and convert it to | ||
49 | // the toplevel parent's coordinate system and then pass it to | ||
50 | // wlr_xdg_popup_unconstrain_from_box | ||
51 | |||
52 | struct sway_view *view = popup->child.view; | 48 | struct sway_view *view = popup->child.view; |
53 | struct wlr_output_layout *output_layout = | ||
54 | root_container.sway_root->output_layout; | ||
55 | struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; | 49 | struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; |
56 | 50 | ||
57 | int anchor_lx, anchor_ly; | 51 | struct sway_container *output = container_parent(view->swayc, C_OUTPUT); |
58 | wlr_xdg_popup_v6_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); | ||
59 | |||
60 | int popup_lx, popup_ly; | ||
61 | wlr_xdg_popup_v6_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, | ||
62 | wlr_popup->geometry.y, &popup_lx, &popup_ly); | ||
63 | popup_lx += view->x; | ||
64 | popup_ly += view->y; | ||
65 | |||
66 | anchor_lx += popup_lx; | ||
67 | anchor_ly += popup_ly; | ||
68 | |||
69 | double dest_x = 0, dest_y = 0; | ||
70 | wlr_output_layout_closest_point(output_layout, NULL, anchor_lx, anchor_ly, | ||
71 | &dest_x, &dest_y); | ||
72 | |||
73 | struct wlr_output *output = | ||
74 | wlr_output_layout_output_at(output_layout, dest_x, dest_y); | ||
75 | if (output == NULL) { | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | int width = 0, height = 0; | ||
80 | wlr_output_effective_resolution(output, &width, &height); | ||
81 | 52 | ||
82 | // the output box expressed in the coordinate system of the toplevel parent | 53 | // the output box expressed in the coordinate system of the toplevel parent |
83 | // of the popup | 54 | // of the popup |
84 | struct wlr_box output_toplevel_sx_box = { | 55 | struct wlr_box output_toplevel_sx_box = { |
85 | .x = output->lx - view->x, | 56 | .x = output->x - view->x, |
86 | .y = output->ly - view->y, | 57 | .y = output->y - view->y, |
87 | .width = width, | 58 | .width = output->width, |
88 | .height = height | 59 | .height = output->height, |
89 | }; | 60 | }; |
90 | 61 | ||
91 | wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); | 62 | wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); |
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index b18989d0..0b7cb766 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c | |||
@@ -181,6 +181,12 @@ static void input_manager_libinput_config_pointer( | |||
181 | ic->identifier, ic->tap); | 181 | ic->identifier, ic->tap); |
182 | libinput_device_config_tap_set_enabled(libinput_device, ic->tap); | 182 | libinput_device_config_tap_set_enabled(libinput_device, ic->tap); |
183 | } | 183 | } |
184 | if (ic->tap_button_map != INT_MIN) { | ||
185 | wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_button_map(%d)", | ||
186 | ic->identifier, ic->tap); | ||
187 | libinput_device_config_tap_set_button_map(libinput_device, | ||
188 | ic->tap_button_map); | ||
189 | } | ||
184 | } | 190 | } |
185 | 191 | ||
186 | static void handle_device_destroy(struct wl_listener *listener, void *data) { | 192 | static void handle_device_destroy(struct wl_listener *listener, void *data) { |
diff --git a/sway/main.c b/sway/main.c index c6453226..1d772b48 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -251,6 +251,18 @@ static void drop_permissions(bool keep_caps) { | |||
251 | #endif | 251 | #endif |
252 | } | 252 | } |
253 | 253 | ||
254 | void enable_debug_flag(const char *flag) { | ||
255 | if (strcmp(flag, "render-tree") == 0) { | ||
256 | enable_debug_tree = true; | ||
257 | } else if (strncmp(flag, "damage=", 7) == 0) { | ||
258 | damage_debug = &flag[7]; | ||
259 | } else if (strcmp(flag, "txn-debug") == 0) { | ||
260 | txn_debug = true; | ||
261 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { | ||
262 | txn_timeout_ms = atoi(&flag[12]); | ||
263 | } | ||
264 | } | ||
265 | |||
254 | int main(int argc, char **argv) { | 266 | int main(int argc, char **argv) { |
255 | static int verbose = 0, debug = 0, validate = 0; | 267 | static int verbose = 0, debug = 0, validate = 0; |
256 | 268 | ||
@@ -290,7 +302,7 @@ int main(int argc, char **argv) { | |||
290 | int c; | 302 | int c; |
291 | while (1) { | 303 | while (1) { |
292 | int option_index = 0; | 304 | int option_index = 0; |
293 | c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index); | 305 | c = getopt_long(argc, argv, "hCdD:vVc:", long_options, &option_index); |
294 | if (c == -1) { | 306 | if (c == -1) { |
295 | break; | 307 | break; |
296 | } | 308 | } |
@@ -309,7 +321,7 @@ int main(int argc, char **argv) { | |||
309 | debug = 1; | 321 | debug = 1; |
310 | break; | 322 | break; |
311 | case 'D': // extended debug options | 323 | case 'D': // extended debug options |
312 | enable_debug_tree = true; | 324 | enable_debug_flag(optarg); |
313 | break; | 325 | break; |
314 | case 'v': // version | 326 | case 'v': // version |
315 | fprintf(stdout, "sway version " SWAY_VERSION "\n"); | 327 | fprintf(stdout, "sway version " SWAY_VERSION "\n"); |
diff --git a/sway/meson.build b/sway/meson.build index 6fc78db3..f878450d 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -121,6 +121,7 @@ sway_sources = files( | |||
121 | 'commands/input/scroll_button.c', | 121 | 'commands/input/scroll_button.c', |
122 | 'commands/input/scroll_method.c', | 122 | 'commands/input/scroll_method.c', |
123 | 'commands/input/tap.c', | 123 | 'commands/input/tap.c', |
124 | 'commands/input/tap_button_map.c', | ||
124 | 'commands/input/xkb_layout.c', | 125 | 'commands/input/xkb_layout.c', |
125 | 'commands/input/xkb_model.c', | 126 | 'commands/input/xkb_model.c', |
126 | 'commands/input/xkb_options.c', | 127 | 'commands/input/xkb_options.c', |
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 4bc66394..b6391431 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd | |||
@@ -100,6 +100,12 @@ For more information on these xkb configuration options, see | |||
100 | *input* <identifier> tap enabled|disabled | 100 | *input* <identifier> tap enabled|disabled |
101 | Enables or disables tap for specified input device. | 101 | Enables or disables tap for specified input device. |
102 | 102 | ||
103 | *input* <identifier> tap_button_map lrm|lmr | ||
104 | Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as | ||
105 | left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_ | ||
106 | treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as | ||
107 | right click. | ||
108 | |||
103 | ## SEAT CONFIGURATION | 109 | ## SEAT CONFIGURATION |
104 | 110 | ||
105 | Configure options for multiseat mode. sway-seat commands must be used inside a | 111 | Configure options for multiseat mode. sway-seat commands must be used inside a |
diff --git a/swaybar/render.c b/swaybar/render.c index 2ebd338e..909b56f4 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -503,6 +503,9 @@ void render_frame(struct swaybar *bar, struct swaybar_output *output) { | |||
503 | output->buffers, | 503 | output->buffers, |
504 | output->width * output->scale, | 504 | output->width * output->scale, |
505 | output->height * output->scale); | 505 | output->height * output->scale); |
506 | if (!output->current_buffer) { | ||
507 | return; | ||
508 | } | ||
506 | cairo_t *shm = output->current_buffer->cairo; | 509 | cairo_t *shm = output->current_buffer->cairo; |
507 | 510 | ||
508 | cairo_save(shm); | 511 | cairo_save(shm); |
diff --git a/swaybg/main.c b/swaybg/main.c index 1796b245..f8e7e7ef 100644 --- a/swaybg/main.c +++ b/swaybg/main.c | |||
@@ -68,6 +68,9 @@ static void render_frame(struct swaybg_state *state) { | |||
68 | buffer_height = state->height * state->scale; | 68 | buffer_height = state->height * state->scale; |
69 | state->current_buffer = get_next_buffer(state->shm, | 69 | state->current_buffer = get_next_buffer(state->shm, |
70 | state->buffers, buffer_width, buffer_height); | 70 | state->buffers, buffer_width, buffer_height); |
71 | if (!state->current_buffer) { | ||
72 | return; | ||
73 | } | ||
71 | cairo_t *cairo = state->current_buffer->cairo; | 74 | cairo_t *cairo = state->current_buffer->cairo; |
72 | if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) { | 75 | if (state->args->mode == BACKGROUND_MODE_SOLID_COLOR) { |
73 | cairo_set_source_u32(cairo, state->context.color); | 76 | cairo_set_source_u32(cairo, state->context.color); |