aboutsummaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c106
-rw-r--r--sway/commands/assign.c2
-rw-r--r--sway/commands/bar.c9
-rw-r--r--sway/commands/bar/activate_button.c8
-rw-r--r--sway/commands/bar/bind.c106
-rw-r--r--sway/commands/bar/bindsym.c69
-rw-r--r--sway/commands/bar/colors.c4
-rw-r--r--sway/commands/bar/context_button.c8
-rw-r--r--sway/commands/bar/gaps.c60
-rw-r--r--sway/commands/bar/hidden_state.c2
-rw-r--r--sway/commands/bar/icon_theme.c26
-rw-r--r--sway/commands/bar/id.c2
-rw-r--r--sway/commands/bar/mode.c2
-rw-r--r--sway/commands/bar/modifier.c5
-rw-r--r--sway/commands/bar/output.c2
-rw-r--r--sway/commands/bar/secondary_button.c8
-rw-r--r--sway/commands/bar/separator_symbol.c2
-rw-r--r--sway/commands/bar/status_edge_padding.c21
-rw-r--r--sway/commands/bar/status_padding.c21
-rw-r--r--sway/commands/bar/strip_workspace_name.c32
-rw-r--r--sway/commands/bar/strip_workspace_numbers.c17
-rw-r--r--sway/commands/bar/tray_bindsym.c55
-rw-r--r--sway/commands/bar/tray_output.c40
-rw-r--r--sway/commands/bar/tray_padding.c37
-rw-r--r--sway/commands/bind.c167
-rw-r--r--sway/commands/exec_always.c2
-rw-r--r--sway/commands/focus.c5
-rw-r--r--sway/commands/for_window.c1
-rw-r--r--sway/commands/fullscreen.c4
-rw-r--r--sway/commands/input/events.c76
-rw-r--r--sway/commands/input/scroll_button.c34
-rw-r--r--sway/commands/input/xkb_layout.c2
-rw-r--r--sway/commands/input/xkb_model.c2
-rw-r--r--sway/commands/input/xkb_options.c2
-rw-r--r--sway/commands/input/xkb_rules.c2
-rw-r--r--sway/commands/input/xkb_variant.c2
-rw-r--r--sway/commands/mode.c2
-rw-r--r--sway/commands/move.c7
-rw-r--r--sway/commands/no_focus.c1
-rw-r--r--sway/commands/output/background.c7
-rw-r--r--sway/commands/output/transform.c2
-rw-r--r--sway/commands/reload.c9
-rw-r--r--sway/commands/rename.c9
-rw-r--r--sway/commands/resize.c28
-rw-r--r--sway/commands/seat.c16
-rw-r--r--sway/commands/seat/attach.c23
-rw-r--r--sway/commands/seat/cursor.c96
-rw-r--r--sway/commands/seat/fallback.c19
-rw-r--r--sway/commands/seat/hide_cursor.c29
-rw-r--r--sway/commands/set.c2
-rw-r--r--sway/commands/split.c4
-rw-r--r--sway/commands/swap.c2
-rw-r--r--sway/commands/tiling_drag_threshold.c22
-rw-r--r--sway/commands/title_align.c30
-rw-r--r--sway/commands/titlebar_border_thickness.c30
-rw-r--r--sway/commands/titlebar_padding.c42
-rw-r--r--sway/commands/workspace.c6
-rw-r--r--sway/config.c223
-rw-r--r--sway/config/bar.c22
-rw-r--r--sway/config/input.c2
-rw-r--r--sway/config/output.c114
-rw-r--r--sway/config/seat.c64
-rw-r--r--sway/criteria.c2
-rw-r--r--sway/desktop/output.c30
-rw-r--r--sway/desktop/render.c217
-rw-r--r--sway/desktop/transaction.c6
-rw-r--r--sway/desktop/xdg_shell.c4
-rw-r--r--sway/desktop/xdg_shell_v6.c4
-rw-r--r--sway/desktop/xwayland.c4
-rw-r--r--sway/input/cursor.c631
-rw-r--r--sway/input/input-manager.c227
-rw-r--r--sway/input/keyboard.c13
-rw-r--r--sway/input/seat.c297
-rw-r--r--sway/input/seatop_down.c77
-rw-r--r--sway/input/seatop_move_floating.c65
-rw-r--r--sway/input/seatop_move_tiling.c335
-rw-r--r--sway/input/seatop_resize_floating.c199
-rw-r--r--sway/input/seatop_resize_tiling.c92
-rw-r--r--sway/ipc-json.c359
-rw-r--r--sway/ipc-server.c68
-rw-r--r--sway/main.c83
-rw-r--r--sway/meson.build21
-rw-r--r--sway/security.c2
-rw-r--r--sway/server.c10
-rw-r--r--sway/sway-bar.5.scd64
-rw-r--r--sway/sway-input.5.scd37
-rw-r--r--sway/sway-output.5.scd22
-rw-r--r--sway/sway.1.scd10
-rw-r--r--sway/sway.5.scd64
-rw-r--r--sway/tree/container.c52
-rw-r--r--sway/tree/output.c18
-rw-r--r--sway/tree/root.c46
-rw-r--r--sway/tree/view.c109
-rw-r--r--sway/tree/workspace.c44
94 files changed, 3444 insertions, 1522 deletions
diff --git a/sway/commands.c b/sway/commands.c
index a68c724a..1d190e0b 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -42,22 +42,6 @@ struct cmd_results *checkarg(int argc, const char *name, enum expected_args type
: NULL;
}
-void apply_seat_config(struct seat_config *seat_config) {
- int i;
- i = list_seq_find(config->seat_configs, seat_name_cmp, seat_config->name);
- if (i >= 0) {
- // merge existing config
- struct seat_config *sc = config->seat_configs->items[i];
- merge_seat_config(sc, seat_config);
- free_seat_config(seat_config);
- seat_config = sc;
- } else {
- list_add(config->seat_configs, seat_config);
- }
-
- input_manager_apply_seat_config(seat_config);
-}
-
/* Keep alphabetized */
static struct cmd_handler handlers[] = {
{ "assign", cmd_assign },
@@ -103,6 +87,10 @@ static struct cmd_handler handlers[] = {
{ "smart_borders", cmd_smart_borders },
{ "smart_gaps", cmd_smart_gaps },
{ "tiling_drag", cmd_tiling_drag },
+ { "tiling_drag_threshold", cmd_tiling_drag_threshold },
+ { "title_align", cmd_title_align },
+ { "titlebar_border_thickness", cmd_titlebar_border_thickness },
+ { "titlebar_padding", cmd_titlebar_padding },
{ "workspace", cmd_workspace },
{ "workspace_auto_back_and_forth", cmd_ws_auto_back_and_forth },
};
@@ -213,12 +201,9 @@ static void set_config_node(struct sway_node *node) {
}
}
-struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
+list_t *execute_command(char *_exec, struct sway_seat *seat,
struct sway_container *con) {
- // Even though this function will process multiple commands we will only
- // return the last error, if any (for now). (Since we have access to an
- // error string we could e.g. concatenate all errors there.)
- struct cmd_results *results = NULL;
+ list_t *res_list = create_list();
char *exec = strdup(_exec);
char *head = exec;
char *cmdlist;
@@ -233,15 +218,6 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
}
}
- // This is the container or workspace which this command will run on.
- // Ignored if the command string contains criteria.
- struct sway_node *node;
- if (con) {
- node = &con->node;
- } else {
- node = seat_get_focus_inactive(seat, &root->node);
- }
-
config->handler_context.seat = seat;
head = exec;
@@ -252,8 +228,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
char *error = NULL;
struct criteria *criteria = criteria_parse(head, &error);
if (!criteria) {
- results = cmd_results_new(CMD_INVALID, head,
- "%s", error);
+ list_add(res_list, cmd_results_new(CMD_INVALID, head,
+ "%s", error));
free(error);
goto cleanup;
}
@@ -262,15 +238,15 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
criteria_destroy(criteria);
config->handler_context.using_criteria = true;
// Skip leading whitespace
- head += strspn(head, whitespace);
+ for (; isspace(*head); ++head) {}
}
// Split command list
cmdlist = argsep(&head, ";");
- cmdlist += strspn(cmdlist, whitespace);
+ for (; isspace(*cmdlist); ++cmdlist) {}
do {
// Split commands
cmd = argsep(&cmdlist, ",");
- cmd += strspn(cmd, whitespace);
+ for (; isspace(*cmd); ++cmd) {}
if (strcmp(cmd, "") == 0) {
wlr_log(WLR_INFO, "Ignoring empty command.");
continue;
@@ -289,10 +265,8 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
}
struct cmd_handler *handler = find_handler(argv[0], NULL, 0);
if (!handler) {
- if (results) {
- free_cmd_results(results);
- }
- results = cmd_results_new(CMD_INVALID, cmd, "Unknown/invalid command");
+ list_add(res_list, cmd_results_new(CMD_INVALID, cmd,
+ "Unknown/invalid command"));
free_argv(argc, argv);
goto cleanup;
}
@@ -304,31 +278,26 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
}
if (!config->handler_context.using_criteria) {
+ // The container or workspace which this command will run on.
+ struct sway_node *node = con ? &con->node :
+ seat_get_focus_inactive(seat, &root->node);
set_config_node(node);
struct cmd_results *res = handler->handle(argc-1, argv+1);
- if (res->status != CMD_SUCCESS) {
+ list_add(res_list, res);
+ if (res->status == CMD_INVALID) {
free_argv(argc, argv);
- if (results) {
- free_cmd_results(results);
- }
- results = res;
goto cleanup;
}
- free_cmd_results(res);
} else {
for (int i = 0; i < views->length; ++i) {
struct sway_view *view = views->items[i];
set_config_node(&view->container->node);
struct cmd_results *res = handler->handle(argc-1, argv+1);
- if (res->status != CMD_SUCCESS) {
+ list_add(res_list, res);
+ if (res->status == CMD_INVALID) {
free_argv(argc, argv);
- if (results) {
- free_cmd_results(results);
- }
- results = res;
goto cleanup;
}
- free_cmd_results(res);
}
}
free_argv(argc, argv);
@@ -337,10 +306,7 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat,
cleanup:
free(exec);
list_free(views);
- if (!results) {
- results = cmd_results_new(CMD_SUCCESS, NULL, NULL);
- }
- return results;
+ return res_list;
}
// this is like execute_command above, except:
@@ -418,6 +384,7 @@ struct cmd_results *config_command(char *exec) {
// 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_mode
&& handler->handle != cmd_bindsym
&& handler->handle != cmd_bindcode
&& handler->handle != cmd_set
@@ -572,20 +539,25 @@ void free_cmd_results(struct cmd_results *results) {
free(results);
}
-char *cmd_results_to_json(struct cmd_results *results) {
+char *cmd_results_to_json(list_t *res_list) {
json_object *result_array = json_object_new_array();
- json_object *root = json_object_new_object();
- json_object_object_add(root, "success",
- json_object_new_boolean(results->status == CMD_SUCCESS));
- if (results->input) {
- json_object_object_add(
- root, "input", json_object_new_string(results->input));
- }
- if (results->error) {
- json_object_object_add(
- root, "error", json_object_new_string(results->error));
+ for (int i = 0; i < res_list->length; ++i) {
+ struct cmd_results *results = res_list->items[i];
+ json_object *root = json_object_new_object();
+ json_object_object_add(root, "success",
+ json_object_new_boolean(results->status == CMD_SUCCESS));
+ if (results->error) {
+ json_object_object_add(root, "parse_error",
+ json_object_new_boolean(results->status == CMD_INVALID));
+ json_object_object_add(
+ root, "error", json_object_new_string(results->error));
+ }
+ if (results->input) {
+ json_object_object_add(
+ root, "input", json_object_new_string(results->input));
+ }
+ json_object_array_add(result_array, root);
}
- json_object_array_add(result_array, root);
const char *json = json_object_to_json_string(result_array);
char *res = strdup(json);
json_object_put(result_array);
diff --git a/sway/commands/assign.c b/sway/commands/assign.c
index 04582e88..716d70cf 100644
--- a/sway/commands/assign.c
+++ b/sway/commands/assign.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <string.h>
#include "sway/commands.h"
diff --git a/sway/commands/bar.c b/sway/commands/bar.c
index c808aef2..2a82d508 100644
--- a/sway/commands/bar.c
+++ b/sway/commands/bar.c
@@ -8,12 +8,12 @@
// Must be in alphabetical order for bsearch
static struct cmd_handler bar_handlers[] = {
- { "activate_button", bar_cmd_activate_button },
+ { "bindcode", bar_cmd_bindcode },
{ "binding_mode_indicator", bar_cmd_binding_mode_indicator },
{ "bindsym", bar_cmd_bindsym },
{ "colors", bar_cmd_colors },
- { "context_button", bar_cmd_context_button },
{ "font", bar_cmd_font },
+ { "gaps", bar_cmd_gaps },
{ "height", bar_cmd_height },
{ "hidden_state", bar_cmd_hidden_state },
{ "icon_theme", bar_cmd_icon_theme },
@@ -22,10 +22,13 @@ static struct cmd_handler bar_handlers[] = {
{ "output", bar_cmd_output },
{ "pango_markup", bar_cmd_pango_markup },
{ "position", bar_cmd_position },
- { "secondary_button", bar_cmd_secondary_button },
{ "separator_symbol", bar_cmd_separator_symbol },
{ "status_command", bar_cmd_status_command },
+ { "status_edge_padding", bar_cmd_status_edge_padding },
+ { "status_padding", bar_cmd_status_padding },
+ { "strip_workspace_name", bar_cmd_strip_workspace_name },
{ "strip_workspace_numbers", bar_cmd_strip_workspace_numbers },
+ { "tray_bindsym", bar_cmd_tray_bindsym },
{ "tray_output", bar_cmd_tray_output },
{ "tray_padding", bar_cmd_tray_padding },
{ "workspace_buttons", bar_cmd_workspace_buttons },
diff --git a/sway/commands/bar/activate_button.c b/sway/commands/bar/activate_button.c
deleted file mode 100644
index 7310e7ec..00000000
--- a/sway/commands/bar/activate_button.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdlib.h>
-#include "sway/commands.h"
-#include "log.h"
-
-struct cmd_results *bar_cmd_activate_button(int argc, char **argv) {
- // TODO TRAY
- return cmd_results_new(CMD_INVALID, "activate_button", "TODO TRAY");
-}
diff --git a/sway/commands/bar/bind.c b/sway/commands/bar/bind.c
new file mode 100644
index 00000000..a4c65ec4
--- /dev/null
+++ b/sway/commands/bar/bind.c
@@ -0,0 +1,106 @@
+#include <libevdev/libevdev.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/input/cursor.h"
+#include "list.h"
+#include "log.h"
+#include "stringop.h"
+
+static struct cmd_results *bar_cmd_bind(int argc, char **argv, bool code) {
+ const char *command = code ? "bar bindcode" : "bar bindsym";
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, command, EXPECTED_AT_LEAST, 2))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, command, "No bar defined.");
+ }
+
+ struct bar_binding *binding = calloc(1, sizeof(struct bar_binding));
+ if (!binding) {
+ return cmd_results_new(CMD_FAILURE, command,
+ "Unable to allocate bar binding");
+ }
+
+ binding->release = false;
+ if (strcmp("--release", argv[0]) == 0) {
+ binding->release = true;
+ argv++;
+ argc--;
+ }
+
+ char *message = NULL;
+ if (code) {
+ binding->button = get_mouse_bindcode(argv[0], &message);
+ } else {
+ binding->button = get_mouse_bindsym(argv[0], &message);
+ }
+ if (message) {
+ free_bar_binding(binding);
+ error = cmd_results_new(CMD_INVALID, command, message);
+ free(message);
+ return error;
+ } else if (!binding->button) {
+ free_bar_binding(binding);
+ return cmd_results_new(CMD_INVALID, command,
+ "Unknown button %s", argv[0]);
+ }
+
+ const char *name = libevdev_event_code_get_name(EV_KEY, binding->button);
+ if (!name) {
+ switch (binding->button) {
+ case SWAY_SCROLL_UP:
+ name = "SWAY_SCROLL_UP";
+ break;
+ case SWAY_SCROLL_DOWN:
+ name = "SWAY_SCROLL_DOWN";
+ break;
+ case SWAY_SCROLL_LEFT:
+ name = "SWAY_SCROLL_LEFT";
+ break;
+ case SWAY_SCROLL_RIGHT:
+ name = "SWAY_SCROLL_RIGHT";
+ break;
+ default:
+ // Unreachable
+ break;
+ }
+ }
+
+ binding->command = join_args(argv + 1, argc - 1);
+
+ list_t *bindings = config->current_bar->bindings;
+ bool overwritten = false;
+ for (int i = 0; i < bindings->length; i++) {
+ struct bar_binding *other = bindings->items[i];
+ if (other->button == binding->button &&
+ other->release == binding->release) {
+ overwritten = true;
+ bindings->items[i] = binding;
+ free_bar_binding(other);
+ wlr_log(WLR_DEBUG, "[bar %s] Updated binding for %u (%s)%s",
+ config->current_bar->id, binding->button, name,
+ binding->release ? " - release" : "");
+ break;
+ }
+ }
+ if (!overwritten) {
+ list_add(bindings, binding);
+ wlr_log(WLR_DEBUG, "[bar %s] Added binding for %u (%s)%s",
+ config->current_bar->id, binding->button, name,
+ binding->release ? " - release" : "");
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
+struct cmd_results *bar_cmd_bindcode(int argc, char **argv) {
+ return bar_cmd_bind(argc, argv, true);
+}
+
+struct cmd_results *bar_cmd_bindsym(int argc, char **argv) {
+ return bar_cmd_bind(argc, argv, false);
+}
diff --git a/sway/commands/bar/bindsym.c b/sway/commands/bar/bindsym.c
deleted file mode 100644
index 965c8903..00000000
--- a/sway/commands/bar/bindsym.c
+++ /dev/null
@@ -1,69 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include "sway/commands.h"
-#include "sway/config.h"
-#include "list.h"
-#include "log.h"
-#include "stringop.h"
-
-struct cmd_results *bar_cmd_bindsym(int argc, char **argv) {
- struct cmd_results *error = NULL;
- if ((error = checkarg(argc, "bar bindsym", EXPECTED_AT_LEAST, 2))) {
- return error;
- }
- if (!config->current_bar) {
- return cmd_results_new(CMD_FAILURE, "bar bindsym", "No bar defined.");
- }
-
- struct bar_binding *binding = calloc(1, sizeof(struct bar_binding));
- if (!binding) {
- return cmd_results_new(CMD_FAILURE, "bar bindsym",
- "Unable to allocate bar binding");
- }
-
- binding->release = false;
- if (strcmp("--release", argv[0]) == 0) {
- binding->release = true;
- argv++;
- argc--;
- }
-
- binding->button = 0;
- if (strncasecmp(argv[0], "button", strlen("button")) == 0 &&
- strlen(argv[0]) == strlen("button0")) {
- binding->button = argv[0][strlen("button")] - '0';
- }
- if (binding->button < 1 || binding->button > 9) {
- free_bar_binding(binding);
- return cmd_results_new(CMD_FAILURE, "bar bindsym",
- "Only button<1-9> is supported");
- }
-
- binding->command = join_args(argv + 1, argc - 1);
-
- list_t *bindings = config->current_bar->bindings;
- bool overwritten = false;
- for (int i = 0; i < bindings->length; i++) {
- struct bar_binding *other = bindings->items[i];
- if (other->button == binding->button &&
- other->release == binding->release) {
- overwritten = true;
- bindings->items[i] = binding;
- free_bar_binding(other);
- wlr_log(WLR_DEBUG, "[bar %s] Updated binding for button%u%s",
- config->current_bar->id, binding->button,
- binding->release ? " (release)" : "");
- break;
- }
- }
- if (!overwritten) {
- list_add(bindings, binding);
- wlr_log(WLR_DEBUG, "[bar %s] Added binding for button%u%s",
- config->current_bar->id, binding->button,
- binding->release ? " (release)" : "");
- }
-
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
-}
diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c
index 8c862ca9..ebf1e3e1 100644
--- a/sway/commands/bar/colors.c
+++ b/sway/commands/bar/colors.c
@@ -118,8 +118,8 @@ struct cmd_results *bar_colors_cmd_statusline(int argc, char **argv) {
}
struct cmd_results *bar_colors_cmd_focused_statusline(int argc, char **argv) {
- return parse_single_color(&(config->current_bar->colors.focused_separator),
- "focused_separator", argc, argv);
+ return parse_single_color(&(config->current_bar->colors.focused_statusline),
+ "focused_statusline", argc, argv);
}
struct cmd_results *bar_colors_cmd_urgent_workspace(int argc, char **argv) {
diff --git a/sway/commands/bar/context_button.c b/sway/commands/bar/context_button.c
deleted file mode 100644
index 3b76885a..00000000
--- a/sway/commands/bar/context_button.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdlib.h>
-#include "sway/commands.h"
-#include "log.h"
-
-struct cmd_results *bar_cmd_context_button(int argc, char **argv) {
- // TODO TRAY
- return cmd_results_new(CMD_INVALID, "context_button", "TODO TRAY");
-}
diff --git a/sway/commands/bar/gaps.c b/sway/commands/bar/gaps.c
new file mode 100644
index 00000000..f78f3742
--- /dev/null
+++ b/sway/commands/bar/gaps.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/ipc-server.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_gaps(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ if ((error = checkarg(argc, "gaps", EXPECTED_AT_MOST, 4))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "bar gaps", "No bar defined.");
+ }
+
+ int top = 0, right = 0, bottom = 0, left = 0;
+
+ for (int i = 0; i < argc; i++) {
+ char *end;
+ int amount = strtol(argv[i], &end, 10);
+ if (strlen(end) && strcasecmp(end, "px") != 0) {
+ return cmd_results_new(CMD_INVALID, "bar gaps",
+ "Expected 'bar [<bar-id>] gaps <all> | <horizonal> "
+ "<vertical> | <top> <right> <bottom> <left>'");
+ }
+
+ if (i == 0) {
+ top = amount;
+ }
+ if (i == 0 || i == 1) {
+ right = amount;
+ }
+ if (i == 0 || i == 2) {
+ bottom = amount;
+ }
+ if (i == 0 || i == 1 || i == 3) {
+ left = amount;
+ }
+ }
+
+ config->current_bar->gaps.top = top;
+ config->current_bar->gaps.right = right;
+ config->current_bar->gaps.bottom = bottom;
+ config->current_bar->gaps.left = left;
+
+ wlr_log(WLR_DEBUG, "Setting bar gaps to %d %d %d %d on bar: %s",
+ config->current_bar->gaps.top, config->current_bar->gaps.right,
+ config->current_bar->gaps.bottom, config->current_bar->gaps.left,
+ config->current_bar->id);
+
+ if (!config->reading) {
+ ipc_event_barconfig_update(config->current_bar);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c
index 5be6c2dc..79eaf01c 100644
--- a/sway/commands/bar/hidden_state.c
+++ b/sway/commands/bar/hidden_state.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
diff --git a/sway/commands/bar/icon_theme.c b/sway/commands/bar/icon_theme.c
index 44cd3076..9d3b6040 100644
--- a/sway/commands/bar/icon_theme.c
+++ b/sway/commands/bar/icon_theme.c
@@ -1,8 +1,28 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
+#include "config.h"
#include "sway/commands.h"
+#include "sway/config.h"
+#include "log.h"
struct cmd_results *bar_cmd_icon_theme(int argc, char **argv) {
- // TODO TRAY
- return cmd_results_new(CMD_INVALID, "icon_theme", "TODO TRAY");
+#if HAVE_TRAY
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "icon_theme", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "tray_padding", "No bar defined.");
+ }
+
+ wlr_log(WLR_DEBUG, "[Bar %s] Setting icon theme to %s",
+ config->current_bar->id, argv[0]);
+ free(config->current_bar->icon_theme);
+ config->current_bar->icon_theme = strdup(argv[0]);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+#else
+ return cmd_results_new(CMD_INVALID, "icon_theme",
+ "Sway has been compiled without tray support");
+#endif
}
diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c
index 7690a852..35509459 100644
--- a/sway/commands/bar/id.c
+++ b/sway/commands/bar/id.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include "sway/commands.h"
#include "log.h"
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c
index 2cba785e..dcaf6da9 100644
--- a/sway/commands/bar/mode.c
+++ b/sway/commands/bar/mode.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c
index 09025fff..b5a16f45 100644
--- a/sway/commands/bar/modifier.c
+++ b/sway/commands/bar/modifier.c
@@ -20,15 +20,14 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) {
uint32_t tmp_mod;
if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) {
mod |= tmp_mod;
- continue;
} else {
error = cmd_results_new(CMD_INVALID, "modifier",
"Unknown modifier '%s'", split->items[i]);
- free_flat_list(split);
+ list_free_items_and_destroy(split);
return error;
}
}
- free_flat_list(split);
+ list_free_items_and_destroy(split);
config->current_bar->modifier = mod;
wlr_log(WLR_DEBUG,
"Show/Hide the bar when pressing '%s' in hide mode.", argv[0]);
diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c
index 72754e05..930d779d 100644
--- a/sway/commands/bar/output.c
+++ b/sway/commands/bar/output.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <string.h>
#include "sway/commands.h"
diff --git a/sway/commands/bar/secondary_button.c b/sway/commands/bar/secondary_button.c
deleted file mode 100644
index 449124cb..00000000
--- a/sway/commands/bar/secondary_button.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include <stdlib.h>
-#include "sway/commands.h"
-#include "log.h"
-
-struct cmd_results *bar_cmd_secondary_button(int argc, char **argv) {
- // TODO TRAY
- return cmd_results_new(CMD_INVALID, "secondary_button", "TODO TRAY");
-}
diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c
index 392ab730..060b8f52 100644
--- a/sway/commands/bar/separator_symbol.c
+++ b/sway/commands/bar/separator_symbol.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include "sway/commands.h"
#include "log.h"
diff --git a/sway/commands/bar/status_edge_padding.c b/sway/commands/bar/status_edge_padding.c
new file mode 100644
index 00000000..f3b10631
--- /dev/null
+++ b/sway/commands/bar/status_edge_padding.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_status_edge_padding(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "status_edge_padding", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ char *end;
+ int padding = strtol(argv[0], &end, 10);
+ if (strlen(end) || padding < 0) {
+ return cmd_results_new(CMD_INVALID, "status_edge_padding",
+ "Padding must be a positive integer");
+ }
+ config->current_bar->status_edge_padding = padding;
+ wlr_log(WLR_DEBUG, "Status edge padding on bar %s: %d",
+ config->current_bar->id, config->current_bar->status_edge_padding);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/status_padding.c b/sway/commands/bar/status_padding.c
new file mode 100644
index 00000000..13b8eb6b
--- /dev/null
+++ b/sway/commands/bar/status_padding.c
@@ -0,0 +1,21 @@
+#include <stdlib.h>
+#include <string.h>
+#include "sway/commands.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_status_padding(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "status_padding", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ char *end;
+ int padding = strtol(argv[0], &end, 10);
+ if (strlen(end) || padding < 0) {
+ return cmd_results_new(CMD_INVALID, "status_padding",
+ "Padding must be a positive integer");
+ }
+ config->current_bar->status_padding = padding;
+ wlr_log(WLR_DEBUG, "Status padding on bar %s: %d",
+ config->current_bar->id, config->current_bar->status_padding);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/strip_workspace_name.c b/sway/commands/bar/strip_workspace_name.c
new file mode 100644
index 00000000..79692f6e
--- /dev/null
+++ b/sway/commands/bar/strip_workspace_name.c
@@ -0,0 +1,32 @@
+#include <string.h>
+#include <strings.h>
+#include "sway/commands.h"
+#include "log.h"
+#include "util.h"
+
+struct cmd_results *bar_cmd_strip_workspace_name(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc,
+ "strip_workspace_name", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE,
+ "strip_workspace_name", "No bar defined.");
+ }
+
+ config->current_bar->strip_workspace_name =
+ parse_boolean(argv[0], config->current_bar->strip_workspace_name);
+
+ if (config->current_bar->strip_workspace_name) {
+ config->current_bar->strip_workspace_numbers = false;
+
+ wlr_log(WLR_DEBUG, "Stripping workspace name on bar: %s",
+ config->current_bar->id);
+ } else {
+ wlr_log(WLR_DEBUG, "Enabling workspace name on bar: %s",
+ config->current_bar->id);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/bar/strip_workspace_numbers.c b/sway/commands/bar/strip_workspace_numbers.c
index 4e47d047..b33d01e5 100644
--- a/sway/commands/bar/strip_workspace_numbers.c
+++ b/sway/commands/bar/strip_workspace_numbers.c
@@ -2,6 +2,7 @@
#include <strings.h>
#include "sway/commands.h"
#include "log.h"
+#include "util.h"
struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) {
struct cmd_results *error = NULL;
@@ -13,17 +14,19 @@ struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE,
"strip_workspace_numbers", "No bar defined.");
}
- if (strcasecmp("yes", argv[0]) == 0) {
- config->current_bar->strip_workspace_numbers = true;
+
+ config->current_bar->strip_workspace_numbers =
+ parse_boolean(argv[0], config->current_bar->strip_workspace_numbers);
+
+ if (config->current_bar->strip_workspace_numbers) {
+ config->current_bar->strip_workspace_name = false;
+
wlr_log(WLR_DEBUG, "Stripping workspace numbers on bar: %s",
config->current_bar->id);
- } else if (strcasecmp("no", argv[0]) == 0) {
- config->current_bar->strip_workspace_numbers = false;
+ } else {
wlr_log(WLR_DEBUG, "Enabling workspace numbers on bar: %s",
config->current_bar->id);
- } else {
- return cmd_results_new(CMD_INVALID,
- "strip_workspace_numbers", "Invalid value %s", argv[0]);
}
+
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/bar/tray_bindsym.c b/sway/commands/bar/tray_bindsym.c
new file mode 100644
index 00000000..ad413446
--- /dev/null
+++ b/sway/commands/bar/tray_bindsym.c
@@ -0,0 +1,55 @@
+#include <strings.h>
+#include "config.h"
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "log.h"
+
+struct cmd_results *bar_cmd_tray_bindsym(int argc, char **argv) {
+#if HAVE_TRAY
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "tray_bindsym", EXPECTED_EQUAL_TO, 2))) {
+ return error;
+ }
+
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "tray_bindsym", "No bar defined.");
+ }
+
+ int button = 0;
+ if (strncasecmp(argv[0], "button", strlen("button")) == 0 &&
+ strlen(argv[0]) == strlen("button0")) {
+ button = argv[0][strlen("button")] - '0';
+ }
+ if (button < 1 || button > 9) {
+ return cmd_results_new(CMD_FAILURE, "tray_bindsym",
+ "[Bar %s] Only buttons 1 to 9 are supported",
+ config->current_bar->id);
+ }
+
+ static const char *commands[] = {
+ "ContextMenu",
+ "Activate",
+ "SecondaryActivate",
+ "ScrollDown",
+ "ScrollLeft",
+ "ScrollRight",
+ "ScrollUp",
+ "nop"
+ };
+
+ for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); ++i) {
+ if (strcasecmp(argv[1], commands[i]) == 0) {
+ wlr_log(WLR_DEBUG, "[Bar %s] Binding button %d to %s",
+ config->current_bar->id, button, commands[i]);
+ config->current_bar->tray_bindings[button] = commands[i];
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ }
+ }
+
+ return cmd_results_new(CMD_INVALID, "tray_bindsym",
+ "[Bar %s] Invalid command %s", config->current_bar->id, argv[1]);
+#else
+ return cmd_results_new(CMD_INVALID, "tray_bindsym",
+ "Sway has been compiled without tray support");
+#endif
+}
diff --git a/sway/commands/bar/tray_output.c b/sway/commands/bar/tray_output.c
index 6ab16731..a1169c20 100644
--- a/sway/commands/bar/tray_output.c
+++ b/sway/commands/bar/tray_output.c
@@ -1,8 +1,42 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
+#include "config.h"
#include "sway/commands.h"
+#include "sway/config.h"
+#include "list.h"
+#include "log.h"
struct cmd_results *bar_cmd_tray_output(int argc, char **argv) {
- // TODO TRAY
- return cmd_results_new(CMD_INVALID, "tray_output", "TODO TRAY");
+#if HAVE_TRAY
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "tray_output", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "tray_output", "No bar defined.");
+ }
+
+ list_t *outputs = config->current_bar->tray_outputs;
+ if (!outputs) {
+ config->current_bar->tray_outputs = outputs = create_list();
+ }
+
+ if (strcmp(argv[0], "none") == 0) {
+ wlr_log(WLR_DEBUG, "Hiding tray on bar: %s", config->current_bar->id);
+ for (int i = 0; i < outputs->length; ++i) {
+ free(outputs->items[i]);
+ }
+ outputs->length = 0;
+ } else {
+ wlr_log(WLR_DEBUG, "Showing tray on output '%s' for bar: %s", argv[0],
+ config->current_bar->id);
+ }
+ list_add(outputs, strdup(argv[0]));
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+#else
+ return cmd_results_new(CMD_INVALID, "tray_output",
+ "Sway has been compiled without tray support");
+#endif
}
diff --git a/sway/commands/bar/tray_padding.c b/sway/commands/bar/tray_padding.c
index 91c56f19..eb795b00 100644
--- a/sway/commands/bar/tray_padding.c
+++ b/sway/commands/bar/tray_padding.c
@@ -1,9 +1,42 @@
#include <stdlib.h>
#include <strings.h>
+#include "config.h"
#include "sway/commands.h"
+#include "sway/config.h"
#include "log.h"
struct cmd_results *bar_cmd_tray_padding(int argc, char **argv) {
- // TODO TRAY
- return cmd_results_new(CMD_INVALID, "tray_padding", "TODO TRAY");
+#if HAVE_TRAY
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "tray_padding", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ if ((error = checkarg(argc, "tray_padding", EXPECTED_AT_MOST, 2))) {
+ return error;
+ }
+
+ if (!config->current_bar) {
+ return cmd_results_new(CMD_FAILURE, "tray_padding", "No bar defined.");
+ }
+ struct bar_config *bar = config->current_bar;
+
+ char *end;
+ int padding = strtol(argv[0], &end, 10);
+ if (padding < 0 || (*end != '\0' && strcasecmp(end, "px") != 0)) {
+ return cmd_results_new(CMD_INVALID, "tray_padding",
+ "[Bar %s] Invalid tray padding value: %s", bar->id, argv[0]);
+ }
+
+ if (argc == 2 && strcasecmp(argv[1], "px") != 0) {
+ return cmd_results_new(CMD_INVALID, "tray_padding",
+ "Expected 'tray_padding <px> [px]'");
+ }
+
+ wlr_log(WLR_DEBUG, "[Bar %s] Setting tray padding to %d", bar->id, padding);
+ config->current_bar->tray_padding = padding;
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+#else
+ return cmd_results_new(CMD_INVALID, "tray_padding",
+ "Sway has been compiled without tray support");
+#endif
}
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index a9de227f..be47d412 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -1,15 +1,13 @@
-#define _XOPEN_SOURCE 500
-#ifdef __linux__
+#define _POSIX_C_SOURCE 200809L
+#include <libevdev/libevdev.h>
#include <linux/input-event-codes.h>
-#elif __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#endif
#include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-names.h>
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/input/cursor.h"
#include "sway/ipc-server.h"
#include "list.h"
#include "log.h"
@@ -23,9 +21,7 @@ void free_sway_binding(struct sway_binding *binding) {
return;
}
- if (binding->keys) {
- free_flat_list(binding->keys);
- }
+ list_free_items_and_destroy(binding->keys);
free(binding->input);
free(binding->command);
free(binding);
@@ -80,7 +76,6 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) {
return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0);
}
-
/**
* From a keycode, bindcode, or bindsym name and the most likely binding type,
* identify the appropriate numeric value corresponding to the key. Return NULL
@@ -90,52 +85,91 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) {
*/
static struct cmd_results *identify_key(const char* name, bool first_key,
uint32_t* key_val, enum binding_input_type* type) {
- if (*type == BINDING_KEYCODE) {
- // check for keycode
+ if (*type == BINDING_MOUSECODE) {
+ // check for mouse bindcodes
+ char *message = NULL;
+ uint32_t button = get_mouse_bindcode(name, &message);
+ if (!button) {
+ if (message) {
+ struct cmd_results *error =
+ cmd_results_new(CMD_INVALID, "bindcode", message);
+ free(message);
+ return error;
+ } else {
+ return cmd_results_new(CMD_INVALID, "bindcode",
+ "Unknown button code %s", name);
+ }
+ }
+ *key_val = button;
+ } else if (*type == BINDING_MOUSESYM) {
+ // check for mouse bindsyms (x11 buttons or event names)
+ char *message = NULL;
+ uint32_t button = get_mouse_bindsym(name, &message);
+ if (!button) {
+ if (message) {
+ struct cmd_results *error =
+ cmd_results_new(CMD_INVALID, "bindsym", message);
+ free(message);
+ return error;
+ } else if (!button) {
+ return cmd_results_new(CMD_INVALID, "bindsym",
+ "Unknown button %s", name);
+ }
+ }
+ *key_val = button;
+ } else if (*type == BINDING_KEYCODE) {
+ // check for keycode. If it is the first key, allow mouse bindcodes
+ if (first_key) {
+ char *message = NULL;
+ uint32_t button = get_mouse_bindcode(name, &message);
+ free(message);
+ if (button) {
+ *type = BINDING_MOUSECODE;
+ *key_val = button;
+ return NULL;
+ }
+ }
+
xkb_keycode_t keycode = strtol(name, NULL, 10);
if (!xkb_keycode_is_legal_ext(keycode)) {
- return cmd_results_new(CMD_INVALID, "bindcode",
- "Invalid keycode '%s'", name);
+ if (first_key) {
+ return cmd_results_new(CMD_INVALID, "bindcode",
+ "Invalid keycode or button code '%s'", name);
+ } else {
+ return cmd_results_new(CMD_INVALID, "bindcode",
+ "Invalid keycode '%s'", name);
+ }
}
*key_val = keycode;
} else {
- // check for keysym
- xkb_keysym_t keysym = xkb_keysym_from_name(name,
- XKB_KEYSYM_CASE_INSENSITIVE);
-
- // Check for mouse binding
- uint32_t button = 0;
- if (strncasecmp(name, "button", strlen("button")) == 0 &&
- strlen(name) == strlen("button0")) {
- button = name[strlen("button")] - '1' + BTN_LEFT;
+ // check for keysym. If it is the first key, allow mouse bindsyms
+ if (first_key) {
+ char *message = NULL;
+ uint32_t button = get_mouse_bindsym(name, &message);
+ if (message) {
+ struct cmd_results *error =
+ cmd_results_new(CMD_INVALID, "bindsym", message);
+ free(message);
+ return error;
+ } else if (button) {
+ *type = BINDING_MOUSESYM;
+ *key_val = button;
+ return NULL;
+ }
}
- if (*type == BINDING_KEYSYM) {
- if (button) {
- if (first_key) {
- *type = BINDING_MOUSE;
- *key_val = button;
- } else {
- return cmd_results_new(CMD_INVALID, "bindsym",
- "Mixed button '%s' into key sequence", name);
- }
- } else if (keysym) {
- *key_val = keysym;
- } else {
- return cmd_results_new(CMD_INVALID, "bindsym",
- "Unknown key '%s'", name);
- }
- } else {
- if (button) {
- *key_val = button;
- } else if (keysym) {
+ xkb_keysym_t keysym = xkb_keysym_from_name(name,
+ XKB_KEYSYM_CASE_INSENSITIVE);
+ if (!keysym) {
+ if (first_key) {
return cmd_results_new(CMD_INVALID, "bindsym",
- "Mixed keysym '%s' into button sequence", name);
+ "Unknown key or button '%s'", name);
} else {
return cmd_results_new(CMD_INVALID, "bindsym",
- "Unknown button '%s'", name);
+ "Unknown key '%s'", name);
}
}
+ *key_val = keysym;
}
return NULL;
}
@@ -161,6 +195,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM;
bool exclude_titlebar = false;
+ bool warn = true;
// Handle --release and --locked
while (argc > 0) {
@@ -178,6 +213,8 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
strlen("--input-device=")) == 0) {
free(binding->input);
binding->input = strdup(argv[0] + strlen("--input-device="));
+ } else if (strcmp("--no-warn", argv[0]) == 0) {
+ warn = false;
} else {
break;
}
@@ -186,7 +223,8 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
}
if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR)
|| exclude_titlebar) {
- binding->type = BINDING_MOUSE;
+ binding->type = binding->type == BINDING_KEYCODE ?
+ BINDING_MOUSECODE : BINDING_MOUSESYM;
}
if (argc < 2) {
@@ -220,21 +258,22 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
uint32_t *key = calloc(1, sizeof(uint32_t));
if (!key) {
free_sway_binding(binding);
- free_flat_list(split);
+ list_free_items_and_destroy(split);
return cmd_results_new(CMD_FAILURE, bindtype,
"Unable to allocate binding key");
}
*key = key_val;
list_add(binding->keys, key);
}
- free_flat_list(split);
+ list_free_items_and_destroy(split);
binding->order = binding_order++;
// refine region of interest for mouse binding once we are certain
// that this is one
if (exclude_titlebar) {
binding->flags &= ~BINDING_TITLEBAR;
- } else if (binding->type == BINDING_MOUSE) {
+ } else if (binding->type == BINDING_MOUSECODE
+ || binding->type == BINDING_MOUSESYM) {
binding->flags |= BINDING_TITLEBAR;
}
@@ -255,8 +294,15 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
for (int i = 0; i < mode_bindings->length; ++i) {
struct sway_binding *config_binding = mode_bindings->items[i];
if (binding_key_compare(binding, config_binding)) {
- wlr_log(WLR_DEBUG, "overwriting old binding with command '%s'",
- config_binding->command);
+ wlr_log(WLR_INFO, "Overwriting binding '%s' for device '%s' "
+ "from `%s` to `%s`", argv[0], binding->input,
+ binding->command, config_binding->command);
+ if (warn) {
+ config_add_swaynag_warning("Overwriting binding"
+ "'%s' for device '%s' to `%s` from `%s`",
+ argv[0], binding->input, binding->command,
+ config_binding->command);
+ }
free_sway_binding(config_binding);
mode_bindings->items[i] = binding;
overwritten = true;
@@ -270,7 +316,6 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
wlr_log(WLR_DEBUG, "%s - Bound %s to command `%s` for device '%s'",
bindtype, argv[0], binding->command, binding->input);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
-
}
struct cmd_results *cmd_bindsym(int argc, char **argv) {
@@ -281,21 +326,25 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
return cmd_bindsym_or_bindcode(argc, argv, true);
}
-
/**
* Execute the command associated to a binding
*/
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) {
wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command);
- config->handler_context.seat = seat;
- struct cmd_results *results = execute_command(binding->command, NULL, NULL);
- if (results->status == CMD_SUCCESS) {
+ list_t *res_list = execute_command(binding->command, seat, NULL);
+ bool success = true;
+ for (int i = 0; i < res_list->length; ++i) {
+ struct cmd_results *results = res_list->items[i];
+ if (results->status != CMD_SUCCESS) {
+ wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
+ binding->command, results->error);
+ success = false;
+ }
+ free_cmd_results(results);
+ }
+ list_free(res_list);
+ if (success) {
ipc_event_binding(binding);
- } else {
- wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)",
- binding->command, results->error);
}
-
- free_cmd_results(results);
}
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index 7a15709b..9ec28d81 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index f6338c55..97ffe91c 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -193,7 +193,7 @@ static struct cmd_results *focus_output(struct sway_seat *seat,
"Expected 'focus output <direction|name>'");
}
char *identifier = join_args(argv, argc);
- struct sway_output *output = output_by_name(identifier);
+ struct sway_output *output = output_by_name_or_id(identifier);
if (!output) {
enum wlr_direction direction;
@@ -269,6 +269,9 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
}
if (argc == 0 && container) {
+ if (container->scratchpad && !container->workspace) {
+ root_scratchpad_show(container);
+ }
seat_set_focus_container(seat, container);
seat_consider_warp_to_focus(seat);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/for_window.c b/sway/commands/for_window.c
index ac4d6563..7c0f7d7f 100644
--- a/sway/commands/for_window.c
+++ b/sway/commands/for_window.c
@@ -1,4 +1,3 @@
-#define _XOPEN_SOURCE 500
#include <string.h>
#include "sway/commands.h"
#include "sway/criteria.h"
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c
index ff7cbba7..b78187d9 100644
--- a/sway/commands/fullscreen.c
+++ b/sway/commands/fullscreen.c
@@ -13,14 +13,14 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) {
return error;
}
if (!root->outputs->length) {
- return cmd_results_new(CMD_INVALID, "fullscreen",
+ return cmd_results_new(CMD_FAILURE, "fullscreen",
"Can't run this command while there's no outputs connected.");
}
struct sway_node *node = config->handler_context.node;
struct sway_container *container = config->handler_context.container;
struct sway_workspace *workspace = config->handler_context.workspace;
if (node->type == N_WORKSPACE && workspace->tiling->length == 0) {
- return cmd_results_new(CMD_INVALID, "fullscreen",
+ return cmd_results_new(CMD_FAILURE, "fullscreen",
"Can't fullscreen an empty workspace");
}
if (node->type == N_WORKSPACE) {
diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c
index e7ed69c6..69f46269 100644
--- a/sway/commands/input/events.c
+++ b/sway/commands/input/events.c
@@ -1,10 +1,69 @@
+#include <limits.h>
#include <string.h>
#include <strings.h>
+#include <wlr/backend/libinput.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "log.h"
+static void toggle_send_events_for_device(struct input_config *ic,
+ struct sway_input_device *input_device) {
+ struct wlr_input_device *wlr_device = input_device->wlr_device;
+ if (!wlr_input_device_is_libinput(wlr_device)) {
+ return;
+ }
+ struct libinput_device *libinput_dev
+ = wlr_libinput_get_device_handle(wlr_device);
+
+ enum libinput_config_send_events_mode mode =
+ libinput_device_config_send_events_get_mode(libinput_dev);
+ uint32_t possible =
+ libinput_device_config_send_events_get_modes(libinput_dev);
+
+ switch (mode) {
+ case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
+ mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
+ if (possible & mode) {
+ break;
+ }
+ // fall through
+ case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
+ mode = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
+ if (possible & mode) {
+ break;
+ }
+ // fall through
+ case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
+ default:
+ mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
+ break;
+ }
+
+ ic->send_events = mode;
+}
+
+static void toggle_send_events(struct input_config *ic) {
+ struct sway_input_device *input_device = NULL;
+ wl_list_for_each(input_device, &server.input->devices, link) {
+ if (strcmp(input_device->identifier, ic->identifier) == 0) {
+ toggle_send_events_for_device(ic, input_device);
+ }
+ }
+}
+
+static void toggle_wildcard_send_events() {
+ struct sway_input_device *input_device = NULL;
+ wl_list_for_each(input_device, &server.input->devices, link) {
+ struct input_config *ic = new_input_config(input_device->identifier);
+ if (!ic) {
+ break;
+ }
+ toggle_send_events_for_device(ic, input_device);
+ store_input_config(ic);
+ }
+}
+
struct cmd_results *input_cmd_events(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "events", EXPECTED_AT_LEAST, 1))) {
@@ -23,9 +82,24 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
} else if (strcasecmp(argv[0], "disabled_on_external_mouse") == 0) {
ic->send_events =
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
- } else {
+ } else if (config->reading) {
return cmd_results_new(CMD_INVALID, "events",
"Expected 'events <enabled|disabled|disabled_on_external_mouse>'");
+ } else if (strcasecmp(argv[0], "toggle") == 0) {
+ if (strcmp(ic->identifier, "*") == 0) {
+ // Update the device input configs and then reset the wildcard
+ // config send events mode so that is does not override the device
+ // ones. The device ones will be applied when attempting to apply
+ // the wildcard config
+ toggle_wildcard_send_events();
+ ic->send_events = INT_MIN;
+ } else {
+ toggle_send_events(ic);
+ }
+ } else {
+ return cmd_results_new(CMD_INVALID, "events",
+ "Expected 'events <enabled|disabled|disabled_on_external_mouse|"
+ "toggle>'");
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/input/scroll_button.c b/sway/commands/input/scroll_button.c
index 1958f23c..d82a1fe1 100644
--- a/sway/commands/input/scroll_button.c
+++ b/sway/commands/input/scroll_button.c
@@ -1,9 +1,7 @@
-#include <string.h>
-#include <strings.h>
-#include <errno.h>
+#include <libevdev/libevdev.h>
#include "sway/config.h"
#include "sway/commands.h"
-#include "sway/input/input-manager.h"
+#include "sway/input/cursor.h"
struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
struct cmd_results *error = NULL;
@@ -16,22 +14,26 @@ struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
"No input device defined.");
}
- errno = 0;
- char *endptr;
- int scroll_button = strtol(*argv, &endptr, 10);
- if (endptr == *argv && scroll_button == 0) {
- return cmd_results_new(CMD_INVALID, "scroll_button",
- "Scroll button identifier must be an integer.");
+ if (strcmp(*argv, "disable") == 0) {
+ ic->scroll_button = 0;
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
- if (errno == ERANGE) {
+
+ char *message = NULL;
+ uint32_t button = get_mouse_button(*argv, &message);
+ if (message) {
+ error = cmd_results_new(CMD_INVALID, "scroll_button", message);
+ free(message);
+ return error;
+ } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN
+ || button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) {
return cmd_results_new(CMD_INVALID, "scroll_button",
- "Scroll button identifier out of range.");
- }
- if (scroll_button < 0) {
+ "X11 axis buttons are not supported for scroll_button");
+ } else if (!button) {
return cmd_results_new(CMD_INVALID, "scroll_button",
- "Scroll button identifier cannot be negative.");
+ "Unknown button %s", *argv);
}
- ic->scroll_button = scroll_button;
+ ic->scroll_button = button;
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c
index 5fccd4a3..43166401 100644
--- a/sway/commands/input/xkb_layout.c
+++ b/sway/commands/input/xkb_layout.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c
index c4d04638..066f632b 100644
--- a/sway/commands/input/xkb_model.c
+++ b/sway/commands/input/xkb_model.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c
index 794ab6e9..09dc4a5c 100644
--- a/sway/commands/input/xkb_options.c
+++ b/sway/commands/input/xkb_options.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c
index 257c3288..d3e576e6 100644
--- a/sway/commands/input/xkb_rules.c
+++ b/sway/commands/input/xkb_rules.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c
index 3832dc8e..2d7581d1 100644
--- a/sway/commands/input/xkb_variant.c
+++ b/sway/commands/input/xkb_variant.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
index 637ca45e..189e3c1a 100644
--- a/sway/commands/mode.c
+++ b/sway/commands/mode.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <stdbool.h>
#include <string.h>
#include <strings.h>
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 7d8c1f1a..72e177e8 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
@@ -64,7 +64,7 @@ static struct sway_output *output_in_direction(const char *direction_string,
}
}
- return output_by_name(direction_string);
+ return output_by_name_or_id(direction_string);
}
static bool is_parallel(enum sway_container_layout layout,
@@ -154,6 +154,8 @@ static void container_move_to_container_from_direction(
static void container_move_to_workspace_from_direction(
struct sway_container *container, struct sway_workspace *workspace,
enum wlr_direction move_dir) {
+ container->width = container->height = 0;
+
if (is_parallel(workspace->layout, move_dir)) {
wlr_log(WLR_DEBUG, "Reparenting container (parallel)");
int index =
@@ -216,6 +218,7 @@ static void container_move_to_container(struct sway_container *container,
return;
}
if (container_is_floating(container)) {
+ container_move_to_workspace(container, destination->workspace);
return;
}
struct sway_workspace *old_workspace = container->workspace;
diff --git a/sway/commands/no_focus.c b/sway/commands/no_focus.c
index 61a8de7e..cb81a445 100644
--- a/sway/commands/no_focus.c
+++ b/sway/commands/no_focus.c
@@ -1,4 +1,3 @@
-#define _XOPEN_SOURCE 500
#include <string.h>
#include "sway/commands.h"
#include "sway/criteria.h"
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 30fb47c4..2cd1b76a 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -116,11 +116,8 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
if (!can_access) {
wlr_log(WLR_ERROR, "Unable to access background file '%s': %s",
src, strerror(errno));
- if (config->reading && !config->validating) {
- swaynag_log(config->swaynag_command,
- &config->swaynag_config_errors,
- "Unable to access background file '%s'", src);
- }
+ config_add_swaynag_warning("Unable to access background file '%s'",
+ src);
free(src);
} else {
// Escape double quotes in the final path for swaybg
diff --git a/sway/commands/output/transform.c b/sway/commands/output/transform.c
index c1555323..ca6f73a4 100644
--- a/sway/commands/output/transform.c
+++ b/sway/commands/output/transform.c
@@ -45,7 +45,7 @@ struct cmd_results *output_cmd_transform(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "output",
"Cannot apply relative transform to all outputs.");
}
- struct sway_output *s_output = output_by_name(output->name);
+ struct sway_output *s_output = output_by_name_or_id(output->name);
if (s_output == NULL) {
return cmd_results_new(CMD_INVALID, "output",
"Cannot apply relative transform to unknown output %s", output->name);
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 62105cdc..3ccbbf34 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
#include "sway/commands.h"
#include "sway/config.h"
@@ -24,8 +24,7 @@ static void do_reload(void *data) {
if (!load_main_config(config->current_config_path, true, false)) {
wlr_log(WLR_ERROR, "Error(s) reloading config");
- list_foreach(bar_ids, free);
- list_free(bar_ids);
+ list_free_items_and_destroy(bar_ids);
return;
}
@@ -42,9 +41,7 @@ static void do_reload(void *data) {
}
}
}
-
- list_foreach(bar_ids, free);
- list_free(bar_ids);
+ list_free_items_and_destroy(bar_ids);
config_update_font_height(true);
root_for_each_container(rebuild_textures_iterator, NULL);
diff --git a/sway/commands/rename.c b/sway/commands/rename.c
index 0cee9293..491dbab0 100644
--- a/sway/commands/rename.c
+++ b/sway/commands/rename.c
@@ -1,4 +1,3 @@
-#define _XOPEN_SOURCE 500
#include <ctype.h>
#include <string.h>
#include <strings.h>
@@ -82,8 +81,12 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
struct sway_workspace *tmp_workspace = workspace_by_name(new_name);
if (tmp_workspace) {
free(new_name);
- return cmd_results_new(CMD_INVALID, "rename",
- "Workspace already exists");
+ if (tmp_workspace == workspace) {
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ } else {
+ return cmd_results_new(CMD_INVALID, "rename",
+ "Workspace already exists");
+ }
}
wlr_log(WLR_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
diff --git a/sway/commands/resize.c b/sway/commands/resize.c
index a90d578e..cf5dea02 100644
--- a/sway/commands/resize.c
+++ b/sway/commands/resize.c
@@ -512,34 +512,42 @@ static struct cmd_results *resize_set_floating(struct sway_container *con,
calculate_constraints(&min_width, &max_width, &min_height, &max_height);
if (width->amount) {
- if (width->unit == RESIZE_UNIT_PPT ||
- width->unit == RESIZE_UNIT_DEFAULT) {
+ switch (width->unit) {
+ case RESIZE_UNIT_PPT:
// Convert to px
width->amount = con->workspace->width * width->amount / 100;
width->unit = RESIZE_UNIT_PX;
- }
- if (width->unit == RESIZE_UNIT_PX) {
+ // Falls through
+ case RESIZE_UNIT_PX:
+ case RESIZE_UNIT_DEFAULT:
width->amount = fmax(min_width, fmin(width->amount, max_width));
grow_width = width->amount - con->width;
-
con->x -= grow_width / 2;
con->width = width->amount;
+ break;
+ case RESIZE_UNIT_INVALID:
+ sway_assert(false, "invalid width unit");
+ break;
}
}
if (height->amount) {
- if (height->unit == RESIZE_UNIT_PPT ||
- height->unit == RESIZE_UNIT_DEFAULT) {
+ switch (height->unit) {
+ case RESIZE_UNIT_PPT:
// Convert to px
height->amount = con->workspace->height * height->amount / 100;
height->unit = RESIZE_UNIT_PX;
- }
- if (height->unit == RESIZE_UNIT_PX) {
+ // Falls through
+ case RESIZE_UNIT_PX:
+ case RESIZE_UNIT_DEFAULT:
height->amount = fmax(min_height, fmin(height->amount, max_height));
grow_height = height->amount - con->height;
-
con->y -= grow_height / 2;
con->height = height->amount;
+ break;
+ case RESIZE_UNIT_INVALID:
+ sway_assert(false, "invalid height unit");
+ break;
}
}
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
index 5abb19b0..b8db862b 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -10,6 +10,7 @@ static struct cmd_handler seat_handlers[] = {
{ "attach", seat_cmd_attach },
{ "cursor", seat_cmd_cursor },
{ "fallback", seat_cmd_fallback },
+ { "hide_cursor", seat_cmd_hide_cursor },
};
struct cmd_results *cmd_seat(int argc, char **argv) {
@@ -26,9 +27,18 @@ struct cmd_results *cmd_seat(int argc, char **argv) {
struct cmd_results *res = config_subcommand(argv + 1, argc - 1,
seat_handlers, sizeof(seat_handlers));
+ if (res && res->status != CMD_SUCCESS) {
+ free_seat_config(config->handler_context.seat_config);
+ config->handler_context.seat_config = NULL;
+ return res;
+ }
- free_seat_config(config->handler_context.seat_config);
- config->handler_context.seat_config = NULL;
+ struct seat_config *sc =
+ store_seat_config(config->handler_context.seat_config);
+ if (!config->reading) {
+ input_manager_apply_seat_config(sc);
+ }
- return res;
+ config->handler_context.seat_config = NULL;
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c
index 6b4bcf1f..0fb17f1d 100644
--- a/sway/commands/seat/attach.c
+++ b/sway/commands/seat/attach.c
@@ -1,10 +1,7 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <string.h>
-#include <strings.h>
-#include "sway/input/input-manager.h"
#include "sway/commands.h"
#include "sway/config.h"
-#include "log.h"
#include "stringop.h"
struct cmd_results *seat_cmd_attach(int argc, char **argv) {
@@ -12,19 +9,17 @@ struct cmd_results *seat_cmd_attach(int argc, char **argv) {
if ((error = checkarg(argc, "attach", EXPECTED_AT_LEAST, 1))) {
return error;
}
- struct seat_config *current_seat_config =
- config->handler_context.seat_config;
- if (!current_seat_config) {
+ if (!config->handler_context.seat_config) {
return cmd_results_new(CMD_FAILURE, "attach", "No seat defined");
}
- struct seat_config *new_config = new_seat_config(current_seat_config->name);
- struct seat_attachment_config *new_attachment = seat_attachment_config_new();
- new_attachment->identifier = strdup(argv[0]);
- list_add(new_config->attachments, new_attachment);
-
- if (!config->validating) {
- apply_seat_config(new_config);
+ struct seat_attachment_config *attachment = seat_attachment_config_new();
+ if (!attachment) {
+ return cmd_results_new(CMD_FAILURE, "attach",
+ "Failed to allocate seat attachment config");
}
+ attachment->identifier = strdup(argv[0]);
+ list_add(config->handler_context.seat_config->attachments, attachment);
+
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c
index 1d41a94e..8d9e426a 100644
--- a/sway/commands/seat/cursor.c
+++ b/sway/commands/seat/cursor.c
@@ -1,12 +1,9 @@
-#define _XOPEN_SOURCE 700
-#ifdef __linux__
+#define _POSIX_C_SOURCE 200809L
#include <linux/input-event-codes.h>
-#elif __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#endif
#include <strings.h>
#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_pointer.h>
#include "sway/commands.h"
#include "sway/input/cursor.h"
@@ -15,20 +12,10 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
static const char *expected_syntax = "Expected 'cursor <move> <x> <y>' or "
"'cursor <set> <x> <y>' or "
- "'curor <press|release> <left|right|1|2|3...>'";
-
-struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
- struct cmd_results *error = NULL;
- if ((error = checkarg(argc, "cursor", EXPECTED_AT_LEAST, 2))) {
- return error;
- }
- struct sway_seat *seat = config->handler_context.seat;
- if (!seat) {
- return cmd_results_new(CMD_FAILURE, "cursor", "No seat defined");
- }
-
- struct sway_cursor *cursor = seat->cursor;
+ "'curor <press|release> <button[1-9]|event-name-or-code>'";
+static struct cmd_results *handle_command(struct sway_cursor *cursor,
+ int argc, char **argv) {
if (strcasecmp(argv[0], "move") == 0) {
if (argc < 3) {
return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
@@ -50,6 +37,7 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
if (argc < 2) {
return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
}
+ struct cmd_results *error = NULL;
if ((error = press_or_release(cursor, argv[0], argv[1]))) {
return error;
}
@@ -58,6 +46,40 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
+struct cmd_results *seat_cmd_cursor(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "cursor", EXPECTED_AT_LEAST, 2))) {
+ return error;
+ }
+ struct seat_config *sc = config->handler_context.seat_config;
+ if (!sc) {
+ return cmd_results_new(CMD_FAILURE, "cursor", "No seat defined");
+ }
+
+ if (config->reading || !config->active) {
+ return cmd_results_new(CMD_DEFER, NULL, NULL);
+ }
+
+ if (strcmp(sc->name, "*") != 0) {
+ struct sway_seat *seat = input_manager_get_seat(sc->name);
+ if (!seat) {
+ return cmd_results_new(CMD_FAILURE, "cursor",
+ "Failed to get seat");
+ }
+ error = handle_command(seat->cursor, argc, argv);
+ } else {
+ struct sway_seat *seat = NULL;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ error = handle_command(seat->cursor, argc, argv);
+ if ((error && error->status != CMD_SUCCESS)) {
+ break;
+ }
+ }
+ }
+
+ return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
+
static struct cmd_results *press_or_release(struct sway_cursor *cursor,
char *action, char *button_str) {
enum wlr_button_state state;
@@ -70,15 +92,35 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
}
- if (strcasecmp(button_str, "left") == 0) {
- button = BTN_LEFT;
- } else if (strcasecmp(button_str, "right") == 0) {
- button = BTN_RIGHT;
- } else {
- button = strtol(button_str, NULL, 10);
- if (button == 0) {
- return cmd_results_new(CMD_INVALID, "cursor", expected_syntax);
- }
+ char *message = NULL;
+ button = get_mouse_button(button_str, &message);
+ if (message) {
+ struct cmd_results *error =
+ cmd_results_new(CMD_INVALID, "cursor", message);
+ free(message);
+ return error;
+ } else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN
+ || button == SWAY_SCROLL_LEFT || button == SWAY_SCROLL_RIGHT) {
+ // Dispatch axis event
+ enum wlr_axis_orientation orientation =
+ (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN)
+ ? WLR_AXIS_ORIENTATION_VERTICAL
+ : WLR_AXIS_ORIENTATION_HORIZONTAL;
+ double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT)
+ ? -1 : 1;
+ struct wlr_event_pointer_axis event = {
+ .device = NULL,
+ .time_msec = 0,
+ .source = WLR_AXIS_SOURCE_WHEEL,
+ .orientation = orientation,
+ .delta = delta * 15,
+ .delta_discrete = delta
+ };
+ dispatch_cursor_axis(cursor, &event);
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ } else if (!button) {
+ return cmd_results_new(CMD_INVALID, "curor",
+ "Unknown button %s", button_str);
}
dispatch_cursor_button(cursor, NULL, 0, button, state);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/seat/fallback.c b/sway/commands/seat/fallback.c
index a0ddf3ef..8f1ab12c 100644
--- a/sway/commands/seat/fallback.c
+++ b/sway/commands/seat/fallback.c
@@ -1,27 +1,18 @@
-#include <string.h>
-#include <strings.h>
#include "sway/config.h"
#include "sway/commands.h"
-#include "sway/input/input-manager.h"
#include "util.h"
struct cmd_results *seat_cmd_fallback(int argc, char **argv) {
struct cmd_results *error = NULL;
- if ((error = checkarg(argc, "fallback", EXPECTED_AT_LEAST, 1))) {
+ if ((error = checkarg(argc, "fallback", EXPECTED_EQUAL_TO, 1))) {
return error;
}
- struct seat_config *current_seat_config =
- config->handler_context.seat_config;
- if (!current_seat_config) {
+ if (!config->handler_context.seat_config) {
return cmd_results_new(CMD_FAILURE, "fallback", "No seat defined");
}
- struct seat_config *new_config =
- new_seat_config(current_seat_config->name);
-
- new_config->fallback = parse_boolean(argv[0], false);
- if (!config->validating) {
- apply_seat_config(new_config);
- }
+ config->handler_context.seat_config->fallback =
+ parse_boolean(argv[0], false);
+
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
diff --git a/sway/commands/seat/hide_cursor.c b/sway/commands/seat/hide_cursor.c
new file mode 100644
index 00000000..343573b5
--- /dev/null
+++ b/sway/commands/seat/hide_cursor.c
@@ -0,0 +1,29 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/input/seat.h"
+#include "stringop.h"
+
+struct cmd_results *seat_cmd_hide_cursor(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "hide_cursor", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+ if (!config->handler_context.seat_config) {
+ return cmd_results_new(CMD_FAILURE, "hide_cursor", "No seat defined");
+ }
+
+ char *end;
+ int timeout = strtol(argv[0], &end, 10);
+ if (*end) {
+ return cmd_results_new(CMD_INVALID, "hide_cursor",
+ "Expected an integer timeout");
+ }
+ if (timeout < 100 && timeout != 0) {
+ timeout = 100;
+ }
+ config->handler_context.seat_config->hide_cursor_timeout = timeout;
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/set.c b/sway/commands/set.c
index be51230b..d912e4fd 100644
--- a/sway/commands/set.c
+++ b/sway/commands/set.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <string.h>
#include <strings.h>
diff --git a/sway/commands/split.c b/sway/commands/split.c
index ed106a86..84385fa9 100644
--- a/sway/commands/split.c
+++ b/sway/commands/split.c
@@ -18,6 +18,10 @@ static struct cmd_results *do_split(int layout) {
workspace_split(ws, layout);
}
+ if (con && con->parent && con->parent->parent) {
+ container_flatten(con->parent->parent);
+ }
+
arrange_workspace(ws);
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index 08860264..670d6bca 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -108,7 +108,7 @@ static void container_swap(struct sway_container *con1,
container_set_fullscreen(con2, false);
}
- struct sway_seat *seat = input_manager_get_default_seat();
+ struct sway_seat *seat = config->handler_context.seat;
struct sway_container *focus = seat_get_focused_container(seat);
struct sway_workspace *vis1 =
output_get_active_workspace(con1->workspace->output);
diff --git a/sway/commands/tiling_drag_threshold.c b/sway/commands/tiling_drag_threshold.c
new file mode 100644
index 00000000..6b0531c3
--- /dev/null
+++ b/sway/commands/tiling_drag_threshold.c
@@ -0,0 +1,22 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "log.h"
+
+struct cmd_results *cmd_tiling_drag_threshold(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "tiling_drag_threshold", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+
+ char *inv;
+ int value = strtol(argv[0], &inv, 10);
+ if (*inv != '\0' || value < 0) {
+ return cmd_results_new(CMD_INVALID, "tiling_drag_threshold",
+ "Invalid threshold specified");
+ }
+
+ config->tiling_drag_threshold = value;
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/title_align.c b/sway/commands/title_align.c
new file mode 100644
index 00000000..82578186
--- /dev/null
+++ b/sway/commands/title_align.c
@@ -0,0 +1,30 @@
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/output.h"
+#include "sway/tree/container.h"
+#include "sway/tree/root.h"
+
+struct cmd_results *cmd_title_align(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ if (strcmp(argv[0], "left") == 0) {
+ config->title_align = ALIGN_LEFT;
+ } else if (strcmp(argv[0], "center") == 0) {
+ config->title_align = ALIGN_CENTER;
+ } else if (strcmp(argv[0], "right") == 0) {
+ config->title_align = ALIGN_RIGHT;
+ } else {
+ return cmd_results_new(CMD_INVALID, "title_align",
+ "Expected 'title_align left|center|right'");
+ }
+
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole(output);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/titlebar_border_thickness.c b/sway/commands/titlebar_border_thickness.c
new file mode 100644
index 00000000..c1e9bb52
--- /dev/null
+++ b/sway/commands/titlebar_border_thickness.c
@@ -0,0 +1,30 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/output.h"
+#include "sway/tree/arrange.h"
+#include "log.h"
+
+struct cmd_results *cmd_titlebar_border_thickness(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "titlebar_border_thickness", EXPECTED_EQUAL_TO, 1))) {
+ return error;
+ }
+
+ char *inv;
+ int value = strtol(argv[0], &inv, 10);
+ if (*inv != '\0' || value < 0 || value > config->titlebar_v_padding) {
+ return cmd_results_new(CMD_FAILURE, "titlebar_border_thickness",
+ "Invalid size specified");
+ }
+
+ config->titlebar_border_thickness = value;
+
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ arrange_workspace(output_get_active_workspace(output));
+ output_damage_whole(output);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/titlebar_padding.c b/sway/commands/titlebar_padding.c
new file mode 100644
index 00000000..a642e945
--- /dev/null
+++ b/sway/commands/titlebar_padding.c
@@ -0,0 +1,42 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/output.h"
+#include "sway/tree/arrange.h"
+#include "log.h"
+
+struct cmd_results *cmd_titlebar_padding(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "titlebar_padding", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+
+ char *inv;
+ int h_value = strtol(argv[0], &inv, 10);
+ if (*inv != '\0' || h_value < 0 || h_value < config->titlebar_border_thickness) {
+ return cmd_results_new(CMD_FAILURE, "titlebar_padding",
+ "Invalid size specified");
+ }
+
+ int v_value;
+ if (argc == 1) {
+ v_value = h_value;
+ } else {
+ v_value = strtol(argv[1], &inv, 10);
+ if (*inv != '\0' || v_value < 0 || v_value < config->titlebar_border_thickness) {
+ return cmd_results_new(CMD_FAILURE, "titlebar_padding",
+ "Invalid size specified");
+ }
+ }
+
+ config->titlebar_v_padding = v_value;
+ config->titlebar_h_padding = h_value;
+
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ arrange_workspace(output_get_active_workspace(output));
+ output_damage_whole(output);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c
index 92118ecf..211b344d 100644
--- a/sway/commands/workspace.c
+++ b/sway/commands/workspace.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 500
+#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <limits.h>
#include <string.h>
@@ -33,12 +33,12 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
void free_workspace_config(struct workspace_config *wsc) {
free(wsc->workspace);
- free_flat_list(wsc->outputs);
+ list_free_items_and_destroy(wsc->outputs);
free(wsc);
}
static void prevent_invalid_outer_gaps(struct workspace_config *wsc) {
- if (wsc->gaps_outer.top != INT_MIN &&
+ if (wsc->gaps_outer.top != INT_MIN &&
wsc->gaps_outer.top < -wsc->gaps_inner) {
wsc->gaps_outer.top = -wsc->gaps_inner;
}
diff --git a/sway/config.c b/sway/config.c
index 6f65d0c2..18fee404 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -1,5 +1,4 @@
-#define _POSIX_C_SOURCE 200809L
-#define _XOPEN_SOURCE 700
+#define _XOPEN_SOURCE 700 // for realpath
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -14,11 +13,7 @@
#include <limits.h>
#include <dirent.h>
#include <strings.h>
-#ifdef __linux__
#include <linux/input-event-codes.h>
-#elif __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#endif
#include <wlr/types/wlr_output.h>
#include "sway/input/input-manager.h"
#include "sway/input/seat.h"
@@ -31,7 +26,6 @@
#include "sway/tree/workspace.h"
#include "cairo.h"
#include "pango.h"
-#include "readline.h"
#include "stringop.h"
#include "list.h"
#include "log.h"
@@ -39,26 +33,24 @@
struct sway_config *config = NULL;
static void free_mode(struct sway_mode *mode) {
- int i;
-
if (!mode) {
return;
}
free(mode->name);
if (mode->keysym_bindings) {
- for (i = 0; i < mode->keysym_bindings->length; i++) {
+ for (int i = 0; i < mode->keysym_bindings->length; i++) {
free_sway_binding(mode->keysym_bindings->items[i]);
}
list_free(mode->keysym_bindings);
}
if (mode->keycode_bindings) {
- for (i = 0; i < mode->keycode_bindings->length; i++) {
+ for (int i = 0; i < mode->keycode_bindings->length; i++) {
free_sway_binding(mode->keycode_bindings->items[i]);
}
list_free(mode->keycode_bindings);
}
if (mode->mouse_bindings) {
- for (i = 0; i < mode->mouse_bindings->length; i++) {
+ for (int i = 0; i < mode->mouse_bindings->length; i++) {
free_sway_binding(mode->mouse_bindings->items[i]);
}
list_free(mode->mouse_bindings);
@@ -214,6 +206,10 @@ static void config_defaults(struct sway_config *config) {
config->popup_during_fullscreen = POPUP_SMART;
config->xwayland = true;
+ config->titlebar_border_thickness = 1;
+ config->titlebar_h_padding = 5;
+ config->titlebar_v_padding = 4;
+
// floating view
config->floating_maximum_width = 0;
config->floating_maximum_height = 0;
@@ -231,7 +227,9 @@ static void config_defaults(struct sway_config *config) {
config->auto_back_and_forth = false;
config->reading = false;
config->show_marks = true;
+ config->title_align = ALIGN_LEFT;
config->tiling_drag = true;
+ config->tiling_drag_threshold = 9;
config->smart_gaps = false;
config->gaps_inner = 0;
@@ -313,27 +311,16 @@ static char *get_config_path(void) {
SYSCONFDIR "/i3/config",
};
- if (!getenv("XDG_CONFIG_HOME")) {
- char *home = getenv("HOME");
- char *config_home = malloc(strlen(home) + strlen("/.config") + 1);
- if (!config_home) {
- wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config");
- } else {
- strcpy(config_home, home);
- strcat(config_home, "/.config");
- setenv("XDG_CONFIG_HOME", config_home, 1);
- wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home);
- free(config_home);
- }
+ char *config_home = getenv("XDG_CONFIG_HOME");
+ if (!config_home || !*config_home) {
+ config_paths[1] = "$HOME/.config/sway/config";
+ config_paths[3] = "$HOME/.config/i3/config";
}
- wordexp_t p;
- char *path;
-
- int i;
- for (i = 0; i < (int)(sizeof(config_paths) / sizeof(char *)); ++i) {
- if (wordexp(config_paths[i], &p, 0) == 0) {
- path = strdup(p.we_wordv[0]);
+ for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) {
+ wordexp_t p;
+ if (wordexp(config_paths[i], &p, WRDE_UNDEF) == 0) {
+ char *path = strdup(p.we_wordv[0]);
wordfree(&p);
if (file_exists(path)) {
return path;
@@ -342,7 +329,7 @@ static char *get_config_path(void) {
}
}
- return NULL; // Not reached
+ return NULL;
}
static bool load_config(const char *path, struct sway_config *config,
@@ -402,7 +389,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
&old_config->swaynag_config_errors,
sizeof(struct swaynag_instance));
- create_default_output_configs();
+ input_manager_reset_all_inputs();
}
config->current_config_path = path;
@@ -454,7 +441,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
}
}
- free_flat_list(secconfigs);
+ list_free_items_and_destroy(secconfigs);
}
*/
@@ -475,6 +462,11 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
if (config->swaynag_config_errors.pid > 0) {
swaynag_show(&config->swaynag_config_errors);
}
+
+ input_manager_verify_fallback_seat();
+ for (int i = 0; i < config->seat_configs->length; i++) {
+ input_manager_apply_seat_config(config->seat_configs->items[i]);
+ }
}
if (old_config) {
@@ -581,29 +573,56 @@ bool load_include_configs(const char *path, struct sway_config *config,
return true;
}
-static int detect_brace_on_following_line(FILE *file, char *line,
- int line_number) {
- int lines = 0;
- if (line[strlen(line) - 1] != '{' && line[strlen(line) - 1] != '}') {
- char *peeked = NULL;
- long position = 0;
- do {
- free(peeked);
- peeked = peek_line(file, lines, &position);
- if (peeked) {
- peeked = strip_whitespace(peeked);
+// get line, with backslash continuation
+static ssize_t getline_with_cont(char **lineptr, size_t *line_size, FILE *file,
+ int *nlines) {
+ char *next_line = NULL;
+ size_t next_line_size = 0;
+ ssize_t nread = getline(lineptr, line_size, file);
+ *nlines = nread == -1 ? 0 : 1;
+ while (nread >= 2 && strcmp(&(*lineptr)[nread - 2], "\\\n") == 0) {
+ ssize_t next_nread = getline(&next_line, &next_line_size, file);
+ if (next_nread == -1) {
+ break;
+ }
+ (*nlines)++;
+
+ nread += next_nread - 2;
+ if ((ssize_t) *line_size < nread + 1) {
+ *line_size = nread + 1;
+ *lineptr = realloc(*lineptr, *line_size);
+ if (!*lineptr) {
+ nread = -1;
+ break;
}
- lines++;
- } while (peeked && strlen(peeked) == 0);
+ }
+ strcpy(&(*lineptr)[nread - next_nread], next_line);
+ }
+ free(next_line);
+ return nread;
+}
- if (peeked && strlen(peeked) == 1 && peeked[0] == '{') {
- fseek(file, position, SEEK_SET);
- } else {
- lines = 0;
+static int detect_brace(FILE *file) {
+ int ret = 0;
+ int lines = 0;
+ long pos = ftell(file);
+ char *line = NULL;
+ size_t line_size = 0;
+ while ((getline(&line, &line_size, file)) != -1) {
+ lines++;
+ strip_whitespace(line);
+ if (*line) {
+ if (strcmp(line, "{") == 0) {
+ ret = lines;
+ }
+ break;
}
- free(peeked);
}
- return lines;
+ free(line);
+ if (ret == 0) {
+ fseek(file, pos, SEEK_SET);
+ }
+ return ret;
}
static char *expand_line(const char *block, const char *line, bool add_brace) {
@@ -645,58 +664,51 @@ bool read_config(FILE *file, struct sway_config *config,
bool success = true;
int line_number = 0;
- char *line;
+ char *line = NULL;
+ size_t line_size = 0;
+ ssize_t nread;
list_t *stack = create_list();
size_t read = 0;
- while (!feof(file)) {
- char *block = stack->length ? stack->items[0] : NULL;
- line = read_line(file);
- if (!line) {
- continue;
- }
- line_number++;
- wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line);
-
+ int nlines = 0;
+ while ((nread = getline_with_cont(&line, &line_size, file, &nlines)) != -1) {
if (reading_main_config) {
- size_t length = strlen(line);
-
- if (read + length > config_size) {
+ if (read + nread > config_size) {
wlr_log(WLR_ERROR, "Config file changed during reading");
- list_foreach(stack, free);
- list_free(stack);
- free(line);
- return false;
+ success = false;
+ break;
}
- strcpy(this_config + read, line);
- if (line_number != 1) {
- this_config[read - 1] = '\n';
- }
- read += length + 1;
+ strcpy(&this_config[read], line);
+ read += nread;
}
- line = strip_whitespace(line);
- if (line[0] == '#') {
- free(line);
- continue;
+ if (line[nread - 1] == '\n') {
+ line[nread - 1] = '\0';
}
- if (strlen(line) == 0) {
- free(line);
+
+ line_number += nlines;
+ wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line);
+
+ strip_whitespace(line);
+ if (!*line || line[0] == '#') {
continue;
}
- int brace_detected = detect_brace_on_following_line(file, line,
- line_number);
- if (brace_detected > 0) {
- line_number += brace_detected;
- wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number);
+ int brace_detected = 0;
+ if (line[strlen(line) - 1] != '{' && line[strlen(line) - 1] != '}') {
+ brace_detected = detect_brace(file);
+ if (brace_detected > 0) {
+ line_number += brace_detected;
+ wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number);
+ }
}
+ char *block = stack->length ? stack->items[0] : NULL;
char *expanded = expand_line(block, line, brace_detected > 0);
if (!expanded) {
- list_foreach(stack, free);
- list_free(stack);
- free(line);
- return false;
+ success = false;
+ break;
}
+ config->current_config_line_number = line_number;
+ config->current_config_line = line;
struct cmd_results *res;
if (block && strcmp(block, "<commands>") == 0) {
// Special case
@@ -753,15 +765,40 @@ bool read_config(FILE *file, struct sway_config *config,
default:;
}
free(expanded);
- free(line);
free_cmd_results(res);
}
- list_foreach(stack, free);
- list_free(stack);
+ free(line);
+ list_free_items_and_destroy(stack);
+ config->current_config_line_number = 0;
+ config->current_config_line = NULL;
return success;
}
+void config_add_swaynag_warning(char *fmt, ...) {
+ if (config->reading && !config->validating) {
+ va_list args;
+ va_start(args, fmt);
+ size_t length = vsnprintf(NULL, 0, fmt, args) + 1;
+ va_end(args);
+
+ char *temp = malloc(length + 1);
+ if (!temp) {
+ wlr_log(WLR_ERROR, "Failed to allocate buffer for warning.");
+ return;
+ }
+
+ va_start(args, fmt);
+ vsnprintf(temp, length, fmt, args);
+ va_end(args);
+
+ swaynag_log(config->swaynag_command, &config->swaynag_config_errors,
+ "Warning on line %i (%s) '%s': %s",
+ config->current_config_line_number, config->current_config_path,
+ config->current_config_line, temp);
+ }
+}
+
char *do_var_replacement(char *str) {
int i;
char *find = str;
diff --git a/sway/config/bar.c b/sway/config/bar.c
index 7bca5f49..701bf051 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -1,5 +1,4 @@
#define _POSIX_C_SOURCE 200809L
-#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
@@ -13,6 +12,7 @@
#include <signal.h>
#include "sway/config.h"
#include "sway/output.h"
+#include "config.h"
#include "stringop.h"
#include "list.h"
#include "log.h"
@@ -50,13 +50,10 @@ void free_bar_config(struct bar_config *bar) {
free(bar->font);
free(bar->separator_symbol);
for (int i = 0; i < bar->bindings->length; i++) {
- struct bar_binding *binding = bar->bindings->items[i];
- free_bar_binding(binding);
+ free_bar_binding(bar->bindings->items[i]);
}
list_free(bar->bindings);
- if (bar->outputs) {
- free_flat_list(bar->outputs);
- }
+ list_free_items_and_destroy(bar->outputs);
if (bar->pid != 0) {
terminate_swaybar(bar->pid);
}
@@ -81,6 +78,10 @@ void free_bar_config(struct bar_config *bar) {
free(bar->colors.binding_mode_border);
free(bar->colors.binding_mode_bg);
free(bar->colors.binding_mode_text);
+#if HAVE_TRAY
+ list_free_items_and_destroy(bar->tray_outputs);
+ free(bar->icon_theme);
+#endif
free(bar);
}
@@ -95,15 +96,18 @@ struct bar_config *default_bar_config(void) {
bar->pango_markup = false;
bar->swaybar_command = NULL;
bar->font = NULL;
- bar->height = -1;
+ bar->height = 0;
bar->workspace_buttons = true;
bar->wrap_scroll = false;
bar->separator_symbol = NULL;
bar->strip_workspace_numbers = false;
+ bar->strip_workspace_name = false;
bar->binding_mode_indicator = true;
bar->verbose = false;
bar->pid = 0;
bar->modifier = get_modifier_mask_by_name("Mod4");
+ bar->status_padding = 1;
+ bar->status_edge_padding = 3;
if (!(bar->mode = strdup("dock"))) {
goto cleanup;
}
@@ -168,6 +172,10 @@ struct bar_config *default_bar_config(void) {
bar->colors.binding_mode_bg = NULL;
bar->colors.binding_mode_text = NULL;
+#if HAVE_TRAY
+ bar->tray_padding = 2;
+#endif
+
list_add(config->bars, bar);
return bar;
cleanup:
diff --git a/sway/config/input.c b/sway/config/input.c
index d5d2d90b..d649d34d 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <limits.h>
#include <float.h>
diff --git a/sway/config/output.c b/sway/config/output.c
index 07543e3c..f24e7d66 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdbool.h>
#include <string.h>
@@ -179,10 +179,6 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) {
if (oc && oc->enabled == 0) {
if (output->enabled) {
- if (output->bg_pid != 0) {
- terminate_swaybg(output->bg_pid);
- output->bg_pid = 0;
- }
output_disable(output);
wlr_output_layout_remove(root->output_layout, wlr_output);
}
@@ -276,18 +272,86 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) {
}
}
-static struct output_config *get_output_config(char *name, char *identifier) {
+static void default_output_config(struct output_config *oc,
+ struct wlr_output *wlr_output) {
+ oc->enabled = 1;
+ if (!wl_list_empty(&wlr_output->modes)) {
+ struct wlr_output_mode *mode =
+ wl_container_of(wlr_output->modes.prev, mode, link);
+ oc->width = mode->width;
+ oc->height = mode->height;
+ oc->refresh_rate = mode->refresh;
+ }
+ oc->x = oc->y = -1;
+ oc->scale = 1;
+ oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+}
+
+static struct output_config *get_output_config(char *identifier,
+ struct sway_output *sway_output) {
+ const char *name = sway_output->wlr_output->name;
+ struct output_config *oc_name = NULL;
int i = list_seq_find(config->output_configs, output_name_cmp, name);
if (i >= 0) {
- return config->output_configs->items[i];
+ oc_name = config->output_configs->items[i];
}
+ struct output_config *oc_id = NULL;
i = list_seq_find(config->output_configs, output_name_cmp, identifier);
if (i >= 0) {
- return config->output_configs->items[i];
+ oc_id = config->output_configs->items[i];
+ }
+
+ struct output_config *result = result = new_output_config("temp");
+ if (config->reloading) {
+ default_output_config(result, sway_output->wlr_output);
+ }
+ if (oc_name && oc_id) {
+ // Generate a config named `<identifier> on <name>` which contains a
+ // merged copy of the identifier on name. This will make sure that both
+ // identifier and name configs are respected, with identifier getting
+ // priority
+ size_t length = snprintf(NULL, 0, "%s on %s", identifier, name) + 1;
+ char *temp = malloc(length);
+ snprintf(temp, length, "%s on %s", identifier, name);
+
+ free(result->name);
+ result->name = temp;
+ merge_output_config(result, oc_name);
+ merge_output_config(result, oc_id);
+
+ wlr_log(WLR_DEBUG, "Generated output config \"%s\" (enabled: %d)"
+ " (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
+ " (dpms %d)", result->name, result->enabled, result->width,
+ result->height, result->refresh_rate, result->x, result->y,
+ result->scale, result->transform, result->background,
+ result->background_option, result->dpms_state);
+ } else if (oc_name) {
+ // No identifier config, just return a copy of the name config
+ free(result->name);
+ result->name = strdup(name);
+ merge_output_config(result, oc_name);
+ } else if (oc_id) {
+ // No name config, just return a copy of the identifier config
+ free(result->name);
+ result->name = strdup(identifier);
+ merge_output_config(result, oc_id);
+ } else if (config->reloading) {
+ // Neither config exists, but we need to reset the output so create a
+ // default config for the output and if a wildcard config exists, merge
+ // that on top
+ free(result->name);
+ result->name = strdup("*");
+ i = list_seq_find(config->output_configs, output_name_cmp, "*");
+ if (i >= 0) {
+ merge_output_config(result, config->output_configs->items[i]);
+ }
+ } else {
+ free_output_config(result);
+ result = NULL;
}
- return NULL;
+ return result;
}
void apply_output_config_to_outputs(struct output_config *oc) {
@@ -301,14 +365,17 @@ void apply_output_config_to_outputs(struct output_config *oc) {
char *name = sway_output->wlr_output->name;
output_get_identifier(id, sizeof(id), sway_output);
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
- struct output_config *current = oc;
+ struct output_config *current = new_output_config(oc->name);
+ merge_output_config(current, oc);
if (wildcard) {
- struct output_config *tmp = get_output_config(name, id);
+ struct output_config *tmp = get_output_config(id, sway_output);
if (tmp) {
+ free_output_config(current);
current = tmp;
}
}
apply_output_config(current, sway_output);
+ free_output_config(current);
if (!wildcard) {
// Stop looking if the output config isn't applicable to all
@@ -329,28 +396,3 @@ void free_output_config(struct output_config *oc) {
free(oc->background_fallback);
free(oc);
}
-
-static void default_output_config(struct output_config *oc,
- struct wlr_output *wlr_output) {
- oc->enabled = 1;
- if (!wl_list_empty(&wlr_output->modes)) {
- struct wlr_output_mode *mode =
- wl_container_of(wlr_output->modes.prev, mode, link);
- oc->width = mode->width;
- oc->height = mode->height;
- oc->refresh_rate = mode->refresh;
- }
- oc->x = oc->y = -1;
- oc->scale = 1;
- oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
-}
-
-void create_default_output_configs(void) {
- struct sway_output *sway_output;
- wl_list_for_each(sway_output, &root->all_outputs, link) {
- char *name = sway_output->wlr_output->name;
- struct output_config *oc = new_output_config(name);
- default_output_config(oc, sway_output->wlr_output);
- list_add(config->output_configs, oc);
- }
-}
diff --git a/sway/config/seat.c b/sway/config/seat.c
index 46456caf..d7316c68 100644
--- a/sway/config/seat.c
+++ b/sway/config/seat.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include "sway/config.h"
@@ -11,7 +11,6 @@ struct seat_config *new_seat_config(const char* name) {
return NULL;
}
- wlr_log(WLR_DEBUG, "new_seat_config(%s)", name);
seat->name = strdup(name);
if (!sway_assert(seat->name, "could not allocate name for seat")) {
free(seat);
@@ -26,10 +25,57 @@ struct seat_config *new_seat_config(const char* name) {
free(seat);
return NULL;
}
+ seat->hide_cursor_timeout = -1;
return seat;
}
+static void merge_wildcard_on_all(struct seat_config *wildcard) {
+ for (int i = 0; i < config->seat_configs->length; i++) {
+ struct seat_config *sc = config->seat_configs->items[i];
+ if (strcmp(wildcard->name, sc->name) != 0) {
+ wlr_log(WLR_DEBUG, "Merging seat * config on %s", sc->name);
+ merge_seat_config(sc, wildcard);
+ }
+ }
+}
+
+struct seat_config *store_seat_config(struct seat_config *sc) {
+ bool wildcard = strcmp(sc->name, "*") == 0;
+ if (wildcard) {
+ merge_wildcard_on_all(sc);
+ }
+
+ int i = list_seq_find(config->seat_configs, seat_name_cmp, sc->name);
+ if (i >= 0) {
+ wlr_log(WLR_DEBUG, "Merging on top of existing seat config");
+ struct seat_config *current = config->seat_configs->items[i];
+ merge_seat_config(current, sc);
+ free_seat_config(sc);
+ sc = current;
+ } else if (!wildcard) {
+ wlr_log(WLR_DEBUG, "Adding non-wildcard seat config");
+ i = list_seq_find(config->seat_configs, seat_name_cmp, "*");
+ if (i >= 0) {
+ wlr_log(WLR_DEBUG, "Merging on top of seat * config");
+ struct seat_config *current = new_seat_config(sc->name);
+ merge_seat_config(current, config->seat_configs->items[i]);
+ merge_seat_config(current, sc);
+ free_seat_config(sc);
+ sc = current;
+ }
+ list_add(config->seat_configs, sc);
+ } else {
+ // New wildcard config. Just add it
+ wlr_log(WLR_DEBUG, "Adding seat * config");
+ list_add(config->seat_configs, sc);
+ }
+
+ wlr_log(WLR_DEBUG, "Config stored for seat %s", sc->name);
+
+ return sc;
+}
+
struct seat_attachment_config *seat_attachment_config_new(void) {
struct seat_attachment_config *attachment =
calloc(1, sizeof(struct seat_attachment_config));
@@ -65,11 +111,6 @@ static void merge_seat_attachment_config(struct seat_attachment_config *dest,
}
void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
- if (source->name) {
- free(dest->name);
- dest->name = strdup(source->name);
- }
-
if (source->fallback != -1) {
dest->fallback = source->fallback;
}
@@ -97,6 +138,10 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
}
}
}
+
+ if (source->hide_cursor_timeout != -1) {
+ dest->hide_cursor_timeout = source->hide_cursor_timeout;
+ }
}
struct seat_config *copy_seat_config(struct seat_config *seat) {
@@ -117,11 +162,8 @@ void free_seat_config(struct seat_config *seat) {
free(seat->name);
for (int i = 0; i < seat->attachments->length; ++i) {
- struct seat_attachment_config *attachment =
- seat->attachments->items[i];
- seat_attachment_config_free(attachment);
+ seat_attachment_config_free(seat->attachments->items[i]);
}
-
list_free(seat->attachments);
free(seat);
}
diff --git a/sway/criteria.c b/sway/criteria.c
index 3393852c..54583b04 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index d649100f..04c9b4f6 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -29,23 +29,13 @@
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
-struct sway_output *output_by_name(const char *name) {
+struct sway_output *output_by_name_or_id(const char *name_or_id) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
- if (strcasecmp(output->wlr_output->name, name) == 0) {
- return output;
- }
- }
- return NULL;
-}
-
-struct sway_output *output_by_identifier(const char *identifier) {
- for (int i = 0; i < root->outputs->length; ++i) {
- struct sway_output *output = root->outputs->items[i];
- char output_identifier[128];
- snprintf(output_identifier, sizeof(output_identifier), "%s %s %s", output->wlr_output->make,
- output->wlr_output->model, output->wlr_output->serial);
- if (strcasecmp(output_identifier, identifier) == 0) {
+ char identifier[128];
+ output_get_identifier(identifier, sizeof(identifier), output);
+ if (strcasecmp(identifier, name_or_id) == 0
+ || strcasecmp(output->wlr_output->name, name_or_id) == 0) {
return output;
}
}
@@ -110,7 +100,7 @@ static bool get_surface_box(struct surface_iterator_data *data,
}
struct wlr_box rotated_box;
- wlr_box_rotated_bounds(&box, data->rotation, &rotated_box);
+ wlr_box_rotated_bounds(&rotated_box, &box, data->rotation);
struct wlr_box output_box = {
.width = output->width,
@@ -118,7 +108,7 @@ static bool get_surface_box(struct surface_iterator_data *data,
};
struct wlr_box intersection;
- return wlr_box_intersection(&output_box, &rotated_box, &intersection);
+ return wlr_box_intersection(&intersection, &output_box, &rotated_box);
}
static void output_for_each_surface_iterator(struct wlr_surface *surface,
@@ -310,7 +300,7 @@ static int scale_length(int length, int offset, float scale) {
return round((offset + length) * scale) - round(offset * scale);
}
-static void scale_box(struct wlr_box *box, float scale) {
+void scale_box(struct wlr_box *box, float scale) {
box->width = scale_length(box->width, box->x, scale);
box->height = scale_length(box->height, box->y, scale);
box->x = round(box->x * scale);
@@ -433,7 +423,7 @@ static void damage_surface_iterator(struct sway_output *output,
}
if (whole) {
- wlr_box_rotated_bounds(&box, rotation, &box);
+ wlr_box_rotated_bounds(&box, &box, rotation);
wlr_output_damage_add_box(output->damage, &box);
}
@@ -568,6 +558,8 @@ void handle_new_output(struct wl_listener *listener, void *data) {
if (!oc || oc->enabled) {
output_enable(output, oc);
+ } else {
+ wlr_output_enable(output->wlr_output, false);
}
transaction_commit_dirty();
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 8d4a701b..a38c6a07 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -49,13 +49,6 @@ static int scale_length(int length, int offset, float scale) {
return round((offset + length) * scale) - round(offset * scale);
}
-static void scale_box(struct wlr_box *box, float scale) {
- box->width = scale_length(box->width, box->x, scale);
- box->height = scale_length(box->height, box->y, scale);
- box->x = round(box->x * scale);
- box->y = round(box->y * scale);
-}
-
static void scissor_output(struct wlr_output *wlr_output,
pixman_box32_t *rect) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
@@ -73,7 +66,7 @@ static void scissor_output(struct wlr_output *wlr_output,
enum wl_output_transform transform =
wlr_output_transform_invert(wlr_output->transform);
- wlr_box_transform(&box, transform, ow, oh, &box);
+ wlr_box_transform(&box, &box, transform, ow, oh);
wlr_renderer_scissor(renderer, &box);
}
@@ -164,7 +157,7 @@ static void render_drag_icons(struct sway_output *output,
// _box.x and .y are expected to be layout-local
// _box.width and .height are expected to be output-buffer-local
-static void render_rect(struct wlr_output *wlr_output,
+void render_rect(struct wlr_output *wlr_output,
pixman_region32_t *output_damage, const struct wlr_box *_box,
float color[static 4]) {
struct wlr_renderer *renderer =
@@ -197,7 +190,7 @@ damage_finish:
pixman_region32_fini(&damage);
}
-static void premultiply_alpha(float color[4], float opacity) {
+void premultiply_alpha(float color[4], float opacity) {
color[3] *= opacity;
color[0] *= color[3];
color[1] *= color[3];
@@ -261,7 +254,7 @@ static void render_saved_view(struct sway_view *view,
};
struct wlr_box intersection;
- bool intersects = wlr_box_intersection(&output_box, &box, &intersection);
+ bool intersects = wlr_box_intersection(&intersection, &output_box, &box);
if (!intersects) {
return;
}
@@ -368,6 +361,10 @@ static void render_titlebar(struct sway_output *output,
children->items[children->length - 1] == con;
double output_x = output->wlr_output->lx;
double output_y = output->wlr_output->ly;
+ int titlebar_border_thickness = config->titlebar_border_thickness;
+ int titlebar_h_padding = config->titlebar_h_padding;
+ int titlebar_v_padding = config->titlebar_v_padding;
+ enum alignment title_align = config->title_align;
// Single pixel bar above title
memcpy(&color, colors->border, sizeof(float) * 4);
@@ -375,7 +372,7 @@ static void render_titlebar(struct sway_output *output,
box.x = x;
box.y = y;
box.width = width;
- box.height = TITLEBAR_BORDER_THICKNESS;
+ box.height = titlebar_border_thickness;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
@@ -391,45 +388,51 @@ static void render_titlebar(struct sway_output *output,
}
}
box.x = x + left_offset;
- box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
+ box.y = y + container_titlebar_height() - titlebar_border_thickness;
box.width = width - left_offset - right_offset;
- box.height = TITLEBAR_BORDER_THICKNESS;
+ box.height = titlebar_border_thickness;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
if (layout == L_TABBED) {
// Single pixel left edge
box.x = x;
- box.y = y + TITLEBAR_BORDER_THICKNESS;
- box.width = TITLEBAR_BORDER_THICKNESS;
+ box.y = y + titlebar_border_thickness;
+ box.width = titlebar_border_thickness;
box.height =
- container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
+ container_titlebar_height() - titlebar_border_thickness * 2;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
// Single pixel right edge
- box.x = x + width - TITLEBAR_BORDER_THICKNESS;
- box.y = y + TITLEBAR_BORDER_THICKNESS;
- box.width = TITLEBAR_BORDER_THICKNESS;
+ box.x = x + width - titlebar_border_thickness;
+ box.y = y + titlebar_border_thickness;
+ box.width = titlebar_border_thickness;
box.height =
- container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
+ container_titlebar_height() - titlebar_border_thickness * 2;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
}
- size_t inner_width = width - TITLEBAR_H_PADDING * 2;
- int bg_y = y + TITLEBAR_BORDER_THICKNESS;
+ int inner_x = x - output_x + titlebar_h_padding;
+ int bg_y = y + titlebar_border_thickness;
+ size_t inner_width = width - titlebar_h_padding * 2;
+
+ // output-buffer local
+ int ob_inner_x = round(inner_x * output_scale);
+ int ob_inner_width = scale_length(inner_width, inner_x, output_scale);
int ob_bg_height = scale_length(
- (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
+ (titlebar_v_padding - titlebar_border_thickness) * 2 +
config->font_height, bg_y, output_scale);
// Marks
- int marks_ob_width = 0; // output-buffer-local
+ int ob_marks_x = 0; // output-buffer-local
+ int ob_marks_width = 0; // output-buffer-local
if (config->show_marks && marks_texture) {
struct wlr_box texture_box;
wlr_texture_get_size(marks_texture,
&texture_box.width, &texture_box.height);
- marks_ob_width = texture_box.width;
+ ob_marks_width = texture_box.width;
// The marks texture might be shorter than the config->font_height, in
// which case we need to pad it as evenly as possible above and below.
@@ -437,9 +440,15 @@ static void render_titlebar(struct sway_output *output,
int ob_padding_above = floor(ob_padding_total / 2.0);
int ob_padding_below = ceil(ob_padding_total / 2.0);
- // Render texture
- texture_box.x = round((x - output_x + width - TITLEBAR_H_PADDING)
- * output_scale) - texture_box.width;
+ // Render texture. If the title is on the right, the marks will be on
+ // the left. Otherwise, they will be on the right.
+ if (title_align == ALIGN_RIGHT || texture_box.width > ob_inner_width) {
+ texture_box.x = ob_inner_x;
+ } else {
+ texture_box.x = ob_inner_x + ob_inner_width - texture_box.width;
+ }
+ ob_marks_x = texture_box.x;
+
texture_box.y = round((bg_y - output_y) * output_scale) +
ob_padding_above;
@@ -448,8 +457,8 @@ static void render_titlebar(struct sway_output *output,
WL_OUTPUT_TRANSFORM_NORMAL,
0.0, output->wlr_output->transform_matrix);
- if (inner_width * output_scale < texture_box.width) {
- texture_box.width = inner_width * output_scale;
+ if (ob_inner_width < texture_box.width) {
+ texture_box.width = ob_inner_width;
}
render_texture(output->wlr_output, output_damage, marks_texture,
&texture_box, matrix, con->alpha);
@@ -458,7 +467,7 @@ static void render_titlebar(struct sway_output *output,
memcpy(&color, colors->background, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
box.x = texture_box.x + round(output_x * output_scale);
- box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale);
+ box.y = round((y + titlebar_border_thickness) * output_scale);
box.width = texture_box.width;
box.height = ob_padding_above;
render_rect(output->wlr_output, output_damage, &box, color);
@@ -470,24 +479,43 @@ static void render_titlebar(struct sway_output *output,
}
// Title text
- size_t title_ob_width = 0; // output-buffer-local
+ int ob_title_x = 0; // output-buffer-local
+ int ob_title_width = 0; // output-buffer-local
if (title_texture) {
struct wlr_box texture_box;
wlr_texture_get_size(title_texture,
&texture_box.width, &texture_box.height);
- title_ob_width = texture_box.width;
+ ob_title_width = texture_box.width;
// The title texture might be shorter than the config->font_height,
// in which case we need to pad it above and below.
int ob_padding_above = round((config->font_baseline -
- con->title_baseline + TITLEBAR_V_PADDING -
- TITLEBAR_BORDER_THICKNESS) * output_scale);
+ con->title_baseline + titlebar_v_padding -
+ titlebar_border_thickness) * output_scale);
int ob_padding_below = ob_bg_height - ob_padding_above -
texture_box.height;
// Render texture
- texture_box.x =
- round((x - output_x + TITLEBAR_H_PADDING) * output_scale);
+ if (texture_box.width > ob_inner_width - ob_marks_width) {
+ texture_box.x = (title_align == ALIGN_RIGHT && ob_marks_width)
+ ? ob_marks_x + ob_marks_width : ob_inner_x;
+ } else if (title_align == ALIGN_LEFT) {
+ texture_box.x = ob_inner_x;
+ } else if (title_align == ALIGN_CENTER) {
+ // If there are marks visible, center between the edge and marks.
+ // Otherwise, center in the inner area.
+ if (ob_marks_width) {
+ texture_box.x = (ob_inner_x + ob_marks_x) / 2
+ - texture_box.width / 2;
+ } else {
+ texture_box.x = ob_inner_x + ob_inner_width / 2
+ - texture_box.width / 2;
+ }
+ } else {
+ texture_box.x = ob_inner_x + ob_inner_width - texture_box.width;
+ }
+ ob_title_x = texture_box.x;
+
texture_box.y =
round((bg_y - output_y) * output_scale) + ob_padding_above;
@@ -496,11 +524,10 @@ static void render_titlebar(struct sway_output *output,
WL_OUTPUT_TRANSFORM_NORMAL,
0.0, output->wlr_output->transform_matrix);
- int inner_x = x - output_x + TITLEBAR_H_PADDING;
- int ob_inner_width = scale_length(inner_width, inner_x, output_scale);
- if (ob_inner_width - marks_ob_width < texture_box.width) {
- texture_box.width = ob_inner_width - marks_ob_width;
+ if (ob_inner_width - ob_marks_width < texture_box.width) {
+ texture_box.width = ob_inner_width - ob_marks_width;
}
+
render_texture(output->wlr_output, output_damage, title_texture,
&texture_box, matrix, con->alpha);
@@ -508,7 +535,7 @@ static void render_titlebar(struct sway_output *output,
memcpy(&color, colors->background, sizeof(float) * 4);
premultiply_alpha(color, con->alpha);
box.x = texture_box.x + round(output_x * output_scale);
- box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale);
+ box.y = round((y + titlebar_border_thickness) * output_scale);
box.width = texture_box.width;
box.height = ob_padding_above;
render_rect(output->wlr_output, output_damage, &box, color);
@@ -519,50 +546,83 @@ static void render_titlebar(struct sway_output *output,
render_rect(output->wlr_output, output_damage, &box, color);
}
+ // Determine the left + right extends of the textures (output-buffer local)
+ int ob_left_x, ob_left_width, ob_right_x, ob_right_width;
+ if (ob_title_width == 0 && ob_marks_width == 0) {
+ ob_left_x = ob_inner_x;
+ ob_left_width = 0;
+ ob_right_x = ob_inner_x;
+ ob_right_width = 0;
+ } else if (ob_title_x < ob_marks_x) {
+ ob_left_x = ob_title_x;
+ ob_left_width = ob_title_width;
+ ob_right_x = ob_marks_x;
+ ob_right_width = ob_marks_width;
+ } else {
+ ob_left_x = ob_marks_x;
+ ob_left_width = ob_marks_width;
+ ob_right_x = ob_title_x;
+ ob_right_width = ob_title_width;
+ }
+ if (ob_left_x < ob_inner_x) {
+ ob_left_x = ob_inner_x;
+ } else if (ob_left_x + ob_left_width > ob_right_x + ob_right_width) {
+ ob_right_x = ob_left_x;
+ ob_right_width = ob_left_width;
+ }
+
// Filler between title and marks
- box.width =
- round(inner_width * output_scale) - title_ob_width - marks_ob_width;
+ box.width = ob_right_x - ob_left_x - ob_left_width;
if (box.width > 0) {
- box.x = round((x + TITLEBAR_H_PADDING) * output_scale) + title_ob_width;
+ box.x = ob_left_x + ob_left_width + round(output_x * output_scale);
box.y = round(bg_y * output_scale);
box.height = ob_bg_height;
render_rect(output->wlr_output, output_damage, &box, color);
}
- // Padding left of title
- left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
+ // Padding on left side
+ left_offset = (layout == L_TABBED) * titlebar_border_thickness;
box.x = x + left_offset;
- box.y = y + TITLEBAR_BORDER_THICKNESS;
- box.width = TITLEBAR_H_PADDING - left_offset;
- box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
+ box.y = y + titlebar_border_thickness;
+ box.width = titlebar_h_padding - left_offset;
+ box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 +
config->font_height;
scale_box(&box, output_scale);
+ int left_x = ob_left_x + round(output_x * output_scale);
+ if (box.x + box.width < left_x) {
+ box.width += left_x - box.x - box.width;
+ }
render_rect(output->wlr_output, output_damage, &box, color);
- // Padding right of marks
- right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
- box.x = x + width - TITLEBAR_H_PADDING;
- box.y = y + TITLEBAR_BORDER_THICKNESS;
- box.width = TITLEBAR_H_PADDING - right_offset;
- box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
+ // Padding on right side
+ right_offset = (layout == L_TABBED) * titlebar_border_thickness;
+ box.x = x + width - titlebar_h_padding;
+ box.y = y + titlebar_border_thickness;
+ box.width = titlebar_h_padding - right_offset;
+ box.height = (titlebar_v_padding - titlebar_border_thickness) * 2 +
config->font_height;
scale_box(&box, output_scale);
+ int right_rx = ob_right_x + ob_right_width + round(output_x * output_scale);
+ if (right_rx < box.x) {
+ box.width += box.x - right_rx;
+ box.x = right_rx;
+ }
render_rect(output->wlr_output, output_damage, &box, color);
if (connects_sides) {
// Left pixel in line with bottom bar
box.x = x;
- box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
+ box.y = y + container_titlebar_height() - titlebar_border_thickness;
box.width = state->border_thickness * state->border_left;
- box.height = TITLEBAR_BORDER_THICKNESS;
+ box.height = titlebar_border_thickness;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
// Right pixel in line with bottom bar
box.x = x + width - state->border_thickness * state->border_right;
- box.y = y + container_titlebar_height() - TITLEBAR_BORDER_THICKNESS;
+ box.y = y + container_titlebar_height() - titlebar_border_thickness;
box.width = state->border_thickness * state->border_right;
- box.height = TITLEBAR_BORDER_THICKNESS;
+ box.height = titlebar_border_thickness;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
}
@@ -882,21 +942,11 @@ static void render_floating(struct sway_output *soutput,
}
}
-static void render_dropzones(struct sway_output *output,
+static void render_seatops(struct sway_output *output,
pixman_region32_t *damage) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
- if (seat->operation == OP_MOVE_TILING && seat->op_target_node
- && node_get_output(seat->op_target_node) == output) {
- float color[4];
- memcpy(&color, config->border_colors.focused.indicator,
- sizeof(float) * 4);
- premultiply_alpha(color, 0.5);
- struct wlr_box box;
- memcpy(&box, &seat->op_drop_box, sizeof(struct wlr_box));
- scale_box(&box, output->wlr_output->scale);
- render_rect(output->wlr_output, damage, &box, color);
- }
+ seatop_render(seat, output, damage);
}
}
@@ -950,7 +1000,7 @@ void output_render(struct sway_output *output, struct timespec *when,
if (fullscreen_con->view) {
if (fullscreen_con->view->saved_buffer) {
render_saved_view(fullscreen_con->view, output, damage, 1.0f);
- } else {
+ } else if (fullscreen_con->view->surface) {
render_view_toplevels(fullscreen_con->view,
output, damage, 1.0f);
}
@@ -993,7 +1043,7 @@ void output_render(struct sway_output *output, struct timespec *when,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
}
- render_dropzones(output, damage);
+ render_seatops(output, damage);
struct sway_seat *seat = input_manager_current_seat();
struct sway_container *focus = seat_get_focused_container(seat);
@@ -1012,15 +1062,22 @@ renderer_end:
wlr_render_texture(renderer, root->debug_tree,
wlr_output->transform_matrix, 0, 40, 1);
}
- if (debug.damage == DAMAGE_HIGHLIGHT) {
- 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_output_render_software_cursors(wlr_output, damage);
wlr_renderer_end(renderer);
+
+ int width, height;
+ wlr_output_transformed_resolution(wlr_output, &width, &height);
+
+ if (debug.damage == DAMAGE_HIGHLIGHT) {
+ pixman_region32_union_rect(damage, damage, 0, 0, width, height);
+ }
+
+ enum wl_output_transform transform =
+ wlr_output_transform_invert(wlr_output->transform);
+ wlr_region_transform(damage, damage, transform, width, height);
+
if (!wlr_output_damage_swap_buffers(output->damage, when, damage)) {
return;
}
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index bf0038b4..1cdd7c6d 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -299,7 +299,7 @@ static void transaction_apply(struct sway_transaction *transaction) {
if (root->outputs->length) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
- if (seat->operation == OP_NONE) {
+ if (!seat_doing_seatop(seat)) {
cursor_rebase(seat->cursor);
}
}
@@ -363,7 +363,7 @@ static void transaction_progress_queue(void) {
static int handle_timeout(void *data) {
struct sway_transaction *transaction = data;
- wlr_log(WLR_DEBUG, "Transaction %p timed out (%li waiting)",
+ wlr_log(WLR_DEBUG, "Transaction %p timed out (%zi waiting)",
transaction, transaction->num_waiting);
transaction->num_waiting = 0;
transaction_progress_queue();
@@ -472,7 +472,7 @@ static void set_instruction_ready(
struct timespec *start = &transaction->commit_time;
float ms = (now.tv_sec - start->tv_sec) * 1000 +
(now.tv_nsec - start->tv_nsec) / 1000000.0;
- wlr_log(WLR_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)",
+ wlr_log(WLR_DEBUG, "Transaction %p: %zi/%zi ready in %.1fms (%s)",
transaction,
transaction->num_configures - transaction->num_waiting + 1,
transaction->num_configures, ms,
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 801dcee0..f05e156f 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -360,7 +360,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel_move_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_move_floating(seat, view->container, seat->last_button);
+ seatop_begin_move_floating(seat, view->container, seat->last_button);
}
}
@@ -374,7 +374,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel_resize_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_resize_floating(seat, view->container,
+ seatop_begin_resize_floating(seat, view->container,
seat->last_button, e->edges);
}
}
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index 4bc83b8e..9f6741c8 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -357,7 +357,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel_v6_move_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_move_floating(seat, view->container, seat->last_button);
+ seatop_begin_move_floating(seat, view->container, seat->last_button);
}
}
@@ -371,7 +371,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel_v6_resize_event *e = data;
struct sway_seat *seat = e->seat->seat->data;
if (e->serial == seat->last_button_serial) {
- seat_begin_resize_floating(seat, view->container,
+ seatop_begin_resize_floating(seat, view->container,
seat->last_button, e->edges);
}
}
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 1838ad32..080f6c41 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -470,7 +470,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
return;
}
struct sway_seat *seat = input_manager_current_seat();
- seat_begin_move_floating(seat, view->container, seat->last_button);
+ seatop_begin_move_floating(seat, view->container, seat->last_button);
}
static void handle_request_resize(struct wl_listener *listener, void *data) {
@@ -486,7 +486,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
}
struct wlr_xwayland_resize_event *e = data;
struct sway_seat *seat = input_manager_current_seat();
- seat_begin_resize_floating(seat, view->container,
+ seatop_begin_resize_floating(seat, view->container,
seat->last_button, e->edges);
}
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index d89f64d8..08222494 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -1,12 +1,11 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <math.h>
-#ifdef __linux__
+#include <libevdev/libevdev.h>
#include <linux/input-event-codes.h>
-#elif __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#endif
+#include <errno.h>
#include <float.h>
#include <limits.h>
+#include <strings.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_idle.h>
@@ -28,10 +27,6 @@
#include "sway/tree/workspace.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
-// When doing a tiling drag, this is the thickness of the dropzone
-// when dragging to the edge of a layout container.
-#define DROP_LAYOUT_BORDER 30
-
static uint32_t get_current_time_msec(void) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -60,7 +55,7 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
* Returns the node at the cursor's position. If there is a surface at that
* location, it is stored in **surface (it may not be a view).
*/
-static struct sway_node *node_at_coords(
+struct sway_node *node_at_coords(
struct sway_seat *seat, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
// check for unmanaged views first
@@ -88,6 +83,10 @@ static struct sway_node *node_at_coords(
return NULL;
}
struct sway_output *output = wlr_output->data;
+ if (!output) {
+ // output is being destroyed
+ return NULL;
+ }
double ox = lx, oy = ly;
wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
@@ -223,323 +222,6 @@ static enum wlr_edges find_resize_edge(struct sway_container *cont,
return edge;
}
-static void handle_down_motion(struct sway_seat *seat,
- struct sway_cursor *cursor, uint32_t time_msec) {
- struct sway_container *con = seat->op_container;
- if (seat_is_input_allowed(seat, con->view->surface)) {
- double moved_x = cursor->cursor->x - seat->op_ref_lx;
- double moved_y = cursor->cursor->y - seat->op_ref_ly;
- double sx = seat->op_ref_con_lx + moved_x;
- double sy = seat->op_ref_con_ly + moved_y;
- wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
- }
- seat->op_moved = true;
-}
-
-static void handle_move_floating_motion(struct sway_seat *seat,
- struct sway_cursor *cursor) {
- struct sway_container *con = seat->op_container;
- desktop_damage_whole_container(con);
- container_floating_translate(con,
- cursor->cursor->x - cursor->previous.x,
- cursor->cursor->y - cursor->previous.y);
- desktop_damage_whole_container(con);
-}
-
-static void resize_box(struct wlr_box *box, enum wlr_edges edge,
- int thickness) {
- switch (edge) {
- case WLR_EDGE_TOP:
- box->height = thickness;
- break;
- case WLR_EDGE_LEFT:
- box->width = thickness;
- break;
- case WLR_EDGE_RIGHT:
- box->x = box->x + box->width - thickness;
- box->width = thickness;
- break;
- case WLR_EDGE_BOTTOM:
- box->y = box->y + box->height - thickness;
- box->height = thickness;
- break;
- case WLR_EDGE_NONE:
- box->x += thickness;
- box->y += thickness;
- box->width -= thickness * 2;
- box->height -= thickness * 2;
- break;
- }
-}
-
-static void handle_move_tiling_motion(struct sway_seat *seat,
- struct sway_cursor *cursor) {
- struct wlr_surface *surface = NULL;
- double sx, sy;
- struct sway_node *node = node_at_coords(seat,
- cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
- // Damage the old location
- desktop_damage_box(&seat->op_drop_box);
-
- if (!node) {
- // Eg. hovered over a layer surface such as swaybar
- seat->op_target_node = NULL;
- seat->op_target_edge = WLR_EDGE_NONE;
- return;
- }
-
- if (node->type == N_WORKSPACE) {
- // Emtpy workspace
- seat->op_target_node = node;
- seat->op_target_edge = WLR_EDGE_NONE;
- workspace_get_box(node->sway_workspace, &seat->op_drop_box);
- desktop_damage_box(&seat->op_drop_box);
- return;
- }
-
- // Deny moving within own workspace if this is the only child
- struct sway_container *con = node->sway_container;
- if (workspace_num_tiling_views(seat->op_container->workspace) == 1 &&
- con->workspace == seat->op_container->workspace) {
- seat->op_target_node = NULL;
- seat->op_target_edge = WLR_EDGE_NONE;
- return;
- }
-
- // Traverse the ancestors, trying to find a layout container perpendicular
- // to the edge. Eg. close to the top or bottom of a horiz layout.
- while (con) {
- enum wlr_edges edge = WLR_EDGE_NONE;
- enum sway_container_layout layout = container_parent_layout(con);
- struct wlr_box parent;
- con->parent ? container_get_box(con->parent, &parent) :
- workspace_get_box(con->workspace, &parent);
- if (layout == L_HORIZ || layout == L_TABBED) {
- if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) {
- edge = WLR_EDGE_TOP;
- } else if (cursor->cursor->y > parent.y + parent.height
- - DROP_LAYOUT_BORDER) {
- edge = WLR_EDGE_BOTTOM;
- }
- } else if (layout == L_VERT || layout == L_STACKED) {
- if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) {
- edge = WLR_EDGE_LEFT;
- } else if (cursor->cursor->x > parent.x + parent.width
- - DROP_LAYOUT_BORDER) {
- edge = WLR_EDGE_RIGHT;
- }
- }
- if (edge) {
- seat->op_target_node = node_get_parent(&con->node);
- seat->op_target_edge = edge;
- node_get_box(seat->op_target_node, &seat->op_drop_box);
- resize_box(&seat->op_drop_box, edge, DROP_LAYOUT_BORDER);
- desktop_damage_box(&seat->op_drop_box);
- return;
- }
- con = con->parent;
- }
-
- // Use the hovered view - but we must be over the actual surface
- con = node->sway_container;
- if (!con->view->surface || node == &seat->op_container->node) {
- seat->op_target_node = NULL;
- seat->op_target_edge = WLR_EDGE_NONE;
- return;
- }
-
- // Find the closest edge
- size_t thickness = fmin(con->content_width, con->content_height) * 0.3;
- size_t closest_dist = INT_MAX;
- size_t dist;
- seat->op_target_edge = WLR_EDGE_NONE;
- if ((dist = cursor->cursor->y - con->y) < closest_dist) {
- closest_dist = dist;
- seat->op_target_edge = WLR_EDGE_TOP;
- }
- if ((dist = cursor->cursor->x - con->x) < closest_dist) {
- closest_dist = dist;
- seat->op_target_edge = WLR_EDGE_LEFT;
- }
- if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) {
- closest_dist = dist;
- seat->op_target_edge = WLR_EDGE_RIGHT;
- }
- if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) {
- closest_dist = dist;
- seat->op_target_edge = WLR_EDGE_BOTTOM;
- }
-
- if (closest_dist > thickness) {
- seat->op_target_edge = WLR_EDGE_NONE;
- }
-
- seat->op_target_node = node;
- seat->op_drop_box.x = con->content_x;
- seat->op_drop_box.y = con->content_y;
- seat->op_drop_box.width = con->content_width;
- seat->op_drop_box.height = con->content_height;
- resize_box(&seat->op_drop_box, seat->op_target_edge, thickness);
- desktop_damage_box(&seat->op_drop_box);
-}
-
-static void calculate_floating_constraints(struct sway_container *con,
- int *min_width, int *max_width, int *min_height, int *max_height) {
- if (config->floating_minimum_width == -1) { // no minimum
- *min_width = 0;
- } else if (config->floating_minimum_width == 0) { // automatic
- *min_width = 75;
- } else {
- *min_width = config->floating_minimum_width;
- }
-
- if (config->floating_minimum_height == -1) { // no minimum
- *min_height = 0;
- } else if (config->floating_minimum_height == 0) { // automatic
- *min_height = 50;
- } else {
- *min_height = config->floating_minimum_height;
- }
-
- if (config->floating_maximum_width == -1) { // no maximum
- *max_width = INT_MAX;
- } else if (config->floating_maximum_width == 0) { // automatic
- *max_width = con->workspace->width;
- } else {
- *max_width = config->floating_maximum_width;
- }
-
- if (config->floating_maximum_height == -1) { // no maximum
- *max_height = INT_MAX;
- } else if (config->floating_maximum_height == 0) { // automatic
- *max_height = con->workspace->height;
- } else {
- *max_height = config->floating_maximum_height;
- }
-}
-
-static void handle_resize_floating_motion(struct sway_seat *seat,
- struct sway_cursor *cursor) {
- struct sway_container *con = seat->op_container;
- enum wlr_edges edge = seat->op_resize_edge;
-
- // The amount the mouse has moved since the start of the resize operation
- // Positive is down/right
- double mouse_move_x = cursor->cursor->x - seat->op_ref_lx;
- double mouse_move_y = cursor->cursor->y - seat->op_ref_ly;
-
- if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) {
- mouse_move_x = 0;
- }
- if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) {
- mouse_move_y = 0;
- }
-
- double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x;
- double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y;
-
- if (seat->op_resize_preserve_ratio) {
- double x_multiplier = grow_width / seat->op_ref_width;
- double y_multiplier = grow_height / seat->op_ref_height;
- double max_multiplier = fmax(x_multiplier, y_multiplier);
- grow_width = seat->op_ref_width * max_multiplier;
- grow_height = seat->op_ref_height * max_multiplier;
- }
-
- // Determine new width/height, and accommodate for floating min/max values
- double width = seat->op_ref_width + grow_width;
- double height = seat->op_ref_height + grow_height;
- int min_width, max_width, min_height, max_height;
- calculate_floating_constraints(con, &min_width, &max_width,
- &min_height, &max_height);
- width = fmax(min_width, fmin(width, max_width));
- height = fmax(min_height, fmin(height, max_height));
-
- // Apply the view's min/max size
- if (con->view) {
- double view_min_width, view_max_width, view_min_height, view_max_height;
- view_get_constraints(con->view, &view_min_width, &view_max_width,
- &view_min_height, &view_max_height);
- width = fmax(view_min_width, fmin(width, view_max_width));
- height = fmax(view_min_height, fmin(height, view_max_height));
- }
-
- // Recalculate these, in case we hit a min/max limit
- grow_width = width - seat->op_ref_width;
- grow_height = height - seat->op_ref_height;
-
- // Determine grow x/y values - these are relative to the container's x/y at
- // the start of the resize operation.
- double grow_x = 0, grow_y = 0;
- if (edge & WLR_EDGE_LEFT) {
- grow_x = -grow_width;
- } else if (edge & WLR_EDGE_RIGHT) {
- grow_x = 0;
- } else {
- grow_x = -grow_width / 2;
- }
- if (edge & WLR_EDGE_TOP) {
- grow_y = -grow_height;
- } else if (edge & WLR_EDGE_BOTTOM) {
- grow_y = 0;
- } else {
- grow_y = -grow_height / 2;
- }
-
- // Determine the amounts we need to bump everything relative to the current
- // size.
- int relative_grow_width = width - con->width;
- int relative_grow_height = height - con->height;
- int relative_grow_x = (seat->op_ref_con_lx + grow_x) - con->x;
- int relative_grow_y = (seat->op_ref_con_ly + grow_y) - con->y;
-
- // Actually resize stuff
- con->x += relative_grow_x;
- con->y += relative_grow_y;
- con->width += relative_grow_width;
- con->height += relative_grow_height;
-
- con->content_x += relative_grow_x;
- con->content_y += relative_grow_y;
- con->content_width += relative_grow_width;
- con->content_height += relative_grow_height;
-
- arrange_container(con);
-}
-
-static void handle_resize_tiling_motion(struct sway_seat *seat,
- struct sway_cursor *cursor) {
- int amount_x = 0;
- int amount_y = 0;
- int moved_x = cursor->cursor->x - seat->op_ref_lx;
- int moved_y = cursor->cursor->y - seat->op_ref_ly;
- enum wlr_edges edge_x = WLR_EDGE_NONE;
- enum wlr_edges edge_y = WLR_EDGE_NONE;
- struct sway_container *con = seat->op_container;
-
- if (seat->op_resize_edge & WLR_EDGE_TOP) {
- amount_y = (seat->op_ref_height - moved_y) - con->height;
- edge_y = WLR_EDGE_TOP;
- } else if (seat->op_resize_edge & WLR_EDGE_BOTTOM) {
- amount_y = (seat->op_ref_height + moved_y) - con->height;
- edge_y = WLR_EDGE_BOTTOM;
- }
- if (seat->op_resize_edge & WLR_EDGE_LEFT) {
- amount_x = (seat->op_ref_width - moved_x) - con->width;
- edge_x = WLR_EDGE_LEFT;
- } else if (seat->op_resize_edge & WLR_EDGE_RIGHT) {
- amount_x = (seat->op_ref_width + moved_x) - con->width;
- edge_x = WLR_EDGE_RIGHT;
- }
-
- if (amount_x != 0) {
- container_resize_tiled(seat->op_container, edge_x, amount_x);
- }
- if (amount_y != 0) {
- container_resize_tiled(seat->op_container, edge_y, amount_y);
- }
-}
-
static void cursor_do_rebase(struct sway_cursor *cursor, uint32_t time_msec,
struct sway_node *node, struct wlr_surface *surface,
double sx, double sy) {
@@ -589,6 +271,50 @@ void cursor_rebase(struct sway_cursor *cursor) {
cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy);
}
+static int hide_notify(void *data) {
+ struct sway_cursor *cursor = data;
+ wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
+ cursor->hidden = true;
+ return 1;
+}
+
+int cursor_get_timeout(struct sway_cursor *cursor){
+ struct seat_config *sc = seat_get_config(cursor->seat);
+ if (!sc) {
+ sc = seat_get_config_by_name("*");
+ }
+ int timeout = sc ? sc->hide_cursor_timeout : 0;
+ if (timeout < 0) {
+ timeout = 0;
+ }
+ return timeout;
+}
+
+void cursor_handle_activity(struct sway_cursor *cursor) {
+ wl_event_source_timer_update(
+ cursor->hide_source, cursor_get_timeout(cursor));
+
+ wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
+ if (cursor->hidden) {
+ cursor_unhide(cursor);
+ }
+}
+
+void cursor_unhide(struct sway_cursor *cursor) {
+ cursor->hidden = false;
+ if (cursor->image_surface) {
+ cursor_set_image_surface(cursor,
+ cursor->image_surface,
+ cursor->hotspot_x,
+ cursor->hotspot_y,
+ cursor->image_client);
+ } else {
+ const char *image = cursor->image;
+ cursor->image = NULL;
+ cursor_set_image(cursor, image, cursor->image_client);
+ }
+}
+
void cursor_send_pointer_motion(struct sway_cursor *cursor,
uint32_t time_msec) {
if (time_msec == 0) {
@@ -598,26 +324,8 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor,
struct sway_seat *seat = cursor->seat;
struct wlr_seat *wlr_seat = seat->wlr_seat;
- if (seat->operation != OP_NONE) {
- switch (seat->operation) {
- case OP_DOWN:
- handle_down_motion(seat, cursor, time_msec);
- break;
- case OP_MOVE_FLOATING:
- handle_move_floating_motion(seat, cursor);
- break;
- case OP_MOVE_TILING:
- handle_move_tiling_motion(seat, cursor);
- break;
- case OP_RESIZE_FLOATING:
- handle_resize_floating_motion(seat, cursor);
- break;
- case OP_RESIZE_TILING:
- handle_resize_tiling_motion(seat, cursor);
- break;
- case OP_NONE:
- break;
- }
+ if (seat_doing_seatop(seat)) {
+ seatop_motion(seat, time_msec);
cursor->previous.x = cursor->cursor->x;
cursor->previous.y = cursor->cursor->y;
return;
@@ -679,11 +387,11 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor,
static void handle_cursor_motion(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
- wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
struct wlr_event_pointer_motion *event = data;
wlr_cursor_move(cursor->cursor, event->device,
event->delta_x, event->delta_y);
cursor_send_pointer_motion(cursor, event->time_msec);
+ cursor_handle_activity(cursor);
transaction_commit_dirty();
}
@@ -691,10 +399,10 @@ static void handle_cursor_motion_absolute(
struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, motion_absolute);
- wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
struct wlr_event_pointer_motion_absolute *event = data;
wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y);
cursor_send_pointer_motion(cursor, event->time_msec);
+ cursor_handle_activity(cursor);
transaction_commit_dirty();
}
@@ -794,11 +502,16 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
struct sway_seat *seat = cursor->seat;
// Handle existing seat operation
- if (cursor->seat->operation != OP_NONE) {
- if (button == cursor->seat->op_button && state == WLR_BUTTON_RELEASED) {
- seat_end_mouse_operation(seat);
+ if (seat_doing_seatop(seat)) {
+ if (button == seat->seatop_button && state == WLR_BUTTON_RELEASED) {
+ seatop_finish(seat);
seat_pointer_notify_button(seat, time_msec, button, state);
}
+ if (state == WLR_BUTTON_PRESSED) {
+ state_add_button(cursor, button);
+ } else {
+ state_erase_button(cursor, button);
+ }
return;
}
@@ -864,7 +577,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
if (cont && resize_edge && button == BTN_LEFT &&
state == WLR_BUTTON_PRESSED && !is_floating) {
seat_set_focus_container(seat, cont);
- seat_begin_resize_tiling(seat, cont, button, edge);
+ seatop_begin_resize_tiling(seat, cont, button, edge);
return;
}
@@ -894,7 +607,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
}
cursor_set_image(seat->cursor, image, NULL);
seat_set_focus_container(seat, cont);
- seat_begin_resize_tiling(seat, cont, button, edge);
+ seatop_begin_resize_tiling(seat, cont, button, edge);
return;
}
}
@@ -909,7 +622,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
cont = cont->parent;
}
seat_set_focus_container(seat, cont);
- seat_begin_move_floating(seat, cont, button);
+ seatop_begin_move_floating(seat, cont, button);
return;
}
}
@@ -919,7 +632,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
state == WLR_BUTTON_PRESSED) {
// Via border
if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
- seat_begin_resize_floating(seat, cont, button, resize_edge);
+ seatop_begin_resize_floating(seat, cont, button, resize_edge);
return;
}
@@ -936,16 +649,30 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
edge |= cursor->cursor->y > floater->y + floater->height / 2 ?
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
- seat_begin_resize_floating(seat, floater, button, edge);
+ seatop_begin_resize_floating(seat, floater, button, edge);
return;
}
}
// Handle moving a tiling container
- if (config->tiling_drag && mod_pressed && state == WLR_BUTTON_PRESSED &&
- !is_floating_or_child && cont && !cont->is_fullscreen) {
+ if (config->tiling_drag && (mod_pressed || on_titlebar) &&
+ state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
+ cont && !cont->is_fullscreen) {
+ struct sway_container *focus = seat_get_focused_container(seat);
+ bool focused = focus == cont || container_has_ancestor(focus, cont);
+ if (on_titlebar && !focused) {
+ node = seat_get_focus_inactive(seat, &cont->node);
+ seat_set_focus(seat, node);
+ }
+
seat_pointer_notify_button(seat, time_msec, button, state);
- seat_begin_move_tiling(seat, cont, button);
+
+ // If moving a container by it's title bar, use a threshold for the drag
+ if (!mod_pressed && config->tiling_drag_threshold > 0) {
+ seatop_begin_move_tiling_threshold(seat, cont, button);
+ } else {
+ seatop_begin_move_tiling(seat, cont, button);
+ }
return;
}
@@ -953,7 +680,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
if (surface && cont && state == WLR_BUTTON_PRESSED) {
seat_set_focus_container(seat, cont);
seat_pointer_notify_button(seat, time_msec, button, state);
- seat_begin_down(seat, cont, button, sx, sy);
+ seatop_begin_down(seat, cont, button, sx, sy);
return;
}
@@ -970,18 +697,32 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
static void handle_cursor_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
- wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
struct wlr_event_pointer_button *event = data;
dispatch_cursor_button(cursor, event->device,
event->time_msec, event->button, event->state);
+ cursor_handle_activity(cursor);
transaction_commit_dirty();
}
-static void dispatch_cursor_axis(struct sway_cursor *cursor,
+static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
+ switch (event->orientation) {
+ case WLR_AXIS_ORIENTATION_VERTICAL:
+ return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
+ case WLR_AXIS_ORIENTATION_HORIZONTAL:
+ return event->delta < 0 ? SWAY_SCROLL_LEFT : SWAY_SCROLL_RIGHT;
+ default:
+ wlr_log(WLR_DEBUG, "Unknown axis orientation");
+ return 0;
+ }
+}
+
+void dispatch_cursor_axis(struct sway_cursor *cursor,
struct wlr_event_pointer_axis *event) {
struct sway_seat *seat = cursor->seat;
- struct sway_input_device *input_device = event->device->data;
- struct input_config *ic = input_device_get_config(input_device);
+ struct sway_input_device *input_device =
+ event->device ? event->device->data : NULL;
+ struct input_config *ic =
+ input_device ? input_device_get_config(input_device) : NULL;
// Determine what's under the cursor
struct wlr_surface *surface = NULL;
@@ -993,11 +734,35 @@ static void dispatch_cursor_axis(struct sway_cursor *cursor,
enum wlr_edges edge = cont ? find_edge(cont, cursor) : WLR_EDGE_NONE;
bool on_border = edge != WLR_EDGE_NONE;
bool on_titlebar = cont && !on_border && !surface;
+ bool on_titlebar_border = cont && on_border &&
+ cursor->cursor->y < cont->content_y;
+ bool on_contents = cont && !on_border && surface;
float scroll_factor =
(ic == NULL || ic->scroll_factor == FLT_MIN) ? 1.0f : ic->scroll_factor;
- // Scrolling on a tabbed or stacked title bar
- if (on_titlebar) {
+ bool handled = false;
+
+ // Gather information needed for mouse bindings
+ struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
+ uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
+ struct wlr_input_device *device =
+ input_device ? input_device->wlr_device : NULL;
+ char *dev_id = device ? input_device_get_identifier(device) : strdup("*");
+ uint32_t button = wl_axis_to_button(event);
+
+ // Handle mouse bindings - x11 mouse buttons 4-7 - press event
+ struct sway_binding *binding = NULL;
+ state_add_button(cursor, button);
+ binding = get_active_mouse_binding(cursor,
+ config->current_mode->mouse_bindings, modifiers, false,
+ on_titlebar, on_border, on_contents, dev_id);
+ if (binding) {
+ seat_execute_command(seat, binding);
+ handled = true;
+ }
+
+ // Scrolling on a tabbed or stacked title bar (handled as press event)
+ if (!handled && (on_titlebar || on_titlebar_border)) {
enum sway_container_layout layout = container_parent_layout(cont);
if (layout == L_TABBED || layout == L_STACKED) {
struct sway_node *tabcontainer = node_get_parent(node);
@@ -1024,20 +789,33 @@ static void dispatch_cursor_axis(struct sway_cursor *cursor,
seat_set_raw_focus(seat, new_focus);
seat_set_raw_focus(seat, old_focus);
}
- return;
+ handled = true;
}
}
- wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
- event->orientation, scroll_factor * event->delta,
- round(scroll_factor * event->delta_discrete), event->source);
+ // Handle mouse bindings - x11 mouse buttons 4-7 - release event
+ binding = get_active_mouse_binding(cursor,
+ config->current_mode->mouse_bindings, modifiers, true,
+ on_titlebar, on_border, on_contents, dev_id);
+ state_erase_button(cursor, button);
+ if (binding) {
+ seat_execute_command(seat, binding);
+ handled = true;
+ }
+ free(dev_id);
+
+ if (!handled) {
+ wlr_seat_pointer_notify_axis(cursor->seat->wlr_seat, event->time_msec,
+ event->orientation, scroll_factor * event->delta,
+ round(scroll_factor * event->delta_discrete), event->source);
+ }
}
static void handle_cursor_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
- wlr_idle_notify_activity(server.idle, cursor->seat->wlr_seat);
struct wlr_event_pointer_axis *event = data;
dispatch_cursor_axis(cursor, event);
+ cursor_handle_activity(cursor);
transaction_commit_dirty();
}
@@ -1209,7 +987,7 @@ static void handle_request_set_cursor(struct wl_listener *listener,
void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, request_set_cursor);
- if (cursor->seat->operation != OP_NONE) {
+ if (seat_doing_seatop(cursor->seat)) {
return;
}
struct wlr_seat_pointer_request_set_cursor_event *event = data;
@@ -1228,10 +1006,8 @@ static void handle_request_set_cursor(struct wl_listener *listener,
return;
}
- wlr_cursor_set_surface(cursor->cursor, event->surface, event->hotspot_x,
- event->hotspot_y);
- cursor->image = NULL;
- cursor->image_client = focused_client;
+ cursor_set_image_surface(cursor, event->surface, event->hotspot_x,
+ event->hotspot_y, focused_client);
}
void cursor_set_image(struct sway_cursor *cursor, const char *image,
@@ -1239,14 +1015,43 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image,
if (!(cursor->seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
return;
}
+
+ const char *current_image = cursor->image;
+ cursor->image = image;
+ cursor->image_surface = NULL;
+ cursor->hotspot_x = cursor->hotspot_y = 0;
+ cursor->image_client = client;
+
+ if (cursor->hidden) {
+ return;
+ }
+
if (!image) {
wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
- } else if (!cursor->image || strcmp(cursor->image, image) != 0) {
+ } else if (!current_image || strcmp(current_image, image) != 0) {
wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
cursor->cursor);
}
- cursor->image = image;
+}
+
+void cursor_set_image_surface(struct sway_cursor *cursor,
+ struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y,
+ struct wl_client *client) {
+ if (!(cursor->seat->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) {
+ return;
+ }
+
+ cursor->image = NULL;
+ cursor->image_surface = surface;
+ cursor->hotspot_x = hotspot_x;
+ cursor->hotspot_y = hotspot_y;
cursor->image_client = client;
+
+ if (cursor->hidden) {
+ return;
+ }
+
+ wlr_cursor_set_surface(cursor->cursor, surface, hotspot_x, hotspot_y);
}
void sway_cursor_destroy(struct sway_cursor *cursor) {
@@ -1254,6 +1059,8 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
return;
}
+ wl_event_source_remove(cursor->hide_source);
+
wlr_xcursor_manager_destroy(cursor->xcursor_manager);
wlr_cursor_destroy(cursor->cursor);
free(cursor);
@@ -1277,6 +1084,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
cursor->seat = seat;
wlr_cursor_attach_output_layout(wlr_cursor, root->output_layout);
+ cursor->hide_source = wl_event_loop_add_timer(server.wl_event_loop,
+ hide_notify, cursor);
+
// input events
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
cursor->motion.notify = handle_cursor_motion;
@@ -1362,3 +1172,66 @@ void cursor_warp_to_workspace(struct sway_cursor *cursor,
wlr_cursor_warp(cursor->cursor, NULL, x, y);
}
+
+uint32_t get_mouse_bindsym(const char *name, char **error) {
+ if (strncasecmp(name, "button", strlen("button")) == 0) {
+ // Map to x11 mouse buttons
+ int number = name[strlen("button")] - '0';
+ if (number < 1 || number > 9 || strlen(name) > strlen("button0")) {
+ *error = strdup("Only buttons 1-9 are supported. For other mouse "
+ "buttons, use the name of the event code.");
+ return 0;
+ }
+ static const uint32_t buttons[] = {BTN_LEFT, BTN_MIDDLE, BTN_RIGHT,
+ SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT,
+ SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA};
+ return buttons[number - 1];
+ } else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) {
+ // Get event code from name
+ int code = libevdev_event_code_from_name(EV_KEY, name);
+ if (code == -1) {
+ size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1;
+ *error = malloc(len);
+ if (*error) {
+ snprintf(*error, len, "Unknown event %s", name);
+ }
+ return 0;
+ }
+ return code;
+ }
+ return 0;
+}
+
+uint32_t get_mouse_bindcode(const char *name, char **error) {
+ // Validate event code
+ errno = 0;
+ char *endptr;
+ int code = strtol(name, &endptr, 10);
+ if (endptr == name && code <= 0) {
+ *error = strdup("Button event code must be a positive integer.");
+ return 0;
+ } else if (errno == ERANGE) {
+ *error = strdup("Button event code out of range.");
+ return 0;
+ }
+ const char *event = libevdev_event_code_get_name(EV_KEY, code);
+ if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
+ size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button",
+ code, event) + 1;
+ *error = malloc(len);
+ if (*error) {
+ snprintf(*error, len, "Event code %d (%s) is not a button",
+ code, event);
+ }
+ return 0;
+ }
+ return code;
+}
+
+uint32_t get_mouse_button(const char *name, char **error) {
+ uint32_t button = get_mouse_bindsym(name, error);
+ if (!button && !*error) {
+ button = get_mouse_bindcode(name, error);
+ }
+ return button;
+}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index 68445d68..d90803f6 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <float.h>
#include <limits.h>
@@ -49,7 +49,7 @@ char *input_device_get_identifier(struct wlr_input_device *device) {
int vendor = device->vendor;
int product = device->product;
char *name = strdup(device->name);
- name = strip_whitespace(name);
+ strip_whitespace(name);
char *p = name;
for (; *p; ++p) {
@@ -82,11 +82,12 @@ static struct sway_input_device *input_sway_device_from_wlr(
return NULL;
}
-static bool input_has_seat_configuration(void) {
+static bool input_has_seat_fallback_configuration(void) {
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
struct seat_config *seat_config = seat_get_config(seat);
- if (seat_config) {
+ if (seat_config && strcmp(seat_config->name, "*") != 0
+ && seat_config->fallback != -1) {
return true;
}
}
@@ -94,6 +95,18 @@ static bool input_has_seat_configuration(void) {
return false;
}
+void input_manager_verify_fallback_seat(void) {
+ struct sway_seat *seat = NULL;
+ if (!input_has_seat_fallback_configuration()) {
+ wlr_log(WLR_DEBUG, "no fallback seat config - creating default");
+ seat = input_manager_get_default_seat();
+ struct seat_config *sc = new_seat_config(seat->wlr_seat->name);
+ sc->fallback = true;
+ sc = store_seat_config(sc);
+ input_manager_apply_seat_config(sc);
+ }
+}
+
static void input_manager_libinput_config_keyboard(
struct sway_input_device *input_device) {
struct wlr_input_device *wlr_device = input_device->wlr_device;
@@ -116,6 +129,24 @@ static void input_manager_libinput_config_keyboard(
}
}
+static void input_manager_libinput_reset_keyboard(
+ struct sway_input_device *input_device) {
+ struct wlr_input_device *wlr_device = input_device->wlr_device;
+ struct libinput_device *libinput_device;
+
+ if (!wlr_input_device_is_libinput(wlr_device)) {
+ return;
+ }
+
+ libinput_device = wlr_libinput_get_device_handle(wlr_device);
+
+ uint32_t send_events =
+ libinput_device_config_send_events_get_default_mode(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_keyboard(%s) send_events_set_mode(%d)",
+ input_device->identifier, send_events);
+ libinput_device_config_send_events_set_mode(libinput_device, send_events);
+}
+
static void input_manager_libinput_config_touch(
struct sway_input_device *input_device) {
struct wlr_input_device *wlr_device = input_device->wlr_device;
@@ -138,6 +169,24 @@ static void input_manager_libinput_config_touch(
}
}
+static void input_manager_libinput_reset_touch(
+ struct sway_input_device *input_device) {
+ struct wlr_input_device *wlr_device = input_device->wlr_device;
+ struct libinput_device *libinput_device;
+
+ if (!wlr_input_device_is_libinput(wlr_device)) {
+ return;
+ }
+
+ libinput_device = wlr_libinput_get_device_handle(wlr_device);
+
+ uint32_t send_events =
+ libinput_device_config_send_events_get_default_mode(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_touch(%s) send_events_set_mode(%d)",
+ input_device->identifier, send_events);
+ libinput_device_config_send_events_set_mode(libinput_device, send_events);
+}
+
static void input_manager_libinput_config_pointer(
struct sway_input_device *input_device) {
struct wlr_input_device *wlr_device = input_device->wlr_device;
@@ -167,14 +216,14 @@ static void input_manager_libinput_config_pointer(
if (ic->drag != INT_MIN) {
wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) tap_set_drag_enabled(%d)",
- ic->identifier, ic->click_method);
+ ic->identifier, ic->drag);
libinput_device_config_tap_set_drag_enabled(libinput_device,
ic->drag);
}
if (ic->drag_lock != INT_MIN) {
wlr_log(WLR_DEBUG,
"libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)",
- ic->identifier, ic->click_method);
+ ic->identifier, ic->drag_lock);
libinput_device_config_tap_set_drag_lock_enabled(libinput_device,
ic->drag_lock);
}
@@ -235,12 +284,118 @@ static void input_manager_libinput_config_pointer(
}
if (ic->tap_button_map != INT_MIN) {
wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_button_map(%d)",
- ic->identifier, ic->tap);
+ ic->identifier, ic->tap_button_map);
libinput_device_config_tap_set_button_map(libinput_device,
ic->tap_button_map);
}
}
+static void input_manager_libinput_reset_pointer(
+ struct sway_input_device *input_device) {
+ struct wlr_input_device *wlr_device = input_device->wlr_device;
+
+ if (!wlr_input_device_is_libinput(wlr_device)) {
+ return;
+ }
+
+ struct libinput_device *libinput_device =
+ wlr_libinput_get_device_handle(wlr_device);
+
+ enum libinput_config_accel_profile accel_profile =
+ libinput_device_config_accel_get_default_profile(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) accel_set_profile(%d)",
+ input_device->identifier, accel_profile);
+ libinput_device_config_accel_set_profile(libinput_device, accel_profile);
+
+ enum libinput_config_click_method click_method =
+ libinput_device_config_click_get_default_method(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) click_set_method(%d)",
+ input_device->identifier, click_method);
+ libinput_device_config_click_set_method(libinput_device, click_method);
+
+ enum libinput_config_drag_state drag =
+ libinput_device_config_tap_get_default_drag_enabled(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) tap_set_drag_enabled(%d)",
+ input_device->identifier, drag);
+ libinput_device_config_tap_set_drag_enabled(libinput_device, drag);
+
+ enum libinput_config_drag_lock_state drag_lock =
+ libinput_device_config_tap_get_default_drag_lock_enabled(
+ libinput_device);
+ wlr_log(WLR_DEBUG,
+ "libinput_reset_pointer(%s) tap_set_drag_lock_enabled(%d)",
+ input_device->identifier, drag_lock);
+ libinput_device_config_tap_set_drag_lock_enabled(libinput_device,
+ drag_lock);
+
+ enum libinput_config_dwt_state dwt =
+ libinput_device_config_dwt_get_default_enabled(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) dwt_set_enabled(%d)",
+ input_device->identifier, dwt);
+ libinput_device_config_dwt_set_enabled(libinput_device, dwt);
+
+ int left_handed =
+ libinput_device_config_left_handed_get_default(libinput_device);
+ wlr_log(WLR_DEBUG,
+ "libinput_reset_pointer(%s) left_handed_set_enabled(%d)",
+ input_device->identifier, left_handed);
+ libinput_device_config_left_handed_set(libinput_device, left_handed);
+
+ enum libinput_config_middle_emulation_state middle_emulation =
+ libinput_device_config_middle_emulation_get_default_enabled(
+ libinput_device);
+ wlr_log(WLR_DEBUG,
+ "libinput_reset_pointer(%s) middle_emulation_set_enabled(%d)",
+ input_device->identifier, middle_emulation);
+ libinput_device_config_middle_emulation_set_enabled(libinput_device,
+ middle_emulation);
+
+ int natural_scroll =
+ libinput_device_config_scroll_get_default_natural_scroll_enabled(
+ libinput_device);
+ wlr_log(WLR_DEBUG,
+ "libinput_reset_pointer(%s) natural_scroll_set_enabled(%d)",
+ input_device->identifier, natural_scroll);
+ libinput_device_config_scroll_set_natural_scroll_enabled(
+ libinput_device, natural_scroll);
+
+ double pointer_accel =
+ libinput_device_config_accel_get_default_speed(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) accel_set_speed(%f)",
+ input_device->identifier, pointer_accel);
+ libinput_device_config_accel_set_speed(libinput_device, pointer_accel);
+
+ uint32_t scroll_button =
+ libinput_device_config_scroll_get_default_button(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) scroll_set_button(%d)",
+ input_device->identifier, scroll_button);
+ libinput_device_config_scroll_set_button(libinput_device, scroll_button);
+
+ enum libinput_config_scroll_method scroll_method =
+ libinput_device_config_scroll_get_default_method(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) scroll_set_method(%d)",
+ input_device->identifier, scroll_method);
+ libinput_device_config_scroll_set_method(libinput_device, scroll_method);
+
+ uint32_t send_events =
+ libinput_device_config_send_events_get_default_mode(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) send_events_set_mode(%d)",
+ input_device->identifier, send_events);
+ libinput_device_config_send_events_set_mode(libinput_device, send_events);
+
+ enum libinput_config_tap_state tap =
+ libinput_device_config_tap_get_default_enabled(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) tap_set_enabled(%d)",
+ input_device->identifier, tap);
+ libinput_device_config_tap_set_enabled(libinput_device, tap);
+
+ enum libinput_config_tap_button_map tap_button_map =
+ libinput_device_config_tap_get_button_map(libinput_device);
+ wlr_log(WLR_DEBUG, "libinput_reset_pointer(%s) tap_set_button_map(%d)",
+ input_device->identifier, tap_button_map);
+ libinput_device_config_tap_set_button_map(libinput_device, tap_button_map);
+}
+
static void handle_device_destroy(struct wl_listener *listener, void *data) {
struct wlr_input_device *device = data;
@@ -295,15 +450,10 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = handle_device_destroy;
- struct sway_seat *seat = NULL;
- if (!input_has_seat_configuration()) {
- wlr_log(WLR_DEBUG, "no seat configuration, using default seat");
- seat = input_manager_get_default_seat();
- seat_add_device(seat, input_device);
- return;
- }
+ input_manager_verify_fallback_seat();
bool added = false;
+ struct sway_seat *seat = NULL;
wl_list_for_each(seat, &input->seats, link) {
struct seat_config *seat_config = seat_get_config(seat);
bool has_attachment = seat_config &&
@@ -458,15 +608,50 @@ void input_manager_apply_input_config(struct input_config *input_config) {
}
}
-void input_manager_apply_seat_config(struct seat_config *seat_config) {
- wlr_log(WLR_DEBUG, "applying new seat config for seat %s",
- seat_config->name);
- struct sway_seat *seat = input_manager_get_seat(seat_config->name);
- if (!seat) {
- return;
+void input_manager_reset_input(struct sway_input_device *input_device) {
+ if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER ||
+ input_device->wlr_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
+ input_manager_libinput_reset_pointer(input_device);
+ } else if (input_device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
+ input_manager_libinput_reset_keyboard(input_device);
+ } else if (input_device->wlr_device->type == WLR_INPUT_DEVICE_TOUCH) {
+ input_manager_libinput_reset_touch(input_device);
+ }
+
+ struct sway_seat *seat = NULL;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat_reset_device(seat, input_device);
}
+}
+
+void input_manager_reset_all_inputs() {
+ struct sway_input_device *input_device = NULL;
+ wl_list_for_each(input_device, &server.input->devices, link) {
+ input_manager_reset_input(input_device);
+ }
+}
- seat_apply_config(seat, seat_config);
+
+void input_manager_apply_seat_config(struct seat_config *seat_config) {
+ wlr_log(WLR_DEBUG, "applying seat config for seat %s", seat_config->name);
+ if (strcmp(seat_config->name, "*") == 0) {
+ struct sway_seat *seat = NULL;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ // Only apply the wildcard config directly if there is no seat
+ // specific config
+ struct seat_config *sc = seat_get_config(seat);
+ if (!sc) {
+ sc = seat_config;
+ }
+ seat_apply_config(seat, sc);
+ }
+ } else {
+ struct sway_seat *seat = input_manager_get_seat(seat_config->name);
+ if (!seat) {
+ return;
+ }
+ seat_apply_config(seat, seat_config);
+ }
// for every device, try to add it to a seat and if no seat has it
// attached, add it to the fallback seats.
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index c1b53237..46286410 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -295,14 +295,10 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
get_active_binding(&keyboard->state_keysyms_raw,
config->current_mode->keysym_bindings, &binding,
raw_modifiers, false, input_inhibited, device_identifier);
-
- if (binding) {
- seat_execute_command(seat, binding);
- handled = true;
- }
}
- // Set up (or clear) keyboard repeat for a pressed binding
+ // Set up (or clear) keyboard repeat for a pressed binding. Since the
+ // binding may remove the keyboard, the timer needs to be updated first
if (binding && wlr_device->keyboard->repeat_info.delay > 0) {
keyboard->repeat_binding = binding;
if (wl_event_source_timer_update(keyboard->key_repeat_source,
@@ -316,6 +312,11 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
}
}
+ if (binding) {
+ seat_execute_command(seat, binding);
+ handled = true;
+ }
+
// Compositor bindings
if (!handled && event->state == WLR_KEY_PRESSED) {
handled = keyboard_execute_compositor_binding(
diff --git a/sway/input/seat.c b/sway/input/seat.c
index 663c5140..a63999b6 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -1,12 +1,7 @@
-#define _XOPEN_SOURCE 700
-#define _POSIX_C_SOURCE 199309L
+#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <errno.h>
-#ifdef __linux__
#include <linux/input-event-codes.h>
-#elif __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#endif
#include <strings.h>
#include <time.h>
#include <wlr/types/wlr_cursor.h>
@@ -175,6 +170,12 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
parent = node_get_parent(parent);
}
+ if (next_focus->type == N_WORKSPACE &&
+ !workspace_is_visible(next_focus->sway_workspace)) {
+ // Do not change focus to a non-visible workspace
+ return;
+ }
+
if (needs_new_focus) {
// The structure change might have caused it to move up to the top of
// the focus stack without sending focus notifications to the view
@@ -307,7 +308,7 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) {
wl_list_insert(&root->drag_icons, &icon->link);
drag_icon_update_position(icon);
- seat_end_mouse_operation(seat);
+ seatop_abort(seat);
}
static void collect_focus_iter(struct sway_node *node, void *data) {
@@ -387,6 +388,7 @@ static void seat_update_capabilities(struct sway_seat *seat) {
caps |= WL_SEAT_CAPABILITY_POINTER;
break;
case WLR_INPUT_DEVICE_TABLET_PAD:
+ case WLR_INPUT_DEVICE_SWITCH:
break;
}
}
@@ -403,6 +405,14 @@ static void seat_update_capabilities(struct sway_seat *seat) {
}
}
+static void seat_reset_input_config(struct sway_seat *seat,
+ struct sway_seat_device *sway_device) {
+ wlr_log(WLR_DEBUG, "Resetting output mapping for input device %s",
+ sway_device->input_device->identifier);
+ wlr_cursor_map_input_to_output(seat->cursor->cursor,
+ sway_device->input_device->wlr_device, NULL);
+}
+
static void seat_apply_input_config(struct sway_seat *seat,
struct sway_seat_device *sway_device) {
const char *mapped_to_output = NULL;
@@ -422,7 +432,13 @@ static void seat_apply_input_config(struct sway_seat *seat,
if (mapped_to_output != NULL) {
wlr_log(WLR_DEBUG, "Mapping input device %s to output %s",
sway_device->input_device->identifier, mapped_to_output);
- struct sway_output *output = output_by_name(mapped_to_output);
+ if (strcmp("*", mapped_to_output) == 0) {
+ wlr_cursor_map_input_to_output(seat->cursor->cursor,
+ sway_device->input_device->wlr_device, NULL);
+ wlr_log(WLR_DEBUG, "Reset output mapping");
+ return;
+ }
+ struct sway_output *output = output_by_name_or_id(mapped_to_output);
if (output) {
wlr_cursor_map_input_to_output(seat->cursor->cursor,
sway_device->input_device->wlr_device, output->wlr_output);
@@ -508,6 +524,38 @@ void seat_configure_device(struct sway_seat *seat,
case WLR_INPUT_DEVICE_TABLET_PAD:
wlr_log(WLR_DEBUG, "TODO: configure tablet pad");
break;
+ case WLR_INPUT_DEVICE_SWITCH:
+ wlr_log(WLR_DEBUG, "TODO: configure switch device");
+ break;
+ }
+}
+
+void seat_reset_device(struct sway_seat *seat,
+ struct sway_input_device *input_device) {
+ struct sway_seat_device *seat_device = seat_get_device(seat, input_device);
+ if (!seat_device) {
+ return;
+ }
+
+ switch (input_device->wlr_device->type) {
+ case WLR_INPUT_DEVICE_POINTER:
+ seat_reset_input_config(seat, seat_device);
+ break;
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ sway_keyboard_configure(seat_device->keyboard);
+ break;
+ case WLR_INPUT_DEVICE_TOUCH:
+ seat_reset_input_config(seat, seat_device);
+ break;
+ case WLR_INPUT_DEVICE_TABLET_TOOL:
+ seat_reset_input_config(seat, seat_device);
+ break;
+ case WLR_INPUT_DEVICE_TABLET_PAD:
+ wlr_log(WLR_DEBUG, "TODO: reset tablet pad");
+ break;
+ case WLR_INPUT_DEVICE_SWITCH:
+ wlr_log(WLR_DEBUG, "TODO: reset switch device");
+ break;
}
}
@@ -614,18 +662,6 @@ static int handle_urgent_timeout(void *data) {
return 0;
}
-static void container_raise_floating(struct sway_container *con) {
- // Bring container to front by putting it at the end of the floating list.
- struct sway_container *floater = con;
- while (floater->parent) {
- floater = floater->parent;
- }
- if (container_is_floating(floater)) {
- list_move_to_end(floater->workspace->floating, floater);
- node_set_dirty(&floater->workspace->node);
- }
-}
-
static void set_workspace(struct sway_seat *seat,
struct sway_workspace *new_ws) {
if (seat->workspace == new_ws) {
@@ -986,6 +1022,8 @@ void seat_apply_config(struct sway_seat *seat,
wl_list_for_each(seat_device, &seat->devices, link) {
seat_configure_device(seat, seat_device->input_device);
}
+
+ cursor_handle_activity(seat->cursor);
}
struct seat_config *seat_get_config(struct sway_seat *seat) {
@@ -1000,174 +1038,16 @@ struct seat_config *seat_get_config(struct sway_seat *seat) {
return NULL;
}
-void seat_begin_down(struct sway_seat *seat, struct sway_container *con,
- uint32_t button, double sx, double sy) {
- seat->operation = OP_DOWN;
- seat->op_container = con;
- seat->op_button = button;
- seat->op_ref_lx = seat->cursor->cursor->x;
- seat->op_ref_ly = seat->cursor->cursor->y;
- seat->op_ref_con_lx = sx;
- seat->op_ref_con_ly = sy;
- seat->op_moved = false;
-
- container_raise_floating(con);
-}
-
-void seat_begin_move_floating(struct sway_seat *seat,
- struct sway_container *con, uint32_t button) {
- if (!seat->cursor) {
- wlr_log(WLR_DEBUG, "Ignoring move request due to no cursor device");
- return;
- }
- seat->operation = OP_MOVE_FLOATING;
- seat->op_container = con;
- seat->op_button = button;
-
- container_raise_floating(con);
-
- cursor_set_image(seat->cursor, "grab", NULL);
-}
-
-void seat_begin_move_tiling(struct sway_seat *seat,
- struct sway_container *con, uint32_t button) {
- seat->operation = OP_MOVE_TILING;
- seat->op_container = con;
- seat->op_button = button;
- seat->op_target_node = NULL;
- seat->op_target_edge = 0;
- cursor_set_image(seat->cursor, "grab", NULL);
-}
-
-void seat_begin_resize_floating(struct sway_seat *seat,
- struct sway_container *con, uint32_t button, enum wlr_edges edge) {
- if (!seat->cursor) {
- wlr_log(WLR_DEBUG, "Ignoring resize request due to no cursor device");
- return;
- }
- struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
- seat->operation = OP_RESIZE_FLOATING;
- seat->op_container = con;
- seat->op_resize_preserve_ratio = keyboard &&
- (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT);
- seat->op_resize_edge = edge == WLR_EDGE_NONE ?
- WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge;
- seat->op_button = button;
- seat->op_ref_lx = seat->cursor->cursor->x;
- seat->op_ref_ly = seat->cursor->cursor->y;
- seat->op_ref_con_lx = con->x;
- seat->op_ref_con_ly = con->y;
- seat->op_ref_width = con->width;
- seat->op_ref_height = con->height;
-
- container_raise_floating(con);
-
- const char *image = edge == WLR_EDGE_NONE ?
- "se-resize" : wlr_xcursor_get_resize_name(edge);
- cursor_set_image(seat->cursor, image, NULL);
-}
-
-void seat_begin_resize_tiling(struct sway_seat *seat,
- struct sway_container *con, uint32_t button, enum wlr_edges edge) {
- seat->operation = OP_RESIZE_TILING;
- seat->op_container = con;
- seat->op_resize_edge = edge;
- seat->op_button = button;
- seat->op_ref_lx = seat->cursor->cursor->x;
- seat->op_ref_ly = seat->cursor->cursor->y;
- seat->op_ref_con_lx = con->x;
- seat->op_ref_con_ly = con->y;
- seat->op_ref_width = con->width;
- seat->op_ref_height = con->height;
-}
-
-static bool is_parallel(enum sway_container_layout layout,
- enum wlr_edges edge) {
- bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED;
- bool edge_is_horiz = edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT;
- return layout_is_horiz == edge_is_horiz;
-}
-
-static void seat_end_move_tiling(struct sway_seat *seat) {
- struct sway_container *con = seat->op_container;
- struct sway_container *old_parent = con->parent;
- struct sway_workspace *old_ws = con->workspace;
- struct sway_node *target_node = seat->op_target_node;
- struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ?
- target_node->sway_workspace : target_node->sway_container->workspace;
- enum wlr_edges edge = seat->op_target_edge;
- int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT;
-
- container_detach(con);
-
- // Moving container into empty workspace
- if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) {
- workspace_add_tiling(new_ws, con);
- } else if (target_node->type == N_CONTAINER) {
- // Moving container before/after another
- struct sway_container *target = target_node->sway_container;
- enum sway_container_layout layout = container_parent_layout(target);
- if (edge && !is_parallel(layout, edge)) {
- enum sway_container_layout new_layout = edge == WLR_EDGE_TOP ||
- edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ;
- container_split(target, new_layout);
- }
- container_add_sibling(target, con, after);
- } else {
- // Target is a workspace which requires splitting
- enum sway_container_layout new_layout = edge == WLR_EDGE_TOP ||
- edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ;
- workspace_split(new_ws, new_layout);
- workspace_insert_tiling(new_ws, con, after);
- }
-
- if (old_parent) {
- container_reap_empty(old_parent);
- }
-
- // This is a bit dirty, but we'll set the dimensions to that of a sibling.
- // I don't think there's any other way to make it consistent without
- // changing how we auto-size containers.
- list_t *siblings = container_get_siblings(con);
- if (siblings->length > 1) {
- int index = list_find(siblings, con);
- struct sway_container *sibling = index == 0 ?
- siblings->items[1] : siblings->items[index - 1];
- con->width = sibling->width;
- con->height = sibling->height;
- }
-
- arrange_workspace(old_ws);
- if (new_ws != old_ws) {
- arrange_workspace(new_ws);
- }
-}
-
-void seat_end_mouse_operation(struct sway_seat *seat) {
- enum sway_seat_operation operation = seat->operation;
- if (seat->operation == OP_MOVE_FLOATING) {
- // We "move" the container to its own location so it discovers its
- // output again.
- struct sway_container *con = seat->op_container;
- container_floating_move_to(con, con->x, con->y);
- } else if (seat->operation == OP_MOVE_TILING && seat->op_target_node) {
- seat_end_move_tiling(seat);
- }
- seat->operation = OP_NONE;
- seat->op_container = NULL;
- if (operation == OP_DOWN) {
- // Set the cursor's previous coords to the x/y at the start of the
- // operation, so the container change will be detected if using
- // focus_follows_mouse and the cursor moved off the original container
- // during the operation.
- seat->cursor->previous.x = seat->op_ref_lx;
- seat->cursor->previous.y = seat->op_ref_ly;
- if (seat->op_moved) {
- cursor_send_pointer_motion(seat->cursor, 0);
+struct seat_config *seat_get_config_by_name(const char *name) {
+ struct seat_config *seat_config = NULL;
+ for (int i = 0; i < config->seat_configs->length; ++i ) {
+ seat_config = config->seat_configs->items[i];
+ if (strcmp(name, seat_config->name) == 0) {
+ return seat_config;
}
- } else {
- cursor_set_image(seat->cursor, "left_ptr", NULL);
}
+
+ return NULL;
}
void seat_pointer_notify_button(struct sway_seat *seat, uint32_t time_msec,
@@ -1197,4 +1077,49 @@ void seat_consider_warp_to_focus(struct sway_seat *seat) {
} else {
cursor_warp_to_workspace(seat->cursor, focus->sway_workspace);
}
+ if (seat->cursor->hidden){
+ cursor_unhide(seat->cursor);
+ wl_event_source_timer_update(seat->cursor->hide_source, cursor_get_timeout(seat->cursor));
+ }
+}
+
+bool seat_doing_seatop(struct sway_seat *seat) {
+ return seat->seatop_impl != NULL;
+}
+
+void seatop_unref(struct sway_seat *seat, struct sway_container *con) {
+ if (seat->seatop_impl && seat->seatop_impl->unref) {
+ seat->seatop_impl->unref(seat, con);
+ }
+}
+
+void seatop_motion(struct sway_seat *seat, uint32_t time_msec) {
+ if (seat->seatop_impl && seat->seatop_impl->motion) {
+ seat->seatop_impl->motion(seat, time_msec);
+ }
+}
+
+void seatop_finish(struct sway_seat *seat) {
+ if (seat->seatop_impl && seat->seatop_impl->finish) {
+ seat->seatop_impl->finish(seat);
+ }
+ free(seat->seatop_data);
+ seat->seatop_data = NULL;
+ seat->seatop_impl = NULL;
+}
+
+void seatop_abort(struct sway_seat *seat) {
+ if (seat->seatop_impl && seat->seatop_impl->abort) {
+ seat->seatop_impl->abort(seat);
+ }
+ free(seat->seatop_data);
+ seat->seatop_data = NULL;
+ seat->seatop_impl = NULL;
+}
+
+void seatop_render(struct sway_seat *seat, struct sway_output *output,
+ pixman_region32_t *damage) {
+ if (seat->seatop_impl && seat->seatop_impl->render) {
+ seat->seatop_impl->render(seat, output, damage);
+ }
}
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c
new file mode 100644
index 00000000..ad11c5ca
--- /dev/null
+++ b/sway/input/seatop_down.c
@@ -0,0 +1,77 @@
+#define _POSIX_C_SOURCE 200809L
+#include <wlr/types/wlr_cursor.h>
+#include "sway/input/cursor.h"
+#include "sway/input/seat.h"
+#include "sway/tree/view.h"
+
+struct seatop_down_event {
+ struct sway_container *con;
+ double ref_lx, ref_ly; // cursor's x/y at start of op
+ double ref_con_lx, ref_con_ly; // container's x/y at start of op
+ bool moved;
+};
+
+static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
+ struct seatop_down_event *e = seat->seatop_data;
+ struct sway_container *con = e->con;
+ if (seat_is_input_allowed(seat, con->view->surface)) {
+ double moved_x = seat->cursor->cursor->x - e->ref_lx;
+ double moved_y = seat->cursor->cursor->y - e->ref_ly;
+ double sx = e->ref_con_lx + moved_x;
+ double sy = e->ref_con_ly + moved_y;
+ wlr_seat_pointer_notify_motion(seat->wlr_seat, time_msec, sx, sy);
+ }
+ e->moved = true;
+}
+
+static void handle_finish(struct sway_seat *seat) {
+ struct seatop_down_event *e = seat->seatop_data;
+ // Set the cursor's previous coords to the x/y at the start of the
+ // operation, so the container change will be detected if using
+ // focus_follows_mouse and the cursor moved off the original container
+ // during the operation.
+ seat->cursor->previous.x = e->ref_lx;
+ seat->cursor->previous.y = e->ref_ly;
+ if (e->moved) {
+ cursor_send_pointer_motion(seat->cursor, 0);
+ }
+}
+
+static void handle_abort(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
+ struct seatop_down_event *e = seat->seatop_data;
+ if (e->con == con) {
+ seatop_abort(seat);
+ }
+}
+
+static const struct sway_seatop_impl seatop_impl = {
+ .motion = handle_motion,
+ .finish = handle_finish,
+ .abort = handle_abort,
+ .unref = handle_unref,
+};
+
+void seatop_begin_down(struct sway_seat *seat,
+ struct sway_container *con, uint32_t button, int sx, int sy) {
+ seatop_abort(seat);
+
+ struct seatop_down_event *e =
+ calloc(1, sizeof(struct seatop_down_event));
+ if (!e) {
+ return;
+ }
+ e->con = con;
+ e->ref_lx = seat->cursor->cursor->x;
+ e->ref_ly = seat->cursor->cursor->y;
+ e->ref_con_lx = sx;
+ e->ref_con_ly = sy;
+ e->moved = false;
+
+ seat->seatop_impl = &seatop_impl;
+ seat->seatop_data = e;
+ seat->seatop_button = button;
+}
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c
new file mode 100644
index 00000000..08e3a5a4
--- /dev/null
+++ b/sway/input/seatop_move_floating.c
@@ -0,0 +1,65 @@
+#define _POSIX_C_SOURCE 200809L
+#include <wlr/types/wlr_cursor.h>
+#include "sway/desktop.h"
+#include "sway/input/cursor.h"
+#include "sway/input/seat.h"
+
+struct seatop_move_floating_event {
+ struct sway_container *con;
+};
+
+static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
+ struct seatop_move_floating_event *e = seat->seatop_data;
+ desktop_damage_whole_container(e->con);
+ container_floating_translate(e->con,
+ seat->cursor->cursor->x - seat->cursor->previous.x,
+ seat->cursor->cursor->y - seat->cursor->previous.y);
+ desktop_damage_whole_container(e->con);
+}
+
+static void handle_finish(struct sway_seat *seat) {
+ struct seatop_move_floating_event *e = seat->seatop_data;
+
+ // We "move" the container to its own location
+ // so it discovers its output again.
+ container_floating_move_to(e->con, e->con->x, e->con->y);
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_abort(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
+ struct seatop_move_floating_event *e = seat->seatop_data;
+ if (e->con == con) {
+ seatop_abort(seat);
+ }
+}
+
+static const struct sway_seatop_impl seatop_impl = {
+ .motion = handle_motion,
+ .finish = handle_finish,
+ .abort = handle_abort,
+ .unref = handle_unref,
+};
+
+void seatop_begin_move_floating(struct sway_seat *seat,
+ struct sway_container *con, uint32_t button) {
+ seatop_abort(seat);
+
+ struct seatop_move_floating_event *e =
+ calloc(1, sizeof(struct seatop_move_floating_event));
+ if (!e) {
+ return;
+ }
+ e->con = con;
+
+ seat->seatop_impl = &seatop_impl;
+ seat->seatop_data = e;
+ seat->seatop_button = button;
+
+ container_raise_floating(con);
+
+ cursor_set_image(seat->cursor, "grab", NULL);
+}
diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c
new file mode 100644
index 00000000..8b541f80
--- /dev/null
+++ b/sway/input/seatop_move_tiling.c
@@ -0,0 +1,335 @@
+#define _POSIX_C_SOURCE 200809L
+#include <limits.h>
+#include <wlr/types/wlr_cursor.h>
+#include <wlr/util/edges.h>
+#include "sway/desktop.h"
+#include "sway/input/cursor.h"
+#include "sway/input/seat.h"
+#include "sway/output.h"
+#include "sway/tree/arrange.h"
+#include "sway/tree/node.h"
+#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
+
+// Thickness of the dropzone when dragging to the edge of a layout container
+#define DROP_LAYOUT_BORDER 30
+
+struct seatop_move_tiling_event {
+ struct sway_container *con;
+ struct sway_node *target_node;
+ enum wlr_edges target_edge;
+ struct wlr_box drop_box;
+ double ref_lx, ref_ly; // cursor's x/y at start of op
+ bool threshold_reached;
+};
+
+static void handle_render(struct sway_seat *seat,
+ struct sway_output *output, pixman_region32_t *damage) {
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+ if (!e->threshold_reached) {
+ return;
+ }
+ if (e->target_node && node_get_output(e->target_node) == output) {
+ float color[4];
+ memcpy(&color, config->border_colors.focused.indicator,
+ sizeof(float) * 4);
+ premultiply_alpha(color, 0.5);
+ struct wlr_box box;
+ memcpy(&box, &e->drop_box, sizeof(struct wlr_box));
+ scale_box(&box, output->wlr_output->scale);
+ render_rect(output->wlr_output, damage, &box, color);
+ }
+}
+
+static void handle_motion_prethreshold(struct sway_seat *seat) {
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+ double cx = seat->cursor->cursor->x;
+ double cy = seat->cursor->cursor->y;
+ double sx = e->ref_lx;
+ double sy = e->ref_ly;
+
+ // Get the scaled threshold for the output. Even if the operation goes
+ // across multiple outputs of varying scales, just use the scale for the
+ // output that the cursor is currently on for simplicity.
+ struct wlr_output *wlr_output = wlr_output_layout_output_at(
+ root->output_layout, cx, cy);
+ double output_scale = wlr_output ? wlr_output->scale : 1;
+ double threshold = config->tiling_drag_threshold * output_scale;
+ threshold *= threshold;
+
+ // If the threshold has been exceeded, start the actual drag
+ if ((cx - sx) * (cx - sx) + (cy - sy) * (cy - sy) > threshold) {
+ e->threshold_reached = true;
+ cursor_set_image(seat->cursor, "grab", NULL);
+ }
+}
+
+static void resize_box(struct wlr_box *box, enum wlr_edges edge,
+ int thickness) {
+ switch (edge) {
+ case WLR_EDGE_TOP:
+ box->height = thickness;
+ break;
+ case WLR_EDGE_LEFT:
+ box->width = thickness;
+ break;
+ case WLR_EDGE_RIGHT:
+ box->x = box->x + box->width - thickness;
+ box->width = thickness;
+ break;
+ case WLR_EDGE_BOTTOM:
+ box->y = box->y + box->height - thickness;
+ box->height = thickness;
+ break;
+ case WLR_EDGE_NONE:
+ box->x += thickness;
+ box->y += thickness;
+ box->width -= thickness * 2;
+ box->height -= thickness * 2;
+ break;
+ }
+}
+
+static void handle_motion_postthreshold(struct sway_seat *seat) {
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+ struct wlr_surface *surface = NULL;
+ double sx, sy;
+ struct sway_cursor *cursor = seat->cursor;
+ struct sway_node *node = node_at_coords(seat,
+ cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy);
+ // Damage the old location
+ desktop_damage_box(&e->drop_box);
+
+ if (!node) {
+ // Eg. hovered over a layer surface such as swaybar
+ e->target_node = NULL;
+ e->target_edge = WLR_EDGE_NONE;
+ return;
+ }
+
+ if (node->type == N_WORKSPACE) {
+ // Emtpy workspace
+ e->target_node = node;
+ e->target_edge = WLR_EDGE_NONE;
+ workspace_get_box(node->sway_workspace, &e->drop_box);
+ desktop_damage_box(&e->drop_box);
+ return;
+ }
+
+ // Deny moving within own workspace if this is the only child
+ struct sway_container *con = node->sway_container;
+ if (workspace_num_tiling_views(e->con->workspace) == 1 &&
+ con->workspace == e->con->workspace) {
+ e->target_node = NULL;
+ e->target_edge = WLR_EDGE_NONE;
+ return;
+ }
+
+ // Traverse the ancestors, trying to find a layout container perpendicular
+ // to the edge. Eg. close to the top or bottom of a horiz layout.
+ while (con) {
+ enum wlr_edges edge = WLR_EDGE_NONE;
+ enum sway_container_layout layout = container_parent_layout(con);
+ struct wlr_box parent;
+ con->parent ? container_get_box(con->parent, &parent) :
+ workspace_get_box(con->workspace, &parent);
+ if (layout == L_HORIZ || layout == L_TABBED) {
+ if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) {
+ edge = WLR_EDGE_TOP;
+ } else if (cursor->cursor->y > parent.y + parent.height
+ - DROP_LAYOUT_BORDER) {
+ edge = WLR_EDGE_BOTTOM;
+ }
+ } else if (layout == L_VERT || layout == L_STACKED) {
+ if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) {
+ edge = WLR_EDGE_LEFT;
+ } else if (cursor->cursor->x > parent.x + parent.width
+ - DROP_LAYOUT_BORDER) {
+ edge = WLR_EDGE_RIGHT;
+ }
+ }
+ if (edge) {
+ e->target_node = node_get_parent(&con->node);
+ e->target_edge = edge;
+ node_get_box(e->target_node, &e->drop_box);
+ resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER);
+ desktop_damage_box(&e->drop_box);
+ return;
+ }
+ con = con->parent;
+ }
+
+ // Use the hovered view - but we must be over the actual surface
+ con = node->sway_container;
+ if (!con->view->surface || node == &e->con->node) {
+ e->target_node = NULL;
+ e->target_edge = WLR_EDGE_NONE;
+ return;
+ }
+
+ // Find the closest edge
+ size_t thickness = fmin(con->content_width, con->content_height) * 0.3;
+ size_t closest_dist = INT_MAX;
+ size_t dist;
+ e->target_edge = WLR_EDGE_NONE;
+ if ((dist = cursor->cursor->y - con->y) < closest_dist) {
+ closest_dist = dist;
+ e->target_edge = WLR_EDGE_TOP;
+ }
+ if ((dist = cursor->cursor->x - con->x) < closest_dist) {
+ closest_dist = dist;
+ e->target_edge = WLR_EDGE_LEFT;
+ }
+ if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) {
+ closest_dist = dist;
+ e->target_edge = WLR_EDGE_RIGHT;
+ }
+ if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) {
+ closest_dist = dist;
+ e->target_edge = WLR_EDGE_BOTTOM;
+ }
+
+ if (closest_dist > thickness) {
+ e->target_edge = WLR_EDGE_NONE;
+ }
+
+ e->target_node = node;
+ e->drop_box.x = con->content_x;
+ e->drop_box.y = con->content_y;
+ e->drop_box.width = con->content_width;
+ e->drop_box.height = con->content_height;
+ resize_box(&e->drop_box, e->target_edge, thickness);
+ desktop_damage_box(&e->drop_box);
+}
+
+static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+ if (e->threshold_reached) {
+ handle_motion_postthreshold(seat);
+ } else {
+ handle_motion_prethreshold(seat);
+ }
+}
+
+static void handle_abort(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static bool is_parallel(enum sway_container_layout layout,
+ enum wlr_edges edge) {
+ bool layout_is_horiz = layout == L_HORIZ || layout == L_TABBED;
+ bool edge_is_horiz = edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT;
+ return layout_is_horiz == edge_is_horiz;
+}
+
+static void handle_finish(struct sway_seat *seat) {
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+
+ if (!e->target_node) {
+ handle_abort(seat);
+ return;
+ }
+
+ struct sway_container *con = e->con;
+ struct sway_container *old_parent = con->parent;
+ struct sway_workspace *old_ws = con->workspace;
+ struct sway_node *target_node = e->target_node;
+ struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ?
+ target_node->sway_workspace : target_node->sway_container->workspace;
+ enum wlr_edges edge = e->target_edge;
+ int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT;
+
+ container_detach(con);
+
+ // Moving container into empty workspace
+ if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) {
+ workspace_add_tiling(new_ws, con);
+ } else if (target_node->type == N_CONTAINER) {
+ // Moving container before/after another
+ struct sway_container *target = target_node->sway_container;
+ enum sway_container_layout layout = container_parent_layout(target);
+ if (edge && !is_parallel(layout, edge)) {
+ enum sway_container_layout new_layout = edge == WLR_EDGE_TOP ||
+ edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ;
+ container_split(target, new_layout);
+ }
+ container_add_sibling(target, con, after);
+ } else {
+ // Target is a workspace which requires splitting
+ enum sway_container_layout new_layout = edge == WLR_EDGE_TOP ||
+ edge == WLR_EDGE_BOTTOM ? L_VERT : L_HORIZ;
+ workspace_split(new_ws, new_layout);
+ workspace_insert_tiling(new_ws, con, after);
+ }
+
+ if (old_parent) {
+ container_reap_empty(old_parent);
+ }
+
+ // This is a bit dirty, but we'll set the dimensions to that of a sibling.
+ // I don't think there's any other way to make it consistent without
+ // changing how we auto-size containers.
+ list_t *siblings = container_get_siblings(con);
+ if (siblings->length > 1) {
+ int index = list_find(siblings, con);
+ struct sway_container *sibling = index == 0 ?
+ siblings->items[1] : siblings->items[index - 1];
+ con->width = sibling->width;
+ con->height = sibling->height;
+ }
+
+ arrange_workspace(old_ws);
+ if (new_ws != old_ws) {
+ arrange_workspace(new_ws);
+ }
+
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+ if (e->target_node == &con->node) { // Drop target
+ e->target_node = NULL;
+ }
+ if (e->con == con) { // The container being moved
+ seatop_abort(seat);
+ }
+}
+
+static const struct sway_seatop_impl seatop_impl = {
+ .motion = handle_motion,
+ .finish = handle_finish,
+ .abort = handle_abort,
+ .unref = handle_unref,
+ .render = handle_render,
+};
+
+void seatop_begin_move_tiling_threshold(struct sway_seat *seat,
+ struct sway_container *con, uint32_t button) {
+ seatop_abort(seat);
+
+ struct seatop_move_tiling_event *e =
+ calloc(1, sizeof(struct seatop_move_tiling_event));
+ if (!e) {
+ return;
+ }
+ e->con = con;
+ e->ref_lx = seat->cursor->cursor->x;
+ e->ref_ly = seat->cursor->cursor->y;
+
+ seat->seatop_impl = &seatop_impl;
+ seat->seatop_data = e;
+ seat->seatop_button = button;
+
+ container_raise_floating(con);
+}
+
+void seatop_begin_move_tiling(struct sway_seat *seat,
+ struct sway_container *con, uint32_t button) {
+ seatop_begin_move_tiling_threshold(seat, con, button);
+ struct seatop_move_tiling_event *e = seat->seatop_data;
+ if (e) {
+ e->threshold_reached = true;
+ cursor_set_image(seat->cursor, "grab", NULL);
+ }
+}
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c
new file mode 100644
index 00000000..12851b40
--- /dev/null
+++ b/sway/input/seatop_resize_floating.c
@@ -0,0 +1,199 @@
+#define _POSIX_C_SOURCE 200809L
+#include <limits.h>
+#include <wlr/types/wlr_cursor.h>
+#include <wlr/types/wlr_xcursor_manager.h>
+#include "sway/input/cursor.h"
+#include "sway/input/seat.h"
+#include "sway/tree/arrange.h"
+#include "sway/tree/view.h"
+#include "sway/tree/workspace.h"
+
+struct seatop_resize_floating_event {
+ struct sway_container *con;
+ enum wlr_edges edge;
+ bool preserve_ratio;
+ double ref_lx, ref_ly; // cursor's x/y at start of op
+ double ref_width, ref_height; // container's size at start of op
+ double ref_con_lx, ref_con_ly; // container's x/y at start of op
+};
+
+static void calculate_floating_constraints(struct sway_container *con,
+ int *min_width, int *max_width, int *min_height, int *max_height) {
+ if (config->floating_minimum_width == -1) { // no minimum
+ *min_width = 0;
+ } else if (config->floating_minimum_width == 0) { // automatic
+ *min_width = 75;
+ } else {
+ *min_width = config->floating_minimum_width;
+ }
+
+ if (config->floating_minimum_height == -1) { // no minimum
+ *min_height = 0;
+ } else if (config->floating_minimum_height == 0) { // automatic
+ *min_height = 50;
+ } else {
+ *min_height = config->floating_minimum_height;
+ }
+
+ if (config->floating_maximum_width == -1) { // no maximum
+ *max_width = INT_MAX;
+ } else if (config->floating_maximum_width == 0) { // automatic
+ *max_width = con->workspace->width;
+ } else {
+ *max_width = config->floating_maximum_width;
+ }
+
+ if (config->floating_maximum_height == -1) { // no maximum
+ *max_height = INT_MAX;
+ } else if (config->floating_maximum_height == 0) { // automatic
+ *max_height = con->workspace->height;
+ } else {
+ *max_height = config->floating_maximum_height;
+ }
+}
+
+static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
+ struct seatop_resize_floating_event *e = seat->seatop_data;
+ struct sway_container *con = e->con;
+ enum wlr_edges edge = e->edge;
+ struct sway_cursor *cursor = seat->cursor;
+
+ // The amount the mouse has moved since the start of the resize operation
+ // Positive is down/right
+ double mouse_move_x = cursor->cursor->x - e->ref_lx;
+ double mouse_move_y = cursor->cursor->y - e->ref_ly;
+
+ if (edge == WLR_EDGE_TOP || edge == WLR_EDGE_BOTTOM) {
+ mouse_move_x = 0;
+ }
+ if (edge == WLR_EDGE_LEFT || edge == WLR_EDGE_RIGHT) {
+ mouse_move_y = 0;
+ }
+
+ double grow_width = edge & WLR_EDGE_LEFT ? -mouse_move_x : mouse_move_x;
+ double grow_height = edge & WLR_EDGE_TOP ? -mouse_move_y : mouse_move_y;
+
+ if (e->preserve_ratio) {
+ double x_multiplier = grow_width / e->ref_width;
+ double y_multiplier = grow_height / e->ref_height;
+ double max_multiplier = fmax(x_multiplier, y_multiplier);
+ grow_width = e->ref_width * max_multiplier;
+ grow_height = e->ref_height * max_multiplier;
+ }
+
+ // Determine new width/height, and accommodate for floating min/max values
+ double width = e->ref_width + grow_width;
+ double height = e->ref_height + grow_height;
+ int min_width, max_width, min_height, max_height;
+ calculate_floating_constraints(con, &min_width, &max_width,
+ &min_height, &max_height);
+ width = fmax(min_width, fmin(width, max_width));
+ height = fmax(min_height, fmin(height, max_height));
+
+ // Apply the view's min/max size
+ if (con->view) {
+ double view_min_width, view_max_width, view_min_height, view_max_height;
+ view_get_constraints(con->view, &view_min_width, &view_max_width,
+ &view_min_height, &view_max_height);
+ width = fmax(view_min_width, fmin(width, view_max_width));
+ height = fmax(view_min_height, fmin(height, view_max_height));
+ }
+
+ // Recalculate these, in case we hit a min/max limit
+ grow_width = width - e->ref_width;
+ grow_height = height - e->ref_height;
+
+ // Determine grow x/y values - these are relative to the container's x/y at
+ // the start of the resize operation.
+ double grow_x = 0, grow_y = 0;
+ if (edge & WLR_EDGE_LEFT) {
+ grow_x = -grow_width;
+ } else if (edge & WLR_EDGE_RIGHT) {
+ grow_x = 0;
+ } else {
+ grow_x = -grow_width / 2;
+ }
+ if (edge & WLR_EDGE_TOP) {
+ grow_y = -grow_height;
+ } else if (edge & WLR_EDGE_BOTTOM) {
+ grow_y = 0;
+ } else {
+ grow_y = -grow_height / 2;
+ }
+
+ // Determine the amounts we need to bump everything relative to the current
+ // size.
+ int relative_grow_width = width - con->width;
+ int relative_grow_height = height - con->height;
+ int relative_grow_x = (e->ref_con_lx + grow_x) - con->x;
+ int relative_grow_y = (e->ref_con_ly + grow_y) - con->y;
+
+ // Actually resize stuff
+ con->x += relative_grow_x;
+ con->y += relative_grow_y;
+ con->width += relative_grow_width;
+ con->height += relative_grow_height;
+
+ con->content_x += relative_grow_x;
+ con->content_y += relative_grow_y;
+ con->content_width += relative_grow_width;
+ con->content_height += relative_grow_height;
+
+ arrange_container(con);
+}
+
+static void handle_finish(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_abort(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
+ struct seatop_resize_floating_event *e = seat->seatop_data;
+ if (e->con == con) {
+ seatop_abort(seat);
+ }
+}
+
+static const struct sway_seatop_impl seatop_impl = {
+ .motion = handle_motion,
+ .finish = handle_finish,
+ .abort = handle_abort,
+ .unref = handle_unref,
+};
+
+void seatop_begin_resize_floating(struct sway_seat *seat,
+ struct sway_container *con, uint32_t button, enum wlr_edges edge) {
+ seatop_abort(seat);
+
+ struct seatop_resize_floating_event *e =
+ calloc(1, sizeof(struct seatop_resize_floating_event));
+ if (!e) {
+ return;
+ }
+ e->con = con;
+
+ struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
+ e->preserve_ratio = keyboard &&
+ (wlr_keyboard_get_modifiers(keyboard) & WLR_MODIFIER_SHIFT);
+
+ e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge;
+ e->ref_lx = seat->cursor->cursor->x;
+ e->ref_ly = seat->cursor->cursor->y;
+ e->ref_con_lx = con->x;
+ e->ref_con_ly = con->y;
+ e->ref_width = con->width;
+ e->ref_height = con->height;
+
+ seat->seatop_impl = &seatop_impl;
+ seat->seatop_data = e;
+ seat->seatop_button = button;
+
+ container_raise_floating(con);
+
+ const char *image = edge == WLR_EDGE_NONE ?
+ "se-resize" : wlr_xcursor_get_resize_name(edge);
+ cursor_set_image(seat->cursor, image, NULL);
+}
diff --git a/sway/input/seatop_resize_tiling.c b/sway/input/seatop_resize_tiling.c
new file mode 100644
index 00000000..30431f04
--- /dev/null
+++ b/sway/input/seatop_resize_tiling.c
@@ -0,0 +1,92 @@
+#define _POSIX_C_SOURCE 200809L
+#include <wlr/types/wlr_cursor.h>
+#include "sway/commands.h"
+#include "sway/input/cursor.h"
+#include "sway/input/seat.h"
+
+struct seatop_resize_tiling_event {
+ struct sway_container *con;
+ enum wlr_edges edge;
+ double ref_lx, ref_ly; // cursor's x/y at start of op
+ double ref_width, ref_height; // container's size at start of op
+ double ref_con_lx, ref_con_ly; // container's x/y at start of op
+};
+
+static void handle_motion(struct sway_seat *seat, uint32_t time_msec) {
+ struct seatop_resize_tiling_event *e = seat->seatop_data;
+ int amount_x = 0;
+ int amount_y = 0;
+ int moved_x = seat->cursor->cursor->x - e->ref_lx;
+ int moved_y = seat->cursor->cursor->y - e->ref_ly;
+ enum wlr_edges edge_x = WLR_EDGE_NONE;
+ enum wlr_edges edge_y = WLR_EDGE_NONE;
+ struct sway_container *con = e->con;
+
+ if (e->edge & WLR_EDGE_TOP) {
+ amount_y = (e->ref_height - moved_y) - con->height;
+ edge_y = WLR_EDGE_TOP;
+ } else if (e->edge & WLR_EDGE_BOTTOM) {
+ amount_y = (e->ref_height + moved_y) - con->height;
+ edge_y = WLR_EDGE_BOTTOM;
+ }
+ if (e->edge & WLR_EDGE_LEFT) {
+ amount_x = (e->ref_width - moved_x) - con->width;
+ edge_x = WLR_EDGE_LEFT;
+ } else if (e->edge & WLR_EDGE_RIGHT) {
+ amount_x = (e->ref_width + moved_x) - con->width;
+ edge_x = WLR_EDGE_RIGHT;
+ }
+
+ if (amount_x != 0) {
+ container_resize_tiled(e->con, edge_x, amount_x);
+ }
+ if (amount_y != 0) {
+ container_resize_tiled(e->con, edge_y, amount_y);
+ }
+}
+
+static void handle_finish(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_abort(struct sway_seat *seat) {
+ cursor_set_image(seat->cursor, "left_ptr", NULL);
+}
+
+static void handle_unref(struct sway_seat *seat, struct sway_container *con) {
+ struct seatop_resize_tiling_event *e = seat->seatop_data;
+ if (e->con == con) {
+ seatop_abort(seat);
+ }
+}
+
+static const struct sway_seatop_impl seatop_impl = {
+ .motion = handle_motion,
+ .finish = handle_finish,
+ .abort = handle_abort,
+ .unref = handle_unref,
+};
+
+void seatop_begin_resize_tiling(struct sway_seat *seat,
+ struct sway_container *con, uint32_t button, enum wlr_edges edge) {
+ seatop_abort(seat);
+
+ struct seatop_resize_tiling_event *e =
+ calloc(1, sizeof(struct seatop_resize_tiling_event));
+ if (!e) {
+ return;
+ }
+ e->con = con;
+ e->edge = edge;
+
+ e->ref_lx = seat->cursor->cursor->x;
+ e->ref_ly = seat->cursor->cursor->y;
+ e->ref_con_lx = con->x;
+ e->ref_con_ly = con->y;
+ e->ref_width = con->width;
+ e->ref_height = con->height;
+
+ seat->seatop_impl = &seatop_impl;
+ seat->seatop_data = e;
+ seat->seatop_button = button;
+}
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index e3450df1..6e5ba4fd 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -1,6 +1,8 @@
#include <json-c/json.h>
+#include <libevdev/libevdev.h>
#include <stdio.h>
#include <ctype.h>
+#include "config.h"
#include "log.h"
#include "sway/config.h"
#include "sway/ipc-json.h"
@@ -9,12 +11,17 @@
#include "sway/tree/workspace.h"
#include "sway/output.h"
#include "sway/input/input-manager.h"
+#include "sway/input/cursor.h"
#include "sway/input/seat.h"
+#include <wlr/backend/libinput.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 int i3_output_id = INT32_MAX;
+static const int i3_scratch_id = INT32_MAX - 1;
+
static const char *ipc_json_layout_description(enum sway_container_layout l) {
switch (l) {
case L_VERT:
@@ -32,15 +39,68 @@ static const char *ipc_json_layout_description(enum sway_container_layout l) {
}
static const char *ipc_json_orientation_description(enum sway_container_layout l) {
- if (l == L_VERT) {
+ switch (l) {
+ case L_VERT:
return "vertical";
+ case L_HORIZ:
+ return "horizontal";
+ default:
+ return "none";
}
+}
- if (l == L_HORIZ) {
- return "horizontal";
+static const char *ipc_json_border_description(enum sway_container_border border) {
+ switch (border) {
+ case B_NONE:
+ return "none";
+ case B_PIXEL:
+ return "pixel";
+ case B_NORMAL:
+ return "normal";
+ case B_CSD:
+ return "csd";
}
+ return "unknown";
+}
- return "none";
+static const char *ipc_json_output_transform_description(enum wl_output_transform transform) {
+ switch (transform) {
+ case WL_OUTPUT_TRANSFORM_NORMAL:
+ return "normal";
+ case WL_OUTPUT_TRANSFORM_90:
+ return "90";
+ case WL_OUTPUT_TRANSFORM_180:
+ return "180";
+ case WL_OUTPUT_TRANSFORM_270:
+ return "270";
+ case WL_OUTPUT_TRANSFORM_FLIPPED:
+ return "flipped";
+ case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+ return "flipped-90";
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ return "flipped-180";
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ return "flipped-270";
+ }
+ return NULL;
+}
+
+static const char *ipc_json_device_type_description(struct sway_input_device *device) {
+ switch (device->wlr_device->type) {
+ case WLR_INPUT_DEVICE_POINTER:
+ return "pointer";
+ case WLR_INPUT_DEVICE_KEYBOARD:
+ return "keyboard";
+ case WLR_INPUT_DEVICE_TOUCH:
+ return "touch";
+ case WLR_INPUT_DEVICE_TABLET_TOOL:
+ return "tablet_tool";
+ case WLR_INPUT_DEVICE_TABLET_PAD:
+ return "tablet_pad";
+ case WLR_INPUT_DEVICE_SWITCH:
+ return "switch";
+ }
+ return "unknown";
}
json_object *ipc_json_get_version(void) {
@@ -76,30 +136,43 @@ static json_object *ipc_json_create_empty_rect(void) {
return ipc_json_create_rect(&empty);
}
-static void ipc_json_describe_root(struct sway_root *root, json_object *object) {
- json_object_object_add(object, "type", json_object_new_string("root"));
+static json_object *ipc_json_create_node(int id, char *name,
+ bool focused, json_object *focus, struct wlr_box *box) {
+ json_object *object = json_object_new_object();
+
+ json_object_object_add(object, "id", json_object_new_int(id));
+ json_object_object_add(object, "name",
+ name ? json_object_new_string(name) : NULL);
+ json_object_object_add(object, "rect", ipc_json_create_rect(box));
+ json_object_object_add(object, "focused", json_object_new_boolean(focused));
+ json_object_object_add(object, "focus", focus);
+
+ // set default values to be compatible with i3
+ json_object_object_add(object, "border",
+ json_object_new_string(
+ ipc_json_border_description(B_NONE)));
+ json_object_object_add(object, "current_border_width",
+ json_object_new_int(0));
+ json_object_object_add(object, "layout",
+ json_object_new_string(
+ ipc_json_layout_description(L_HORIZ)));
+ json_object_object_add(object, "orientation",
+ json_object_new_string(
+ ipc_json_orientation_description(L_HORIZ)));
+ json_object_object_add(object, "percent", NULL);
+ json_object_object_add(object, "window_rect", ipc_json_create_empty_rect());
+ json_object_object_add(object, "deco_rect", ipc_json_create_empty_rect());
+ json_object_object_add(object, "geometry", ipc_json_create_empty_rect());
+ json_object_object_add(object, "window", NULL);
+ json_object_object_add(object, "urgent", json_object_new_boolean(false));
+ json_object_object_add(object, "floating_nodes", json_object_new_array());
+ json_object_object_add(object, "sticky", json_object_new_boolean(false));
+
+ return object;
}
-static const char *ipc_json_get_output_transform(enum wl_output_transform transform) {
- switch (transform) {
- case WL_OUTPUT_TRANSFORM_NORMAL:
- return "normal";
- case WL_OUTPUT_TRANSFORM_90:
- return "90";
- case WL_OUTPUT_TRANSFORM_180:
- return "180";
- case WL_OUTPUT_TRANSFORM_270:
- return "270";
- case WL_OUTPUT_TRANSFORM_FLIPPED:
- return "flipped";
- case WL_OUTPUT_TRANSFORM_FLIPPED_90:
- return "flipped-90";
- case WL_OUTPUT_TRANSFORM_FLIPPED_180:
- return "flipped-180";
- case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- return "flipped-270";
- }
- return NULL;
+static void ipc_json_describe_root(struct sway_root *root, json_object *object) {
+ json_object_object_add(object, "type", json_object_new_string("root"));
}
static void ipc_json_describe_output(struct sway_output *output,
@@ -110,7 +183,8 @@ static void ipc_json_describe_output(struct sway_output *output,
json_object_object_add(object, "primary", json_object_new_boolean(false));
json_object_object_add(object, "layout", json_object_new_string("output"));
json_object_object_add(object, "orientation",
- json_object_new_string(ipc_json_orientation_description(L_NONE)));
+ json_object_new_string(
+ ipc_json_orientation_description(L_NONE)));
json_object_object_add(object, "make",
json_object_new_string(wlr_output->make));
json_object_object_add(object, "model",
@@ -121,7 +195,7 @@ static void ipc_json_describe_output(struct sway_output *output,
json_object_new_double(wlr_output->scale));
json_object_object_add(object, "transform",
json_object_new_string(
- ipc_json_get_output_transform(wlr_output->transform)));
+ ipc_json_output_transform_description(wlr_output->transform)));
struct sway_workspace *ws = output_get_active_workspace(output);
json_object_object_add(object, "current_workspace",
@@ -187,6 +261,52 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
return object;
}
+static json_object *ipc_json_describe_scratchpad_output(void) {
+ struct wlr_box box;
+ root_get_box(root, &box);
+
+ // Create focus stack for __i3_scratch workspace
+ json_object *workspace_focus = json_object_new_array();
+ for (int i = root->scratchpad->length - 1; i >= 0; --i) {
+ struct sway_container *container = root->scratchpad->items[i];
+ json_object_array_add(workspace_focus,
+ json_object_new_int(container->node.id));
+ }
+
+ json_object *workspace = ipc_json_create_node(i3_scratch_id,
+ "__i3_scratch", false, workspace_focus, &box);
+ json_object_object_add(workspace, "type",
+ json_object_new_string("workspace"));
+
+ // List all hidden scratchpad containers as floating nodes
+ json_object *floating_array = json_object_new_array();
+ for (int i = 0; i < root->scratchpad->length; ++i) {
+ struct sway_container *container = root->scratchpad->items[i];
+ if (!container->workspace) {
+ json_object_array_add(floating_array,
+ ipc_json_describe_node_recursive(&container->node));
+ }
+ }
+ json_object_object_add(workspace, "floating_nodes", floating_array);
+
+ // Create focus stack for __i3 output
+ json_object *output_focus = json_object_new_array();
+ json_object_array_add(output_focus, json_object_new_int(i3_scratch_id));
+
+ json_object *output = ipc_json_create_node(i3_output_id,
+ "__i3", false, output_focus, &box);
+ json_object_object_add(output, "type",
+ json_object_new_string("output"));
+ json_object_object_add(output, "layout",
+ json_object_new_string("output"));
+
+ json_object *nodes = json_object_new_array();
+ json_object_array_add(nodes, workspace);
+ json_object_object_add(output, "nodes", nodes);
+
+ return output;
+}
+
static void ipc_json_describe_workspace(struct sway_workspace *workspace,
json_object *object) {
int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1;
@@ -200,11 +320,12 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
json_object_object_add(object, "representation", workspace->representation ?
json_object_new_string(workspace->representation) : NULL);
- const char *layout = ipc_json_layout_description(workspace->layout);
- json_object_object_add(object, "layout", json_object_new_string(layout));
-
- const char *orientation = ipc_json_orientation_description(workspace->layout);
- json_object_object_add(object, "orientation", json_object_new_string(orientation));
+ json_object_object_add(object, "layout",
+ json_object_new_string(
+ ipc_json_layout_description(workspace->layout)));
+ json_object_object_add(object, "orientation",
+ json_object_new_string(
+ ipc_json_orientation_description(workspace->layout)));
// Floating
json_object *floating_array = json_object_new_array();
@@ -216,20 +337,6 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
json_object_object_add(object, "floating_nodes", floating_array);
}
-static const char *describe_container_border(enum sway_container_border border) {
- switch (border) {
- case B_NONE:
- return "none";
- case B_PIXEL:
- return "pixel";
- case B_NORMAL:
- return "normal";
- case B_CSD:
- return "csd";
- }
- return "unknown";
-}
-
static void ipc_json_describe_view(struct sway_container *c, json_object *object) {
json_object_object_add(object, "pid", json_object_new_int(c->view->pid));
@@ -307,15 +414,18 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
json_object_new_string(container_is_floating(c) ? "floating_con" : "con"));
json_object_object_add(object, "layout",
- json_object_new_string(ipc_json_layout_description(c->layout)));
+ json_object_new_string(
+ ipc_json_layout_description(c->layout)));
json_object_object_add(object, "orientation",
- json_object_new_string(ipc_json_orientation_description(c->layout)));
+ json_object_new_string(
+ ipc_json_orientation_description(c->layout)));
bool urgent = c->view ?
view_is_urgent(c->view) : container_has_urgent_child(c);
json_object_object_add(object, "urgent", json_object_new_boolean(urgent));
json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky));
+ json_object_object_add(object, "fullscreen_mode", json_object_new_int(c->is_fullscreen));
struct sway_node *parent = node_get_parent(&c->node);
struct wlr_box parent_box = {0, 0, 0, 0};
@@ -331,7 +441,8 @@ static void ipc_json_describe_container(struct sway_container *c, json_object *o
}
json_object_object_add(object, "border",
- json_object_new_string(describe_container_border(c->current.border)));
+ json_object_new_string(
+ ipc_json_border_description(c->current.border)));
json_object_object_add(object, "current_border_width",
json_object_new_int(c->current.border_thickness));
json_object_object_add(object, "floating_nodes", json_object_new_array());
@@ -372,17 +483,10 @@ static void focus_inactive_children_iterator(struct sway_node *node,
json_object *ipc_json_describe_node(struct sway_node *node) {
struct sway_seat *seat = input_manager_get_default_seat();
bool focused = seat_get_focus(seat) == node;
-
- json_object *object = json_object_new_object();
char *name = node_get_name(node);
struct wlr_box box;
node_get_box(node, &box);
- json_object_object_add(object, "id", json_object_new_int((int)node->id));
- json_object_object_add(object, "name",
- name ? json_object_new_string(name) : NULL);
- json_object_object_add(object, "rect", ipc_json_create_rect(&box));
- json_object_object_add(object, "focused", json_object_new_boolean(focused));
json_object *focus = json_object_new_array();
struct focus_inactive_data data = {
@@ -390,24 +494,9 @@ json_object *ipc_json_describe_node(struct sway_node *node) {
.object = focus,
};
seat_for_each_node(seat, focus_inactive_children_iterator, &data);
- json_object_object_add(object, "focus", focus);
- // set default values to be compatible with i3
- json_object_object_add(object, "border",
- json_object_new_string(describe_container_border(B_NONE)));
- json_object_object_add(object, "current_border_width", json_object_new_int(0));
- json_object_object_add(object, "layout",
- json_object_new_string(ipc_json_layout_description(L_HORIZ)));
- json_object_object_add(object, "orientation",
- json_object_new_string(ipc_json_orientation_description(L_HORIZ)));
- json_object_object_add(object, "percent", NULL);
- json_object_object_add(object, "window_rect", ipc_json_create_empty_rect());
- json_object_object_add(object, "deco_rect", ipc_json_create_empty_rect());
- json_object_object_add(object, "geometry", ipc_json_create_empty_rect());
- json_object_object_add(object, "window", NULL);
- json_object_object_add(object, "urgent", json_object_new_boolean(false));
- json_object_object_add(object, "floating_nodes", json_object_new_array());
- json_object_object_add(object, "sticky", json_object_new_boolean(false));
+ json_object *object = ipc_json_create_node(
+ (int)node->id, name, focused, focus, &box);
switch (node->type) {
case N_ROOT:
@@ -434,6 +523,8 @@ json_object *ipc_json_describe_node_recursive(struct sway_node *node) {
json_object *children = json_object_new_array();
switch (node->type) {
case N_ROOT:
+ json_object_array_add(children,
+ ipc_json_describe_scratchpad_output());
for (i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
json_object_array_add(children,
@@ -470,22 +561,6 @@ json_object *ipc_json_describe_node_recursive(struct sway_node *node) {
return object;
}
-static const char *describe_device_type(struct sway_input_device *device) {
- switch (device->wlr_device->type) {
- case WLR_INPUT_DEVICE_POINTER:
- return "pointer";
- case WLR_INPUT_DEVICE_KEYBOARD:
- return "keyboard";
- case WLR_INPUT_DEVICE_TOUCH:
- return "touch";
- case WLR_INPUT_DEVICE_TABLET_TOOL:
- return "tablet_tool";
- case WLR_INPUT_DEVICE_TABLET_PAD:
- return "tablet_pad";
- }
- return "unknown";
-}
-
json_object *ipc_json_describe_input(struct sway_input_device *device) {
if (!(sway_assert(device, "Device must not be null"))) {
return NULL;
@@ -502,7 +577,8 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
json_object_object_add(object, "product",
json_object_new_int(device->wlr_device->product));
json_object_object_add(object, "type",
- json_object_new_string(describe_device_type(device)));
+ json_object_new_string(
+ ipc_json_device_type_description(device)));
if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
struct wlr_keyboard *keyboard = device->wlr_device->keyboard;
@@ -525,6 +601,26 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
}
}
+ if (wlr_input_device_is_libinput(device->wlr_device)) {
+ struct libinput_device *libinput_dev;
+ libinput_dev = wlr_libinput_get_device_handle(device->wlr_device);
+
+ const char *events = "unknown";
+ switch (libinput_device_config_send_events_get_mode(libinput_dev)) {
+ case LIBINPUT_CONFIG_SEND_EVENTS_ENABLED:
+ events = "enabled";
+ break;
+ case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE:
+ events = "disabled_on_external_mouse";
+ break;
+ case LIBINPUT_CONFIG_SEND_EVENTS_DISABLED:
+ events = "disabled";
+ break;
+ }
+ json_object_object_add(object, "libinput_send_events",
+ json_object_new_string(events));
+ }
+
return object;
}
@@ -553,6 +649,31 @@ json_object *ipc_json_describe_seat(struct sway_seat *seat) {
return object;
}
+static uint32_t event_to_x11_button(uint32_t event) {
+ switch (event) {
+ case BTN_LEFT:
+ return 1;
+ case BTN_MIDDLE:
+ return 2;
+ case BTN_RIGHT:
+ return 3;
+ case SWAY_SCROLL_UP:
+ return 4;
+ case SWAY_SCROLL_DOWN:
+ return 5;
+ case SWAY_SCROLL_LEFT:
+ return 6;
+ case SWAY_SCROLL_RIGHT:
+ return 7;
+ case BTN_SIDE:
+ return 8;
+ case BTN_EXTRA:
+ return 9;
+ default:
+ return 0;
+ }
+}
+
json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
if (!sway_assert(bar, "Bar must not be NULL")) {
return NULL;
@@ -569,18 +690,36 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
json_object_new_string(bar->status_command) : NULL);
json_object_object_add(json, "font",
json_object_new_string((bar->font) ? bar->font : config->font));
+
+ json_object *gaps = json_object_new_object();
+ json_object_object_add(gaps, "top",
+ json_object_new_int(bar->gaps.top));
+ json_object_object_add(gaps, "right",
+ json_object_new_int(bar->gaps.right));
+ json_object_object_add(gaps, "bottom",
+ json_object_new_int(bar->gaps.bottom));
+ json_object_object_add(gaps, "left",
+ json_object_new_int(bar->gaps.left));
+ json_object_object_add(json, "gaps", gaps);
+
if (bar->separator_symbol) {
json_object_object_add(json, "separator_symbol",
json_object_new_string(bar->separator_symbol));
}
json_object_object_add(json, "bar_height",
json_object_new_int(bar->height));
+ json_object_object_add(json, "status_padding",
+ json_object_new_int(bar->status_padding));
+ json_object_object_add(json, "status_edge_padding",
+ json_object_new_int(bar->status_edge_padding));
json_object_object_add(json, "wrap_scroll",
json_object_new_boolean(bar->wrap_scroll));
json_object_object_add(json, "workspace_buttons",
json_object_new_boolean(bar->workspace_buttons));
json_object_object_add(json, "strip_workspace_numbers",
json_object_new_boolean(bar->strip_workspace_numbers));
+ json_object_object_add(json, "strip_workspace_name",
+ json_object_new_boolean(bar->strip_workspace_name));
json_object_object_add(json, "binding_mode_indicator",
json_object_new_boolean(bar->binding_mode_indicator));
json_object_object_add(json, "verbose",
@@ -680,6 +819,8 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
struct bar_binding *binding = bar->bindings->items[i];
json_object *bind = json_object_new_object();
json_object_object_add(bind, "input_code",
+ json_object_new_int(event_to_x11_button(binding->button)));
+ json_object_object_add(bind, "event_code",
json_object_new_int(binding->button));
json_object_object_add(bind, "command",
json_object_new_string(binding->command));
@@ -699,5 +840,41 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) {
}
json_object_object_add(json, "outputs", outputs);
}
+#if HAVE_TRAY
+ // Add tray outputs if defined
+ if (bar->tray_outputs && bar->tray_outputs->length > 0) {
+ json_object *tray_outputs = json_object_new_array();
+ for (int i = 0; i < bar->tray_outputs->length; ++i) {
+ const char *name = bar->tray_outputs->items[i];
+ json_object_array_add(tray_outputs, json_object_new_string(name));
+ }
+ json_object_object_add(json, "tray_outputs", tray_outputs);
+ }
+
+ json_object *tray_bindings = json_object_new_array();
+ for (int i = 0; i < 10; ++i) {
+ if (bar->tray_bindings[i]) {
+ json_object *bind = json_object_new_object();
+ json_object_object_add(bind, "input_code",
+ json_object_new_int(i));
+ json_object_object_add(bind, "command",
+ json_object_new_string(bar->tray_bindings[i]));
+ json_object_array_add(tray_bindings, bind);
+ }
+ }
+ if (json_object_array_length(tray_bindings) > 0) {
+ json_object_object_add(json, "tray_bindings", tray_bindings);
+ } else {
+ json_object_put(tray_bindings);
+ }
+
+ if (bar->icon_theme) {
+ json_object_object_add(json, "icon_theme",
+ json_object_new_string(bar->icon_theme));
+ }
+
+ json_object_object_add(json, "tray_padding",
+ json_object_new_int(bar->tray_padding));
+#endif
return json;
}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 6466d263..ff1bc89f 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -1,10 +1,6 @@
// See https://i3wm.org/docs/ipc.html for protocol information
#define _POSIX_C_SOURCE 200112L
-#ifdef __linux__
#include <linux/input-event-codes.h>
-#elif __FreeBSD__
-#include <dev/evdev/input-event-codes.h>
-#endif
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
@@ -73,14 +69,11 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
unlink(ipc_sockaddr->sun_path);
while (ipc_client_list->length) {
- struct ipc_client *client = ipc_client_list->items[0];
- ipc_client_disconnect(client);
+ ipc_client_disconnect(ipc_client_list->items[ipc_client_list->length-1]);
}
list_free(ipc_client_list);
- if (ipc_sockaddr) {
- free(ipc_sockaddr);
- }
+ free(ipc_sockaddr);
wl_list_remove(&ipc_display_destroy.link);
}
@@ -452,8 +445,12 @@ void ipc_event_binding(struct sway_binding *binding) {
json_object_object_add(json_binding, "input_code", json_object_new_int(input_code));
json_object_object_add(json_binding, "symbols", symbols);
json_object_object_add(json_binding, "symbol", symbol);
- json_object_object_add(json_binding, "input_type", binding->type == BINDING_MOUSE ?
- json_object_new_string("mouse") : json_object_new_string("keyboard"));
+
+ bool mouse = binding->type == BINDING_MOUSECODE ||
+ binding->type == BINDING_MOUSESYM;
+ json_object_object_add(json_binding, "input_type", mouse
+ ? json_object_new_string("mouse")
+ : json_object_new_string("keyboard"));
json_object *json = json_object_new_object();
json_object_object_add(json, "change", json_object_new_string("run"));
@@ -597,13 +594,18 @@ void ipc_client_handle_command(struct ipc_client *client) {
switch (client->current_command) {
case IPC_COMMAND:
{
- struct cmd_results *results = execute_command(buf, NULL, NULL);
+ list_t *res_list = execute_command(buf, NULL, NULL);
transaction_commit_dirty();
- char *json = cmd_results_to_json(results);
+ char *json = cmd_results_to_json(res_list);
int length = strlen(json);
client_valid = ipc_send_reply(client, json, (uint32_t)length);
free(json);
- free_cmd_results(results);
+ while (res_list->length) {
+ struct cmd_results *results = res_list->items[0];
+ free_cmd_results(results);
+ list_del(res_list, 0);
+ }
+ list_free(res_list);
goto exit_cleanup;
}
@@ -619,8 +621,19 @@ void ipc_client_handle_command(struct ipc_client *client) {
json_object *outputs = json_object_new_array();
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
- json_object_array_add(outputs,
- ipc_json_describe_node(&output->node));
+ json_object *output_json = ipc_json_describe_node(&output->node);
+
+ // override the default focused indicator because it's set
+ // differently for the get_outputs reply
+ struct sway_seat *seat = input_manager_get_default_seat();
+ struct sway_workspace *focused_ws =
+ seat_get_focused_workspace(seat);
+ bool focused = focused_ws && output == focused_ws->output;
+ json_object_object_del(output_json, "focused");
+ json_object_object_add(output_json, "focused",
+ json_object_new_boolean(focused));
+
+ json_object_array_add(outputs, output_json);
}
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
@@ -651,8 +664,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
{
// TODO: Check if they're permitted to use these events
struct json_object *request = json_tokener_parse(buf);
- if (request == NULL) {
- client_valid = ipc_send_reply(client, "{\"success\": false}", 18);
+ if (request == NULL || !json_object_is_type(request, json_type_array)) {
+ const char msg[] = "{\"success\": false}";
+ client_valid = ipc_send_reply(client, msg, strlen(msg));
wlr_log(WLR_INFO, "Failed to parse subscribe request");
goto exit_cleanup;
}
@@ -679,8 +693,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
client->subscribed_events |= event_mask(IPC_EVENT_TICK);
is_tick = true;
} else {
- client_valid =
- ipc_send_reply(client, "{\"success\": false}", 18);
+ const char msg[] = "{\"success\": false}";
+ client_valid = ipc_send_reply(client, msg, strlen(msg));
json_object_put(request);
wlr_log(WLR_INFO, "Unsupported event type in subscribe request");
goto exit_cleanup;
@@ -688,10 +702,12 @@ void ipc_client_handle_command(struct ipc_client *client) {
}
json_object_put(request);
- client_valid = ipc_send_reply(client, "{\"success\": true}", 17);
+ const char msg[] = "{\"success\": true}";
+ client_valid = ipc_send_reply(client, msg, strlen(msg));
if (is_tick) {
client->current_command = IPC_EVENT_TICK;
- ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30);
+ const char tickmsg[] = "{\"first\": true, \"payload\": \"\"}";
+ ipc_send_reply(client, tickmsg, strlen(tickmsg));
}
goto exit_cleanup;
}
@@ -820,6 +836,14 @@ void ipc_client_handle_command(struct ipc_client *client) {
goto exit_cleanup;
}
+ case IPC_SYNC:
+ {
+ // It was decided sway will not support this, just return success:false
+ const char msg[] = "{\"success\": false}";
+ ipc_send_reply(client, msg, strlen(msg));
+ goto exit_cleanup;
+ }
+
default:
wlr_log(WLR_INFO, "Unknown IPC command type %i", client->current_command);
goto exit_cleanup;
diff --git a/sway/main.c b/sway/main.c
index 86374163..6e3f6b67 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -1,9 +1,9 @@
-#define _XOPEN_SOURCE 700
-#define _POSIX_C_SOURCE 200112L
+#define _POSIX_C_SOURCE 200809L
#include <getopt.h>
#include <pango/pangocairo.h>
#include <signal.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -23,7 +23,6 @@
#include "sway/ipc-server.h"
#include "ipc-client.h"
#include "log.h"
-#include "readline.h"
#include "stringop.h"
#include "util.h"
@@ -48,31 +47,28 @@ void detect_raspi(void) {
if (!f) {
return;
}
- char *line;
- while(!feof(f)) {
- if (!(line = read_line(f))) {
- break;
- }
+ char *line = NULL;
+ size_t line_size = 0;
+ while (getline(&line, &line_size, f) != -1) {
if (strstr(line, "Raspberry Pi")) {
raspi = true;
+ break;
}
- free(line);
}
fclose(f);
FILE *g = fopen("/proc/modules", "r");
if (!g) {
+ free(line);
return;
}
bool vc4 = false;
- while (!feof(g)) {
- if (!(line = read_line(g))) {
- break;
- }
+ while (getline(&line, &line_size, g) != -1) {
if (strstr(line, "vc4")) {
vc4 = true;
+ break;
}
- free(line);
}
+ free(line);
fclose(g);
if (!vc4 && raspi) {
fprintf(stderr, "\x1B[1;31mWarning: You have a "
@@ -87,13 +83,10 @@ void detect_proprietary(int allow_unsupported_gpu) {
if (!f) {
return;
}
- while (!feof(f)) {
- char *line;
- if (!(line = read_line(f))) {
- break;
- }
+ char *line = NULL;
+ size_t line_size = 0;
+ while (getline(&line, &line_size, f) != -1) {
if (strstr(line, "nvidia")) {
- free(line);
if (allow_unsupported_gpu) {
wlr_log(WLR_ERROR,
"!!! Proprietary Nvidia drivers are in use !!!");
@@ -107,7 +100,6 @@ void detect_proprietary(int allow_unsupported_gpu) {
break;
}
if (strstr(line, "fglrx")) {
- free(line);
if (allow_unsupported_gpu) {
wlr_log(WLR_ERROR,
"!!! Proprietary AMD drivers are in use !!!");
@@ -119,8 +111,8 @@ void detect_proprietary(int allow_unsupported_gpu) {
}
break;
}
- free(line);
}
+ free(line);
fclose(f);
}
@@ -147,6 +139,19 @@ static void log_env(void) {
}
}
+static void log_file(FILE *f) {
+ char *line = NULL;
+ size_t line_size = 0;
+ ssize_t nread;
+ while ((nread = getline(&line, &line_size, f)) != -1) {
+ if (line[nread - 1] == '\n') {
+ line[nread - 1] = '\0';
+ }
+ wlr_log(WLR_INFO, "%s", line);
+ }
+ free(line);
+}
+
static void log_distro(void) {
const char *paths[] = {
"/etc/lsb-release",
@@ -159,16 +164,7 @@ static void log_distro(void) {
FILE *f = fopen(paths[i], "r");
if (f) {
wlr_log(WLR_INFO, "Contents of %s:", paths[i]);
- while (!feof(f)) {
- char *line;
- if (!(line = read_line(f))) {
- break;
- }
- if (*line) {
- wlr_log(WLR_INFO, "%s", line);
- }
- free(line);
- }
+ log_file(f);
fclose(f);
}
}
@@ -180,16 +176,7 @@ static void log_kernel(void) {
wlr_log(WLR_INFO, "Unable to determine kernel version");
return;
}
- while (!feof(f)) {
- char *line;
- if (!(line = read_line(f))) {
- break;
- }
- if (*line) {
- wlr_log(WLR_INFO, "%s", line);
- }
- free(line);
- }
+ log_file(f);
pclose(f);
}
@@ -393,11 +380,15 @@ int main(int argc, char **argv) {
wlr_log(WLR_DEBUG, "Running deferred commands");
while (config->cmd_queue->length) {
char *line = config->cmd_queue->items[0];
- struct cmd_results *res = execute_command(line, NULL, NULL);
- if (res->status != CMD_SUCCESS) {
- wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
+ list_t *res_list = execute_command(line, NULL, NULL);
+ for (int i = 0; i < res_list->length; ++i) {
+ struct cmd_results *res = res_list->items[i];
+ if (res->status != CMD_SUCCESS) {
+ wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error);
+ }
+ free_cmd_results(res);
}
- free_cmd_results(res);
+ list_free(res_list);
free(line);
list_del(config->cmd_queue, 0);
}
diff --git a/sway/meson.build b/sway/meson.build
index 4524bac9..c2ed6298 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -23,6 +23,11 @@ sway_sources = files(
'input/input-manager.c',
'input/seat.c',
+ 'input/seatop_down.c',
+ 'input/seatop_move_floating.c',
+ 'input/seatop_move_tiling.c',
+ 'input/seatop_resize_floating.c',
+ 'input/seatop_resize_tiling.c',
'input/cursor.c',
'input/keyboard.c',
@@ -78,6 +83,7 @@ sway_sources = files(
'commands/seat/attach.c',
'commands/seat/cursor.c',
'commands/seat/fallback.c',
+ 'commands/seat/hide_cursor.c',
'commands/set.c',
'commands/show_marks.c',
'commands/smart_borders.c',
@@ -88,7 +94,11 @@ sway_sources = files(
'commands/swaynag_command.c',
'commands/swap.c',
'commands/tiling_drag.c',
+ 'commands/tiling_drag_threshold.c',
+ 'commands/title_align.c',
'commands/title_format.c',
+ 'commands/titlebar_border_thickness.c',
+ 'commands/titlebar_padding.c',
'commands/unmark.c',
'commands/urgent.c',
'commands/workspace.c',
@@ -96,12 +106,11 @@ sway_sources = files(
'commands/ws_auto_back_and_forth.c',
'commands/xwayland.c',
- 'commands/bar/activate_button.c',
+ 'commands/bar/bind.c',
'commands/bar/binding_mode_indicator.c',
- 'commands/bar/bindsym.c',
'commands/bar/colors.c',
- 'commands/bar/context_button.c',
'commands/bar/font.c',
+ 'commands/bar/gaps.c',
'commands/bar/height.c',
'commands/bar/hidden_state.c',
'commands/bar/icon_theme.c',
@@ -111,11 +120,14 @@ sway_sources = files(
'commands/bar/output.c',
'commands/bar/pango_markup.c',
'commands/bar/position.c',
- 'commands/bar/secondary_button.c',
'commands/bar/separator_symbol.c',
'commands/bar/status_command.c',
+ 'commands/bar/status_edge_padding.c',
+ 'commands/bar/status_padding.c',
'commands/bar/strip_workspace_numbers.c',
+ 'commands/bar/strip_workspace_name.c',
'commands/bar/swaybar_command.c',
+ 'commands/bar/tray_bindsym.c',
'commands/bar/tray_output.c',
'commands/bar/tray_padding.c',
'commands/bar/workspace_buttons.c',
@@ -170,6 +182,7 @@ sway_deps = [
cairo,
gdk_pixbuf,
jsonc,
+ libevdev,
libinput,
math,
pango,
diff --git a/sway/security.c b/sway/security.c
index cc0d3f66..6a00229e 100644
--- a/sway/security.c
+++ b/sway/security.c
@@ -1,4 +1,4 @@
-#define _XOPEN_SOURCE 700
+#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <string.h>
#include "sway/security.h"
diff --git a/sway/server.c b/sway/server.c
index 68142e87..0529cab1 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -7,25 +7,26 @@
#include <wlr/backend/session.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h>
+#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
-#include <wlr/types/wlr_gamma_control.h>
#include <wlr/types/wlr_gamma_control_v1.h>
+#include <wlr/types/wlr_gamma_control.h>
+#include <wlr/types/wlr_gtk_primary_selection.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_layer_shell_v1.h>
-#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/util/log.h>
+#include "config.h"
#include "list.h"
#include "sway/config.h"
#include "sway/desktop/idle_inhibit_v1.h"
#include "sway/input/input-manager.h"
#include "sway/server.h"
#include "sway/tree/root.h"
-#include "config.h"
#if HAVE_XWAYLAND
#include "sway/xwayland.h"
#endif
@@ -57,7 +58,7 @@ bool server_init(struct sway_server *server) {
wlr_gamma_control_manager_create(server->wl_display);
wlr_gamma_control_manager_v1_create(server->wl_display);
- wlr_primary_selection_device_manager_create(server->wl_display);
+ wlr_gtk_primary_selection_device_manager_create(server->wl_display);
server->new_output.notify = handle_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
@@ -106,6 +107,7 @@ bool server_init(struct sway_server *server) {
wlr_export_dmabuf_manager_v1_create(server->wl_display);
wlr_screencopy_manager_v1_create(server->wl_display);
+ wlr_data_control_manager_v1_create(server->wl_display);
server->socket = wl_display_add_socket_auto(server->wl_display);
if (!server->socket) {
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd
index 873741c0..3f6b4298 100644
--- a/sway/sway-bar.5.scd
+++ b/sway/sway-bar.5.scd
@@ -50,6 +50,10 @@ Sway allows configuring swaybar in the sway configuration file.
*workspace\_buttons* yes|no
Enables or disables workspace buttons on the bar. Default is _yes_.
+*strip\_workspace\_name* yes|no
+ If set to _yes_, then workspace names will be omitted from the workspace
+ button and only the custom number will be shown. Default is _no_.
+
*strip\_workspace\_numbers* yes|no
If set to _yes_, then workspace numbers will be omitted from the workspace
button and only the custom name will be shown. Default is _no_.
@@ -57,13 +61,28 @@ Sway allows configuring swaybar in the sway configuration file.
*binding\_mode\_indicator* yes|no
Enable or disable binding mode indicator. Default is _yes_.
+*gaps* <all> | <horizontal> <vertical> | <top> <right> <bottom> <left>
+ Sets the gaps from the edge of the screen for the bar. Gaps can either be
+ set all at once, per direction, or per side. Note that only sides that
+ touch an edge of the screen can have gaps. For the side that does not
+ touch an edge of the screen, per-side outer gaps for workspaces may be of
+ use.
+
*height* <height>
- Sets the height of the bar. Default height will match the font size.
+ Sets the height of the bar. Default height (0) will match the font size.
+
+*bindcode* [--release] <event-code> <command>
+ Executes _command_ when the mouse button has been pressed (or if _released_
+ is given, when the button has been released). The buttons can be given as
+ an event code, which can be obtaining from `libinput debug-events`. To
+ disable the default behavior for a button, use the command _nop_.
-*bindsym* [--release] button<n> <command>
- Executes _command_ when mouse button _n_ has been pressed (or if _released_
- is given, when mouse button _n_ has been released). To disable the default
- behavior for a button, use the command _nop_.
+*bindsym* [--release] button[1-9]|<event-name> <command>
+ Executes _command_ when the mouse button has been pressed (or if _released_
+ is given, when the button has been released). The buttons can be given as a
+ x11 button number or an event name, which can be obtained from `libinput
+ debug-events`. To disable the default behavior for a button, use the
+ command _nop_.
*mode* dock|hide|invisible
Specifies the visibility of the bar. In _dock_ mode, it is permanently
@@ -81,6 +100,16 @@ Sway allows configuring swaybar in the sway configuration file.
*modifier* <Modifier>|none
Specifies the modifier key that shows a hidden bar. Default is _Mod4_.
+*status\_padding* <padding>
+ Sets the vertical padding that is used for the status line. The default is
+ _1_. If _padding_ is _0_, blocks will be able to take up the full height of
+ the bar. This value will be multiplied by the output scale.
+
+*status\_edge\_padding* <padding>
+ Sets the padding that is used when the status line is at the right edge of
+ the bar. This value will be multiplied by the output scale. The default is
+ _3_.
+
## TRAY
Swaybar provides a system tray where third-party applications may place icons.
@@ -89,27 +118,20 @@ The following commands configure the tray.
The _button_ argument in all cases is a platform-specific button code. On Linux
you can find a list of these at linux/input-event-codes.h.
-*activate\_button* <button>
- Sets the button to be used for the _activate_ (primary click) tray item
- event. The default is BTN\_LEFT (0x110).
-
-*context\_button* <button>
- Sets the button to be used for the _context menu_ (right click) tray item
- event. The default is BTN\_RIGHT (0x111).
-
-*secondary\_button* <button>
- Sets the button to be used for the _secondary_ (middle click) tray item
- event. The default is BTN\_MIDDLE (0x112).
-
-*tray\_output* none|all|<output>
- Sets the output that the tray will appear on or none. Unlike i3bar, swaybar
- is able to show icons on any number of bars and outputs without races.
- The default is _all_.
+*tray\_bindsym* button<n> ContextMenu|Activate|SecondaryActivate|ScrollDown|ScrollLeft|ScrollRight|ScrollUp|nop
+ Binds mouse button _n_ (1 to 9) to the specified action. Use the command
+ _nop_ to disable the default action (Activate for button 1, ContextMenu for
+ button 2 and SecondaryActivate for button 3).
*tray\_padding* <px> [px]
Sets the pixel padding of the system tray. This padding will surround the
tray on all sides and between each item. The default value for _px_ is 2.
+*tray\_output* none|<output>
+ Restrict the tray to a certain output, can be specified multiple times. If
+ omitted, the tray will be displayed on all outputs. Unlike i3bar, swaybar
+ can show icons on any number of bars and outputs without races.
+
*icon\_theme* <name>
Sets the icon theme that sway will look for item icons in. This option has
no default value, because sway will always default to the fallback theme,
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index 45994644..c2673f2a 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -82,9 +82,12 @@ The following commands may only be used in the configuration file.
*input* <identifier> dwt enabled|disabled
Enables or disables disable-while-typing for the specified input device.
-*input* <identifier> events enabled|disabled|disabled\_on\_external\_mouse
- Enables or disables send\_events for specified input device. (Disabling
- send\_events disables the input device)
+*input* <identifier> events enabled|disabled|disabled\_on\_external\_mouse|toggle
+ Enables or disables send\_events for specified input device. Disabling
+ send\_events disables the input device. The _toggle_ option cannot be used
+ in the config. The order is enabled, disabled\_on\_external\_mouse,
+ disabled, (loop back to enabled). Any mode which is not supported by the
+ device will be skipped during the toggle.
*input* <identifier> left\_handed enabled|disabled
Enables or disables left handed mode for specified input device.
@@ -105,10 +108,11 @@ The following commands may only be used in the configuration file.
*input* <identifier> repeat\_rate <characters per second>
Sets the frequency of key repeats once the repeat\_delay has passed.
-*input* <identifier> scroll\_button <button\_identifier>
- Sets button used for scroll\_method on\_button\_down. The button identifier
- can be obtained from `libinput debug-events`.
- If set to 0, it disables the scroll\_button on\_button\_down.
+*input* <identifier> scroll\_button disable|button[1-3,8,9]|<event-code-or-name>
+ Sets the button used for scroll\_method on\_button\_down. The button can
+ be given as an event name or code, which can be obtained from `libinput
+ debug-events`, or as a x11 mouse button (button[1-3,8,9]). If set to
+ _disable_, it disables the scroll\_method on\_button\_down.
*input* <identifier> scroll\_factor <floating point value>
Changes the scroll factor for the specified input device. Scroll speed will
@@ -141,10 +145,29 @@ in their own "seat").
Attach an input device to this seat by its input identifier. A special
value of "\*" will attach all devices to the seat.
+*seat* <seat> cursor move|set <x> <y>
+ Move specified seat's cursor relative to current position or wrap to
+ absolute coordinates (with respect to the global coordinate space).
+ Specifying either value as 0 will not update that coordinate.
+
+*seat* <seat> cursor press|release button[1-9]|<event-name-or-code>
+ Simulate pressing (or releasing) the specified mouse button on the
+ specified seat. The button can either be provided as a button event name or
+ event code, which can be obtained from `libinput debug-events`, or as an x11
+ mouse button (button[1-9]). If using button[4-7], which map to axes, an axis
+ event will be simulated, however _press_ and _release_ will be ignored and
+ both will occur.
+
*seat* <name> fallback true|false
Set this seat as the fallback seat. A fallback seat will attach any device
not explicitly attached to another seat (similar to a "default" seat).
+*seat* <name> hide\_cursor <timeout>
+ Hides the cursor image after the specified _timeout_ (in milliseconds)
+ has elapsed with no activity on that cursor. A timeout of 0 (default)
+ disables hiding the cursor. The minimal timeout is 100 and any value less
+ than that (aside from 0), will be increased to 100.
+
# SEE ALSO
*sway*(5) *sway-output*(5)
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 37b7108b..28524478 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -36,7 +36,22 @@ must be separated by one space. For example:
*output* <name> position|pos <X> <Y>
Places the specified output at the specific position in the global
- coordinate space.
+ coordinate space. If scaling is active, it has to be considered when
+ positioning. For example, if the scaling factor for the left output is 2,
+ the relative position for the right output has to be divided by 2. The
+ reference point is the top left corner so if you want the bottoms aligned
+ this has to be considered as well.
+
+ Example:
+
+ output HDMI1 scale 2
+
+ output HDMI1 pos 0 1020 res 3200x1800
+
+ output eDP1 pos 1600 0 res 1920x1080
+
+ Note that the left x-pos of eDP1 is 1600 = 3200/2 and the bottom y-pos is
+ 1020 + (1800 / 2) = 1920 = 0 + 1920
*output* <name> scale <factor>
Scales the specified output by the specified scale _factor_. An integer is
@@ -45,7 +60,8 @@ must be separated by one space. For example:
represent the contents of your windows - they will be rendered at the next
highest integral scale factor and downscaled. You may be better served by
setting an integral scale factor and adjusting the font size of your
- applications to taste.
+ applications to taste. HiDPI isn't supported with Xwayland clients (windows
+ will blur).
*output* <name> background|bg <file> <mode> [<fallback\_color>]
Sets the wallpaper for the given output to the specified file, using the
@@ -65,7 +81,7 @@ must be separated by one space. For example:
to apply a rotation and flip, or "normal" to apply no transform. If a single
output is chosen and a rotation direction is specified
(_clockwise_ or _anticlockwise_) then the transform is added or
- subtracted from the current tranform.
+ subtracted from the current transform.
*output* <name> disable|enable
Enables or disables the specified output (all outputs are enabled by
diff --git a/sway/sway.1.scd b/sway/sway.1.scd
index f66c4cdb..09c8ccfd 100644
--- a/sway/sway.1.scd
+++ b/sway/sway.1.scd
@@ -71,18 +71,14 @@ with *i3-msg*(1) or even with *i3*(1).
The following environment variables have an effect on sway:
-_SWAY\_CURSOR\_THEME_
- Specifies the name of the cursor theme to use.
-
-_SWAY\_CURSOR\_SIZE_
- Specifies the size of the cursor to use.
-
_SWAYSOCK_
Specifies the path to the sway IPC socket.
_XKB\_DEFAULT\_RULES_, _XKB\_DEFAULT\_MODEL_, _XKB\_DEFAULT\_LAYOUT_,
_XKB\_DEFAULT\_VARIANT_, _XKB\_DEFAULT\_OPTIONS_
- Configures the xkb keyboard settings. See *xkeyboard-config*(7).
+ Configures the xkb keyboard settings. See *xkeyboard-config*(7). The
+ preferred way to configure the keyboard is via the configuration file, see
+ *sway-input*(5).
# AUTHORS
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index 95376ccc..06bc0dbf 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -134,8 +134,9 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
*focus* mode\_toggle
Moves focus between the floating and tiled layers.
-*fullscreen*
- Toggles fullscreen for the focused view.
+*fullscreen* [enable|disable|toggle]
+ Makes focused view fullscreen, non-fullscreen, or the opposite of what it
+ is now. If no argument is given, it does the same as _toggle_.
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current
set|plus|minus <amount>
@@ -280,14 +281,23 @@ runtime.
for\_window <criteria> move container to output <output>
-*bindsym* [--release|--locked] [--input-device=<device>] <key combo> <command>
+*bindsym* [--release|--locked] [--input-device=<device>] [--no-warn] <key combo> <command>
Binds _key combo_ to execute the sway command _command_ when pressed. You
may use XKB key names here (*xev*(1) is a good tool for discovering these).
With the flag _--release_, the command is executed when the key combo is
released. Unless the flag _--locked_ is set, the command will not be run
when a screen locking program is active. If _input-device_ is given, the
binding will only be executed for that input device and will be executed
- instead of any binding that is generic to all devices.
+ instead of any binding that is generic to all devices. By default, if you
+ overwrite a binding, swaynag will give you a warning. To silence this, use
+ the _--no-warn_ flag.
+
+ Mouse buttons can either be specified in the form _button[1-9]_ or by using
+ the name of the event code (ex _BTN\_LEFT_ or _BTN\_RIGHT_). For the former
+ option, the buttons will be mapped to their values in X11 (1=left, 2=middle,
+ 3=right, 4=scroll up, 5=scroll down, 6=scroll left, 7=scroll right, 8=back,
+ 9=forward). For the latter option, you can find the event names using
+ _libinput debug-events_.
Example:
```
@@ -295,8 +305,8 @@ runtime.
bindsym Mod1+Shift+f exec firefox
```
- *bindcode* [--release|--locked] [--input-device=<device>] <code> <command>
- is also available for binding with key codes instead of key names.
+ *bindcode* [--release|--locked] [--input-device=<device>] [--no-warn] <code> <command>
+ is also available for binding with key/button codes instead of key/button names.
*client.<class>* <border> <background> <text> <indicator> <child\_border>
Configures the color of window borders and title bars. All 5 colors are
@@ -321,7 +331,8 @@ runtime.
A view that does not have focus.
*client.urgent*
- A view with an urgency hint. *Note*: This is not currently implemented.
+ A view with an urgency hint. *Note*: Native Wayland windows do not
+ support urgency. Urgency only works for Xwayland windows.
The meaning of each color is:
@@ -440,6 +451,16 @@ The default colors are:
*font* <font>
Sets font for use in title bars in Pango format.
+*titlebar\_border\_thickness* <thickness>
+ Thickness of the titlebar border in pixels
+
+*titlebar\_padding* <horizontal> [<vertical>]
+ Padding of the text in the titlebar. _horizontal_ value affects horizontal
+ padding of the text while _vertical_ value affects vertical padding (space
+ above and below text). Padding includes titlebar borders so their value
+ should be greater than titlebar\_border\_thickness. If _vertical_ value is
+ not specified it is set to the _horizontal_ value.
+
*for\_window* <criteria> <command>
Whenever a window that matches _criteria_ appears, run list of commands.
See *CRITERIA* for more details.
@@ -474,15 +495,6 @@ The default colors are:
*seat* <seat> <seat-subcommands...>
For details on seat subcommands, see *sway-input*(5).
-*seat* <seat> cursor move|set <x> <y>
- Move specified seat's cursor relative to current position or wrap to
- absolute coordinates (with respect to the global coordinate space).
- Specifying either value as 0 will not update that coordinate.
-
-*seat* <seat> cursor press|release left|right|1|2|3...
- Simulate pressing (or releasing) the specified mouse button on the
- specified seat.
-
*kill*
Kills (closes) the currently focused container and all of its children.
@@ -549,6 +561,26 @@ The default colors are:
Set the opacity of the window between 0 (completely transparent) and 1
(completely opaque).
+*tiling\_drag* enable|disable|toggle
+ Sets whether or not tiling containers can be dragged with the mouse. If
+ enabled (default), the _floating\_mod_ can be used to drag tiling, as well
+ as floating, containers. Using the left mouse button on title bars without
+ the _floating\_mod_ will also allow the container to be dragged. _toggle_
+ should not be used in the config file.
+
+*tiling\_drag\_threshold* <threshold>
+ Sets the threshold that must be exceeded for a container to be dragged by
+ its titlebar. This has no effect if _floating\_mod_ is used or if
+ _tiling\_drag_ is set to _disable_. Once the threshold has been exceeded
+ once, the drag starts and the cursor can come back inside the threshold
+ without stopping the drag. _threshold_ is multiplied by the scale of the
+ output that the cursor on. The default is 9.
+
+*title\_align* left|center|right
+ Sets the title alignment. If _right_ is selected and _show\_marks_ is set
+ to _yes_, the marks will be shown on the _left_ side instead of the
+ _right_ side.
+
*unmark* [<identifier>]
*unmark* will remove _identifier_ from the list of current marks on a
window. If _identifier_ is omitted, all marks are removed.
diff --git a/sway/tree/container.c b/sway/tree/container.c
index cf6f5b54..d9c721f5 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -21,6 +21,7 @@
#include "sway/tree/arrange.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
+#include "list.h"
#include "log.h"
#include "stringop.h"
@@ -67,8 +68,7 @@ void container_destroy(struct sway_container *con) {
list_free(con->current.children);
list_free(con->outputs);
- list_foreach(con->marks, free);
- list_free(con->marks);
+ list_free_items_and_destroy(con->marks);
wlr_texture_destroy(con->marks_focused);
wlr_texture_destroy(con->marks_focused_inactive);
wlr_texture_destroy(con->marks_unfocused);
@@ -453,19 +453,26 @@ static void update_title_texture(struct sway_container *con,
int width = 0;
int height = con->title_height * scale;
- cairo_t *c = cairo_create(NULL);
+ // We must use a non-nil cairo_t for cairo_set_font_options to work.
+ // Therefore, we cannot use cairo_create(NULL).
+ cairo_surface_t *dummy_surface = cairo_image_surface_create(
+ CAIRO_FORMAT_ARGB32, 0, 0);
+ cairo_t *c = cairo_create(dummy_surface);
+ cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
+ cairo_font_options_t *fo = cairo_font_options_create();
+ cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
+ cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
+ cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel));
+ cairo_set_font_options(c, fo);
get_text_size(c, config->font, &width, NULL, NULL, scale,
config->pango_markup, "%s", con->formatted_title);
+ cairo_surface_destroy(dummy_surface);
cairo_destroy(c);
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cairo = cairo_create(surface);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
- cairo_font_options_t *fo = cairo_font_options_create();
- cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
- cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
- cairo_font_options_set_subpixel_order(fo, to_cairo_subpixel_order(output->wlr_output->subpixel));
cairo_set_font_options(cairo, fo);
cairo_font_options_destroy(fo);
cairo_set_source_rgba(cairo, class->background[0], class->background[1],
@@ -594,7 +601,7 @@ void container_update_representation(struct sway_container *con) {
}
size_t container_titlebar_height(void) {
- return config->font_height + TITLEBAR_V_PADDING * 2;
+ return config->font_height + config->titlebar_v_padding * 2;
}
void container_init_floating(struct sway_container *con) {
@@ -857,15 +864,7 @@ bool container_has_urgent_child(struct sway_container *container) {
void container_end_mouse_operation(struct sway_container *container) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
- if (seat->op_container == container) {
- seat->op_target_node = NULL; // ensure tiling move doesn't apply
- seat_end_mouse_operation(seat);
- }
- // If the user is doing a tiling drag over this container,
- // keep the operation active but unset the target container.
- if (seat->op_target_node == &container->node) {
- seat->op_target_node = NULL;
- }
+ seatop_unref(seat, container);
}
}
@@ -979,7 +978,7 @@ void container_discover_outputs(struct sway_container *con) {
output_get_box(output, &output_box);
struct wlr_box intersection;
bool intersects =
- wlr_box_intersection(&con_box, &output_box, &intersection);
+ wlr_box_intersection(&intersection, &con_box, &output_box);
int index = list_find(con->outputs, output);
if (intersects && index == -1) {
@@ -1267,7 +1266,9 @@ bool container_find_and_unmark(char *mark) {
}
void container_clear_marks(struct sway_container *con) {
- list_foreach(con->marks, free);
+ for (int i = 0; i < con->marks->length; ++i) {
+ free(con->marks->items[i]);
+ }
con->marks->length = 0;
ipc_event_window(con, "mark");
}
@@ -1375,3 +1376,16 @@ void container_update_marks_textures(struct sway_container *con) {
&config->border_colors.urgent);
container_damage_whole(con);
}
+
+void container_raise_floating(struct sway_container *con) {
+ // Bring container to front by putting it at the end of the floating list.
+ struct sway_container *floater = con;
+ while (floater->parent) {
+ floater = floater->parent;
+ }
+ if (container_is_floating(floater)) {
+ list_move_to_end(floater->workspace->floating, floater);
+ node_set_dirty(&floater->workspace->node);
+ }
+}
+
diff --git a/sway/tree/output.c b/sway/tree/output.c
index 3c4614a8..f24be010 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -58,6 +58,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
wlr_output->data = output;
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
+ wl_signal_init(&output->events.destroy);
wl_list_insert(&root->all_outputs, &output->link);
@@ -76,7 +77,6 @@ void output_enable(struct sway_output *output, struct output_config *oc) {
for (size_t i = 0; i < len; ++i) {
wl_list_init(&output->layers[i]);
}
- wl_signal_init(&output->events.destroy);
output->enabled = true;
list_add(root->outputs, output);
@@ -88,11 +88,12 @@ void output_enable(struct sway_output *output, struct output_config *oc) {
restore_workspaces(output);
+ struct sway_workspace *ws = NULL;
if (!output->workspaces->length) {
// Create workspace
char *ws_name = workspace_next_name(wlr_output->name);
wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name);
- struct sway_workspace *ws = workspace_create(output, ws_name);
+ ws = workspace_create(output, ws_name);
// Set each seat's focus if not already set
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
@@ -104,9 +105,15 @@ void output_enable(struct sway_output *output, struct output_config *oc) {
ipc_event_workspace(NULL, ws, "init");
}
-
apply_output_config(oc, output);
+ if (ws && config->default_orientation == L_NONE) {
+ // Since the output transformation and resolution could have changed
+ // due to applying the output config, the previously set layout for the
+ // created workspace may not be correct for `default_orientation auto`
+ ws->layout = output_get_default_layout(output);
+ }
+
input_manager_configure_xcursor();
wl_signal_add(&wlr_output->events.mode, &output->mode);
@@ -218,6 +225,11 @@ void output_disable(struct sway_output *output) {
root_for_each_container(untrack_output, output);
+ if (output->bg_pid) {
+ terminate_swaybg(output->bg_pid);
+ output->bg_pid = 0;
+ }
+
int index = list_find(root->outputs, output);
list_del(root->outputs, index);
diff --git a/sway/tree/root.c b/sway/tree/root.c
index 544d666a..e1624863 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -5,6 +5,7 @@
#include <wlr/types/wlr_output_layout.h>
#include "sway/desktop/transaction.h"
#include "sway/input/seat.h"
+#include "sway/ipc-server.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
@@ -68,13 +69,18 @@ void root_scratchpad_add_container(struct sway_container *con) {
list_add(root->scratchpad, con);
struct sway_seat *seat = input_manager_current_seat();
+ struct sway_node *new_focus = NULL;
if (parent) {
arrange_container(parent);
- seat_set_focus(seat, seat_get_focus_inactive(seat, &parent->node));
- } else {
+ new_focus = seat_get_focus_inactive(seat, &parent->node);
+ }
+ if (!new_focus) {
arrange_workspace(workspace);
- seat_set_focus(seat, seat_get_focus_inactive(seat, &workspace->node));
+ new_focus = seat_get_focus_inactive(seat, &workspace->node);
}
+ seat_set_focus(seat, new_focus);
+
+ ipc_event_window(con, "move");
}
void root_scratchpad_remove_container(struct sway_container *con) {
@@ -85,45 +91,51 @@ void root_scratchpad_remove_container(struct sway_container *con) {
int index = list_find(root->scratchpad, con);
if (index != -1) {
list_del(root->scratchpad, index);
+ ipc_event_window(con, "move");
}
}
void root_scratchpad_show(struct sway_container *con) {
struct sway_seat *seat = input_manager_current_seat();
- struct sway_workspace *ws = seat_get_focused_workspace(seat);
+ struct sway_workspace *new_ws = seat_get_focused_workspace(seat);
+ struct sway_workspace *old_ws = con->workspace;
- // If the current con or any of its parents are in fullscreen mode, we
- // first need to disable it before showing the scratchpad con.
- if (ws->fullscreen) {
- container_set_fullscreen(ws->fullscreen, false);
+ // If the current con or any of its parents are in fullscreen mode, we
+ // first need to disable it before showing the scratchpad con.
+ if (new_ws->fullscreen) {
+ container_set_fullscreen(new_ws->fullscreen, false);
}
// Show the container
- if (con->workspace) {
+ if (old_ws) {
container_detach(con);
}
- workspace_add_floating(ws, con);
+ workspace_add_floating(new_ws, con);
// Make sure the container's center point overlaps this workspace
double center_lx = con->x + con->width / 2;
double center_ly = con->y + con->height / 2;
struct wlr_box workspace_box;
- workspace_get_box(ws, &workspace_box);
+ workspace_get_box(new_ws, &workspace_box);
if (!wlr_box_contains_point(&workspace_box, center_lx, center_ly)) {
// Maybe resize it
- if (con->width > ws->width || con->height > ws->height) {
+ if (con->width > new_ws->width || con->height > new_ws->height) {
container_init_floating(con);
}
// Center it
- double new_lx = ws->x + (ws->width - con->width) / 2;
- double new_ly = ws->y + (ws->height - con->height) / 2;
+ double new_lx = new_ws->x + (new_ws->width - con->width) / 2;
+ double new_ly = new_ws->y + (new_ws->height - con->height) / 2;
container_floating_move_to(con, new_lx, new_ly);
}
- arrange_workspace(ws);
+ arrange_workspace(new_ws);
seat_set_focus(seat, seat_get_focus_inactive(seat, &con->node));
+
+ if (new_ws != old_ws) {
+ ipc_event_window(con, "move");
+ }
}
void root_scratchpad_hide(struct sway_container *con) {
@@ -133,10 +145,12 @@ void root_scratchpad_hide(struct sway_container *con) {
container_detach(con);
arrange_workspace(ws);
- if (&con->node == focus) {
+ if (&con->node == focus || node_has_ancestor(focus, &con->node)) {
seat_set_focus(seat, seat_get_focus_inactive(seat, &ws->node));
}
list_move_to_end(root->scratchpad, con);
+
+ ipc_event_window(con, "move");
}
struct pid_workspace {
diff --git a/sway/tree/view.c b/sway/tree/view.c
index d7110619..5371ee20 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -437,9 +437,14 @@ void view_execute_criteria(struct sway_view *view) {
wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'",
criteria->raw, view, criteria->cmdlist);
list_add(view->executed_criteria, criteria);
- struct cmd_results *res = execute_command(
+ list_t *res_list = execute_command(
criteria->cmdlist, NULL, view->container);
- free_cmd_results(res);
+ while (res_list->length) {
+ struct cmd_results *res = res_list->items[0];
+ free_cmd_results(res);
+ list_del(res_list, 0);
+ }
+ list_free(res_list);
}
list_free(criterias);
}
@@ -454,7 +459,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
for (int i = 0; i < criterias->length; ++i) {
struct criteria *criteria = criterias->items[i];
if (criteria->type == CT_ASSIGN_OUTPUT) {
- struct sway_output *output = output_by_name(criteria->target);
+ struct sway_output *output = output_by_name_or_id(criteria->target);
if (output) {
ws = output_get_active_workspace(output);
break;
@@ -600,7 +605,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
view_update_title(view, false);
container_update_representation(view->container);
- view_execute_criteria(view);
if (decoration) {
view_update_csd_from_client(view, decoration);
@@ -617,6 +621,8 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
}
}
+ view_execute_criteria(view);
+
if (should_focus(view)) {
input_manager_set_focus(&view->container->node);
}
@@ -648,14 +654,8 @@ void view_unmap(struct sway_view *view) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
- if (config->mouse_warping == WARP_CONTAINER) {
- struct sway_node *node = seat_get_focus(seat);
- if (node && node->type == N_CONTAINER) {
- cursor_warp_to_container(seat->cursor, node->sway_container);
- } else if (node && node->type == N_WORKSPACE) {
- cursor_warp_to_workspace(seat->cursor, node->sway_workspace);
- }
- }
+ seat->cursor->image_surface = NULL;
+ seat_consider_warp_to_focus(seat);
}
transaction_commit_dirty();
@@ -674,6 +674,8 @@ void view_update_size(struct sway_view *view, int width, int height) {
container_set_geometry_from_content(view->container);
}
+static const struct sway_view_child_impl subsurface_impl;
+
static void subsurface_get_root_coords(struct sway_view_child *child,
int *root_sx, int *root_sy) {
struct wlr_surface *surface = child->surface;
@@ -689,18 +691,47 @@ static void subsurface_get_root_coords(struct sway_view_child *child,
}
}
+static void subsurface_destroy(struct sway_view_child *child) {
+ if (!sway_assert(child->impl == &subsurface_impl,
+ "Expected a subsurface")) {
+ return;
+ }
+ struct sway_subsurface *subsurface = (struct sway_subsurface *)child;
+ wl_list_remove(&subsurface->destroy.link);
+ free(subsurface);
+}
+
static const struct sway_view_child_impl subsurface_impl = {
.get_root_coords = subsurface_get_root_coords,
+ .destroy = subsurface_destroy,
};
+static void subsurface_handle_destroy(struct wl_listener *listener,
+ void *data) {
+ struct sway_subsurface *subsurface =
+ wl_container_of(listener, subsurface, destroy);
+ struct sway_view_child *child = &subsurface->child;
+ view_child_destroy(child);
+}
+
+static void view_child_damage(struct sway_view_child *child, bool whole);
+
static void view_subsurface_create(struct sway_view *view,
- struct wlr_subsurface *subsurface) {
- struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child));
- if (child == NULL) {
+ struct wlr_subsurface *wlr_subsurface) {
+ struct sway_subsurface *subsurface =
+ calloc(1, sizeof(struct sway_subsurface));
+ if (subsurface == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
return;
}
- view_child_init(child, &subsurface_impl, view, subsurface->surface);
+ view_child_init(&subsurface->child, &subsurface_impl, view,
+ wlr_subsurface->surface);
+
+ wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
+ subsurface->destroy.notify = subsurface_handle_destroy;
+
+ subsurface->child.mapped = true;
+ view_child_damage(&subsurface->child, true);
}
static void view_child_damage(struct sway_view_child *child, bool whole) {
@@ -745,6 +776,7 @@ static void view_child_handle_surface_map(struct wl_listener *listener,
void *data) {
struct sway_view_child *child =
wl_container_of(listener, child, surface_map);
+ child->mapped = true;
view_child_damage(child, true);
}
@@ -753,6 +785,7 @@ static void view_child_handle_surface_unmap(struct wl_listener *listener,
struct sway_view_child *child =
wl_container_of(listener, child, surface_unmap);
view_child_damage(child, true);
+ child->mapped = false;
}
void view_child_init(struct sway_view_child *child,
@@ -771,6 +804,7 @@ void view_child_init(struct sway_view_child *child,
wl_signal_add(&surface->events.destroy, &child->surface_destroy);
child->surface_destroy.notify = view_child_handle_surface_destroy;
+ // Not all child views have a map/unmap event
child->surface_map.notify = view_child_handle_surface_map;
child->surface_unmap.notify = view_child_handle_surface_unmap;
@@ -781,6 +815,10 @@ void view_child_init(struct sway_view_child *child,
}
void view_child_destroy(struct sway_view_child *child) {
+ if (child->mapped && child->view->container != NULL) {
+ view_child_damage(child, true);
+ }
+
wl_list_remove(&child->surface_commit.link);
wl_list_remove(&child->surface_destroy.link);
@@ -824,12 +862,29 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
return NULL;
}
+static char *escape_pango_markup(const char *buffer) {
+ size_t length = escape_markup_text(buffer, NULL);
+ char *escaped_title = calloc(length + 1, sizeof(char));
+ escape_markup_text(buffer, escaped_title);
+ return escaped_title;
+}
+
static size_t append_prop(char *buffer, const char *value) {
if (!value) {
return 0;
}
- lenient_strcat(buffer, value);
- return strlen(value);
+ // If using pango_markup in font, we need to escape all markup chars
+ // from values to make sure tags are not inserted by clients
+ if (config->pango_markup) {
+ char *escaped_value = escape_pango_markup(value);
+ lenient_strcat(buffer, escaped_value);
+ size_t len = strlen(escaped_value);
+ free(escaped_value);
+ return len;
+ } else {
+ lenient_strcat(buffer, value);
+ return strlen(value);
+ }
}
/**
@@ -838,11 +893,7 @@ static size_t append_prop(char *buffer, const char *value) {
*/
static size_t parse_title_format(struct sway_view *view, char *buffer) {
if (!view->title_format || strcmp(view->title_format, "%title") == 0) {
- const char *title = view_get_title(view);
- if (buffer && title) {
- strcpy(buffer, title);
- }
- return title ? strlen(title) : 0;
+ return append_prop(buffer, view_get_title(view));
}
size_t len = 0;
@@ -882,14 +933,6 @@ static size_t parse_title_format(struct sway_view *view, char *buffer) {
return len;
}
-static char *escape_title(char *buffer) {
- size_t length = escape_markup_text(buffer, NULL);
- char *escaped_title = calloc(length + 1, sizeof(char));
- escape_markup_text(buffer, escaped_title);
- free(buffer);
- return escaped_title;
-}
-
void view_update_title(struct sway_view *view, bool force) {
const char *title = view_get_title(view);
@@ -912,10 +955,6 @@ void view_update_title(struct sway_view *view, bool force) {
return;
}
parse_title_format(view, buffer);
- // now we have the title, but needs to be escaped when using pango markup
- if (config->pango_markup) {
- buffer = escape_title(buffer);
- }
view->container->title = strdup(title);
view->container->formatted_title = buffer;
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 4be63311..7f18046d 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -35,10 +35,8 @@ struct sway_output *workspace_get_initial_output(const char *name) {
struct workspace_config *wsc = workspace_find_config(name);
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]);
- }
+ struct sway_output *output =
+ output_by_name_or_id(wsc->outputs->items[i]);
if (output) {
return output;
}
@@ -113,7 +111,10 @@ struct sway_workspace *workspace_create(struct sway_output *output,
// Add output priorities
for (int i = 0; i < wsc->outputs->length; ++i) {
- list_add(ws->output_priority, strdup(wsc->outputs->items[i]));
+ char *name = wsc->outputs->items[i];
+ if (strcmp(name, "*") != 0) {
+ list_add(ws->output_priority, strdup(name));
+ }
}
}
}
@@ -142,7 +143,7 @@ void workspace_destroy(struct sway_workspace *workspace) {
free(workspace->name);
free(workspace->representation);
- free_flat_list(workspace->output_priority);
+ list_free_items_and_destroy(workspace->output_priority);
list_free(workspace->floating);
list_free(workspace->tiling);
list_free(workspace->current.floating);
@@ -182,7 +183,11 @@ static bool workspace_valid_on_output(const char *output_name,
const char *ws_name) {
struct workspace_config *wsc = workspace_find_config(ws_name);
char identifier[128];
- struct sway_output *output = output_by_name(output_name);
+ struct sway_output *output = output_by_name_or_id(output_name);
+ if (!output) {
+ return false;
+ }
+ output_name = output->wlr_output->name;
output_get_identifier(identifier, sizeof(identifier), output);
if (!wsc) {
@@ -190,7 +195,8 @@ static bool workspace_valid_on_output(const char *output_name,
}
for (int i = 0; i < wsc->outputs->length; i++) {
- if (strcmp(wsc->outputs->items[i], output_name) == 0 ||
+ if (strcmp(wsc->outputs->items[i], "*") == 0 ||
+ strcmp(wsc->outputs->items[i], output_name) == 0 ||
strcmp(wsc->outputs->items[i], identifier) == 0) {
return true;
}
@@ -286,6 +292,14 @@ char *workspace_next_name(const char *output_name) {
// assignments primarily, falling back to bindings and numbers.
struct sway_mode *mode = config->current_mode;
+ char identifier[128];
+ struct sway_output *output = output_by_name_or_id(output_name);
+ if (!output) {
+ return NULL;
+ }
+ output_name = output->wlr_output->name;
+ output_get_identifier(identifier, sizeof(identifier), output);
+
int order = INT_MAX;
char *target = NULL;
for (int i = 0; i < mode->keysym_bindings->length; ++i) {
@@ -304,7 +318,9 @@ char *workspace_next_name(const char *output_name) {
}
bool found = false;
for (int j = 0; j < wsc->outputs->length; ++j) {
- if (strcmp(wsc->outputs->items[j], output_name) == 0) {
+ if (strcmp(wsc->outputs->items[j], "*") == 0 ||
+ strcmp(wsc->outputs->items[j], output_name) == 0 ||
+ strcmp(wsc->outputs->items[j], identifier) == 0) {
found = true;
free(target);
target = strdup(wsc->workspace);
@@ -525,13 +541,19 @@ void workspace_output_add_priority(struct sway_workspace *workspace,
struct sway_output *workspace_output_get_highest_available(
struct sway_workspace *ws, struct sway_output *exclude) {
+ char exclude_id[128] = {'\0'};
+ if (exclude) {
+ output_get_identifier(exclude_id, sizeof(exclude_id), exclude);
+ }
+
for (int i = 0; i < ws->output_priority->length; i++) {
char *name = ws->output_priority->items[i];
- if (exclude && strcasecmp(name, exclude->wlr_output->name) == 0) {
+ if (exclude && (strcmp(name, exclude->wlr_output->name) == 0
+ || strcmp(name, exclude_id) == 0)) {
continue;
}
- struct sway_output *output = output_by_name(name);
+ struct sway_output *output = output_by_name_or_id(name);
if (output) {
return output;
}