aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h9
-rw-r--r--include/sway/config.h5
-rw-r--r--sway/commands/output.c299
-rw-r--r--sway/commands/output/background.c105
-rw-r--r--sway/commands/output/disable.c13
-rw-r--r--sway/commands/output/dpms.c24
-rw-r--r--sway/commands/output/enable.c14
-rw-r--r--sway/commands/output/mode.c55
-rw-r--r--sway/commands/output/position.c46
-rw-r--r--sway/commands/output/scale.c23
-rw-r--r--sway/commands/output/transform.c39
-rw-r--r--sway/desktop/layer_shell.c5
-rw-r--r--sway/desktop/output.c19
-rw-r--r--sway/desktop/xwayland.c15
-rw-r--r--sway/input/cursor.c2
-rw-r--r--sway/input/seat.c17
-rw-r--r--sway/meson.build9
-rw-r--r--sway/tree/container.c10
-rw-r--r--sway/tree/layout.c16
-rw-r--r--sway/tree/output.c10
-rw-r--r--sway/tree/view.c4
21 files changed, 447 insertions, 292 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 593ae0f1..7ca0bda8 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -216,6 +216,15 @@ sway_cmd input_cmd_xkb_options;
sway_cmd input_cmd_xkb_rules;
sway_cmd input_cmd_xkb_variant;
+sway_cmd output_cmd_background;
+sway_cmd output_cmd_disable;
+sway_cmd output_cmd_dpms;
+sway_cmd output_cmd_enable;
+sway_cmd output_cmd_mode;
+sway_cmd output_cmd_position;
+sway_cmd output_cmd_scale;
+sway_cmd output_cmd_transform;
+
sway_cmd seat_cmd_attach;
sway_cmd seat_cmd_fallback;
sway_cmd seat_cmd_cursor;
diff --git a/include/sway/config.h b/include/sway/config.h
index b597da75..81e9c382 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -372,10 +372,15 @@ struct sway_config {
// Context for command handlers
struct {
struct input_config *input_config;
+ struct output_config *output_config;
struct seat_config *seat_config;
struct sway_seat *seat;
struct sway_container *current_container;
bool using_criteria;
+ struct {
+ int argc;
+ char **argv;
+ } leftovers;
} handler_context;
};
diff --git a/sway/commands/output.c b/sway/commands/output.c
index e8881f77..bc12310e 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -1,254 +1,24 @@
-#define _XOPEN_SOURCE 500
-#include <ctype.h>
-#include <libgen.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <unistd.h>
-#include <wordexp.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "list.h"
#include "log.h"
-#include "stringop.h"
-static char *bg_options[] = {
- "stretch",
- "center",
- "fill",
- "fit",
- "tile",
+// must be in order for the bsearch
+static struct cmd_handler output_handlers[] = {
+ { "background", output_cmd_background },
+ { "bg", output_cmd_background },
+ { "disable", output_cmd_disable },
+ { "dpms", output_cmd_dpms },
+ { "enable", output_cmd_enable },
+ { "mode", output_cmd_mode },
+ { "pos", output_cmd_position },
+ { "position", output_cmd_position },
+ { "res", output_cmd_mode },
+ { "resolution", output_cmd_mode },
+ { "scale", output_cmd_scale },
+ { "transform", output_cmd_transform },
};
-static struct cmd_results *cmd_output_dpms(struct output_config *output,
- int *i, int argc, char **argv) {
-
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
- }
-
- char *value = argv[*i];
- if (strcmp(value, "on") == 0) {
- output->dpms_state = DPMS_ON;
- } else if (strcmp(value, "off") == 0) {
- output->dpms_state = DPMS_OFF;
- } else {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid dpms state, valid states are on/off.");
- }
- return NULL;
-}
-
-static struct cmd_results *cmd_output_mode(struct output_config *output,
- int *i, int argc, char **argv) {
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output", "Missing mode argument.");
- }
-
- char *end;
- output->width = strtol(argv[*i], &end, 10);
- if (*end) {
- // Format is 1234x4321
- if (*end != 'x') {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid mode width.");
- }
- ++end;
- output->height = strtol(end, &end, 10);
- if (*end) {
- if (*end != '@') {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid mode height.");
- }
- ++end;
- output->refresh_rate = strtof(end, &end);
- if (strcasecmp("Hz", end) != 0) {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid mode refresh rate.");
- }
- }
- } else {
- // Format is 1234 4321
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing mode argument (height).");
- }
- output->height = strtol(argv[*i], &end, 10);
- if (*end) {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid mode height.");
- }
- }
-
- return NULL;
-}
-
-static struct cmd_results *cmd_output_position(struct output_config *output,
- int *i, int argc, char **argv) {
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing position argument.");
- }
-
- char *end;
- output->x = strtol(argv[*i], &end, 10);
- if (*end) {
- // Format is 1234,4321
- if (*end != ',') {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid position x.");
- }
- ++end;
- output->y = strtol(end, &end, 10);
- if (*end) {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid position y.");
- }
- } else {
- // Format is 1234 4321 (legacy)
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing position argument (y).");
- }
- output->y = strtol(argv[*i], &end, 10);
- if (*end) {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid position y.");
- }
- }
-
- return NULL;
-}
-
-static struct cmd_results *cmd_output_scale(struct output_config *output,
- int *i, int argc, char **argv) {
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing scale argument.");
- }
-
- char *end;
- output->scale = strtof(argv[*i], &end);
- if (*end) {
- return cmd_results_new(CMD_INVALID, "output", "Invalid scale.");
- }
-
- return NULL;
-}
-
-static struct cmd_results *cmd_output_transform(struct output_config *output,
- int *i, int argc, char **argv) {
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing transform argument.");
- }
-
- char *value = argv[*i];
- if (strcmp(value, "normal") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
- } else if (strcmp(value, "90") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_90;
- } else if (strcmp(value, "180") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_180;
- } else if (strcmp(value, "270") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_270;
- } else if (strcmp(value, "flipped") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
- } else if (strcmp(value, "flipped-90") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
- } else if (strcmp(value, "flipped-180") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
- } else if (strcmp(value, "flipped-270") == 0) {
- output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
- } else {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid output transform.");
- }
-
- return NULL;
-}
-
-static struct cmd_results *cmd_output_background(struct output_config *output,
- int *i, int argc, char **argv) {
- if (++*i >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing background file or color specification.");
- }
- const char *background = argv[*i];
- if (*i + 1 >= argc) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing background scaling mode or `solid_color`.");
- }
- const char *background_option = argv[*i];
-
- if (strcasecmp(background_option, "solid_color") == 0) {
- output->background = strdup(background);
- output->background_option = strdup("solid_color");
- } else {
- bool valid = false;
- char *mode;
- size_t j;
- for (j = 0; j < (size_t)(argc - *i); ++j) {
- mode = argv[*i + j];
- size_t n = sizeof(bg_options) / sizeof(char *);
- for (size_t k = 0; k < n; ++k) {
- if (strcasecmp(mode, bg_options[k]) == 0) {
- valid = true;
- break;
- }
- }
- if (valid) {
- break;
- }
- }
- if (!valid) {
- return cmd_results_new(CMD_INVALID, "output",
- "Missing background scaling mode.");
- }
-
- wordexp_t p;
- char *src = join_args(argv + *i, j);
- if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
- return cmd_results_new(CMD_INVALID, "output",
- "Invalid syntax (%s).", src);
- }
- free(src);
- src = p.we_wordv[0];
- if (config->reading && *src != '/') {
- char *conf = strdup(config->current_config);
- if (conf) {
- char *conf_path = dirname(conf);
- src = malloc(strlen(conf_path) + strlen(src) + 2);
- if (src) {
- sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
- } else {
- wlr_log(L_ERROR,
- "Unable to allocate background source");
- }
- free(conf);
- } else {
- wlr_log(L_ERROR, "Unable to allocate background source");
- }
- }
- if (!src || access(src, F_OK) == -1) {
- wordfree(&p);
- return cmd_results_new(CMD_INVALID, "output",
- "Background file unreadable (%s).", src);
- }
-
- output->background = strdup(src);
- output->background_option = strdup(mode);
- if (src != p.we_wordv[0]) {
- free(src);
- }
- wordfree(&p);
-
- *i += j;
- }
-
- return NULL;
-}
-
struct cmd_results *cmd_output(int argc, char **argv) {
struct cmd_results *error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1);
if (error != NULL) {
@@ -260,40 +30,34 @@ struct cmd_results *cmd_output(int argc, char **argv) {
wlr_log(L_ERROR, "Failed to allocate output config");
return NULL;
}
+ argc--; argv++;
+
+ config->handler_context.output_config = output;
- for (int i = 1; i < argc; ++i) {
- const char *command = argv[i];
+ while (argc > 0) {
+ config->handler_context.leftovers.argc = 0;
+ config->handler_context.leftovers.argv = NULL;
- if (strcasecmp(command, "enable") == 0) {
- output->enabled = 1;
- } else if (strcasecmp(command, "disable") == 0) {
- output->enabled = 0;
- } else if (strcasecmp(command, "mode") == 0 ||
- strcasecmp(command, "resolution") == 0 ||
- strcasecmp(command, "res") == 0) {
- error = cmd_output_mode(output, &i, argc, argv);
- } else if (strcasecmp(command, "position") == 0 ||
- strcasecmp(command, "pos") == 0) {
- error = cmd_output_position(output, &i, argc, argv);
- } else if (strcasecmp(command, "scale") == 0) {
- error = cmd_output_scale(output, &i, argc, argv);
- } else if (strcasecmp(command, "transform") == 0) {
- error = cmd_output_transform(output, &i, argc, argv);
- } else if (strcasecmp(command, "background") == 0 ||
- strcasecmp(command, "bg") == 0) {
- error = cmd_output_background(output, &i, argc, argv);
- } else if (strcasecmp(command, "dpms") == 0) {
- error = cmd_output_dpms(output, &i, argc, argv);
+ if (find_handler(*argv, output_handlers, sizeof(output_handlers))) {
+ error = config_subcommand(argv, argc, output_handlers,
+ sizeof(output_handlers));
} else {
error = cmd_results_new(CMD_INVALID, "output",
- "Invalid output subcommand: %s.", command);
+ "Invalid output subcommand: %s.", *argv);
}
if (error != NULL) {
goto fail;
}
+
+ argc = config->handler_context.leftovers.argc;
+ argv = config->handler_context.leftovers.argv;
}
+ config->handler_context.output_config = NULL;
+ config->handler_context.leftovers.argc = 0;
+ config->handler_context.leftovers.argv = NULL;
+
int i = list_seq_find(config->output_configs, output_name_cmp, output->name);
if (i >= 0) {
// Merge existing config
@@ -338,6 +102,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
fail:
+ config->handler_context.output_config = NULL;
free_output_config(output);
return error;
}
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
new file mode 100644
index 00000000..0c5c164f
--- /dev/null
+++ b/sway/commands/output/background.c
@@ -0,0 +1,105 @@
+#define _XOPEN_SOURCE 500
+#include <libgen.h>
+#include <strings.h>
+#include <unistd.h>
+#include <wordexp.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "log.h"
+#include "stringop.h"
+
+static const char *bg_options[] = {
+ "stretch",
+ "center",
+ "fill",
+ "fit",
+ "tile",
+};
+
+struct cmd_results *output_cmd_background(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing background file or color specification.");
+ }
+ if (argc < 2) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing background scaling mode or `solid_color`.");
+ }
+
+ struct output_config *output = config->handler_context.output_config;
+
+ if (strcasecmp(argv[1], "solid_color") == 0) {
+ output->background = calloc(1, strlen(argv[0]) + 3);
+ snprintf(output->background, strlen(argv[0]) + 3, "\"%s\"", argv[0]);
+ output->background_option = strdup("solid_color");
+ argc -= 2; argv += 2;
+ } else {
+ bool valid = false;
+ char *mode;
+ size_t j;
+ for (j = 0; j < (size_t)argc; ++j) {
+ mode = argv[j];
+ size_t n = sizeof(bg_options) / sizeof(char *);
+ for (size_t k = 0; k < n; ++k) {
+ if (strcasecmp(mode, bg_options[k]) == 0) {
+ valid = true;
+ break;
+ }
+ }
+ if (valid) {
+ break;
+ }
+ }
+ if (!valid) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing background scaling mode.");
+ }
+
+ wordexp_t p;
+ char *src = join_args(argv, j);
+ if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid syntax (%s).", src);
+ }
+ free(src);
+ src = p.we_wordv[0];
+ if (config->reading && *src != '/') {
+ char *conf = strdup(config->current_config);
+ if (conf) {
+ char *conf_path = dirname(conf);
+ src = malloc(strlen(conf_path) + strlen(src) + 2);
+ if (src) {
+ sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
+ } else {
+ wlr_log(L_ERROR,
+ "Unable to allocate background source");
+ }
+ free(conf);
+ } else {
+ wlr_log(L_ERROR, "Unable to allocate background source");
+ }
+ }
+ if (!src || access(src, F_OK) == -1) {
+ wordfree(&p);
+ return cmd_results_new(CMD_INVALID, "output",
+ "Background file unreadable (%s).", src);
+ }
+
+ output->background = strdup(src);
+ output->background_option = strdup(mode);
+ if (src != p.we_wordv[0]) {
+ free(src);
+ }
+ wordfree(&p);
+
+ argc -= j + 1; argv += j + 1;
+ }
+
+ config->handler_context.leftovers.argc = argc;
+ config->handler_context.leftovers.argv = argv;
+ return NULL;
+}
+
diff --git a/sway/commands/output/disable.c b/sway/commands/output/disable.c
new file mode 100644
index 00000000..65517c49
--- /dev/null
+++ b/sway/commands/output/disable.c
@@ -0,0 +1,13 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_disable(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ config->handler_context.output_config->enabled = 0;
+
+ config->handler_context.leftovers.argc = argc;
+ config->handler_context.leftovers.argv = argv;
+ return NULL;
+}
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c
new file mode 100644
index 00000000..0959ea6b
--- /dev/null
+++ b/sway/commands/output/dpms.c
@@ -0,0 +1,24 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_dpms(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output", "Missing dpms argument.");
+ }
+
+ if (strcmp(*argv, "on") == 0) {
+ config->handler_context.output_config->dpms_state = DPMS_ON;
+ } else if (strcmp(*argv, "off") == 0) {
+ config->handler_context.output_config->dpms_state = DPMS_OFF;
+ } else {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid dpms state, valid states are on/off.");
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
diff --git a/sway/commands/output/enable.c b/sway/commands/output/enable.c
new file mode 100644
index 00000000..8e3314f8
--- /dev/null
+++ b/sway/commands/output/enable.c
@@ -0,0 +1,14 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_enable(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ config->handler_context.output_config->enabled = 1;
+
+ config->handler_context.leftovers.argc = argc;
+ config->handler_context.leftovers.argv = argv;
+ return NULL;
+}
+
diff --git a/sway/commands/output/mode.c b/sway/commands/output/mode.c
new file mode 100644
index 00000000..daec6d44
--- /dev/null
+++ b/sway/commands/output/mode.c
@@ -0,0 +1,55 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_mode(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output", "Missing mode argument.");
+ }
+
+ struct output_config *output = config->handler_context.output_config;
+
+ char *end;
+ output->width = strtol(*argv, &end, 10);
+ if (*end) {
+ // Format is 1234x4321
+ if (*end != 'x') {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid mode width.");
+ }
+ ++end;
+ output->height = strtol(end, &end, 10);
+ if (*end) {
+ if (*end != '@') {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid mode height.");
+ }
+ ++end;
+ output->refresh_rate = strtof(end, &end);
+ if (strcasecmp("Hz", end) != 0) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid mode refresh rate.");
+ }
+ }
+ } else {
+ // Format is 1234 4321
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing mode argument (height).");
+ }
+ argc--; argv++;
+ output->height = strtol(*argv, &end, 10);
+ if (*end) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid mode height.");
+ }
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
+
diff --git a/sway/commands/output/position.c b/sway/commands/output/position.c
new file mode 100644
index 00000000..c2aeb281
--- /dev/null
+++ b/sway/commands/output/position.c
@@ -0,0 +1,46 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_position(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing position argument.");
+ }
+
+ char *end;
+ config->handler_context.output_config->x = strtol(*argv, &end, 10);
+ if (*end) {
+ // Format is 1234,4321
+ if (*end != ',') {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid position x.");
+ }
+ ++end;
+ config->handler_context.output_config->y = strtol(end, &end, 10);
+ if (*end) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid position y.");
+ }
+ } else {
+ // Format is 1234 4321 (legacy)
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing position argument (y).");
+ }
+ argc--; argv++;
+ config->handler_context.output_config->y = strtol(*argv, &end, 10);
+ if (*end) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid position y.");
+ }
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
+
diff --git a/sway/commands/output/scale.c b/sway/commands/output/scale.c
new file mode 100644
index 00000000..0b4cc131
--- /dev/null
+++ b/sway/commands/output/scale.c
@@ -0,0 +1,23 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_scale(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing scale argument.");
+ }
+
+ char *end;
+ config->handler_context.output_config->scale = strtof(*argv, &end);
+ if (*end) {
+ return cmd_results_new(CMD_INVALID, "output", "Invalid scale.");
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
diff --git a/sway/commands/output/transform.c b/sway/commands/output/transform.c
new file mode 100644
index 00000000..f9a94d64
--- /dev/null
+++ b/sway/commands/output/transform.c
@@ -0,0 +1,39 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_transform(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "output", "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Missing transform argument.");
+ }
+
+ struct output_config *output = config->handler_context.output_config;
+ if (strcmp(*argv, "normal") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+ } else if (strcmp(*argv, "90") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_90;
+ } else if (strcmp(*argv, "180") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_180;
+ } else if (strcmp(*argv, "270") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_270;
+ } else if (strcmp(*argv, "flipped") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+ } else if (strcmp(*argv, "flipped-90") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
+ } else if (strcmp(*argv, "flipped-180") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+ } else if (strcmp(*argv, "flipped-270") == 0) {
+ output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
+ } else {
+ return cmd_results_new(CMD_INVALID, "output",
+ "Invalid output transform.");
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index b60aa487..2d355b74 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -257,6 +257,11 @@ static void unmap(struct sway_layer_surface *sway_layer) {
}
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
+
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ if (seat->focused_layer == sway_layer->layer_surface) {
+ seat_set_focus_layer(seat, NULL);
+ }
}
static void handle_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index a9ff9782..acc9caae 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -846,11 +846,24 @@ static void render_output(struct sway_output *output, struct timespec *when,
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
+ bool damage_whole_before_swap = false;
if (!pixman_region32_not_empty(damage)) {
// Output isn't damaged but needs buffer swap
goto renderer_end;
}
+ const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG");
+ if (damage_debug != NULL) {
+ if (strcmp(damage_debug, "highlight") == 0) {
+ wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
+ damage_whole_before_swap = true;
+ } else if (strcmp(damage_debug, "rerender") == 0) {
+ int width, height;
+ wlr_output_transformed_resolution(wlr_output, &width, &height);
+ pixman_region32_union_rect(damage, damage, 0, 0, width, height);
+ }
+ }
+
struct sway_container *workspace = output_get_active_workspace(output);
if (workspace->sway_workspace->fullscreen) {
@@ -905,6 +918,12 @@ renderer_end:
wlr_output->transform_matrix, 0, 0, 1);
}
+ if (damage_whole_before_swap || root_container.sway_root->debug_tree) {
+ int width, height;
+ wlr_output_transformed_resolution(wlr_output, &width, &height);
+ pixman_region32_union_rect(damage, damage, 0, 0, width, height);
+ }
+
wlr_renderer_scissor(renderer, NULL);
wlr_renderer_end(renderer);
if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) {
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 75bfb7b2..6447b711 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -77,6 +77,21 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
desktop_damage_surface(xsurface->surface, xsurface->x, xsurface->y, true);
wl_list_remove(&surface->link);
wl_list_remove(&surface->commit.link);
+
+ if (!wlr_xwayland_surface_is_unmanaged(xsurface)) {
+ struct sway_seat *seat = input_manager_current_seat(input_manager);
+ if (seat->wlr_seat->keyboard_state.focused_surface ==
+ xsurface->surface) {
+ // Restore focus
+ struct sway_container *previous =
+ seat_get_focus_inactive(seat, &root_container);
+ if (previous) {
+ // Hack to get seat to re-focus the return value of get_focus
+ seat_set_focus(seat, previous->parent);
+ seat_set_focus(seat, previous);
+ }
+ }
+ }
}
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 16e5427b..d6e17ae1 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -264,7 +264,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
if (new_ws != old_ws) {
seat_set_focus(cursor->seat, cont);
}
- } else {
+ } else if (cont) {
seat_set_focus(cursor->seat, cont);
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index d35cbeef..071ef020 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -658,7 +658,8 @@ void seat_set_focus_layer(struct sway_seat *seat,
struct wlr_layer_surface *layer) {
if (!layer && seat->focused_layer) {
seat->focused_layer = NULL;
- struct sway_container *previous = seat_get_focus(seat);
+ struct sway_container *previous =
+ seat_get_focus_inactive(seat, &root_container);
if (previous) {
wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous,
container_type_to_str(previous->type), previous->name);
@@ -728,14 +729,14 @@ struct sway_container *seat_get_focus_inactive(struct sway_seat *seat,
struct sway_container *seat_get_active_child(struct sway_seat *seat,
struct sway_container *container) {
- struct sway_container *focus = seat_get_focus_inactive(seat, container);
- if (!focus) {
- return NULL;
- }
- while (focus->parent != container) {
- focus = focus->parent;
+ struct sway_seat_container *current = NULL;
+ wl_list_for_each(current, &seat->focus_stack, link) {
+ if (current->container->parent == container &&
+ current->container->layout != L_FLOATING) {
+ return current->container;
+ }
}
- return focus;
+ return NULL;
}
struct sway_container *seat_get_focus(struct sway_seat *seat) {
diff --git a/sway/meson.build b/sway/meson.build
index 4c038583..b6bb02a7 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -120,6 +120,15 @@ sway_sources = files(
'commands/input/xkb_rules.c',
'commands/input/xkb_variant.c',
+ 'commands/output/background.c',
+ 'commands/output/disable.c',
+ 'commands/output/dpms.c',
+ 'commands/output/enable.c',
+ 'commands/output/mode.c',
+ 'commands/output/position.c',
+ 'commands/output/scale.c',
+ 'commands/output/transform.c',
+
'tree/arrange.c',
'tree/container.c',
'tree/layout.c',
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 9e70da09..d0d26631 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -204,9 +204,17 @@ static struct sway_container *container_workspace_destroy(
}
}
- free(workspace->sway_workspace);
+ struct sway_workspace *sway_workspace = workspace->sway_workspace;
+
+ // This emits the destroy event and also destroys the swayc.
_container_destroy(workspace);
+ // Clean up the floating container
+ sway_workspace->floating->parent = NULL;
+ _container_destroy(sway_workspace->floating);
+
+ free(sway_workspace);
+
if (output) {
output_damage_whole(output->sway_output);
}
diff --git a/sway/tree/layout.c b/sway/tree/layout.c
index d88948dc..79e7c87e 100644
--- a/sway/tree/layout.c
+++ b/sway/tree/layout.c
@@ -412,19 +412,15 @@ void container_move(struct sway_container *container,
}
case C_WORKSPACE:
if (!is_parallel(current->layout, move_dir)) {
- if (current->children->length > 2) {
+ if (current->children->length >= 2) {
wlr_log(L_DEBUG, "Rejiggering the workspace (%d kiddos)",
current->children->length);
workspace_rejigger(current, container, move_dir);
- } else if (current->children->length == 2) {
- wlr_log(L_DEBUG, "Changing workspace layout");
- current->layout =
- move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ?
- L_HORIZ : L_VERT;
- container_insert_child(current, container, offs < 0 ? 0 : 1);
- arrange_workspace(current);
+ return;
+ } else {
+ wlr_log(L_DEBUG, "Selecting output");
+ current = current->parent;
}
- return;
} else if (current->layout == L_TABBED
|| current->layout == L_STACKED) {
wlr_log(L_DEBUG, "Rejiggering out of tabs/stacks");
@@ -520,7 +516,7 @@ void container_move(struct sway_container *container,
wlr_log(L_DEBUG, "Reparenting container (perpendicular)");
struct sway_container *focus_inactive = seat_get_focus_inactive(
config->handler_context.seat, sibling);
- if (focus_inactive) {
+ if (focus_inactive && focus_inactive != sibling) {
while (focus_inactive->parent != sibling) {
focus_inactive = focus_inactive->parent;
}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 6c7044a2..8823eba0 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -8,10 +8,6 @@
struct sway_container *output_create(
struct sway_output *sway_output) {
- struct wlr_box size;
- wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
- &size.height);
-
const char *name = sway_output->wlr_output->name;
char identifier[128];
output_get_identifier(identifier, sizeof(identifier), sway_output);
@@ -54,6 +50,12 @@ struct sway_container *output_create(
container_add_child(&root_container, output);
load_swaybars();
+ struct wlr_box size;
+ wlr_output_effective_resolution(sway_output->wlr_output, &size.width,
+ &size.height);
+ output->width = size.width;
+ output->height = size.height;
+
// Create workspace
char *ws_name = workspace_next_name(output->name);
wlr_log(L_DEBUG, "Creating default workspace %s", ws_name);
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 79441d49..c9c82405 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -790,8 +790,10 @@ void view_update_title(struct sway_view *view, bool force) {
view->swayc->formatted_title = NULL;
}
container_calculate_title_height(view->swayc);
- container_update_title_textures(view->swayc);
config_update_font_height(false);
+
+ // Update title after the global font height is updated
+ container_update_title_textures(view->swayc);
}
static bool find_by_mark_iterator(struct sway_container *con,