summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h1
-rw-r--r--include/sway/debug.h8
-rw-r--r--sway/commands/input.c1
-rw-r--r--sway/commands/input/tap_button_map.c33
-rw-r--r--sway/commands/resize.c406
-rw-r--r--sway/config/input.c4
-rw-r--r--sway/desktop/render.c4
-rw-r--r--sway/desktop/transaction.c16
-rw-r--r--sway/desktop/xdg_shell.c39
-rw-r--r--sway/desktop/xdg_shell_v6.c39
-rw-r--r--sway/input/input-manager.c6
-rw-r--r--sway/main.c16
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway-input.5.scd6
-rw-r--r--swaybar/render.c3
-rw-r--r--swaybg/main.c3
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;
210sway_cmd input_cmd_scroll_button; 210sway_cmd input_cmd_scroll_button;
211sway_cmd input_cmd_scroll_method; 211sway_cmd input_cmd_scroll_method;
212sway_cmd input_cmd_tap; 212sway_cmd input_cmd_tap;
213sway_cmd input_cmd_tap_button_map;
213sway_cmd input_cmd_xkb_layout; 214sway_cmd input_cmd_xkb_layout;
214sway_cmd input_cmd_xkb_model; 215sway_cmd input_cmd_xkb_model;
215sway_cmd input_cmd_xkb_options; 216sway_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
4extern bool enable_debug_tree; 5extern bool enable_debug_tree;
5void update_debug_tree(); 6void update_debug_tree();
6 7
8// Damage
9extern const char *damage_debug;
10
11// Transactions
12extern int txn_timeout_ms;
13extern 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
7struct 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
12static const int MIN_SANE_W = 100, MIN_SANE_H = 60; 14static const int MIN_SANE_W = 100, MIN_SANE_H = 60;
@@ -21,9 +23,18 @@ enum resize_unit {
21enum resize_axis { 23enum 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
33struct resize_amount {
34 int amount;
35 enum resize_unit unit;
36};
37
27static enum resize_unit parse_resize_unit(const char *unit) { 38static 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.
53static 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
75static 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
40static enum resize_axis parse_resize_axis(const char *axis) { 114static 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
188static 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 277static 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 */
349static 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
213struct 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"); 383static 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 */
392static 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 */
423static 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 */
473static 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
553struct 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
790const char *damage_debug = NULL;
791
789void output_render(struct sway_output *output, struct timespec *when, 792void 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 22int 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 29bool txn_debug = false;
30 30
31struct sway_transaction { 31struct 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
48static void popup_unconstrain(struct sway_xdg_popup *popup) { 48static 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
47static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { 47static 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
186static void handle_device_destroy(struct wl_listener *listener, void *data) { 192static 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
254void 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
254int main(int argc, char **argv) { 266int 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
105Configure options for multiseat mode. sway-seat commands must be used inside a 111Configure 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);