aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c61
-rw-r--r--sway/commands/create_output.c4
-rw-r--r--sway/commands/workspace.c13
-rw-r--r--sway/commands/ws_auto_back_and_forth.c2
-rw-r--r--sway/desktop/output.c9
-rw-r--r--sway/ipc-json.c22
-rw-r--r--sway/sway.5.scd8
-rw-r--r--sway/tree/output.c7
-rw-r--r--sway/tree/workspace.c61
9 files changed, 136 insertions, 51 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 37c7169a..4b86c2fa 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -353,12 +353,14 @@ struct cmd_results *config_command(char *exec) {
struct cmd_results *results = NULL;
int argc;
char **argv = split_args(exec, &argc);
+
+ // Check for empty lines
if (!argc) {
results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
goto cleanup;
}
- // Start block
+ // Check for the start of a block
if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) {
char *block = join_args(argv, argc - 1);
results = cmd_results_new(CMD_BLOCK, block, NULL);
@@ -366,22 +368,54 @@ struct cmd_results *config_command(char *exec) {
goto cleanup;
}
- // Endblock
+ // Check for the end of a block
if (strcmp(argv[argc - 1], "}") == 0) {
results = cmd_results_new(CMD_BLOCK_END, NULL, NULL);
goto cleanup;
}
- wlr_log(WLR_INFO, "handling config command '%s'", exec);
+
+ // Make sure the command is not stored in a variable
+ if (*argv[0] == '$') {
+ argv[0] = do_var_replacement(argv[0]);
+ char *temp = join_args(argv, argc);
+ free_argv(argc, argv);
+ argv = split_args(temp, &argc);
+ free(temp);
+ if (!argc) {
+ results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ goto cleanup;
+ }
+ }
+
+ // Determine the command handler
+ wlr_log(WLR_INFO, "Config command: %s", exec);
struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
- if (!handler) {
+ if (!handler || !handler->handle) {
char *input = argv[0] ? argv[0] : "(empty)";
- results = cmd_results_new(CMD_INVALID, input, "Unknown/invalid command");
+ char *error = handler
+ ? "This command is shimmed, but unimplemented"
+ : "Unknown/invalid command";
+ results = cmd_results_new(CMD_INVALID, input, error);
goto cleanup;
}
- int i;
- // Var replacement, for all but first argument of set
- // TODO commands
- for (i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
+
+ // Do variable replacement
+ if (handler->handle == cmd_set && argc > 1 && *argv[1] == '$') {
+ // Escape the variable name so it does not get replaced by one shorter
+ char *temp = calloc(1, strlen(argv[1]) + 2);
+ temp[0] = '$';
+ strcpy(&temp[1], argv[1]);
+ free(argv[1]);
+ argv[1] = temp;
+ }
+ char *command = do_var_replacement(join_args(argv, argc));
+ wlr_log(WLR_INFO, "After replacement: %s", command);
+ free_argv(argc, argv);
+ argv = split_args(command, &argc);
+ free(command);
+
+ // Strip quotes and unescape the string
+ for (int i = handler->handle == cmd_set ? 2 : 1; i < argc; ++i) {
if (handler->handle != cmd_exec && handler->handle != cmd_exec_always
&& handler->handle != cmd_bindsym
&& handler->handle != cmd_bindcode
@@ -389,14 +423,11 @@ struct cmd_results *config_command(char *exec) {
&& (*argv[i] == '\"' || *argv[i] == '\'')) {
strip_quotes(argv[i]);
}
- argv[i] = do_var_replacement(argv[i]);
unescape_string(argv[i]);
}
- if (handler->handle) {
- results = handler->handle(argc-1, argv+1);
- } else {
- results = cmd_results_new(CMD_INVALID, argv[0], "This command is shimmed, but unimplemented");
- }
+
+ // Run command
+ results = handler->handle(argc - 1, argv + 1);
cleanup:
free_argv(argc, argv);
diff --git a/sway/commands/create_output.c b/sway/commands/create_output.c
index 1c2464ea..3f870acb 100644
--- a/sway/commands/create_output.c
+++ b/sway/commands/create_output.c
@@ -1,7 +1,7 @@
#include <wlr/config.h>
#include <wlr/backend/multi.h>
#include <wlr/backend/wayland.h>
-#ifdef WLR_HAS_X11_BACKEND
+#if WLR_HAS_X11_BACKEND
#include <wlr/backend/x11.h>
#endif
#include "sway/commands.h"
@@ -18,7 +18,7 @@ static void create_output(struct wlr_backend *backend, void *data) {
wlr_wl_output_create(backend);
*done = true;
}
-#ifdef WLR_HAS_X11_BACKEND
+#if WLR_HAS_X11_BACKEND
else if (wlr_backend_is_x11(backend)) {
wlr_x11_output_create(backend);
*done = true;
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index 168494d2..92118ecf 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -21,6 +21,7 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
return NULL;
}
wsc->workspace = strdup(ws_name);
+ wsc->outputs = create_list();
wsc->gaps_inner = INT_MIN;
wsc->gaps_outer.top = INT_MIN;
wsc->gaps_outer.right = INT_MIN;
@@ -32,7 +33,7 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
void free_workspace_config(struct workspace_config *wsc) {
free(wsc->workspace);
- free(wsc->output);
+ free_flat_list(wsc->outputs);
free(wsc);
}
@@ -141,18 +142,20 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
}
if (output_location >= 0) {
- if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, output_location + 2))) {
+ if ((error = checkarg(argc, "workspace", EXPECTED_AT_LEAST,
+ output_location + 2))) {
return error;
}
- char *ws_name = join_args(argv, argc - 2);
+ char *ws_name = join_args(argv, output_location);
struct workspace_config *wsc = workspace_config_find_or_create(ws_name);
free(ws_name);
if (!wsc) {
return cmd_results_new(CMD_FAILURE, "workspace output",
"Unable to allocate workspace output");
}
- free(wsc->output);
- wsc->output = strdup(argv[output_location + 1]);
+ for (int i = output_location + 1; i < argc; ++i) {
+ list_add(wsc->outputs, strdup(argv[i]));
+ }
} else if (gaps_location >= 0) {
if ((error = cmd_workspace_gaps(argc, argv, gaps_location))) {
return error;
diff --git a/sway/commands/ws_auto_back_and_forth.c b/sway/commands/ws_auto_back_and_forth.c
index 3449d4cc..adb851c2 100644
--- a/sway/commands/ws_auto_back_and_forth.c
+++ b/sway/commands/ws_auto_back_and_forth.c
@@ -9,6 +9,6 @@ struct cmd_results *cmd_ws_auto_back_and_forth(int argc, char **argv) {
return error;
}
config->auto_back_and_forth =
- !parse_boolean(argv[0], config->auto_back_and_forth);
+ parse_boolean(argv[0], config->auto_back_and_forth);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index d48ddef3..c53a9c73 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -469,15 +469,6 @@ void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
wlr_output_damage_add_box(output->damage, &box);
}
-static void output_damage_whole_container_iterator(struct sway_container *con,
- void *data) {
- if (!sway_assert(con->view, "expected a view")) {
- return;
- }
- struct sway_output *output = data;
- output_damage_view(output, con->view, true);
-}
-
void output_damage_whole_container(struct sway_output *output,
struct sway_container *con) {
// Pad the box by 1px, because the width is a double and might be a fraction
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 4583558c..4d9a87d8 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -12,6 +12,7 @@
#include "sway/input/seat.h"
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_output.h>
+#include <xkbcommon/xkbcommon.h>
#include "wlr-layer-shell-unstable-v1-protocol.h"
static const char *ipc_json_layout_description(enum sway_container_layout l) {
@@ -503,6 +504,27 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
json_object_object_add(object, "type",
json_object_new_string(describe_device_type(device)));
+ if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
+ struct wlr_keyboard *keyboard = device->wlr_device->keyboard;
+ struct xkb_keymap *keymap = keyboard->keymap;
+ struct xkb_state *state = keyboard->xkb_state;
+ xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(keymap);
+ xkb_layout_index_t layout_idx;
+ for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) {
+ bool is_active =
+ xkb_state_layout_index_is_active(state,
+ layout_idx,
+ XKB_STATE_LAYOUT_EFFECTIVE);
+ if (is_active) {
+ const char *layout =
+ xkb_keymap_layout_get_name(keymap, layout_idx);
+ json_object_object_add(object, "xkb_active_layout_name",
+ json_object_new_string(layout));
+ break;
+ }
+ }
+ }
+
return object;
}
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 8f6b35f1..1a11015f 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -573,8 +573,12 @@ The default colors are:
Specifies that workspace _name_ should have the given gaps settings when it
is created.
-*workspace* <name> output <output>
- Specifies that workspace _name_ should be shown on the specified _output_.
+*workspace* <name> output <outputs...>
+ Specifies that workspace _name_ should be shown on the specified _outputs_.
+ Multiple outputs can be listed and the first available will be used. If the
+ workspace gets placed on an output further down the list and an output that
+ is higher on the list becomes available, the workspace will be move to the
+ higher priority output.
*workspace\_auto\_back\_and\_forth* yes|no
When _yes_, repeating a workspace switch command will switch back to the
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 2704920d..3c4614a8 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -31,6 +31,13 @@ static void restore_workspaces(struct sway_output *output) {
j--;
}
}
+
+ if (other->workspaces->length == 0) {
+ char *next = workspace_next_name(other->wlr_output->name);
+ struct sway_workspace *ws = workspace_create(other, next);
+ free(next);
+ ipc_event_workspace(NULL, ws, "init");
+ }
}
// Saved workspaces
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 93ce50de..4be63311 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -33,14 +33,15 @@ struct workspace_config *workspace_find_config(const char *ws_name) {
struct sway_output *workspace_get_initial_output(const char *name) {
// Check workspace configs for a workspace<->output pair
struct workspace_config *wsc = workspace_find_config(name);
- if (wsc && wsc->output) {
- struct sway_output *output = output_by_name(wsc->output);
- if (!output) {
- output = output_by_identifier(wsc->output);
- }
-
- if (output) {
- return output;
+ if (wsc) {
+ for (int i = 0; i < wsc->outputs->length; i++) {
+ struct sway_output *output = output_by_name(wsc->outputs->items[i]);
+ if (!output) {
+ output = output_by_identifier(wsc->outputs->items[i]);
+ }
+ if (output) {
+ return output;
+ }
}
}
// Otherwise put it on the focused output
@@ -85,7 +86,6 @@ struct sway_workspace *workspace_create(struct sway_output *output,
ws->floating = create_list();
ws->tiling = create_list();
ws->output_priority = create_list();
- workspace_output_add_priority(ws, output);
ws->gaps_outer = config->gaps_outer;
ws->gaps_inner = config->gaps_inner;
@@ -110,9 +110,17 @@ struct sway_workspace *workspace_create(struct sway_output *output,
// Since default outer gaps can be smaller than the negation of
// workspace specific inner gaps, check outer gaps again
prevent_invalid_outer_gaps(ws);
+
+ // Add output priorities
+ for (int i = 0; i < wsc->outputs->length; ++i) {
+ list_add(ws->output_priority, strdup(wsc->outputs->items[i]));
+ }
}
}
+ // If not already added, add the output to the lowest priority
+ workspace_output_add_priority(ws, output);
+
output_add_workspace(output, ws);
output_sort_workspaces(output);
@@ -134,8 +142,7 @@ void workspace_destroy(struct sway_workspace *workspace) {
free(workspace->name);
free(workspace->representation);
- list_foreach(workspace->output_priority, free);
- list_free(workspace->output_priority);
+ free_flat_list(workspace->output_priority);
list_free(workspace->floating);
list_free(workspace->tiling);
list_free(workspace->current.floating);
@@ -177,8 +184,19 @@ static bool workspace_valid_on_output(const char *output_name,
char identifier[128];
struct sway_output *output = output_by_name(output_name);
output_get_identifier(identifier, sizeof(identifier), output);
-
- return !wsc || !wsc->output || strcmp(wsc->output, output_name) == 0 || strcasecmp(identifier, output_name) == 0;
+
+ if (!wsc) {
+ return true;
+ }
+
+ for (int i = 0; i < wsc->outputs->length; i++) {
+ if (strcmp(wsc->outputs->items[i], output_name) == 0 ||
+ strcmp(wsc->outputs->items[i], identifier) == 0) {
+ return true;
+ }
+ }
+
+ return false;
}
static void workspace_name_from_binding(const struct sway_binding * binding,
@@ -281,10 +299,19 @@ char *workspace_next_name(const char *output_name) {
for (int i = 0; i < config->workspace_configs->length; ++i) {
// Unlike with bindings, this does not guarantee order
const struct workspace_config *wsc = config->workspace_configs->items[i];
- if (wsc->output && strcmp(wsc->output, output_name) == 0
- && workspace_by_name(wsc->workspace) == NULL) {
- free(target);
- target = strdup(wsc->workspace);
+ if (workspace_by_name(wsc->workspace)) {
+ continue;
+ }
+ bool found = false;
+ for (int j = 0; j < wsc->outputs->length; ++j) {
+ if (strcmp(wsc->outputs->items[j], output_name) == 0) {
+ found = true;
+ free(target);
+ target = strdup(wsc->workspace);
+ break;
+ }
+ }
+ if (found) {
break;
}
}