summaryrefslogtreecommitdiff
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c17
-rw-r--r--sway/commands/bind.c9
-rw-r--r--sway/commands/exec_always.c28
-rw-r--r--sway/commands/focus.c18
-rw-r--r--sway/commands/font.c27
-rw-r--r--sway/commands/gesture.c166
-rw-r--r--sway/commands/input.c1
-rw-r--r--sway/commands/input/dwtp.c25
-rw-r--r--sway/commands/input/xkb_switch_layout.c36
-rw-r--r--sway/commands/mode.c3
-rw-r--r--sway/commands/move.c19
-rw-r--r--sway/commands/output.c2
-rw-r--r--sway/commands/output/background.c12
-rw-r--r--sway/commands/output/dpms.c45
-rw-r--r--sway/commands/output/power.c43
-rw-r--r--sway/commands/output/unplug.c54
-rw-r--r--sway/commands/rename.c3
-rw-r--r--sway/commands/seat/cursor.c4
-rw-r--r--sway/config.c10
-rw-r--r--sway/config/input.c4
-rw-r--r--sway/config/output.c123
-rw-r--r--sway/criteria.c85
-rw-r--r--sway/desktop/desktop.c9
-rw-r--r--sway/desktop/fx_renderer.c81
-rw-r--r--sway/desktop/idle_inhibit_v1.c2
-rw-r--r--sway/desktop/launcher.c211
-rw-r--r--sway/desktop/layer_shell.c63
-rw-r--r--sway/desktop/output.c155
-rw-r--r--sway/desktop/render.c43
-rw-r--r--sway/desktop/surface.c2
-rw-r--r--sway/desktop/xdg_shell.c132
-rw-r--r--sway/desktop/xwayland.c62
-rw-r--r--sway/input/cursor.c195
-rw-r--r--sway/input/input-manager.c27
-rw-r--r--sway/input/keyboard.c128
-rw-r--r--sway/input/libinput.c23
-rw-r--r--sway/input/seat.c141
-rw-r--r--sway/input/seatop_default.c369
-rw-r--r--sway/input/seatop_down.c4
-rw-r--r--sway/input/switch.c28
-rw-r--r--sway/input/tablet.c23
-rw-r--r--sway/input/text_input.c2
-rw-r--r--sway/ipc-json.c177
-rw-r--r--sway/ipc-server.c15
-rw-r--r--sway/lock.c225
-rw-r--r--sway/main.c106
-rw-r--r--sway/meson.build457
-rw-r--r--sway/realtime.c40
-rw-r--r--sway/server.c41
-rw-r--r--sway/sway-input.5.scd4
-rw-r--r--sway/sway-ipc.7.scd17
-rw-r--r--sway/sway-output.5.scd14
-rw-r--r--sway/sway.5.scd101
-rw-r--r--sway/tree/arrange.c25
-rw-r--r--sway/tree/container.c47
-rw-r--r--sway/tree/node.c8
-rw-r--r--sway/tree/output.c43
-rw-r--r--sway/tree/root.c181
-rw-r--r--sway/tree/view.c44
-rw-r--r--sway/tree/workspace.c8
-rw-r--r--sway/xdg_activation_v1.c21
61 files changed, 2797 insertions, 1211 deletions
diff --git a/sway/commands.c b/sway/commands.c
index 91e559a1..6e473b97 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -46,6 +46,7 @@ static const struct cmd_handler handlers[] = {
{ "assign", cmd_assign },
{ "bar", cmd_bar },
{ "bindcode", cmd_bindcode },
+ { "bindgesture", cmd_bindgesture },
{ "bindswitch", cmd_bindswitch },
{ "bindsym", cmd_bindsym },
{ "client.background", cmd_client_noop },
@@ -96,6 +97,7 @@ static const struct cmd_handler handlers[] = {
{ "titlebar_border_thickness", cmd_titlebar_border_thickness },
{ "titlebar_padding", cmd_titlebar_padding },
{ "unbindcode", cmd_unbindcode },
+ { "unbindgesture", cmd_unbindgesture },
{ "unbindswitch", cmd_unbindswitch },
{ "unbindsym", cmd_unbindsym },
{ "workspace", cmd_workspace },
@@ -412,6 +414,7 @@ struct cmd_results *config_command(char *exec, char **new_block) {
&& handler->handle != cmd_bindsym
&& handler->handle != cmd_bindcode
&& handler->handle != cmd_bindswitch
+ && handler->handle != cmd_bindgesture
&& handler->handle != cmd_set
&& handler->handle != cmd_for_window
&& (*argv[i] == '\"' || *argv[i] == '\'')) {
@@ -487,13 +490,19 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
}
results->status = status;
if (format) {
- char *error = malloc(256);
+ char *error = NULL;
va_list args;
va_start(args, format);
- if (error) {
- vsnprintf(error, 256, format, args);
- }
+ int slen = vsnprintf(NULL, 0, format, args);
va_end(args);
+ if (slen > 0) {
+ error = malloc(slen + 1);
+ if (error != NULL) {
+ va_start(args, format);
+ vsnprintf(error, slen + 1, format, args);
+ va_end(args);
+ }
+ }
results->error = error;
} else {
results->error = NULL;
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 25be415e..c0b383db 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -47,7 +47,7 @@ static bool binding_switch_compare(struct sway_switch_binding *binding_a,
if (binding_a->type != binding_b->type) {
return false;
}
- if (binding_a->state != binding_b->state) {
+ if (binding_a->trigger != binding_b->trigger) {
return false;
}
if ((binding_a->flags & BINDING_LOCKED) !=
@@ -372,6 +372,7 @@ 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="));
+ strip_quotes(binding->input);
} else if (strcmp("--no-warn", argv[0]) == 0) {
warn = false;
} else if (strcmp("--no-repeat", argv[0]) == 0) {
@@ -551,11 +552,11 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
"unknown switch %s)", bindtype, split->items[0]);
}
if (strcmp(split->items[1], "on") == 0) {
- binding->state = WLR_SWITCH_STATE_ON;
+ binding->trigger = SWAY_SWITCH_TRIGGER_ON;
} else if (strcmp(split->items[1], "off") == 0) {
- binding->state = WLR_SWITCH_STATE_OFF;
+ binding->trigger = SWAY_SWITCH_TRIGGER_OFF;
} else if (strcmp(split->items[1], "toggle") == 0) {
- binding->state = WLR_SWITCH_STATE_TOGGLE;
+ binding->trigger = SWAY_SWITCH_TRIGGER_TOGGLE;
} else {
free_switch_binding(binding);
return cmd_results_new(CMD_FAILURE,
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index b35065c1..e6b09e64 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -8,6 +8,8 @@
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/server.h"
+#include "sway/desktop/launcher.h"
+#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
#include "sway/tree/workspace.h"
@@ -25,11 +27,22 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) {
return error;
}
+static void export_xdga_token(struct launcher_ctx *ctx) {
+ const char *token = launcher_ctx_get_token_name(ctx);
+ setenv("XDG_ACTIVATION_TOKEN", token, 1);
+}
+
+static void export_startup_id(struct launcher_ctx *ctx) {
+ const char *token = launcher_ctx_get_token_name(ctx);
+ setenv("DESKTOP_STARTUP_ID", token, 1);
+}
+
struct cmd_results *cmd_exec_process(int argc, char **argv) {
struct cmd_results *error = NULL;
char *cmd = NULL;
+ bool no_startup_id = false;
if (strcmp(argv[0], "--no-startup-id") == 0) {
- sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored.");
+ no_startup_id = true;
--argc; ++argv;
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
return error;
@@ -51,6 +64,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
}
pid_t pid, child;
+ struct launcher_ctx *ctx = launcher_ctx_create();
// Fork process
if ((pid = fork()) == 0) {
// Fork child process again
@@ -63,6 +77,12 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
close(fd[0]);
if ((child = fork()) == 0) {
close(fd[1]);
+ if (ctx) {
+ export_xdga_token(ctx);
+ }
+ if (ctx && !no_startup_id) {
+ export_startup_id(ctx);
+ }
execlp("sh", "sh", "-c", cmd, (void *)NULL);
sway_log_errno(SWAY_ERROR, "execlp failed");
_exit(1);
@@ -90,8 +110,12 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
waitpid(pid, NULL, 0);
if (child > 0) {
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
- root_record_workspace_pid(child);
+ if (ctx != NULL) {
+ sway_log(SWAY_DEBUG, "Recording workspace for process %d", child);
+ ctx->pid = child;
+ }
} else {
+ launcher_ctx_destroy(ctx);
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
}
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index b8d28480..facd82de 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -54,7 +54,7 @@ static bool get_direction_from_next_prev(struct sway_container *container,
} else {
return false;
}
-
+
return true;
}
@@ -285,7 +285,7 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws,
}
} else {
return cmd_results_new(CMD_FAILURE,
- "Failed to find a %s container in workspace",
+ "Failed to find a %s container in workspace.",
floating ? "floating" : "tiling");
}
return cmd_results_new(CMD_SUCCESS, NULL);
@@ -295,7 +295,7 @@ static struct cmd_results *focus_output(struct sway_seat *seat,
int argc, char **argv) {
if (!argc) {
return cmd_results_new(CMD_INVALID,
- "Expected 'focus output <direction|name>'");
+ "Expected 'focus output <direction|name>'.");
}
char *identifier = join_args(argv, argc);
struct sway_output *output = output_by_name_or_id(identifier);
@@ -305,13 +305,13 @@ static struct cmd_results *focus_output(struct sway_seat *seat,
if (!parse_direction(identifier, &direction)) {
free(identifier);
return cmd_results_new(CMD_INVALID,
- "There is no output with that name");
+ "There is no output with that name.");
}
struct sway_workspace *ws = seat_get_focused_workspace(seat);
if (!ws) {
free(identifier);
return cmd_results_new(CMD_FAILURE,
- "No focused workspace to base directions off of");
+ "No focused workspace to base directions off of.");
}
output = output_get_in_direction(ws->output, direction);
@@ -375,10 +375,14 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
struct sway_seat *seat = config->handler_context.seat;
if (node->type < N_WORKSPACE) {
return cmd_results_new(CMD_FAILURE,
- "Command 'focus' cannot be used above the workspace level");
+ "Command 'focus' cannot be used above the workspace level.");
}
- if (argc == 0 && container) {
+ if (argc == 0) {
+ if (!container) {
+ return cmd_results_new(CMD_FAILURE, "No container to focus was specified.");
+ }
+
if (container_is_scratchpad_hidden_or_child(container)) {
root_scratchpad_show(container);
}
diff --git a/sway/commands/font.c b/sway/commands/font.c
index cea720f5..74bb6b9f 100644
--- a/sway/commands/font.c
+++ b/sway/commands/font.c
@@ -4,6 +4,7 @@
#include "sway/config.h"
#include "log.h"
#include "stringop.h"
+#include <pango/pangocairo.h>
struct cmd_results *cmd_font(int argc, char **argv) {
struct cmd_results *error = NULL;
@@ -16,12 +17,34 @@ struct cmd_results *cmd_font(int argc, char **argv) {
if (strncmp(font, "pango:", 6) == 0) {
config->pango_markup = true;
config->font = strdup(font + 6);
+ free(font);
} else {
config->pango_markup = false;
- config->font = strdup(font);
+ config->font = font;
}
- free(font);
+ // Parse the font early so we can reject it if it's not valid for pango.
+ // Also avoids re-parsing each time we render text.
+ PangoFontDescription *font_description = pango_font_description_from_string(config->font);
+
+ const char *family = pango_font_description_get_family(font_description);
+ if (family == NULL) {
+ pango_font_description_free(font_description);
+ return cmd_results_new(CMD_FAILURE, "Invalid font family.");
+ }
+
+ const gint size = pango_font_description_get_size(font_description);
+ if (size == 0) {
+ pango_font_description_free(font_description);
+ return cmd_results_new(CMD_FAILURE, "Invalid font size.");
+ }
+
+ if (config->font_description != NULL) {
+ pango_font_description_free(config->font_description);
+ }
+
+ config->font_description = font_description;
config_update_font_height();
+
return cmd_results_new(CMD_SUCCESS, NULL);
}
diff --git a/sway/commands/gesture.c b/sway/commands/gesture.c
new file mode 100644
index 00000000..d4442cc3
--- /dev/null
+++ b/sway/commands/gesture.c
@@ -0,0 +1,166 @@
+#define _POSIX_C_SOURCE 200809L
+#include "sway/config.h"
+
+#include "gesture.h"
+#include "log.h"
+#include "stringop.h"
+#include "sway/commands.h"
+
+void free_gesture_binding(struct sway_gesture_binding *binding) {
+ if (!binding) {
+ return;
+ }
+ free(binding->input);
+ free(binding->command);
+ free(binding);
+}
+
+/**
+ * Returns true if the bindings have the same gesture type, direction, etc
+ */
+static bool binding_gesture_equal(struct sway_gesture_binding *binding_a,
+ struct sway_gesture_binding *binding_b) {
+ if (strcmp(binding_a->input, binding_b->input) != 0) {
+ return false;
+ }
+
+ if (!gesture_equal(&binding_a->gesture, &binding_b->gesture)) {
+ return false;
+ }
+
+ if ((binding_a->flags & BINDING_EXACT) !=
+ (binding_b->flags & BINDING_EXACT)) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Add gesture binding to config
+ */
+static struct cmd_results *gesture_binding_add(
+ struct sway_gesture_binding *binding,
+ const char *gesturecombo, bool warn) {
+ list_t *mode_bindings = config->current_mode->gesture_bindings;
+ // overwrite the binding if it already exists
+ bool overwritten = false;
+ for (int i = 0; i < mode_bindings->length; ++i) {
+ struct sway_gesture_binding *config_binding = mode_bindings->items[i];
+ if (binding_gesture_equal(binding, config_binding)) {
+ sway_log(SWAY_INFO, "Overwriting binding '%s' to `%s` from `%s`",
+ gesturecombo, binding->command, config_binding->command);
+ if (warn) {
+ config_add_swaynag_warning("Overwriting binding"
+ "'%s' to `%s` from `%s`",
+ gesturecombo, binding->command,
+ config_binding->command);
+ }
+ free_gesture_binding(config_binding);
+ mode_bindings->items[i] = binding;
+ overwritten = true;
+ }
+ }
+
+ if (!overwritten) {
+ list_add(mode_bindings, binding);
+ sway_log(SWAY_DEBUG, "bindgesture - Bound %s to command `%s`",
+ gesturecombo, binding->command);
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL);
+}
+
+/**
+ * Remove gesture binding from config
+ */
+static struct cmd_results *gesture_binding_remove(
+ struct sway_gesture_binding *binding, const char *gesturecombo) {
+ list_t *mode_bindings = config->current_mode->gesture_bindings;
+ for (int i = 0; i < mode_bindings->length; ++i) {
+ struct sway_gesture_binding *config_binding = mode_bindings->items[i];
+ if (binding_gesture_equal(binding, config_binding)) {
+ free_gesture_binding(config_binding);
+ free_gesture_binding(binding);
+ list_del(mode_bindings, i);
+ sway_log(SWAY_DEBUG, "unbindgesture - Unbound %s gesture",
+ gesturecombo);
+ return cmd_results_new(CMD_SUCCESS, NULL);
+ }
+ }
+
+ free_gesture_binding(binding);
+ return cmd_results_new(CMD_FAILURE, "Could not find gesture binding `%s`",
+ gesturecombo);
+}
+
+/**
+ * Parse and execute bindgesture or unbindgesture command.
+ */
+static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, bool unbind) {
+ int minargs = 2;
+ char *bindtype = "bindgesture";
+ if (unbind) {
+ minargs--;
+ bindtype = "unbindgesture";
+ }
+
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, bindtype, EXPECTED_AT_LEAST, minargs))) {
+ return error;
+ }
+ struct sway_gesture_binding *binding = calloc(1, sizeof(struct sway_gesture_binding));
+ if (!binding) {
+ return cmd_results_new(CMD_FAILURE, "Unable to allocate binding");
+ }
+ binding->input = strdup("*");
+
+ bool warn = true;
+
+ // Handle flags
+ while (argc > 0) {
+ if (strcmp("--exact", argv[0]) == 0) {
+ binding->flags |= BINDING_EXACT;
+ } else if (strcmp("--no-warn", argv[0]) == 0) {
+ warn = false;
+ } else if (strncmp("--input-device=", argv[0],
+ strlen("--input-device=")) == 0) {
+ free(binding->input);
+ binding->input = strdup(argv[0] + strlen("--input-device="));
+ } else {
+ break;
+ }
+ argv++;
+ argc--;
+ }
+
+ if (argc < minargs) {
+ free(binding);
+ return cmd_results_new(CMD_FAILURE,
+ "Invalid %s command (expected at least %d "
+ "non-option arguments, got %d)", bindtype, minargs, argc);
+ }
+
+ char* errmsg = NULL;
+ if ((errmsg = gesture_parse(argv[0], &binding->gesture))) {
+ free(binding);
+ struct cmd_results *final = cmd_results_new(CMD_FAILURE,
+ "Invalid %s command (%s)",
+ bindtype, errmsg);
+ free(errmsg);
+ return final;
+ }
+
+ if (unbind) {
+ return gesture_binding_remove(binding, argv[0]);
+ }
+ binding->command = join_args(argv + 1, argc - 1);
+ return gesture_binding_add(binding, argv[0], warn);
+}
+
+struct cmd_results *cmd_bindgesture(int argc, char **argv) {
+ return cmd_bind_or_unbind_gesture(argc, argv, false);
+}
+
+struct cmd_results *cmd_unbindgesture(int argc, char **argv) {
+ return cmd_bind_or_unbind_gesture(argc, argv, true);
+}
diff --git a/sway/commands/input.c b/sway/commands/input.c
index 77acb671..ea531659 100644
--- a/sway/commands/input.c
+++ b/sway/commands/input.c
@@ -14,6 +14,7 @@ static const struct cmd_handler input_handlers[] = {
{ "drag", input_cmd_drag },
{ "drag_lock", input_cmd_drag_lock },
{ "dwt", input_cmd_dwt },
+ { "dwtp", input_cmd_dwtp },
{ "events", input_cmd_events },
{ "left_handed", input_cmd_left_handed },
{ "map_from_region", input_cmd_map_from_region },
diff --git a/sway/commands/input/dwtp.c b/sway/commands/input/dwtp.c
new file mode 100644
index 00000000..232e2b26
--- /dev/null
+++ b/sway/commands/input/dwtp.c
@@ -0,0 +1,25 @@
+#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 *input_cmd_dwtp(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "dwtp", EXPECTED_AT_LEAST, 1))) {
+ return error;
+ }
+ struct input_config *ic = config->handler_context.input_config;
+ if (!ic) {
+ return cmd_results_new(CMD_FAILURE, "No input device defined.");
+ }
+
+ if (parse_boolean(argv[0], true)) {
+ ic->dwtp = LIBINPUT_CONFIG_DWTP_ENABLED;
+ } else {
+ ic->dwtp = LIBINPUT_CONFIG_DWTP_DISABLED;
+ }
+
+ return cmd_results_new(CMD_SUCCESS, NULL);
+}
diff --git a/sway/commands/input/xkb_switch_layout.c b/sway/commands/input/xkb_switch_layout.c
index d6548a68..3cce4ec8 100644
--- a/sway/commands/input/xkb_switch_layout.c
+++ b/sway/commands/input/xkb_switch_layout.c
@@ -1,10 +1,16 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
+#include <wlr/interfaces/wlr_keyboard.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "log.h"
+struct xkb_switch_layout_action {
+ struct wlr_keyboard *keyboard;
+ xkb_layout_index_t layout;
+};
+
static void switch_layout(struct wlr_keyboard *kbd, xkb_layout_index_t idx) {
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap);
if (idx >= num_layouts) {
@@ -28,10 +34,10 @@ static xkb_layout_index_t get_current_layout_index(struct wlr_keyboard *kbd) {
return layout_idx;
}
-static void switch_layout_relative(struct wlr_keyboard *kbd, int dir) {
+static xkb_layout_index_t get_layout_relative(struct wlr_keyboard *kbd, int dir) {
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(kbd->keymap);
xkb_layout_index_t idx = get_current_layout_index(kbd);
- switch_layout(kbd, (idx + num_layouts + dir) % num_layouts);
+ return (idx + num_layouts + dir) % num_layouts;
}
struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
@@ -66,6 +72,18 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
relative = 0;
}
+ struct xkb_switch_layout_action *actions = calloc(
+ wl_list_length(&server.input->devices),
+ sizeof(struct xkb_switch_layout_action));
+ size_t actions_len = 0;
+
+ if (!actions) {
+ return cmd_results_new(CMD_FAILURE, "Unable to allocate actions");
+ }
+
+ /* Calculate new indexes first because switching a layout in one
+ keyboard may result in a change on other keyboards as well because
+ of keyboard groups. */
struct sway_input_device *dev;
wl_list_for_each(dev, &server.input->devices, link) {
if (strcmp(ic->identifier, "*") != 0 &&
@@ -76,12 +94,22 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
if (dev->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
continue;
}
+
+ struct xkb_switch_layout_action *action =
+ &actions[actions_len++];
+
+ action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device);
if (relative) {
- switch_layout_relative(dev->wlr_device->keyboard, relative);
+ action->layout = get_layout_relative(action->keyboard, relative);
} else {
- switch_layout(dev->wlr_device->keyboard, layout);
+ action->layout = layout;
}
}
+ for (size_t i = 0; i < actions_len; i++) {
+ switch_layout(actions[i].keyboard, actions[i].layout);
+ }
+ free(actions);
+
return cmd_results_new(CMD_SUCCESS, NULL);
}
diff --git a/sway/commands/mode.c b/sway/commands/mode.c
index e23e4ee4..7263efcb 100644
--- a/sway/commands/mode.c
+++ b/sway/commands/mode.c
@@ -11,10 +11,12 @@
// Must be in order for the bsearch
static const struct cmd_handler mode_handlers[] = {
{ "bindcode", cmd_bindcode },
+ { "bindgesture", cmd_bindgesture },
{ "bindswitch", cmd_bindswitch },
{ "bindsym", cmd_bindsym },
{ "set", cmd_set },
{ "unbindcode", cmd_unbindcode },
+ { "unbindgesture", cmd_unbindgesture },
{ "unbindswitch", cmd_unbindswitch },
{ "unbindsym", cmd_unbindsym },
};
@@ -59,6 +61,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) {
mode->keycode_bindings = create_list();
mode->mouse_bindings = create_list();
mode->switch_bindings = create_list();
+ mode->gesture_bindings = create_list();
mode->pango = pango;
list_add(config->modes, mode);
}
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 1a05a7a6..7bd1fe3e 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -686,6 +686,9 @@ static struct cmd_results *cmd_move_workspace(int argc, char **argv) {
arrange_output(old_output);
arrange_output(new_output);
+ struct sway_seat *seat = config->handler_context.seat;
+ seat_consider_warp_to_focus(seat);
+
return cmd_results_new(CMD_SUCCESS, NULL);
}
@@ -788,15 +791,15 @@ static struct cmd_results *cmd_move_to_position_pointer(
struct wlr_output *output = wlr_output_layout_output_at(
root->output_layout, cursor->x, cursor->y);
if (output) {
- struct wlr_box *box =
- wlr_output_layout_get_box(root->output_layout, output);
- lx = fmax(lx, box->x);
- ly = fmax(ly, box->y);
- if (lx + container->pending.width > box->x + box->width) {
- lx = box->x + box->width - container->pending.width;
+ struct wlr_box box;
+ wlr_output_layout_get_box(root->output_layout, output, &box);
+ lx = fmax(lx, box.x);
+ ly = fmax(ly, box.y);
+ if (lx + container->pending.width > box.x + box.width) {
+ lx = box.x + box.width - container->pending.width;
}
- if (ly + container->pending.height > box->y + box->height) {
- ly = box->y + box->height - container->pending.height;
+ if (ly + container->pending.height > box.y + box.height) {
+ ly = box.y + box.height - container->pending.height;
}
}
diff --git a/sway/commands/output.c b/sway/commands/output.c
index 125df5a7..df32c673 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -18,6 +18,7 @@ static const struct cmd_handler output_handlers[] = {
{ "modeline", output_cmd_modeline },
{ "pos", output_cmd_position },
{ "position", output_cmd_position },
+ { "power", output_cmd_power },
{ "render_bit_depth", output_cmd_render_bit_depth },
{ "res", output_cmd_mode },
{ "resolution", output_cmd_mode },
@@ -26,6 +27,7 @@ static const struct cmd_handler output_handlers[] = {
{ "subpixel", output_cmd_subpixel },
{ "toggle", output_cmd_toggle },
{ "transform", output_cmd_transform },
+ { "unplug", output_cmd_unplug },
};
struct cmd_results *cmd_output(int argc, char **argv) {
diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c
index 68ee9fe1..67f212ff 100644
--- a/sway/commands/output/background.c
+++ b/sway/commands/output/background.c
@@ -102,19 +102,19 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
}
char *conf_path = dirname(conf);
- char *rel_path = src;
- src = malloc(strlen(conf_path) + strlen(src) + 2);
- if (!src) {
- free(rel_path);
+ char *real_src = malloc(strlen(conf_path) + strlen(src) + 2);
+ if (!real_src) {
+ free(src);
free(conf);
sway_log(SWAY_ERROR, "Unable to allocate memory");
return cmd_results_new(CMD_FAILURE,
"Unable to allocate resources");
}
- sprintf(src, "%s/%s", conf_path, rel_path);
- free(rel_path);
+ snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src);
+ free(src);
free(conf);
+ src = real_src;
}
bool can_access = access(src, F_OK) != -1;
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c
index 638c0ade..c7adbd58 100644
--- a/sway/commands/output/dpms.c
+++ b/sway/commands/output/dpms.c
@@ -1,45 +1,8 @@
+#include "log.h"
#include "sway/commands.h"
-#include "sway/config.h"
-#include "sway/output.h"
-#include "util.h"
-#include <strings.h>
struct cmd_results *output_cmd_dpms(int argc, char **argv) {
- if (!config->handler_context.output_config) {
- return cmd_results_new(CMD_FAILURE, "Missing output config");
- }
- if (!argc) {
- return cmd_results_new(CMD_INVALID, "Missing dpms argument.");
- }
-
- enum config_dpms current_dpms = DPMS_ON;
-
- if (strcasecmp(argv[0], "toggle") == 0) {
-
- const char *oc_name = config->handler_context.output_config->name;
- if (strcmp(oc_name, "*") == 0) {
- return cmd_results_new(CMD_INVALID,
- "Cannot apply toggle to all outputs.");
- }
-
- struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
- if (!sway_output || !sway_output->wlr_output) {
- return cmd_results_new(CMD_FAILURE,
- "Cannot apply toggle to unknown output %s", oc_name);
- }
-
- if (sway_output->enabled && !sway_output->wlr_output->enabled) {
- current_dpms = DPMS_OFF;
- }
- }
-
- if (parse_boolean(argv[0], current_dpms == DPMS_ON)) {
- config->handler_context.output_config->dpms_state = DPMS_ON;
- } else {
- config->handler_context.output_config->dpms_state = DPMS_OFF;
- }
-
- config->handler_context.leftovers.argc = argc - 1;
- config->handler_context.leftovers.argv = argv + 1;
- return NULL;
+ sway_log(SWAY_INFO, "The \"output dpms\" command is deprecated, "
+ "use \"output power\" instead");
+ return output_cmd_power(argc, argv);
}
diff --git a/sway/commands/output/power.c b/sway/commands/output/power.c
new file mode 100644
index 00000000..e6ae2852
--- /dev/null
+++ b/sway/commands/output/power.c
@@ -0,0 +1,43 @@
+#include <strings.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/output.h"
+#include "util.h"
+
+struct cmd_results *output_cmd_power(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "Missing output config");
+ }
+ if (argc == 0) {
+ return cmd_results_new(CMD_INVALID, "Missing power argument");
+ }
+
+ bool current = true;
+ if (strcasecmp(argv[0], "toggle") == 0) {
+ const char *oc_name = config->handler_context.output_config->name;
+ if (strcmp(oc_name, "*") == 0) {
+ return cmd_results_new(CMD_INVALID,
+ "Cannot apply toggle to all outputs");
+ }
+
+ struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
+ if (!sway_output || !sway_output->wlr_output) {
+ return cmd_results_new(CMD_FAILURE,
+ "Cannot apply toggle to unknown output %s", oc_name);
+ }
+
+ if (sway_output->enabled && !sway_output->wlr_output->enabled) {
+ current = false;
+ }
+ }
+
+ if (parse_boolean(argv[0], current)) {
+ config->handler_context.output_config->power = 1;
+ } else {
+ config->handler_context.output_config->power = 0;
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
diff --git a/sway/commands/output/unplug.c b/sway/commands/output/unplug.c
new file mode 100644
index 00000000..dfef626f
--- /dev/null
+++ b/sway/commands/output/unplug.c
@@ -0,0 +1,54 @@
+#include <strings.h>
+#include <wlr/config.h>
+#include <wlr/backend/headless.h>
+#include <wlr/backend/wayland.h>
+#if WLR_HAS_X11_BACKEND
+#include <wlr/backend/x11.h>
+#endif
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/output.h"
+
+static bool is_backend_allowed(struct wlr_backend *backend) {
+ if (wlr_backend_is_headless(backend)) {
+ return true;
+ }
+ if (wlr_backend_is_wl(backend)) {
+ return true;
+ }
+#if WLR_HAS_X11_BACKEND
+ if (wlr_backend_is_x11(backend)) {
+ return true;
+ }
+#endif
+ return false;
+}
+
+/**
+ * This command is intended for developer use only.
+ */
+struct cmd_results *output_cmd_unplug(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "Missing output config");
+ }
+
+ const char *oc_name = config->handler_context.output_config->name;
+ if (strcmp(oc_name, "*") == 0) {
+ return cmd_results_new(CMD_INVALID, "Won't unplug all outputs");
+ }
+
+ struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
+ if (!sway_output) {
+ return cmd_results_new(CMD_INVALID,
+ "Cannot unplug unknown output %s", oc_name);
+ }
+
+ if (!is_backend_allowed(sway_output->wlr_output->backend)) {
+ return cmd_results_new(CMD_INVALID,
+ "Can only unplug outputs with headless, wayland or x11 backend");
+ }
+
+ wlr_output_destroy(sway_output->wlr_output);
+
+ return cmd_results_new(CMD_SUCCESS, NULL);
+}
diff --git a/sway/commands/rename.c b/sway/commands/rename.c
index 3b855fdf..60a66d58 100644
--- a/sway/commands/rename.c
+++ b/sway/commands/rename.c
@@ -7,6 +7,7 @@
#include "sway/config.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
+#include "sway/desktop/launcher.h"
#include "sway/tree/container.h"
#include "sway/tree/workspace.h"
#include "sway/tree/root.h"
@@ -91,8 +92,6 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
sway_log(SWAY_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name);
- root_rename_pid_workspaces(workspace->name, new_name);
-
free(workspace->name);
workspace->name = new_name;
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c
index 749235eb..504a9f5e 100644
--- a/sway/commands/seat/cursor.c
+++ b/sway/commands/seat/cursor.c
@@ -111,8 +111,8 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
: WLR_AXIS_ORIENTATION_HORIZONTAL;
double delta = (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_LEFT)
? -1 : 1;
- struct wlr_event_pointer_axis event = {
- .device = NULL,
+ struct wlr_pointer_axis_event event = {
+ .pointer = NULL,
.time_msec = 0,
.source = WLR_AXIS_SOURCE_WHEEL,
.orientation = orientation,
diff --git a/sway/config.c b/sway/config.c
index f7ff49b3..e99a3458 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -82,6 +82,12 @@ static void free_mode(struct sway_mode *mode) {
}
list_free(mode->switch_bindings);
}
+ if (mode->gesture_bindings) {
+ for (int i = 0; i < mode->gesture_bindings->length; i++) {
+ free_gesture_binding(mode->gesture_bindings->items[i]);
+ }
+ list_free(mode->gesture_bindings);
+ }
free(mode);
}
@@ -222,6 +228,7 @@ static void config_defaults(struct sway_config *config) {
if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
if (!(config->current_mode->mouse_bindings = create_list())) goto cleanup;
if (!(config->current_mode->switch_bindings = create_list())) goto cleanup;
+ if (!(config->current_mode->gesture_bindings = create_list())) goto cleanup;
list_add(config->modes, config->current_mode);
config->floating_mod = 0;
@@ -236,6 +243,7 @@ static void config_defaults(struct sway_config *config) {
config->default_layout = L_NONE;
config->default_orientation = L_NONE;
if (!(config->font = strdup("monospace 10"))) goto cleanup;
+ config->font_description = pango_font_description_from_string(config->font);
config->urgent_timeout = 500;
config->focus_on_window_activation = FOWA_URGENT;
config->popup_during_fullscreen = POPUP_SMART;
@@ -1005,7 +1013,7 @@ int workspace_output_cmp_workspace(const void *a, const void *b) {
void config_update_font_height(void) {
int prev_max_height = config->font_height;
- get_text_metrics(config->font, &config->font_height, &config->font_baseline);
+ get_text_metrics(config->font_description, &config->font_height, &config->font_baseline);
if (config->font_height != prev_max_height) {
arrange_root();
diff --git a/sway/config/input.c b/sway/config/input.c
index a998e170..a98204df 100644
--- a/sway/config/input.c
+++ b/sway/config/input.c
@@ -25,6 +25,7 @@ struct input_config *new_input_config(const char* identifier) {
input->drag = INT_MIN;
input->drag_lock = INT_MIN;
input->dwt = INT_MIN;
+ input->dwtp = INT_MIN;
input->send_events = INT_MIN;
input->click_method = INT_MIN;
input->middle_emulation = INT_MIN;
@@ -61,6 +62,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->dwt != INT_MIN) {
dst->dwt = src->dwt;
}
+ if (src->dwtp != INT_MIN) {
+ dst->dwtp = src->dwtp;
+ }
if (src->left_handed != INT_MIN) {
dst->left_handed = src->left_handed;
}
diff --git a/sway/config/output.c b/sway/config/output.c
index fa509252..9c7082d0 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -27,8 +27,10 @@ int output_name_cmp(const void *item, const void *data) {
void output_get_identifier(char *identifier, size_t len,
struct sway_output *output) {
struct wlr_output *wlr_output = output->wlr_output;
- snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model,
- wlr_output->serial);
+ snprintf(identifier, len, "%s %s %s",
+ wlr_output->make ? wlr_output->make : "Unknown",
+ wlr_output->model ? wlr_output->model : "Unknown",
+ wlr_output->serial ? wlr_output->serial : "Unknown");
}
const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
@@ -69,6 +71,7 @@ struct output_config *new_output_config(const char *name) {
oc->max_render_time = -1;
oc->adaptive_sync = -1;
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
+ oc->power = -1;
return oc;
}
@@ -130,8 +133,8 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
free(dst->background_fallback);
dst->background_fallback = strdup(src->background_fallback);
}
- if (src->dpms_state != 0) {
- dst->dpms_state = src->dpms_state;
+ if (src->power != -1) {
+ dst->power = src->power;
}
}
@@ -190,11 +193,11 @@ static void merge_id_on_name(struct output_config *oc) {
list_add(config->output_configs, ion_oc);
sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\""
" (enabled: %d) (%dx%d@%fHz position %d,%d scale %f "
- "transform %d) (bg %s %s) (dpms %d) (max render time: %d)",
+ "transform %d) (bg %s %s) (power %d) (max render time: %d)",
ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height,
ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale,
ion_oc->transform, ion_oc->background,
- ion_oc->background_option, ion_oc->dpms_state,
+ ion_oc->background_option, ion_oc->power,
ion_oc->max_render_time);
}
}
@@ -235,18 +238,18 @@ struct output_config *store_output_config(struct output_config *oc) {
}
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
- "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (dpms %d) "
+ "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
"(max render time: %d)",
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
- oc->transform, oc->background, oc->background_option, oc->dpms_state,
+ oc->transform, oc->background, oc->background_option, oc->power,
oc->max_render_time);
return oc;
}
-static void set_mode(struct wlr_output *output, int width, int height,
- float refresh_rate, bool custom) {
+static void set_mode(struct wlr_output *output, struct wlr_output_state *pending,
+ int width, int height, float refresh_rate, bool custom) {
// Not all floating point integers can be represented exactly
// as (int)(1000 * mHz / 1000.f)
// round() the result to avoid any error
@@ -254,7 +257,7 @@ static void set_mode(struct wlr_output *output, int width, int height,
if (wl_list_empty(&output->modes) || custom) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
- wlr_output_set_custom_mode(output, width, height,
+ wlr_output_state_set_custom_mode(pending, width, height,
refresh_rate > 0 ? mhz : 0);
return;
}
@@ -278,10 +281,11 @@ static void set_mode(struct wlr_output *output, int width, int height,
} else {
sway_log(SWAY_DEBUG, "Assigning configured mode to %s", output->name);
}
- wlr_output_set_mode(output, best);
+ wlr_output_state_set_mode(pending, best);
}
-static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
+static void set_modeline(struct wlr_output *output,
+ struct wlr_output_state *pending, drmModeModeInfo *drm_mode) {
if (!wlr_output_is_drm(output)) {
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
return;
@@ -289,7 +293,7 @@ static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) {
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
if (mode) {
- wlr_output_set_mode(output, mode);
+ wlr_output_state_set_mode(pending, mode);
}
}
@@ -311,23 +315,24 @@ static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
// 1 inch = 25.4 mm
#define MM_PER_INCH 25.4
-static int compute_default_scale(struct wlr_output *output) {
+static int compute_default_scale(struct wlr_output *output,
+ struct wlr_output_state *pending) {
struct wlr_box box = { .width = output->width, .height = output->height };
- if (output->pending.committed & WLR_OUTPUT_STATE_MODE) {
- switch (output->pending.mode_type) {
+ if (pending->committed & WLR_OUTPUT_STATE_MODE) {
+ switch (pending->mode_type) {
case WLR_OUTPUT_STATE_MODE_FIXED:
- box.width = output->pending.mode->width;
- box.height = output->pending.mode->height;
+ box.width = pending->mode->width;
+ box.height = pending->mode->height;
break;
case WLR_OUTPUT_STATE_MODE_CUSTOM:
- box.width = output->pending.custom_mode.width;
- box.height = output->pending.custom_mode.height;
+ box.width = pending->custom_mode.width;
+ box.height = pending->custom_mode.height;
break;
}
}
enum wl_output_transform transform = output->transform;
- if (output->pending.committed & WLR_OUTPUT_STATE_TRANSFORM) {
- transform = output->pending.transform;
+ if (pending->committed & WLR_OUTPUT_STATE_TRANSFORM) {
+ transform = pending->transform;
}
wlr_box_transform(&box, &box, transform, box.width, box.height);
@@ -374,38 +379,38 @@ static const uint32_t *bit_depth_preferences[] = {
};
static void queue_output_config(struct output_config *oc,
- struct sway_output *output) {
+ struct sway_output *output, struct wlr_output_state *pending) {
if (output == root->fallback_output) {
return;
}
struct wlr_output *wlr_output = output->wlr_output;
- if (oc && (!oc->enabled || oc->dpms_state == DPMS_OFF)) {
+ if (oc && (!oc->enabled || oc->power == 0)) {
sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
- wlr_output_enable(wlr_output, false);
+ wlr_output_state_set_enabled(pending, false);
return;
}
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
- wlr_output_enable(wlr_output, true);
+ wlr_output_state_set_enabled(pending, true);
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
sway_log(SWAY_DEBUG, "Set %s modeline",
wlr_output->name);
- set_modeline(wlr_output, &oc->drm_mode);
+ set_modeline(wlr_output, pending, &oc->drm_mode);
} else if (oc && oc->width > 0 && oc->height > 0) {
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
wlr_output->name, oc->width, oc->height, oc->refresh_rate);
- set_mode(wlr_output, oc->width, oc->height,
+ set_mode(wlr_output, pending, oc->width, oc->height,
oc->refresh_rate, oc->custom_mode == 1);
} else if (!wl_list_empty(&wlr_output->modes)) {
sway_log(SWAY_DEBUG, "Set preferred mode");
struct wlr_output_mode *preferred_mode =
wlr_output_preferred_mode(wlr_output);
- wlr_output_set_mode(wlr_output, preferred_mode);
+ wlr_output_state_set_mode(pending, preferred_mode);
- if (!wlr_output_test(wlr_output)) {
+ if (!wlr_output_test_state(wlr_output, pending)) {
sway_log(SWAY_DEBUG, "Preferred mode rejected, "
"falling back to another mode");
struct wlr_output_mode *mode;
@@ -414,8 +419,8 @@ static void queue_output_config(struct output_config *oc,
continue;
}
- wlr_output_set_mode(wlr_output, mode);
- if (wlr_output_test(wlr_output)) {
+ wlr_output_state_set_mode(pending, mode);
+ if (wlr_output_test_state(wlr_output, pending)) {
break;
}
}
@@ -425,7 +430,7 @@ static void queue_output_config(struct output_config *oc,
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
sway_wl_output_subpixel_to_string(oc->subpixel));
- wlr_output_set_subpixel(wlr_output, oc->subpixel);
+ wlr_output_state_set_subpixel(pending, oc->subpixel);
}
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
@@ -437,7 +442,7 @@ static void queue_output_config(struct output_config *oc,
}
if (wlr_output->transform != tr) {
sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
- wlr_output_set_transform(wlr_output, tr);
+ wlr_output_state_set_transform(pending, tr);
}
// Apply the scale last before the commit, because the scale auto-detection
@@ -446,18 +451,22 @@ static void queue_output_config(struct output_config *oc,
if (oc && oc->scale > 0) {
scale = oc->scale;
} else {
- scale = compute_default_scale(wlr_output);
+ scale = compute_default_scale(wlr_output, pending);
sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
}
if (scale != wlr_output->scale) {
sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale);
- wlr_output_set_scale(wlr_output, scale);
+ wlr_output_state_set_scale(pending, scale);
}
if (oc && oc->adaptive_sync != -1) {
sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
oc->adaptive_sync);
- wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1);
+ wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
+ if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) {
+ sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring");
+ wlr_output_state_set_adaptive_sync_enabled(pending, false);
+ }
}
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
@@ -465,8 +474,8 @@ static void queue_output_config(struct output_config *oc,
assert(fmts);
for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
- wlr_output_set_render_format(wlr_output, fmts[i]);
- if (wlr_output_test(wlr_output)) {
+ wlr_output_state_set_render_format(pending, fmts[i]);
+ if (wlr_output_test_state(wlr_output, pending)) {
break;
}
@@ -487,14 +496,15 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
// Flag to prevent the output mode event handler from calling us
output->enabling = (!oc || oc->enabled);
- queue_output_config(oc, output);
+ struct wlr_output_state pending = {0};
+ queue_output_config(oc, output, &pending);
- if (!oc || oc->dpms_state != DPMS_OFF) {
- output->current_mode = wlr_output->pending.mode;
+ if (!oc || oc->power != 0) {
+ output->current_mode = pending.mode;
}
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
- if (!wlr_output_commit(wlr_output)) {
+ if (!wlr_output_commit_state(wlr_output, &pending)) {
// Failed to commit output changes, maybe the output is missing a CRTC.
// Leave the output disabled for now and try again when the output gets
// the mode we asked for.
@@ -546,12 +556,12 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
}
// Update output->{lx, ly, width, height}
- struct wlr_box *output_box =
- wlr_output_layout_get_box(root->output_layout, wlr_output);
- output->lx = output_box->x;
- output->ly = output_box->y;
- output->width = output_box->width;
- output->height = output_box->height;
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box);
+ output->lx = output_box.x;
+ output->ly = output_box.y;
+ output->width = output_box.width;
+ output->height = output_box.height;
if (!output->enabled) {
output_enable(output);
@@ -577,15 +587,15 @@ bool test_output_config(struct output_config *oc, struct sway_output *output) {
return false;
}
- queue_output_config(oc, output);
- bool ok = wlr_output_test(output->wlr_output);
- wlr_output_rollback(output->wlr_output);
- return ok;
+ struct wlr_output_state pending = {0};
+ queue_output_config(oc, output, &pending);
+ return wlr_output_test_state(output->wlr_output, &pending);
}
static void default_output_config(struct output_config *oc,
struct wlr_output *wlr_output) {
oc->enabled = 1;
+ oc->power = 1;
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
if (mode != NULL) {
oc->width = mode->width;
@@ -598,7 +608,6 @@ static void default_output_config(struct output_config *oc,
struct sway_output *output = wlr_output->data;
oc->subpixel = output->detected_subpixel;
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
- oc->dpms_state = DPMS_ON;
oc->max_render_time = 0;
}
@@ -653,10 +662,10 @@ static struct output_config *get_output_config(char *identifier,
sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)"
" (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
- " (dpms %d) (max render time: %d)", result->name, result->enabled,
+ " (power %d) (max render time: %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,
+ result->background, result->background_option, result->power,
result->max_render_time);
} else if (oc_name) {
// No identifier config, just return a copy of the name config
diff --git a/sway/criteria.c b/sway/criteria.c
index d2a5566f..d7326bea 100644
--- a/sway/criteria.c
+++ b/sway/criteria.c
@@ -3,7 +3,8 @@
#include <stdio.h>
#include <stdbool.h>
#include <strings.h>
-#include <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
#include "sway/criteria.h"
#include "sway/tree/container.h"
#include "sway/config.h"
@@ -40,17 +41,19 @@ bool criteria_is_empty(struct criteria *criteria) {
char *error = NULL;
// Returns error string on failure or NULL otherwise.
-static bool generate_regex(pcre **regex, char *value) {
- const char *reg_err;
- int offset;
-
- *regex = pcre_compile(value, PCRE_UTF8 | PCRE_UCP, &reg_err, &offset, NULL);
+static bool generate_regex(pcre2_code **regex, char *value) {
+ int errorcode;
+ PCRE2_SIZE offset;
+ *regex = pcre2_compile((PCRE2_SPTR)value, PCRE2_ZERO_TERMINATED, PCRE2_UTF | PCRE2_UCP, &errorcode, &offset, NULL);
if (!*regex) {
+ PCRE2_UCHAR buffer[256];
+ pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
+
const char *fmt = "Regex compilation for '%s' failed: %s";
- int len = strlen(fmt) + strlen(value) + strlen(reg_err) - 3;
+ int len = strlen(fmt) + strlen(value) + strlen((char*) buffer) - 3;
error = malloc(len);
- snprintf(error, len, fmt, value, reg_err);
+ snprintf(error, len, fmt, value, buffer);
return false;
}
@@ -66,7 +69,7 @@ static bool pattern_create(struct pattern **pattern, char *value) {
if (strcmp(value, "__focused__") == 0) {
(*pattern)->match_type = PATTERN_FOCUSED;
} else {
- (*pattern)->match_type = PATTERN_PCRE;
+ (*pattern)->match_type = PATTERN_PCRE2;
if (!generate_regex(&(*pattern)->regex, value)) {
return false;
};
@@ -77,7 +80,7 @@ static bool pattern_create(struct pattern **pattern, char *value) {
static void pattern_destroy(struct pattern *pattern) {
if (pattern) {
if (pattern->regex) {
- pcre_free(pattern->regex);
+ pcre2_code_free(pattern->regex);
}
free(pattern);
}
@@ -93,14 +96,18 @@ void criteria_destroy(struct criteria *criteria) {
pattern_destroy(criteria->window_role);
#endif
pattern_destroy(criteria->con_mark);
- free(criteria->workspace);
+ pattern_destroy(criteria->workspace);
+ free(criteria->target);
free(criteria->cmdlist);
free(criteria->raw);
free(criteria);
}
-static int regex_cmp(const char *item, const pcre *regex) {
- return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0);
+static int regex_cmp(const char *item, const pcre2_code *regex) {
+ pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(regex, NULL);
+ int result = pcre2_match(regex, (PCRE2_SPTR)item, strlen(item), 0, 0, match_data, NULL);
+ pcre2_match_data_free(match_data);
+ return result;
}
#if HAVE_XWAYLAND
@@ -155,7 +162,7 @@ static bool criteria_matches_container(struct criteria *criteria,
bool exists = false;
struct sway_container *con = container;
for (int i = 0; i < con->marks->length; ++i) {
- if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) == 0) {
+ if (regex_cmp(con->marks->items[i], criteria->con_mark->regex) >= 0) {
exists = true;
break;
}
@@ -183,7 +190,7 @@ static bool criteria_matches_view(struct criteria *criteria,
if (criteria->title) {
const char *title = view_get_title(view);
if (!title) {
- return false;
+ title = "";
}
switch (criteria->title->match_type) {
@@ -192,8 +199,8 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(title, criteria->title->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(title, criteria->title->regex) < 0) {
return false;
}
break;
@@ -203,7 +210,7 @@ static bool criteria_matches_view(struct criteria *criteria,
if (criteria->shell) {
const char *shell = view_get_shell(view);
if (!shell) {
- return false;
+ shell = "";
}
switch (criteria->shell->match_type) {
@@ -212,8 +219,8 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(shell, criteria->shell->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(shell, criteria->shell->regex) < 0) {
return false;
}
break;
@@ -223,7 +230,7 @@ static bool criteria_matches_view(struct criteria *criteria,
if (criteria->app_id) {
const char *app_id = view_get_app_id(view);
if (!app_id) {
- return false;
+ app_id = "";
}
switch (criteria->app_id->match_type) {
@@ -232,8 +239,8 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(app_id, criteria->app_id->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(app_id, criteria->app_id->regex) < 0) {
return false;
}
break;
@@ -255,7 +262,7 @@ static bool criteria_matches_view(struct criteria *criteria,
if (criteria->class) {
const char *class = view_get_class(view);
if (!class) {
- return false;
+ class = "";
}
switch (criteria->class->match_type) {
@@ -264,8 +271,8 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(class, criteria->class->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(class, criteria->class->regex) < 0) {
return false;
}
break;
@@ -275,17 +282,17 @@ static bool criteria_matches_view(struct criteria *criteria,
if (criteria->instance) {
const char *instance = view_get_instance(view);
if (!instance) {
- return false;
+ instance = "";
}
switch (criteria->instance->match_type) {
case PATTERN_FOCUSED:
- if (focused && strcmp(instance, view_get_instance(focused))) {
+ if (focused && lenient_strcmp(instance, view_get_instance(focused))) {
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(instance, criteria->instance->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(instance, criteria->instance->regex) < 0) {
return false;
}
break;
@@ -295,17 +302,17 @@ static bool criteria_matches_view(struct criteria *criteria,
if (criteria->window_role) {
const char *window_role = view_get_window_role(view);
if (!window_role) {
- return false;
+ window_role = "";
}
switch (criteria->window_role->match_type) {
case PATTERN_FOCUSED:
- if (focused && strcmp(window_role, view_get_window_role(focused))) {
+ if (focused && lenient_strcmp(window_role, view_get_window_role(focused))) {
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(window_role, criteria->window_role->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(window_role, criteria->window_role->regex) < 0) {
return false;
}
break;
@@ -363,8 +370,8 @@ static bool criteria_matches_view(struct criteria *criteria,
return false;
}
break;
- case PATTERN_PCRE:
- if (regex_cmp(ws->name, criteria->workspace->regex) != 0) {
+ case PATTERN_PCRE2:
+ if (regex_cmp(ws->name, criteria->workspace->regex) < 0) {
return false;
}
break;
@@ -676,7 +683,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
}
name = calloc(head - namestart + 1, 1);
if (head != namestart) {
- strncpy(name, namestart, head - namestart);
+ memcpy(name, namestart, head - namestart);
}
// Parse token value
skip_spaces(&head);
@@ -703,7 +710,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
}
}
value = calloc(head - valuestart + 1, 1);
- strncpy(value, valuestart, head - valuestart);
+ memcpy(value, valuestart, head - valuestart);
if (in_quotes) {
++head;
in_quotes = false;
@@ -734,7 +741,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) {
++head;
int len = head - raw;
criteria->raw = calloc(len + 1, 1);
- strncpy(criteria->raw, raw, len);
+ memcpy(criteria->raw, raw, len);
return criteria;
cleanup:
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c
index ec45d80a..c8d4502c 100644
--- a/sway/desktop/desktop.c
+++ b/sway/desktop/desktop.c
@@ -6,10 +6,11 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly,
bool whole) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
- struct wlr_box *output_box = wlr_output_layout_get_box(
- root->output_layout, output->wlr_output);
- output_damage_surface(output, lx - output_box->x,
- ly - output_box->y, surface, whole);
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout,
+ output->wlr_output, &output_box);
+ output_damage_surface(output, lx - output_box.x,
+ ly - output_box.y, surface, whole);
}
}
diff --git a/sway/desktop/fx_renderer.c b/sway/desktop/fx_renderer.c
index 3b4279fe..782ceb88 100644
--- a/sway/desktop/fx_renderer.c
+++ b/sway/desktop/fx_renderer.c
@@ -35,6 +35,71 @@ static const GLfloat verts[] = {
0, 1, // bottom left
};
+static const float transforms[][9] = {
+ [WL_OUTPUT_TRANSFORM_NORMAL] = {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_90] = {
+ 0.0f, 1.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_180] = {
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_270] = {
+ 0.0f, -1.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED] = {
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED_90] = {
+ 0.0f, 1.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED_180] = {
+ 1.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+ [WL_OUTPUT_TRANSFORM_FLIPPED_270] = {
+ 0.0f, -1.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f,
+ },
+};
+
+static void matrix_projection(float mat[static 9], int width, int height,
+ enum wl_output_transform transform) {
+ memset(mat, 0, sizeof(*mat) * 9);
+
+ const float *t = transforms[transform];
+ float x = 2.0f / width;
+ float y = 2.0f / height;
+
+ // Rotation + reflection
+ mat[0] = x * t[0];
+ mat[1] = x * t[1];
+ mat[3] = y * -t[3];
+ mat[4] = y * -t[4];
+
+ // Translation
+ mat[2] = -copysign(1.0f, mat[0] + mat[1]);
+ mat[5] = -copysign(1.0f, mat[3] + mat[4]);
+
+ // Identity
+ mat[8] = 1.0f;
+}
+
static GLuint compile_shader(GLuint type, const GLchar *src) {
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
@@ -156,7 +221,8 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
// TODO: wlr_egl_make_current or eglMakeCurrent?
// TODO: assert instead of conditional statement?
- if (!wlr_egl_make_current(egl)) {
+ if (!eglMakeCurrent(wlr_egl_get_display(egl), EGL_NO_SURFACE, EGL_NO_SURFACE,
+ wlr_egl_get_context(egl))) {
sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not make EGL current");
return NULL;
}
@@ -242,7 +308,11 @@ struct fx_renderer *fx_renderer_create(struct wlr_egl *egl) {
goto error;
}
- wlr_egl_unset_current(renderer->egl);
+ if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl),
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
+ goto error;
+ }
sway_log(SWAY_INFO, "GLES2 RENDERER: Shaders Initialized Successfully");
return renderer;
@@ -257,7 +327,10 @@ error:
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
- wlr_egl_unset_current(renderer->egl);
+ if (!eglMakeCurrent(wlr_egl_get_display(renderer->egl),
+ EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ sway_log(SWAY_ERROR, "GLES2 RENDERER: Could not unset current EGL");
+ }
// TODO: more freeing?
free(renderer);
@@ -270,7 +343,7 @@ void fx_renderer_begin(struct fx_renderer *renderer, uint32_t width, uint32_t he
glViewport(0, 0, width, height);
// refresh projection matrix
- wlr_matrix_projection(renderer->projection, width, height,
+ matrix_projection(renderer->projection, width, height,
WL_OUTPUT_TRANSFORM_FLIPPED_180);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c
index 82353038..3a4d0b87 100644
--- a/sway/desktop/idle_inhibit_v1.c
+++ b/sway/desktop/idle_inhibit_v1.c
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_idle_notify_v1.h>
#include "log.h"
#include "sway/desktop/idle_inhibit_v1.h"
#include "sway/input/seat.h"
@@ -140,6 +141,7 @@ void sway_idle_inhibit_v1_check_active(
}
}
wlr_idle_set_enabled(manager->idle, NULL, !inhibited);
+ wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited);
}
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c
new file mode 100644
index 00000000..48e5d24c
--- /dev/null
+++ b/sway/desktop/launcher.c
@@ -0,0 +1,211 @@
+#define _POSIX_C_SOURCE 200809L
+#include <stdlib.h>
+#include <string.h>
+#include <wlr/types/wlr_xdg_activation_v1.h>
+#include "sway/input/seat.h"
+#include "sway/output.h"
+#include "sway/desktop/launcher.h"
+#include "sway/tree/node.h"
+#include "sway/tree/container.h"
+#include "sway/tree/workspace.h"
+#include "sway/tree/root.h"
+#include "log.h"
+
+/**
+ * Get the pid of a parent process given the pid of a child process.
+ *
+ * Returns the parent pid or NULL if the parent pid cannot be determined.
+ */
+static pid_t get_parent_pid(pid_t child) {
+ pid_t parent = -1;
+ char file_name[100];
+ char *buffer = NULL;
+ const char *sep = " ";
+ FILE *stat = NULL;
+ size_t buf_size = 0;
+
+ snprintf(file_name, sizeof(file_name), "/proc/%d/stat", child);
+
+ if ((stat = fopen(file_name, "r"))) {
+ if (getline(&buffer, &buf_size, stat) != -1) {
+ strtok(buffer, sep); // pid
+ strtok(NULL, sep); // executable name
+ strtok(NULL, sep); // state
+ char *token = strtok(NULL, sep); // parent pid
+ parent = strtol(token, NULL, 10);
+ }
+ free(buffer);
+ fclose(stat);
+ }
+
+ if (parent) {
+ return (parent == child) ? -1 : parent;
+ }
+
+ return -1;
+}
+
+void launcher_ctx_consume(struct launcher_ctx *ctx) {
+ // The view is now responsible for destroying this ctx
+ wl_list_remove(&ctx->token_destroy.link);
+ wl_list_init(&ctx->token_destroy.link);
+
+ if (!ctx->activated) {
+ // An unactivated token hasn't been destroyed yet
+ wlr_xdg_activation_token_v1_destroy(ctx->token);
+ }
+ ctx->token = NULL;
+
+ // Prevent additional matches
+ wl_list_remove(&ctx->link);
+ wl_list_init(&ctx->link);
+}
+
+void launcher_ctx_destroy(struct launcher_ctx *ctx) {
+ if (ctx == NULL) {
+ return;
+ }
+ wl_list_remove(&ctx->node_destroy.link);
+ wl_list_remove(&ctx->token_destroy.link);
+ wl_list_remove(&ctx->link);
+ wlr_xdg_activation_token_v1_destroy(ctx->token);
+ free(ctx->name);
+ free(ctx);
+}
+
+struct launcher_ctx *launcher_ctx_find_pid(pid_t pid) {
+ if (wl_list_empty(&server.pending_launcher_ctxs)) {
+ return NULL;
+ }
+
+ struct launcher_ctx *ctx = NULL;
+ sway_log(SWAY_DEBUG, "Looking up workspace for pid %d", pid);
+
+ do {
+ struct launcher_ctx *_ctx = NULL;
+ wl_list_for_each(_ctx, &server.pending_launcher_ctxs, link) {
+ if (pid == _ctx->pid) {
+ ctx = _ctx;
+ sway_log(SWAY_DEBUG,
+ "found %s match for pid %d: %s",
+ node_type_to_str(ctx->node->type), pid, node_get_name(ctx->node));
+ break;
+ }
+ }
+ pid = get_parent_pid(pid);
+ } while (pid > 1);
+
+ return ctx;
+}
+
+struct sway_workspace *launcher_ctx_get_workspace(
+ struct launcher_ctx *ctx) {
+ struct sway_workspace *ws = NULL;
+ struct sway_output *output = NULL;
+
+ switch (ctx->node->type) {
+ case N_CONTAINER:
+ // Unimplemented
+ // TODO: add container matching?
+ ws = ctx->node->sway_container->pending.workspace;
+ break;
+ case N_WORKSPACE:
+ ws = ctx->node->sway_workspace;
+ break;
+ case N_OUTPUT:
+ output = ctx->node->sway_output;
+ ws = workspace_by_name(ctx->name);
+ if (!ws) {
+ sway_log(SWAY_DEBUG,
+ "Creating workspace %s for pid %d because it disappeared",
+ ctx->name, ctx->pid);
+ if (!output->enabled) {
+ sway_log(SWAY_DEBUG,
+ "Workspace output %s is disabled, trying another one",
+ output->wlr_output->name);
+ output = NULL;
+ }
+ ws = workspace_create(output, ctx->name);
+ }
+ break;
+ case N_ROOT:
+ ws = workspace_create(NULL, ctx->name);
+ break;
+ }
+
+ return ws;
+}
+
+static void ctx_handle_node_destroy(struct wl_listener *listener, void *data) {
+ struct launcher_ctx *ctx = wl_container_of(listener, ctx, node_destroy);
+ switch (ctx->node->type) {
+ case N_CONTAINER:
+ // Unimplemented
+ break;
+ case N_WORKSPACE:;
+ struct sway_workspace *ws = ctx->node->sway_workspace;
+ wl_list_remove(&ctx->node_destroy.link);
+ wl_list_init(&ctx->node_destroy.link);
+ // We want to save this ws name to recreate later, hopefully on the
+ // same output
+ free(ctx->name);
+ ctx->name = strdup(ws->name);
+ if (!ws->output || ws->output->node.destroying) {
+ // If the output is being destroyed it would be pointless to track
+ // If the output is being disabled, we'll find out if it's still
+ // disabled when we try to match it.
+ ctx->node = &root->node;
+ break;
+ }
+ ctx->node = &ws->output->node;
+ wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
+ break;
+ case N_OUTPUT:
+ wl_list_remove(&ctx->node_destroy.link);
+ wl_list_init(&ctx->node_destroy.link);
+ // We'll make the ws ctx->name somewhere else
+ ctx->node = &root->node;
+ break;
+ case N_ROOT:
+ // Unreachable
+ break;
+ }
+}
+
+static void token_handle_destroy(struct wl_listener *listener, void *data) {
+ struct launcher_ctx *ctx = wl_container_of(listener, ctx, token_destroy);
+ ctx->token = NULL;
+ launcher_ctx_destroy(ctx);
+}
+
+struct launcher_ctx *launcher_ctx_create() {
+ struct sway_seat *seat = input_manager_current_seat();
+ struct sway_workspace *ws = seat_get_focused_workspace(seat);
+ if (!ws) {
+ sway_log(SWAY_DEBUG, "Failed to create launch context. No workspace.");
+ return NULL;
+ }
+
+ struct launcher_ctx *ctx = calloc(1, sizeof(struct launcher_ctx));
+ struct wlr_xdg_activation_token_v1 *token =
+ wlr_xdg_activation_token_v1_create(server.xdg_activation_v1);
+ token->data = ctx;
+ ctx->name = strdup(ws->name);
+ ctx->token = token;
+ ctx->node = &ws->node;
+
+ ctx->node_destroy.notify = ctx_handle_node_destroy;
+ wl_signal_add(&ctx->node->events.destroy, &ctx->node_destroy);
+
+ ctx->token_destroy.notify = token_handle_destroy;
+ wl_signal_add(&token->events.destroy, &ctx->token_destroy);
+
+ wl_list_init(&ctx->link);
+ wl_list_insert(&server.pending_launcher_ctxs, &ctx->link);
+ return ctx;
+}
+
+const char *launcher_ctx_get_token_name(struct launcher_ctx *ctx) {
+ const char *token = wlr_xdg_activation_token_v1_get_name(ctx->token);
+ return token;
+}
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 27e457f1..6e3cc0e2 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -3,8 +3,8 @@
#include <string.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_layer_shell_v1.h>
-#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_subcompositor.h>
#include "log.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
@@ -270,10 +270,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
wl_resource_get_client(sway_layer->layer_surface->resource);
bool set_focus = seat->exclusive_client == client;
- wl_list_remove(&sway_layer->output_destroy.link);
- wl_list_remove(&sway_layer->link);
- wl_list_init(&sway_layer->link);
-
if (set_focus) {
struct sway_layer_surface *layer =
find_mapped_layer_by_client(client, sway_layer->layer_surface->output);
@@ -282,7 +278,6 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) {
}
}
- sway_layer->layer_surface->output = NULL;
wlr_layer_surface_v1_destroy(sway_layer->layer_surface);
}
@@ -291,10 +286,7 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
wl_container_of(listener, layer, surface_commit);
struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface;
struct wlr_output *wlr_output = layer_surface->output;
- if (wlr_output == NULL) {
- return;
- }
-
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
struct wlr_box old_extent = layer->extent;
@@ -341,13 +333,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
cursor_rebase_all();
struct wlr_output *wlr_output = sway_layer->layer_surface->output;
- if (wlr_output == NULL) {
- return;
- }
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
- if (output == NULL) {
- return;
- }
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
}
@@ -375,22 +362,24 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&sway_layer->surface_commit.link);
wl_list_remove(&sway_layer->new_popup.link);
wl_list_remove(&sway_layer->new_subsurface.link);
- if (sway_layer->layer_surface->output != NULL) {
- struct sway_output *output = sway_layer->layer_surface->output->data;
- if (output != NULL) {
- arrange_layers(output);
- transaction_commit_dirty();
- }
- wl_list_remove(&sway_layer->output_destroy.link);
- sway_layer->layer_surface->output = NULL;
- }
+
+ struct wlr_output *wlr_output = sway_layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
+ struct sway_output *output = wlr_output->data;
+ arrange_layers(output);
+ transaction_commit_dirty();
+ wl_list_remove(&sway_layer->output_destroy.link);
+ sway_layer->layer_surface->output = NULL;
+
free(sway_layer);
}
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = wl_container_of(listener,
sway_layer, map);
- struct sway_output *output = sway_layer->layer_surface->output->data;
+ struct wlr_output *wlr_output = sway_layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
+ struct sway_output *output = wlr_output->data;
output_damage_surface(output, sway_layer->geo.x, sway_layer->geo.y,
sway_layer->layer_surface->surface, true);
wlr_surface_send_enter(sway_layer->layer_surface->surface,
@@ -408,9 +397,7 @@ static void subsurface_damage(struct sway_layer_subsurface *subsurface,
bool whole) {
struct sway_layer_surface *layer = subsurface->layer_surface;
struct wlr_output *wlr_output = layer->layer_surface->output;
- if (!wlr_output) {
- return;
- }
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
int ox = subsurface->wlr_subsurface->current.x + layer->geo.x;
int oy = subsurface->wlr_subsurface->current.y + layer->geo.y;
@@ -496,15 +483,15 @@ static struct sway_layer_surface *popup_get_layer(
static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
struct wlr_xdg_popup *popup = layer_popup->wlr_popup;
struct wlr_surface *surface = popup->base->surface;
- int popup_sx = popup->geometry.x - popup->base->current.geometry.x;
- int popup_sy = popup->geometry.y - popup->base->current.geometry.y;
+ int popup_sx = popup->current.geometry.x - popup->base->current.geometry.x;
+ int popup_sy = popup->current.geometry.y - popup->base->current.geometry.y;
int ox = popup_sx, oy = popup_sy;
struct sway_layer_surface *layer;
while (true) {
if (layer_popup->parent_type == LAYER_PARENT_POPUP) {
layer_popup = layer_popup->parent_popup;
- ox += layer_popup->wlr_popup->geometry.x;
- oy += layer_popup->wlr_popup->geometry.y;
+ ox += layer_popup->wlr_popup->current.geometry.x;
+ oy += layer_popup->wlr_popup->current.geometry.y;
} else {
layer = layer_popup->parent_layer;
ox += layer->geo.x;
@@ -513,6 +500,7 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
}
}
struct wlr_output *wlr_output = layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
struct sway_output *output = wlr_output->data;
output_damage_surface(output, ox, oy, surface, whole);
}
@@ -521,6 +509,7 @@ static void popup_handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_output *wlr_output = layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
wlr_surface_send_enter(popup->wlr_popup->base->surface, wlr_output);
popup_damage(popup, true);
}
@@ -550,7 +539,9 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
- struct sway_output *output = layer->layer_surface->output->data;
+ struct wlr_output *wlr_output = layer->layer_surface->output;
+ sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
+ struct sway_output *output = wlr_output->data;
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
@@ -642,6 +633,10 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_log(SWAY_ERROR,
"no output to auto-assign layer surface '%s' to",
layer_surface->namespace);
+ // Note that layer_surface->output can be NULL
+ // here, but none of our destroy callbacks are
+ // registered yet so we don't have to make them
+ // handle that case.
wlr_layer_surface_v1_destroy(layer_surface);
return;
}
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index b6d19dd6..182ca428 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -10,11 +10,10 @@
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_matrix.h>
-#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_presentation_time.h>
-#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_compositor.h>
#include <wlr/util/region.h>
#include "config.h"
#include "log.h"
@@ -276,6 +275,25 @@ static void for_each_surface_container_iterator(struct sway_container *con,
static void output_for_each_surface(struct sway_output *output,
sway_surface_iterator_func_t iterator, void *user_data) {
+ if (server.session_lock.locked) {
+ if (server.session_lock.lock == NULL) {
+ return;
+ }
+ struct wlr_session_lock_surface_v1 *lock_surface;
+ wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
+ if (lock_surface->output != output->wlr_output) {
+ continue;
+ }
+ if (!lock_surface->mapped) {
+ continue;
+ }
+
+ output_surface_for_each_surface(output, lock_surface->surface,
+ 0.0, 0.0, iterator, user_data);
+ }
+ return;
+ }
+
if (output_has_opaque_overlay_layer_surface(output)) {
goto overlay;
}
@@ -435,6 +453,10 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
return false;
}
+ if (server.session_lock.locked) {
+ return false;
+ }
+
if (!wl_list_empty(&view->saved_buffers)) {
return false;
}
@@ -533,31 +555,43 @@ static int output_repaint_timer_handler(void *data) {
}
}
- bool needs_frame;
+ int buffer_age;
+ if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) {
+ return 0;
+ }
+
pixman_region32_t damage;
pixman_region32_init(&damage);
- if (!wlr_output_damage_attach_render(output->damage,
- &needs_frame, &damage)) {
+ wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
+ if (!output->wlr_output->needs_frame &&
+ !pixman_region32_not_empty(&output->damage_ring.current)) {
+ pixman_region32_fini(&damage);
+ wlr_output_rollback(output->wlr_output);
return 0;
}
- if (needs_frame) {
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
- output_render(output, &now, &damage);
- } else {
- wlr_output_rollback(output->wlr_output);
- }
+ output_render(output, &now, &damage);
pixman_region32_fini(&damage);
return 0;
}
-static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
+static void handle_damage(struct wl_listener *listener, void *user_data) {
+ struct sway_output *output =
+ wl_container_of(listener, output, damage);
+ struct wlr_output_event_damage *event = user_data;
+ if (wlr_damage_ring_add(&output->damage_ring, event->damage)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
+}
+
+static void handle_frame(struct wl_listener *listener, void *user_data) {
struct sway_output *output =
- wl_container_of(listener, output, damage_frame);
+ wl_container_of(listener, output, frame);
if (!output->enabled || !output->wlr_output->enabled) {
return;
}
@@ -620,11 +654,18 @@ static void damage_handle_frame(struct wl_listener *listener, void *user_data) {
send_frame_done(output, &data);
}
+static void handle_needs_frame(struct wl_listener *listener, void *user_data) {
+ struct sway_output *output =
+ wl_container_of(listener, output, needs_frame);
+ wlr_output_schedule_frame(output->wlr_output);
+}
+
void output_damage_whole(struct sway_output *output) {
// The output can exist with no wlr_output if it's just been disconnected
// and the transaction to evacuate it has't completed yet.
- if (output && output->wlr_output && output->damage) {
- wlr_output_damage_add_whole(output->damage);
+ if (output != NULL && output->wlr_output != NULL) {
+ wlr_damage_ring_add_whole(&output->damage_ring);
+ wlr_output_schedule_frame(output->wlr_output);
}
}
@@ -648,11 +689,15 @@ static void damage_surface_iterator(struct sway_output *output,
ceil(output->wlr_output->scale) - surface->current.scale);
}
pixman_region32_translate(&damage, box.x, box.y);
- wlr_output_damage_add(output->damage, &damage);
+ if (wlr_damage_ring_add(&output->damage_ring, &damage)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
pixman_region32_fini(&damage);
if (whole) {
- wlr_output_damage_add_box(output->damage, &box);
+ if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
}
if (!wl_list_empty(&surface->current.frame_callback_list)) {
@@ -682,7 +727,9 @@ void output_damage_box(struct sway_output *output, struct wlr_box *_box) {
box.x -= output->lx;
box.y -= output->ly;
scale_box(&box, output->wlr_output->scale);
- wlr_output_damage_add_box(output->damage, &box);
+ if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
}
static void damage_child_views_iterator(struct sway_container *con,
@@ -706,7 +753,9 @@ void output_damage_whole_container(struct sway_output *output,
.height = con->current.height + 2,
};
scale_box(&box, output->wlr_output->scale);
- wlr_output_damage_add_box(output->damage, &box);
+ if (wlr_damage_ring_add_box(&output->damage_ring, &box)) {
+ wlr_output_schedule_frame(output->wlr_output);
+ }
// Damage subsurfaces as well, which may extend outside the box
if (con->view) {
damage_child_views_iterator(con, output);
@@ -715,20 +764,6 @@ void output_damage_whole_container(struct sway_output *output,
}
}
-static void damage_handle_destroy(struct wl_listener *listener, void *data) {
- struct sway_output *output =
- wl_container_of(listener, output, damage_destroy);
- if (!output->enabled) {
- return;
- }
- output_disable(output);
-
- wl_list_remove(&output->damage_destroy.link);
- wl_list_remove(&output->damage_frame.link);
-
- transaction_commit_dirty();
-}
-
static void update_output_manager_config(struct sway_server *server) {
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
@@ -740,14 +775,15 @@ static void update_output_manager_config(struct sway_server *server) {
}
struct wlr_output_configuration_head_v1 *config_head =
wlr_output_configuration_head_v1_create(config, output->wlr_output);
- struct wlr_box *output_box = wlr_output_layout_get_box(
- root->output_layout, output->wlr_output);
- // We mark the output enabled even if it is switched off by DPMS
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout,
+ output->wlr_output, &output_box);
+ // We mark the output enabled when it's switched off but not disabled
config_head->state.enabled = output->current_mode != NULL && output->enabled;
config_head->state.mode = output->current_mode;
- if (output_box) {
- config_head->state.x = output_box->x;
- config_head->state.y = output_box->y;
+ if (!wlr_box_empty(&output_box)) {
+ config_head->state.x = output_box.x;
+ config_head->state.y = output_box.y;
}
}
@@ -757,18 +793,24 @@ static void update_output_manager_config(struct sway_server *server) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, destroy);
struct sway_server *server = output->server;
- output_begin_destroy(output);
if (output->enabled) {
output_disable(output);
}
+ output_begin_destroy(output);
+
wl_list_remove(&output->link);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->mode.link);
wl_list_remove(&output->present.link);
+ wl_list_remove(&output->damage.link);
+ wl_list_remove(&output->frame.link);
+ wl_list_remove(&output->needs_frame.link);
+
+ wlr_damage_ring_finish(&output->damage_ring);
output->wlr_output->data = NULL;
output->wlr_output = NULL;
@@ -796,10 +838,16 @@ static void handle_mode(struct wl_listener *listener, void *data) {
if (!output->enabled) {
return;
}
+
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
+ int width, height;
+ wlr_output_transformed_resolution(output->wlr_output, &width, &height);
+ wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
+ wlr_output_schedule_frame(output->wlr_output);
+
update_output_manager_config(output->server);
}
@@ -827,6 +875,13 @@ static void handle_commit(struct wl_listener *listener, void *data) {
update_output_manager_config(output->server);
}
+
+ if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM)) {
+ int width, height;
+ wlr_output_transformed_resolution(output->wlr_output, &width, &height);
+ wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
+ wlr_output_schedule_frame(output->wlr_output);
+ }
}
static void handle_present(struct wl_listener *listener, void *data) {
@@ -862,10 +917,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
if (wlr_output->non_desktop) {
sway_log(SWAY_DEBUG, "Not configuring non-desktop output");
+ struct sway_output_non_desktop *non_desktop = output_non_desktop_create(wlr_output);
if (server->drm_lease_manager) {
wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager,
wlr_output);
}
+ list_add(root->non_desktop_outputs, non_desktop);
return;
}
@@ -880,7 +937,7 @@ void handle_new_output(struct wl_listener *listener, void *data) {
return;
}
output->server = server;
- output->damage = wlr_output_damage_create(wlr_output);
+ wlr_damage_ring_init(&output->damage_ring);
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
@@ -890,10 +947,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
output->mode.notify = handle_mode;
wl_signal_add(&wlr_output->events.present, &output->present);
output->present.notify = handle_present;
- wl_signal_add(&output->damage->events.frame, &output->damage_frame);
- output->damage_frame.notify = damage_handle_frame;
- wl_signal_add(&output->damage->events.destroy, &output->damage_destroy);
- output->damage_destroy.notify = damage_handle_destroy;
+ wl_signal_add(&wlr_output->events.damage, &output->damage);
+ output->damage.notify = handle_damage;
+ wl_signal_add(&wlr_output->events.frame, &output->frame);
+ output->frame.notify = handle_frame;
+ wl_signal_add(&wlr_output->events.needs_frame, &output->needs_frame);
+ output->needs_frame.notify = handle_needs_frame;
output->repaint_timer = wl_event_loop_add_timer(server->wl_event_loop,
output_repaint_timer_handler, output);
@@ -1007,10 +1066,10 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
struct output_config *oc = new_output_config(output->wlr_output->name);
switch (event->mode) {
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
- oc->dpms_state = DPMS_OFF;
+ oc->power = 0;
break;
case ZWLR_OUTPUT_POWER_V1_MODE_ON:
- oc->dpms_state = DPMS_ON;
+ oc->power = 1;
break;
}
oc = store_output_config(oc);
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 6247d937..35e2150e 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -9,11 +9,11 @@
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h>
+#include <wlr/types/wlr_damage_ring.h>
#include <wlr/types/wlr_matrix.h>
-#include <wlr/types/wlr_output_damage.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
-#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_compositor.h>
#include <wlr/util/region.h>
#include "log.h"
#include "config.h"
@@ -1301,6 +1301,41 @@ void output_render(struct sway_output *output, struct timespec *when,
fx_renderer_clear((float[]){1, 1, 0, 1});
}
+ if (server.session_lock.locked) {
+ float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
+ if (server.session_lock.lock == NULL) {
+ // abandoned lock -> red BG
+ clear_color[0] = 1.f;
+ }
+ int nrects;
+ pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects);
+ for (int i = 0; i < nrects; ++i) {
+ scissor_output(wlr_output, &rects[i]);
+ fx_renderer_clear(clear_color);
+ }
+
+ if (server.session_lock.lock != NULL) {
+ struct render_data data = {
+ .damage = damage,
+ .deco_data = get_undecorated_decoration_data(),
+ };
+
+ struct wlr_session_lock_surface_v1 *lock_surface;
+ wl_list_for_each(lock_surface, &server.session_lock.lock->surfaces, link) {
+ if (lock_surface->output != wlr_output) {
+ continue;
+ }
+ if (!lock_surface->mapped) {
+ continue;
+ }
+
+ output_surface_for_each_surface(output, lock_surface->surface,
+ 0.0, 0.0, render_surface_iterator, &data);
+ }
+ }
+ goto renderer_end;
+ }
+
if (output_has_opaque_overlay_layer_surface(output)) {
goto render_overlay;
}
@@ -1409,7 +1444,7 @@ renderer_end:
enum wl_output_transform transform =
wlr_output_transform_invert(wlr_output->transform);
- wlr_region_transform(&frame_damage, &output->damage->current,
+ wlr_region_transform(&frame_damage, &output->damage_ring.current,
transform, width, height);
if (debug.damage != DAMAGE_DEFAULT) {
@@ -1423,5 +1458,7 @@ renderer_end:
if (!wlr_output_commit(wlr_output)) {
return;
}
+
+ wlr_damage_ring_rotate(&output->damage_ring);
output->last_frame = *when;
}
diff --git a/sway/desktop/surface.c b/sway/desktop/surface.c
index 767b2045..1d7b536d 100644
--- a/sway/desktop/surface.c
+++ b/sway/desktop/surface.c
@@ -1,7 +1,7 @@
#define _POSIX_C_SOURCE 200112L
#include <stdlib.h>
#include <time.h>
-#include <wlr/types/wlr_surface.h>
+#include <wlr/types/wlr_compositor.h>
#include "sway/server.h"
#include "sway/surface.h"
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index 5fae8296..8da922d5 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -24,11 +24,11 @@ static const struct sway_view_child_impl popup_impl;
static void popup_get_view_coords(struct sway_view_child *child,
int *sx, int *sy) {
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
- struct wlr_xdg_surface *surface = popup->wlr_xdg_surface;
+ struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
- wlr_xdg_popup_get_toplevel_coords(surface->popup,
- surface->popup->geometry.x - surface->current.geometry.x,
- surface->popup->geometry.y - surface->current.geometry.y,
+ wlr_xdg_popup_get_toplevel_coords(wlr_popup,
+ wlr_popup->current.geometry.x - wlr_popup->base->current.geometry.x,
+ wlr_popup->current.geometry.y - wlr_popup->base->current.geometry.y,
sx, sy);
}
@@ -65,7 +65,7 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) {
static void popup_unconstrain(struct sway_xdg_popup *popup) {
struct sway_view *view = popup->child.view;
- struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup;
+ struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
struct sway_output *output = view->container->pending.workspace->output;
@@ -91,7 +91,7 @@ static struct sway_xdg_popup *popup_create(
return NULL;
}
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
- popup->wlr_xdg_surface = xdg_surface;
+ popup->wlr_xdg_popup = xdg_surface->popup;
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
popup->new_popup.notify = popup_handle_new_popup;
@@ -119,7 +119,7 @@ static struct sway_xdg_shell_view *xdg_shell_view_from_view(
static void get_constraints(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height) {
struct wlr_xdg_toplevel_state *state =
- &view->wlr_xdg_surface->toplevel->current;
+ &view->wlr_xdg_toplevel->current;
*min_width = state->min_width > 0 ? state->min_width : DBL_MIN;
*max_width = state->max_width > 0 ? state->max_width : DBL_MAX;
*min_height = state->min_height > 0 ? state->min_height : DBL_MIN;
@@ -133,9 +133,9 @@ static const char *get_string_prop(struct sway_view *view,
}
switch (prop) {
case VIEW_PROP_TITLE:
- return view->wlr_xdg_surface->toplevel->title;
+ return view->wlr_xdg_toplevel->title;
case VIEW_PROP_APP_ID:
- return view->wlr_xdg_surface->toplevel->app_id;
+ return view->wlr_xdg_toplevel->app_id;
default:
return NULL;
}
@@ -148,50 +148,45 @@ static uint32_t configure(struct sway_view *view, double lx, double ly,
if (xdg_shell_view == NULL) {
return 0;
}
- return wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
+ return wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel,
+ width, height);
}
static void set_activated(struct sway_view *view, bool activated) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
- wlr_xdg_toplevel_set_activated(surface, activated);
- }
+ wlr_xdg_toplevel_set_activated(view->wlr_xdg_toplevel, activated);
}
static void set_tiled(struct sway_view *view, bool tiled) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
enum wlr_edges edges = WLR_EDGE_NONE;
if (tiled) {
edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
WLR_EDGE_BOTTOM;
}
- wlr_xdg_toplevel_set_tiled(surface, edges);
+ wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges);
}
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- wlr_xdg_toplevel_set_fullscreen(surface, fullscreen);
+ wlr_xdg_toplevel_set_fullscreen(view->wlr_xdg_toplevel, fullscreen);
}
static void set_resizing(struct sway_view *view, bool resizing) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- wlr_xdg_toplevel_set_resizing(surface, resizing);
+ wlr_xdg_toplevel_set_resizing(view->wlr_xdg_toplevel, resizing);
}
static bool wants_floating(struct sway_view *view) {
- struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_surface->toplevel;
+ struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
struct wlr_xdg_toplevel_state *state = &toplevel->current;
return (state->min_width != 0 && state->min_height != 0
&& (state->min_width == state->max_width
@@ -204,7 +199,7 @@ static void for_each_surface(struct sway_view *view,
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- wlr_xdg_surface_for_each_surface(view->wlr_xdg_surface, iterator,
+ wlr_xdg_surface_for_each_surface(view->wlr_xdg_toplevel->base, iterator,
user_data);
}
@@ -213,8 +208,8 @@ static void for_each_popup_surface(struct sway_view *view,
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_surface, iterator,
- user_data);
+ wlr_xdg_surface_for_each_popup_surface(view->wlr_xdg_toplevel->base,
+ iterator, user_data);
}
static bool is_transient_for(struct sway_view *child,
@@ -222,12 +217,12 @@ static bool is_transient_for(struct sway_view *child,
if (xdg_shell_view_from_view(child) == NULL) {
return false;
}
- struct wlr_xdg_surface *surface = child->wlr_xdg_surface;
- while (surface && surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) {
- if (surface->toplevel->parent == ancestor->wlr_xdg_surface) {
+ struct wlr_xdg_toplevel *toplevel = child->wlr_xdg_toplevel;
+ while (toplevel) {
+ if (toplevel->parent == ancestor->wlr_xdg_toplevel) {
return true;
}
- surface = surface->toplevel->parent;
+ toplevel = toplevel->parent;
}
return false;
}
@@ -236,17 +231,13 @@ static void _close(struct sway_view *view) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
- struct wlr_xdg_surface *surface = view->wlr_xdg_surface;
- if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL
- && surface->toplevel) {
- wlr_xdg_toplevel_send_close(surface);
- }
+ wlr_xdg_toplevel_send_close(view->wlr_xdg_toplevel);
}
static void close_popups(struct sway_view *view) {
struct wlr_xdg_popup *popup, *tmp;
- wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) {
- wlr_xdg_popup_destroy(popup->base);
+ wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_toplevel->base->popups, link) {
+ wlr_xdg_popup_destroy(popup);
}
}
@@ -280,7 +271,7 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, commit);
struct sway_view *view = &xdg_shell_view->view;
- struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
+ struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base;
struct wlr_box new_geo;
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
@@ -334,26 +325,27 @@ static void handle_new_popup(struct wl_listener *listener, void *data) {
popup_create(wlr_popup, &xdg_shell_view->view);
}
+static void handle_request_maximize(struct wl_listener *listener, void *data) {
+ struct sway_xdg_shell_view *xdg_shell_view =
+ wl_container_of(listener, xdg_shell_view, request_maximize);
+ struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
+ wlr_xdg_surface_schedule_configure(toplevel->base);
+}
+
static void handle_request_fullscreen(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_fullscreen);
- struct wlr_xdg_toplevel_set_fullscreen_event *e = data;
- struct wlr_xdg_surface *xdg_surface =
- xdg_shell_view->view.wlr_xdg_surface;
+ struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
struct sway_view *view = &xdg_shell_view->view;
- if (!sway_assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL,
- "xdg_shell requested fullscreen of surface with role %i",
- xdg_surface->role)) {
- return;
- }
- if (!xdg_surface->mapped) {
+ if (!toplevel->base->mapped) {
return;
}
struct sway_container *container = view->container;
- if (e->fullscreen && e->output && e->output->data) {
- struct sway_output *output = e->output->data;
+ struct wlr_xdg_toplevel_requested *req = &toplevel->requested;
+ if (req->fullscreen && req->fullscreen_output && req->fullscreen_output->data) {
+ struct sway_output *output = req->fullscreen_output->data;
struct sway_workspace *ws = output_get_active_workspace(output);
if (ws && !container_is_scratchpad_hidden(container) &&
container->pending.workspace != ws) {
@@ -365,7 +357,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
}
}
- container_set_fullscreen(container, e->fullscreen);
+ container_set_fullscreen(container, req->fullscreen);
arrange_root();
transaction_commit_dirty();
@@ -375,7 +367,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, request_move);
struct sway_view *view = &xdg_shell_view->view;
- if (!container_is_floating(view->container)) {
+ if (!container_is_floating(view->container) ||
+ view->container->pending.fullscreen_mode) {
return;
}
struct wlr_xdg_toplevel_move_event *e = data;
@@ -412,6 +405,7 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
wl_list_remove(&xdg_shell_view->commit.link);
wl_list_remove(&xdg_shell_view->new_popup.link);
+ wl_list_remove(&xdg_shell_view->request_maximize.link);
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
wl_list_remove(&xdg_shell_view->request_move.link);
wl_list_remove(&xdg_shell_view->request_resize.link);
@@ -423,13 +417,13 @@ static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xdg_shell_view *xdg_shell_view =
wl_container_of(listener, xdg_shell_view, map);
struct sway_view *view = &xdg_shell_view->view;
- struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface;
+ struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
- view->natural_width = view->wlr_xdg_surface->current.geometry.width;
- view->natural_height = view->wlr_xdg_surface->current.geometry.height;
+ view->natural_width = toplevel->base->current.geometry.width;
+ view->natural_height = toplevel->base->current.geometry.height;
if (!view->natural_width && !view->natural_height) {
- view->natural_width = view->wlr_xdg_surface->surface->current.width;
- view->natural_height = view->wlr_xdg_surface->surface->current.height;
+ view->natural_width = toplevel->base->surface->current.width;
+ view->natural_height = toplevel->base->surface->current.height;
}
bool csd = false;
@@ -440,44 +434,48 @@ static void handle_map(struct wl_listener *listener, void *data) {
csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
} else {
struct sway_server_decoration *deco =
- decoration_from_surface(xdg_surface->surface);
+ decoration_from_surface(toplevel->base->surface);
csd = !deco || deco->wlr_server_decoration->mode ==
WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT;
}
- view_map(view, view->wlr_xdg_surface->surface,
- xdg_surface->toplevel->requested.fullscreen,
- xdg_surface->toplevel->requested.fullscreen_output,
+ view_map(view, toplevel->base->surface,
+ toplevel->requested.fullscreen,
+ toplevel->requested.fullscreen_output,
csd);
transaction_commit_dirty();
xdg_shell_view->commit.notify = handle_commit;
- wl_signal_add(&xdg_surface->surface->events.commit,
+ wl_signal_add(&toplevel->base->surface->events.commit,
&xdg_shell_view->commit);
xdg_shell_view->new_popup.notify = handle_new_popup;
- wl_signal_add(&xdg_surface->events.new_popup,
+ wl_signal_add(&toplevel->base->events.new_popup,
&xdg_shell_view->new_popup);
+ xdg_shell_view->request_maximize.notify = handle_request_maximize;
+ wl_signal_add(&toplevel->events.request_maximize,
+ &xdg_shell_view->request_maximize);
+
xdg_shell_view->request_fullscreen.notify = handle_request_fullscreen;
- wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen,
+ wl_signal_add(&toplevel->events.request_fullscreen,
&xdg_shell_view->request_fullscreen);
xdg_shell_view->request_move.notify = handle_request_move;
- wl_signal_add(&xdg_surface->toplevel->events.request_move,
+ wl_signal_add(&toplevel->events.request_move,
&xdg_shell_view->request_move);
xdg_shell_view->request_resize.notify = handle_request_resize;
- wl_signal_add(&xdg_surface->toplevel->events.request_resize,
+ wl_signal_add(&toplevel->events.request_resize,
&xdg_shell_view->request_resize);
xdg_shell_view->set_title.notify = handle_set_title;
- wl_signal_add(&xdg_surface->toplevel->events.set_title,
+ wl_signal_add(&toplevel->events.set_title,
&xdg_shell_view->set_title);
xdg_shell_view->set_app_id.notify = handle_set_app_id;
- wl_signal_add(&xdg_surface->toplevel->events.set_app_id,
+ wl_signal_add(&toplevel->events.set_app_id,
&xdg_shell_view->set_app_id);
}
@@ -491,7 +489,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xdg_shell_view->destroy.link);
wl_list_remove(&xdg_shell_view->map.link);
wl_list_remove(&xdg_shell_view->unmap.link);
- view->wlr_xdg_surface = NULL;
+ view->wlr_xdg_toplevel = NULL;
if (view->xdg_decoration) {
view->xdg_decoration->view = NULL;
}
@@ -522,7 +520,7 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
}
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
- xdg_shell_view->view.wlr_xdg_surface = xdg_surface;
+ xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel;
xdg_shell_view->map.notify = handle_map;
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 40288f97..e15a3341 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -5,7 +5,9 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_xdg_activation_v1.h>
#include <wlr/xwayland.h>
+#include <xcb/xcb_icccm.h>
#include "log.h"
#include "sway/desktop.h"
#include "sway/desktop/transaction.h"
@@ -15,6 +17,7 @@
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
+#include "sway/server.h"
#include "sway/tree/view.h"
#include "sway/tree/workspace.h"
@@ -121,6 +124,20 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
}
}
+static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) {
+ struct wlr_xwayland_surface *xsurface = data;
+ if (!xsurface->mapped) {
+ return;
+ }
+ struct sway_seat *seat = input_manager_current_seat();
+ struct sway_container *focus = seat_get_focused_container(seat);
+ if (focus && focus->view && focus->view->pid != xsurface->pid) {
+ return;
+ }
+
+ seat_set_focus_surface(seat, xsurface->surface, false);
+}
+
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, destroy);
@@ -129,6 +146,7 @@ static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&surface->unmap.link);
wl_list_remove(&surface->destroy.link);
wl_list_remove(&surface->override_redirect.link);
+ wl_list_remove(&surface->request_activate.link);
free(surface);
}
@@ -176,6 +194,8 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
surface->destroy.notify = unmanaged_handle_destroy;
wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect);
surface->override_redirect.notify = unmanaged_handle_override_redirect;
+ wl_signal_add(&xsurface->events.request_activate, &surface->request_activate);
+ surface->request_activate.notify = unmanaged_handle_request_activate;
return surface;
}
@@ -294,7 +314,7 @@ static bool wants_floating(struct sway_view *view) {
}
}
- struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
+ xcb_size_hints_t *size_hints = surface->size_hints;
if (size_hints != NULL &&
size_hints->min_width > 0 && size_hints->min_height > 0 &&
(size_hints->max_width == size_hints->min_width ||
@@ -348,7 +368,7 @@ static void destroy(struct sway_view *view) {
static void get_constraints(struct sway_view *view, double *min_width,
double *max_width, double *min_height, double *max_height) {
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
- struct wlr_xwayland_surface_size_hints *size_hints = surface->size_hints;
+ xcb_size_hints_t *size_hints = surface->size_hints;
if (size_hints == NULL) {
*min_width = DBL_MIN;
@@ -448,6 +468,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->set_title.link);
wl_list_remove(&xwayland_view->set_class.link);
wl_list_remove(&xwayland_view->set_role.link);
+ wl_list_remove(&xwayland_view->set_startup_id.link);
wl_list_remove(&xwayland_view->set_window_type.link);
wl_list_remove(&xwayland_view->set_hints.link);
wl_list_remove(&xwayland_view->set_decorations.link);
@@ -577,7 +598,8 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) {
return;
}
- if (!container_is_floating(view->container)) {
+ if (!container_is_floating(view->container) ||
+ view->container->pending.fullscreen_mode) {
return;
}
struct sway_seat *seat = input_manager_current_seat();
@@ -647,6 +669,31 @@ static void handle_set_role(struct wl_listener *listener, void *data) {
view_execute_criteria(view);
}
+static void handle_set_startup_id(struct wl_listener *listener, void *data) {
+ struct sway_xwayland_view *xwayland_view =
+ wl_container_of(listener, xwayland_view, set_startup_id);
+ struct sway_view *view = &xwayland_view->view;
+ struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
+ if (xsurface->startup_id == NULL) {
+ return;
+ }
+
+ struct wlr_xdg_activation_token_v1 *token =
+ wlr_xdg_activation_v1_find_token(
+ server.xdg_activation_v1, xsurface->startup_id);
+ if (token == NULL) {
+ // Tried to activate with an unknown or expired token
+ return;
+ }
+
+ struct launcher_ctx *ctx = token->data;
+ if (token->data == NULL) {
+ // TODO: support external launchers in X
+ return;
+ }
+ view_assign_ctx(view, ctx);
+}
+
static void handle_set_window_type(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, set_window_type);
@@ -666,14 +713,15 @@ static void handle_set_hints(struct wl_listener *listener, void *data) {
if (!xsurface->mapped) {
return;
}
- if (!xsurface->hints_urgency && view->urgent_timer) {
+ const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints);
+ if (!hints_urgency && view->urgent_timer) {
// The view is in the timeout period. We'll ignore the request to
// unset urgency so that the view remains urgent until the timer clears
// it.
return;
}
if (view->allow_request_urgent) {
- view_set_urgent(view, (bool)xsurface->hints_urgency);
+ view_set_urgent(view, hints_urgency);
}
}
@@ -731,6 +779,10 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu
wl_signal_add(&xsurface->events.set_role, &xwayland_view->set_role);
xwayland_view->set_role.notify = handle_set_role;
+ wl_signal_add(&xsurface->events.set_startup_id,
+ &xwayland_view->set_startup_id);
+ xwayland_view->set_startup_id.notify = handle_set_startup_id;
+
wl_signal_add(&xsurface->events.set_window_type,
&xwayland_view->set_window_type);
xwayland_view->set_window_type.notify = handle_set_window_type;
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 6fddee90..449aa430 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -386,28 +386,29 @@ static void pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
static void handle_pointer_motion_relative(
struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, motion);
- struct wlr_event_pointer_motion *e = data;
- cursor_handle_activity_from_device(cursor, e->device);
+ struct wlr_pointer_motion_event *e = data;
+ cursor_handle_activity_from_device(cursor, &e->pointer->base);
- pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y,
- e->unaccel_dx, e->unaccel_dy);
+ pointer_motion(cursor, e->time_msec, &e->pointer->base, e->delta_x,
+ e->delta_y, e->unaccel_dx, e->unaccel_dy);
}
static void handle_pointer_motion_absolute(
struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, motion_absolute);
- struct wlr_event_pointer_motion_absolute *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_pointer_motion_absolute_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
double lx, ly;
- wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
+ wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->pointer->base,
event->x, event->y, &lx, &ly);
double dx = lx - cursor->cursor->x;
double dy = ly - cursor->cursor->y;
- pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
+ pointer_motion(cursor, event->time_msec, &event->pointer->base, dx, dy,
+ dx, dy);
}
void dispatch_cursor_button(struct sway_cursor *cursor,
@@ -422,7 +423,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor,
static void handle_pointer_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, button);
- struct wlr_event_pointer_button *event = data;
+ struct wlr_pointer_button_event *event = data;
if (event->state == WLR_BUTTON_PRESSED) {
cursor->pressed_button_count++;
@@ -434,20 +435,20 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) {
}
}
- cursor_handle_activity_from_device(cursor, event->device);
- dispatch_cursor_button(cursor, event->device,
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ dispatch_cursor_button(cursor, &event->pointer->base,
event->time_msec, event->button, event->state);
}
void dispatch_cursor_axis(struct sway_cursor *cursor,
- struct wlr_event_pointer_axis *event) {
+ struct wlr_pointer_axis_event *event) {
seatop_pointer_axis(cursor->seat, event);
}
static void handle_pointer_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, axis);
- struct wlr_event_pointer_axis *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_pointer_axis_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
dispatch_cursor_axis(cursor, event);
}
@@ -458,8 +459,8 @@ static void handle_pointer_frame(struct wl_listener *listener, void *data) {
static void handle_touch_down(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_down);
- struct wlr_event_touch_down *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_touch_down_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->touch->base);
cursor_hide(cursor);
struct sway_seat *seat = cursor->seat;
@@ -467,7 +468,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
struct wlr_surface *surface = NULL;
double lx, ly;
- wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
+ wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
event->x, event->y, &lx, &ly);
double sx, sy;
struct sway_node *focused_node = node_at_coords(seat, lx, ly, &surface, &sx, &sy);
@@ -495,24 +496,25 @@ static void handle_touch_down(struct wl_listener *listener, void *data) {
double dx, dy;
dx = lx - cursor->cursor->x;
dy = ly - cursor->cursor->y;
- pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
- dispatch_cursor_button(cursor, event->device, event->time_msec,
+ pointer_motion(cursor, event->time_msec, &event->touch->base, dx, dy,
+ dx, dy);
+ dispatch_cursor_button(cursor, &event->touch->base, event->time_msec,
BTN_LEFT, WLR_BUTTON_PRESSED);
}
}
static void handle_touch_up(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_up);
- struct wlr_event_touch_up *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_touch_up_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->touch->base);
struct wlr_seat *wlr_seat = cursor->seat->wlr_seat;
if (cursor->simulating_pointer_from_touch) {
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
cursor->pointer_touch_up = true;
- dispatch_cursor_button(cursor, event->device, event->time_msec,
- BTN_LEFT, WLR_BUTTON_RELEASED);
+ dispatch_cursor_button(cursor, &event->touch->base,
+ event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
}
} else {
wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id);
@@ -522,15 +524,15 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, touch_motion);
- struct wlr_event_touch_motion *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_touch_motion_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->touch->base);
struct sway_seat *seat = cursor->seat;
struct wlr_seat *wlr_seat = seat->wlr_seat;
struct wlr_surface *surface = NULL;
double lx, ly;
- wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device,
+ wlr_cursor_absolute_to_layout_coords(cursor->cursor, &event->touch->base,
event->x, event->y, &lx, &ly);
double sx, sy;
node_at_coords(cursor->seat, lx, ly, &surface, &sx, &sy);
@@ -552,7 +554,8 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) {
double dx, dy;
dx = lx - cursor->cursor->x;
dy = ly - cursor->cursor->y;
- pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy);
+ pointer_motion(cursor, event->time_msec, &event->touch->base,
+ dx, dy, dx, dy);
}
} else if (surface) {
wlr_seat_touch_notify_motion(wlr_seat, event->time_msec,
@@ -591,14 +594,15 @@ static void apply_mapping_from_region(struct wlr_input_device *device,
double x1 = region->x1, x2 = region->x2;
double y1 = region->y1, y2 = region->y2;
- if (region->mm) {
- if (device->width_mm == 0 || device->height_mm == 0) {
+ if (region->mm && device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
+ struct wlr_tablet *tablet = wlr_tablet_from_input_device(device);
+ if (tablet->width_mm == 0 || tablet->height_mm == 0) {
return;
}
- x1 /= device->width_mm;
- x2 /= device->width_mm;
- y1 /= device->height_mm;
- y2 /= device->height_mm;
+ x1 /= tablet->width_mm;
+ x2 /= tablet->width_mm;
+ y1 /= tablet->height_mm;
+ y2 /= tablet->height_mm;
}
*x = apply_mapping_from_coord(x1, x2, *x);
@@ -660,8 +664,8 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
static void handle_tool_axis(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_axis);
- struct wlr_event_tablet_tool_axis *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_tablet_tool_axis_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->tablet->base);
struct sway_tablet_tool *sway_tool = event->tool->data;
if (!sway_tool) {
@@ -716,8 +720,8 @@ static void handle_tool_axis(struct wl_listener *listener, void *data) {
static void handle_tool_tip(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_tip);
- struct wlr_event_tablet_tool_tip *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_tablet_tool_tip_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->tablet->base);
struct sway_tablet_tool *sway_tool = event->tool->data;
struct wlr_tablet_v2_tablet *tablet_v2 = sway_tool->tablet->tablet_v2;
@@ -732,7 +736,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
if (cursor->simulating_pointer_from_tool_tip &&
event->state == WLR_TABLET_TOOL_TIP_UP) {
cursor->simulating_pointer_from_tool_tip = false;
- dispatch_cursor_button(cursor, event->device, event->time_msec,
+ dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
BTN_LEFT, WLR_BUTTON_RELEASED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
@@ -744,8 +748,8 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
WLR_TABLET_TOOL_TIP_UP);
} else {
cursor->simulating_pointer_from_tool_tip = true;
- dispatch_cursor_button(cursor, event->device, event->time_msec,
- BTN_LEFT, WLR_BUTTON_PRESSED);
+ dispatch_cursor_button(cursor, &event->tablet->base,
+ event->time_msec, BTN_LEFT, WLR_BUTTON_PRESSED);
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
}
} else {
@@ -767,12 +771,13 @@ static struct sway_tablet *get_tablet_for_device(struct sway_cursor *cursor,
static void handle_tool_proximity(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, tool_proximity);
- struct wlr_event_tablet_tool_proximity *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_tablet_tool_proximity_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->tablet->base);
struct wlr_tablet_tool *tool = event->tool;
if (!tool->data) {
- struct sway_tablet *tablet = get_tablet_for_device(cursor, event->device);
+ struct sway_tablet *tablet = get_tablet_for_device(cursor,
+ &event->tablet->base);
if (!tablet) {
sway_log(SWAY_ERROR, "no tablet for tablet tool");
return;
@@ -797,8 +802,8 @@ static void handle_tool_proximity(struct wl_listener *listener, void *data) {
static void handle_tool_button(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, tool_button);
- struct wlr_event_tablet_tool_button *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
+ struct wlr_tablet_tool_button_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->tablet->base);
struct sway_tablet_tool *sway_tool = event->tool->data;
if (!sway_tool) {
@@ -819,14 +824,14 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
switch (event->state) {
case WLR_BUTTON_PRESSED:
if (cursor->tool_buttons == 0) {
- dispatch_cursor_button(cursor, event->device,
+ dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_RIGHT, event->state);
}
cursor->tool_buttons++;
break;
case WLR_BUTTON_RELEASED:
if (cursor->tool_buttons == 1) {
- dispatch_cursor_button(cursor, event->device,
+ dispatch_cursor_button(cursor, &event->tablet->base,
event->time_msec, BTN_RIGHT, event->state);
}
cursor->tool_buttons--;
@@ -923,65 +928,68 @@ static void handle_request_pointer_set_cursor(struct wl_listener *listener,
event->hotspot_y, focused_client);
}
+static void handle_pointer_hold_begin(struct wl_listener *listener, void *data) {
+ struct sway_cursor *cursor = wl_container_of(
+ listener, cursor, hold_begin);
+ struct wlr_pointer_hold_begin_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_hold_begin(cursor->seat, event);
+}
+
+static void handle_pointer_hold_end(struct wl_listener *listener, void *data) {
+ struct sway_cursor *cursor = wl_container_of(
+ listener, cursor, hold_end);
+ struct wlr_pointer_hold_end_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_hold_end(cursor->seat, event);
+}
+
static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_begin);
- struct wlr_event_pointer_pinch_begin *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
- wlr_pointer_gestures_v1_send_pinch_begin(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
- event->time_msec, event->fingers);
+ struct wlr_pointer_pinch_begin_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_pinch_begin(cursor->seat, event);
}
static void handle_pointer_pinch_update(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_update);
- struct wlr_event_pointer_pinch_update *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
- wlr_pointer_gestures_v1_send_pinch_update(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
- event->time_msec, event->dx, event->dy,
- event->scale, event->rotation);
+ struct wlr_pointer_pinch_update_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_pinch_update(cursor->seat, event);
}
static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_end);
- struct wlr_event_pointer_pinch_end *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
- wlr_pointer_gestures_v1_send_pinch_end(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
- event->time_msec, event->cancelled);
+ struct wlr_pointer_pinch_end_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_pinch_end(cursor->seat, event);
}
static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_begin);
- struct wlr_event_pointer_swipe_begin *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
- wlr_pointer_gestures_v1_send_swipe_begin(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
- event->time_msec, event->fingers);
+ struct wlr_pointer_swipe_begin_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_swipe_begin(cursor->seat, event);
}
static void handle_pointer_swipe_update(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_update);
- struct wlr_event_pointer_swipe_update *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
- wlr_pointer_gestures_v1_send_swipe_update(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
- event->time_msec, event->dx, event->dy);
+ struct wlr_pointer_swipe_update_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_swipe_update(cursor->seat, event);
}
static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_end);
- struct wlr_event_pointer_swipe_end *event = data;
- cursor_handle_activity_from_device(cursor, event->device);
- wlr_pointer_gestures_v1_send_swipe_end(
- cursor->pointer_gestures, cursor->seat->wlr_seat,
- event->time_msec, event->cancelled);
+ struct wlr_pointer_swipe_end_event *event = data;
+ cursor_handle_activity_from_device(cursor, &event->pointer->base);
+ seatop_swipe_end(cursor->seat, event);
}
static void handle_image_surface_destroy(struct wl_listener *listener,
@@ -1055,6 +1063,8 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
wl_event_source_remove(cursor->hide_source);
wl_list_remove(&cursor->image_surface_destroy.link);
+ wl_list_remove(&cursor->hold_begin.link);
+ wl_list_remove(&cursor->hold_end.link);
wl_list_remove(&cursor->pinch_begin.link);
wl_list_remove(&cursor->pinch_update.link);
wl_list_remove(&cursor->pinch_end.link);
@@ -1104,19 +1114,27 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
wl_list_init(&cursor->image_surface_destroy.link);
cursor->image_surface_destroy.notify = handle_image_surface_destroy;
+ // gesture events
cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display);
- cursor->pinch_begin.notify = handle_pointer_pinch_begin;
+
+ wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin);
+ cursor->hold_begin.notify = handle_pointer_hold_begin;
+ wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end);
+ cursor->hold_end.notify = handle_pointer_hold_end;
+
wl_signal_add(&wlr_cursor->events.pinch_begin, &cursor->pinch_begin);
- cursor->pinch_update.notify = handle_pointer_pinch_update;
+ cursor->pinch_begin.notify = handle_pointer_pinch_begin;
wl_signal_add(&wlr_cursor->events.pinch_update, &cursor->pinch_update);
- cursor->pinch_end.notify = handle_pointer_pinch_end;
+ cursor->pinch_update.notify = handle_pointer_pinch_update;
wl_signal_add(&wlr_cursor->events.pinch_end, &cursor->pinch_end);
- cursor->swipe_begin.notify = handle_pointer_swipe_begin;
+ cursor->pinch_end.notify = handle_pointer_pinch_end;
+
wl_signal_add(&wlr_cursor->events.swipe_begin, &cursor->swipe_begin);
- cursor->swipe_update.notify = handle_pointer_swipe_update;
+ cursor->swipe_begin.notify = handle_pointer_swipe_begin;
wl_signal_add(&wlr_cursor->events.swipe_update, &cursor->swipe_update);
- cursor->swipe_end.notify = handle_pointer_swipe_end;
+ cursor->swipe_update.notify = handle_pointer_swipe_update;
wl_signal_add(&wlr_cursor->events.swipe_end, &cursor->swipe_end);
+ cursor->swipe_end.notify = handle_pointer_swipe_end;
// input events
wl_signal_add(&wlr_cursor->events.motion, &cursor->motion);
@@ -1354,12 +1372,9 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) {
sway_constraint->destroy.notify = handle_constraint_destroy;
wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy);
- struct sway_node *focus = seat_get_focus(seat);
- if (focus && node_is_view(focus)) {
- struct wlr_surface *surface = focus->sway_container->view->surface;
- if (surface == constraint->surface) {
- sway_cursor_constrain(seat->cursor, constraint);
- }
+ struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface;
+ if (surface && surface == constraint->surface) {
+ sway_cursor_constrain(seat->cursor, constraint);
}
}
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index f04a8ce0..39f4b795 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -236,7 +236,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
apply_input_type_config(input_device);
- sway_input_configure_libinput_device(input_device);
+ bool config_changed = sway_input_configure_libinput_device(input_device);
wl_signal_add(&device->events.destroy, &input_device->device_destroy);
input_device->device_destroy.notify = handle_device_destroy;
@@ -274,6 +274,10 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
}
ipc_event_input("added", input_device);
+
+ if (config_changed) {
+ ipc_event_input("libinput_config", input_device);
+ }
}
static void handle_inhibit_activate(struct wl_listener *listener, void *data) {
@@ -289,6 +293,10 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
struct sway_input_manager *input_manager = wl_container_of(
listener, input_manager, inhibit_deactivate);
struct sway_seat *seat;
+ if (server.session_lock.locked) {
+ // Don't deactivate the grab of a screenlocker
+ return;
+ }
wl_list_for_each(seat, &input_manager->seats, link) {
seat_set_exclusive_client(seat, NULL);
struct sway_node *previous = seat_get_focus(seat);
@@ -377,7 +385,7 @@ void handle_virtual_keyboard(struct wl_listener *listener, void *data) {
struct sway_input_manager *input_manager =
wl_container_of(listener, input_manager, virtual_keyboard_new);
struct wlr_virtual_keyboard_v1 *keyboard = data;
- struct wlr_input_device *device = &keyboard->input_device;
+ struct wlr_input_device *device = &keyboard->keyboard.base;
// TODO: Amend protocol to allow NULL seat
struct sway_seat *seat = keyboard->seat ?
@@ -410,7 +418,7 @@ void handle_virtual_pointer(struct wl_listener *listener, void *data) {
wl_container_of(listener, input_manager, virtual_pointer_new);
struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
struct wlr_virtual_pointer_v1 *pointer = event->new_pointer;
- struct wlr_input_device *device = &pointer->input_device;
+ struct wlr_input_device *device = &pointer->pointer.base;
struct sway_seat *seat = event->suggested_seat ?
input_manager_sway_seat_from_wlr_seat(event->suggested_seat) :
@@ -524,11 +532,14 @@ static void retranslate_keysyms(struct input_config *input_config) {
static void input_manager_configure_input(
struct sway_input_device *input_device) {
- sway_input_configure_libinput_device(input_device);
+ bool config_changed = sway_input_configure_libinput_device(input_device);
struct sway_seat *seat = NULL;
wl_list_for_each(seat, &server.input->seats, link) {
seat_configure_device(seat, input_device);
}
+ if (config_changed) {
+ ipc_event_input("libinput_config", input_device);
+ }
}
void input_manager_configure_all_inputs(void) {
@@ -564,6 +575,13 @@ void input_manager_reset_input(struct sway_input_device *input_device) {
}
void input_manager_reset_all_inputs(void) {
+ // Set the active keyboard to NULL to avoid spamming configuration updates
+ // for all keyboard devices.
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ wlr_seat_set_keyboard(seat->wlr_seat, NULL);
+ }
+
struct sway_input_device *input_device = NULL;
wl_list_for_each(input_device, &server.input->devices, link) {
input_manager_reset_input(input_device);
@@ -572,7 +590,6 @@ void input_manager_reset_all_inputs(void) {
// If there is at least one keyboard using the default keymap, repeat delay,
// and repeat rate, then it is possible that there is a keyboard group that
// need their keyboard disarmed.
- struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
struct sway_keyboard_group *group;
wl_list_for_each(group, &seat->keyboard_groups, link) {
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index f258ac7d..c5a646c4 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -291,14 +291,12 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
uint32_t *modifiers) {
- struct wlr_input_device *device =
- keyboard->seat_device->input_device->wlr_device;
- *modifiers = wlr_keyboard_get_modifiers(device->keyboard);
+ *modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
- device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
+ keyboard->wlr->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
*modifiers = *modifiers & ~consumed;
- return xkb_state_key_get_syms(device->keyboard->xkb_state,
+ return xkb_state_key_get_syms(keyboard->wlr->xkb_state,
keycode, keysyms);
}
@@ -314,13 +312,11 @@ static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
uint32_t *modifiers) {
- struct wlr_input_device *device =
- keyboard->seat_device->input_device->wlr_device;
- *modifiers = wlr_keyboard_get_modifiers(device->keyboard);
+ *modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
xkb_layout_index_t layout_index = xkb_state_key_get_layout(
- device->keyboard->xkb_state, keycode);
- return xkb_keymap_key_get_syms_by_level(device->keyboard->keymap,
+ keyboard->wlr->xkb_state, keycode);
+ return xkb_keymap_key_get_syms_by_level(keyboard->wlr->keymap,
keycode, layout_index, 0, keysyms);
}
@@ -360,8 +356,7 @@ static void update_keyboard_state(struct sway_keyboard *keyboard,
keyinfo->keycode, &keyinfo->translated_keysyms,
&keyinfo->translated_modifiers);
- keyinfo->code_modifiers = wlr_keyboard_get_modifiers(
- keyboard->seat_device->input_device->wlr_device->keyboard);
+ keyinfo->code_modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
// Update shortcut model keyinfo
update_shortcut_state(&keyboard->state_keycodes, raw_keycode, keystate,
@@ -401,15 +396,16 @@ static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab(
}
static void handle_key_event(struct sway_keyboard *keyboard,
- struct wlr_event_keyboard_key *event) {
+ struct wlr_keyboard_key_event *event) {
struct sway_seat *seat = keyboard->seat_device->sway_seat;
struct wlr_seat *wlr_seat = seat->wlr_seat;
struct wlr_input_device *wlr_device =
keyboard->seat_device->input_device->wlr_device;
char *device_identifier = input_device_get_identifier(wlr_device);
- bool exact_identifier = wlr_device->keyboard->group != NULL;
+ bool exact_identifier = keyboard->wlr->group != NULL;
seat_idle_notify_activity(seat, IDLE_SOURCE_KEYBOARD);
- bool input_inhibited = seat->exclusive_client != NULL;
+ bool input_inhibited = seat->exclusive_client != NULL ||
+ server.session_lock.locked;
struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
keyboard_shortcuts_inhibitor_get_for_focused_surface(seat);
bool shortcuts_inhibited = sway_inhibitor && sway_inhibitor->inhibitor->active;
@@ -477,10 +473,10 @@ static void handle_key_event(struct sway_keyboard *keyboard,
// 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 && !(binding->flags & BINDING_NOREPEAT) &&
- wlr_device->keyboard->repeat_info.delay > 0) {
+ keyboard->wlr->repeat_info.delay > 0) {
keyboard->repeat_binding = binding;
if (wl_event_source_timer_update(keyboard->key_repeat_source,
- wlr_device->keyboard->repeat_info.delay) < 0) {
+ keyboard->wlr->repeat_info.delay) < 0) {
sway_log(SWAY_DEBUG, "failed to set key repeat timer");
}
} else if (keyboard->repeat_binding) {
@@ -492,7 +488,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
handled = true;
}
- if (!handled && wlr_device->keyboard->group) {
+ if (!handled && keyboard->wlr->group) {
// Only handle device specific bindings for keyboards in a group
free(device_identifier);
return;
@@ -517,7 +513,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
&keyboard->state_pressed_sent, event->keycode,
event->state, keyinfo.keycode, 0);
if (pressed_sent) {
- wlr_seat_set_keyboard(wlr_seat, wlr_device);
+ wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
event->keycode, event->state);
handled = true;
@@ -528,8 +524,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
if (kb_grab) {
- wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
- wlr_device->keyboard);
+ wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, keyboard->wlr);
wlr_input_method_keyboard_grab_v2_send_key(kb_grab,
event->time_msec, event->keycode, event->state);
handled = true;
@@ -542,7 +537,7 @@ static void handle_key_event(struct sway_keyboard *keyboard,
update_shortcut_state(
&keyboard->state_pressed_sent, event->keycode, event->state,
keyinfo.keycode, 0);
- wlr_seat_set_keyboard(wlr_seat, wlr_device);
+ wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
event->keycode, event->state);
}
@@ -618,14 +613,12 @@ static void handle_keyboard_group_leave(struct wl_listener *listener,
}
static int handle_keyboard_repeat(void *data) {
- struct sway_keyboard *keyboard = (struct sway_keyboard *)data;
- struct wlr_keyboard *wlr_device =
- keyboard->seat_device->input_device->wlr_device->keyboard;
+ struct sway_keyboard *keyboard = data;
if (keyboard->repeat_binding) {
- if (wlr_device->repeat_info.rate > 0) {
+ if (keyboard->wlr->repeat_info.rate > 0) {
// We queue the next event first, as the command might cancel it
if (wl_event_source_timer_update(keyboard->key_repeat_source,
- 1000 / wlr_device->repeat_info.rate) < 0) {
+ 1000 / keyboard->wlr->repeat_info.rate) < 0) {
sway_log(SWAY_DEBUG, "failed to update key repeat timer");
}
}
@@ -658,31 +651,28 @@ static void determine_bar_visibility(uint32_t modifiers) {
}
static void handle_modifier_event(struct sway_keyboard *keyboard) {
- struct wlr_input_device *wlr_device =
- keyboard->seat_device->input_device->wlr_device;
- if (!wlr_device->keyboard->group) {
+ if (!keyboard->wlr->group) {
struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard);
if (kb_grab) {
- wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab,
- wlr_device->keyboard);
+ wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, keyboard->wlr);
wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab,
- &wlr_device->keyboard->modifiers);
+ &keyboard->wlr->modifiers);
} else {
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
- wlr_seat_set_keyboard(wlr_seat, wlr_device);
+ wlr_seat_set_keyboard(wlr_seat, keyboard->wlr);
wlr_seat_keyboard_notify_modifiers(wlr_seat,
- &wlr_device->keyboard->modifiers);
+ &keyboard->wlr->modifiers);
}
- uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
+ uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->wlr);
determine_bar_visibility(modifiers);
}
- if (wlr_device->keyboard->modifiers.group != keyboard->effective_layout) {
- keyboard->effective_layout = wlr_device->keyboard->modifiers.group;
+ if (keyboard->wlr->modifiers.group != keyboard->effective_layout) {
+ keyboard->effective_layout = keyboard->wlr->modifiers.group;
- if (!wlr_keyboard_group_from_wlr_keyboard(wlr_device->keyboard)) {
+ if (!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr)) {
ipc_event_input("xkb_layout", keyboard->seat_device->input_device);
}
}
@@ -711,6 +701,7 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
}
keyboard->seat_device = device;
+ keyboard->wlr = wlr_keyboard_from_input_device(device->input_device->wlr_device);
device->keyboard = keyboard;
wl_list_init(&keyboard->keyboard_key.link);
@@ -819,13 +810,12 @@ static void destroy_empty_wlr_keyboard_group(void *data) {
static void sway_keyboard_group_remove(struct sway_keyboard *keyboard) {
struct sway_input_device *device = keyboard->seat_device->input_device;
- struct wlr_keyboard *wlr_keyboard = device->wlr_device->keyboard;
- struct wlr_keyboard_group *wlr_group = wlr_keyboard->group;
+ struct wlr_keyboard_group *wlr_group = keyboard->wlr->group;
sway_log(SWAY_DEBUG, "Removing keyboard %s from group %p",
device->identifier, wlr_group);
- wlr_keyboard_group_remove_keyboard(wlr_keyboard->group, wlr_keyboard);
+ wlr_keyboard_group_remove_keyboard(keyboard->wlr->group, keyboard->wlr);
if (wl_list_empty(&wlr_group->devices)) {
sway_log(SWAY_DEBUG, "Destroying empty keyboard group %p",
@@ -850,9 +840,7 @@ static void sway_keyboard_group_remove(struct sway_keyboard *keyboard) {
}
static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
- struct sway_input_device *device = keyboard->seat_device->input_device;
- struct wlr_keyboard *wlr_keyboard = device->wlr_device->keyboard;
- if (!wlr_keyboard->group) {
+ if (!keyboard->wlr->group) {
return;
}
@@ -868,7 +856,7 @@ static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
break;
case KEYBOARD_GROUP_DEFAULT: /* fallthrough */
case KEYBOARD_GROUP_SMART:;
- struct wlr_keyboard_group *group = wlr_keyboard->group;
+ struct wlr_keyboard_group *group = keyboard->wlr->group;
if (!wlr_keyboard_keymaps_match(keyboard->keymap, group->keyboard.keymap) ||
!repeat_info_match(keyboard, &group->keyboard)) {
sway_keyboard_group_remove(keyboard);
@@ -879,7 +867,6 @@ static void sway_keyboard_group_remove_invalid(struct sway_keyboard *keyboard) {
static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
struct sway_input_device *device = keyboard->seat_device->input_device;
- struct wlr_keyboard *wlr_keyboard = device->wlr_device->keyboard;
struct sway_seat *seat = keyboard->seat_device->sway_seat;
struct seat_config *sc = seat_get_config(seat);
@@ -911,7 +898,7 @@ static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
repeat_info_match(keyboard, &wlr_group->keyboard)) {
sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p",
device->identifier, wlr_group);
- wlr_keyboard_group_add_keyboard(wlr_group, wlr_keyboard);
+ wlr_keyboard_group_add_keyboard(wlr_group, keyboard->wlr);
return;
}
break;
@@ -950,7 +937,7 @@ static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
goto cleanup;
}
sway_group->seat_device->input_device->wlr_device =
- sway_group->wlr_group->input_device;
+ &sway_group->wlr_group->keyboard.base;
if (!sway_keyboard_create(seat, sway_group->seat_device)) {
sway_log(SWAY_ERROR, "Failed to allocate sway_keyboard for group");
@@ -959,7 +946,7 @@ static void sway_keyboard_group_add(struct sway_keyboard *keyboard) {
sway_log(SWAY_DEBUG, "Adding keyboard %s to group %p",
device->identifier, sway_group->wlr_group);
- wlr_keyboard_group_add_keyboard(sway_group->wlr_group, wlr_keyboard);
+ wlr_keyboard_group_add_keyboard(sway_group->wlr_group, keyboard->wlr);
wl_list_insert(&seat->keyboard_groups, &sway_group->link);
@@ -991,10 +978,8 @@ cleanup:
void sway_keyboard_configure(struct sway_keyboard *keyboard) {
struct input_config *input_config =
input_device_get_config(keyboard->seat_device->input_device);
- struct wlr_input_device *wlr_device =
- keyboard->seat_device->input_device->wlr_device;
- if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(wlr_device->keyboard),
+ if (!sway_assert(!wlr_keyboard_group_from_wlr_keyboard(keyboard->wlr),
"sway_keyboard_configure should not be called with a "
"keyboard group's keyboard")) {
return;
@@ -1036,11 +1021,11 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
sway_keyboard_group_remove_invalid(keyboard);
- wlr_keyboard_set_keymap(wlr_device->keyboard, keyboard->keymap);
- wlr_keyboard_set_repeat_info(wlr_device->keyboard,
+ wlr_keyboard_set_keymap(keyboard->wlr, keyboard->keymap);
+ wlr_keyboard_set_repeat_info(keyboard->wlr,
keyboard->repeat_rate, keyboard->repeat_delay);
- if (!wlr_device->keyboard->group) {
+ if (!keyboard->wlr->group) {
sway_keyboard_group_add(keyboard);
}
@@ -1060,40 +1045,42 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
}
}
if (locked_mods) {
- wlr_keyboard_notify_modifiers(wlr_device->keyboard, 0, 0,
+ wlr_keyboard_notify_modifiers(keyboard->wlr, 0, 0,
locked_mods, 0);
uint32_t leds = 0;
for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
- if (xkb_state_led_index_is_active(
- wlr_device->keyboard->xkb_state,
- wlr_device->keyboard->led_indexes[i])) {
+ if (xkb_state_led_index_is_active(keyboard->wlr->xkb_state,
+ keyboard->wlr->led_indexes[i])) {
leds |= (1 << i);
}
}
- if (wlr_device->keyboard->group) {
- wlr_keyboard_led_update(
- &wlr_device->keyboard->group->keyboard, leds);
+ if (keyboard->wlr->group) {
+ wlr_keyboard_led_update(&keyboard->wlr->group->keyboard, leds);
} else {
- wlr_keyboard_led_update(wlr_device->keyboard, leds);
+ wlr_keyboard_led_update(keyboard->wlr, leds);
}
}
} else {
xkb_keymap_unref(keymap);
sway_keyboard_group_remove_invalid(keyboard);
- if (!wlr_device->keyboard->group) {
+ if (!keyboard->wlr->group) {
sway_keyboard_group_add(keyboard);
}
}
+ // If the seat has no active keyboard, set this one
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
- wlr_seat_set_keyboard(seat, wlr_device);
+ struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
+ if (current_keyboard == NULL) {
+ wlr_seat_set_keyboard(seat, keyboard->wlr);
+ }
wl_list_remove(&keyboard->keyboard_key.link);
- wl_signal_add(&wlr_device->keyboard->events.key, &keyboard->keyboard_key);
+ wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
keyboard->keyboard_key.notify = handle_keyboard_key;
wl_list_remove(&keyboard->keyboard_modifiers.link);
- wl_signal_add(&wlr_device->keyboard->events.modifiers,
+ wl_signal_add(&keyboard->wlr->events.modifiers,
&keyboard->keyboard_modifiers);
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
@@ -1110,12 +1097,11 @@ void sway_keyboard_destroy(struct sway_keyboard *keyboard) {
if (!keyboard) {
return;
}
- if (keyboard->seat_device->input_device->wlr_device->keyboard->group) {
+ if (keyboard->wlr->group) {
sway_keyboard_group_remove(keyboard);
}
struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat;
- struct sway_input_device *device = keyboard->seat_device->input_device;
- if (wlr_seat_get_keyboard(wlr_seat) == device->wlr_device->keyboard) {
+ if (wlr_seat_get_keyboard(wlr_seat) == keyboard->wlr) {
wlr_seat_set_keyboard(wlr_seat, NULL);
}
if (keyboard->keymap) {
diff --git a/sway/input/libinput.c b/sway/input/libinput.c
index 3c0f359d..53019301 100644
--- a/sway/input/libinput.c
+++ b/sway/input/libinput.c
@@ -166,6 +166,16 @@ static bool set_dwt(struct libinput_device *device, bool dwt) {
return true;
}
+static bool set_dwtp(struct libinput_device *device, bool dwtp) {
+ if (!libinput_device_config_dwtp_is_available(device) ||
+ libinput_device_config_dwtp_get_enabled(device) == dwtp) {
+ return false;
+ }
+ sway_log(SWAY_DEBUG, "dwtp_set_enabled(%d)", dwtp);
+ log_status(libinput_device_config_dwtp_set_enabled(device, dwtp));
+ return true;
+}
+
static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
if (!libinput_device_config_calibration_has_matrix(dev)) {
return false;
@@ -187,10 +197,10 @@ static bool set_calibration_matrix(struct libinput_device *dev, float mat[6]) {
return changed;
}
-void sway_input_configure_libinput_device(struct sway_input_device *input_device) {
+bool sway_input_configure_libinput_device(struct sway_input_device *input_device) {
struct input_config *ic = input_device_get_config(input_device);
if (!ic || !wlr_input_device_is_libinput(input_device->wlr_device)) {
- return;
+ return false;
}
struct libinput_device *device =
@@ -255,13 +265,14 @@ void sway_input_configure_libinput_device(struct sway_input_device *input_device
if (ic->dwt != INT_MIN) {
changed |= set_dwt(device, ic->dwt);
}
+ if (ic->dwtp != INT_MIN) {
+ changed |= set_dwtp(device, ic->dwtp);
+ }
if (ic->calibration_matrix.configured) {
changed |= set_calibration_matrix(device, ic->calibration_matrix.matrix);
}
- if (changed) {
- ipc_event_input("libinput_config", input_device);
- }
+ return changed;
}
void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
@@ -304,6 +315,8 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
libinput_device_config_scroll_get_default_button(device));
changed |= set_dwt(device,
libinput_device_config_dwt_get_default_enabled(device));
+ changed |= set_dwtp(device,
+ libinput_device_config_dwtp_get_default_enabled(device));
float matrix[6];
libinput_device_config_calibration_get_default_matrix(device, matrix);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index ce933b66..646f3866 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -7,10 +7,12 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_primary_selection.h>
#include <wlr/types/wlr_tablet_v2.h>
+#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_xcursor_manager.h>
#include "config.h"
#include "list.h"
@@ -42,6 +44,7 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
sway_keyboard_destroy(seat_device->keyboard);
sway_tablet_destroy(seat_device->tablet);
sway_tablet_pad_destroy(seat_device->tablet_pad);
+ sway_switch_destroy(seat_device->switch_device);
wlr_cursor_detach_input_device(seat_device->sway_seat->cursor->cursor,
seat_device->input_device->wlr_device);
wl_list_remove(&seat_device->link);
@@ -110,6 +113,7 @@ void seat_idle_notify_activity(struct sway_seat *seat,
}
if ((source & mask) > 0) {
wlr_idle_notify_activity(server.idle, seat->wlr_seat);
+ wlr_idle_notifier_v1_notify_activity(server.idle_notifier_v1, seat->wlr_seat);
}
}
@@ -140,7 +144,7 @@ static struct sway_keyboard *sway_keyboard_for_wlr_keyboard(
if (input_device->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
continue;
}
- if (input_device->wlr_device->keyboard == wlr_keyboard) {
+ if (input_device->wlr_device == &wlr_keyboard->base) {
return seat_device->keyboard;
}
}
@@ -148,7 +152,7 @@ static struct sway_keyboard *sway_keyboard_for_wlr_keyboard(
wl_list_for_each(group, &seat->keyboard_groups, link) {
struct sway_input_device *input_device =
group->seat_device->input_device;
- if (input_device->wlr_device->keyboard == wlr_keyboard) {
+ if (input_device->wlr_device == &wlr_keyboard->base) {
return group->seat_device->keyboard;
}
}
@@ -245,7 +249,7 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) {
seat_node_destroy(seat_node);
// If an unmanaged or layer surface is focused when an output gets
// disabled and an empty workspace on the output was focused by the
- // seat, the seat needs to refocus it's focus inactive to update the
+ // seat, the seat needs to refocus its focus inactive to update the
// value of seat->workspace.
if (seat->workspace == node->sway_workspace) {
struct sway_node *node = seat_get_focus_inactive(seat, &root->node);
@@ -378,8 +382,8 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
case WLR_DRAG_GRAB_KEYBOARD:
return;
case WLR_DRAG_GRAB_KEYBOARD_POINTER:
- icon->x = cursor->x;
- icon->y = cursor->y;
+ icon->x = cursor->x + wlr_icon->surface->sx;
+ icon->y = cursor->y + wlr_icon->surface->sy;
break;
case WLR_DRAG_GRAB_KEYBOARD_TOUCH:;
struct wlr_touch_point *point =
@@ -387,8 +391,8 @@ void drag_icon_update_position(struct sway_drag_icon *icon) {
if (point == NULL) {
return;
}
- icon->x = seat->touch_x;
- icon->y = seat->touch_y;
+ icon->x = seat->touch_x + wlr_icon->surface->sx;
+ icon->y = seat->touch_y + wlr_icon->surface->sy;
}
drag_icon_damage_whole(icon);
@@ -724,14 +728,25 @@ static void seat_apply_input_config(struct sway_seat *seat,
ic == NULL ? MAPPED_TO_DEFAULT : ic->mapped_to;
switch (mapped_to) {
- case MAPPED_TO_DEFAULT:
+ case MAPPED_TO_DEFAULT:;
/*
* If the wlroots backend provides an output name, use that.
*
- * Otherwise, try to map built-in touch and tablet tool devices to the
+ * Otherwise, try to map built-in touch and pointer devices to the
* built-in output.
*/
- mapped_to_output = sway_device->input_device->wlr_device->output_name;
+ struct wlr_input_device *dev = sway_device->input_device->wlr_device;
+ switch (dev->type) {
+ case WLR_INPUT_DEVICE_POINTER:
+ mapped_to_output = wlr_pointer_from_input_device(dev)->output_name;
+ break;
+ case WLR_INPUT_DEVICE_TOUCH:
+ mapped_to_output = wlr_touch_from_input_device(dev)->output_name;
+ break;
+ default:
+ mapped_to_output = NULL;
+ break;
+ }
if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) &&
sway_libinput_device_is_builtin(sway_device->input_device)) {
mapped_to_output = get_builtin_output_name();
@@ -799,13 +814,22 @@ static void seat_configure_keyboard(struct sway_seat *seat,
sway_keyboard_create(seat, seat_device);
}
sway_keyboard_configure(seat_device->keyboard);
- wlr_seat_set_keyboard(seat->wlr_seat,
- seat_device->input_device->wlr_device);
- struct sway_node *focus = seat_get_focus(seat);
- if (focus && node_is_view(focus)) {
- // force notify reenter to pick up the new configuration
+
+ // We only need to update the current keyboard, as the rest will be updated
+ // as they are activated.
+ struct wlr_keyboard *wlr_keyboard =
+ wlr_keyboard_from_input_device(seat_device->input_device->wlr_device);
+ struct wlr_keyboard *current_keyboard = seat->wlr_seat->keyboard_state.keyboard;
+ if (wlr_keyboard != current_keyboard) {
+ return;
+ }
+
+ // force notify reenter to pick up the new configuration. This reuses
+ // the current focused surface to avoid breaking input grabs.
+ struct wlr_surface *surface = seat->wlr_seat->keyboard_state.focused_surface;
+ if (surface) {
wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
- seat_keyboard_notify_enter(seat, focus->sway_container->view->surface);
+ seat_keyboard_notify_enter(seat, surface);
}
}
@@ -1057,7 +1081,8 @@ void seat_configure_xcursor(struct sway_seat *seat) {
bool seat_is_input_allowed(struct sway_seat *seat,
struct wlr_surface *surface) {
struct wl_client *client = wl_resource_get_client(surface->resource);
- return !seat->exclusive_client || seat->exclusive_client == client;
+ return seat->exclusive_client == client ||
+ (seat->exclusive_client == NULL && !server.session_lock.locked);
}
static void send_unfocus(struct sway_container *con, void *data) {
@@ -1116,15 +1141,7 @@ void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) {
}
}
-void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
- if (seat->focused_layer) {
- struct wlr_layer_surface_v1 *layer = seat->focused_layer;
- seat_set_focus_layer(seat, NULL);
- seat_set_focus(seat, node);
- seat_set_focus_layer(seat, layer);
- return;
- }
-
+static void seat_set_workspace_focus(struct sway_seat *seat, struct sway_node *node) {
struct sway_node *last_focus = seat_get_focus(seat);
if (last_focus == node) {
return;
@@ -1257,6 +1274,20 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
}
}
+void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
+ if (seat->focused_layer) {
+ struct wlr_layer_surface_v1 *layer = seat->focused_layer;
+ seat_set_focus_layer(seat, NULL);
+ seat_set_workspace_focus(seat, node);
+ seat_set_focus_layer(seat, layer);
+ } else {
+ seat_set_workspace_focus(seat, node);
+ }
+ if (server.session_lock.locked) {
+ seat_set_focus_surface(seat, server.session_lock.focused, false);
+ }
+}
+
void seat_set_focus_container(struct sway_seat *seat,
struct sway_container *con) {
seat_set_focus(seat, con ? &con->node : NULL);
@@ -1561,7 +1592,7 @@ void seatop_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
}
void seatop_pointer_axis(struct sway_seat *seat,
- struct wlr_event_pointer_axis *event) {
+ struct wlr_pointer_axis_event *event) {
if (seat->seatop_impl->pointer_axis) {
seat->seatop_impl->pointer_axis(seat, event);
}
@@ -1584,6 +1615,62 @@ void seatop_tablet_tool_motion(struct sway_seat *seat,
}
}
+void seatop_hold_begin(struct sway_seat *seat,
+ struct wlr_pointer_hold_begin_event *event) {
+ if (seat->seatop_impl->hold_begin) {
+ seat->seatop_impl->hold_begin(seat, event);
+ }
+}
+
+void seatop_hold_end(struct sway_seat *seat,
+ struct wlr_pointer_hold_end_event *event) {
+ if (seat->seatop_impl->hold_end) {
+ seat->seatop_impl->hold_end(seat, event);
+ }
+}
+
+void seatop_pinch_begin(struct sway_seat *seat,
+ struct wlr_pointer_pinch_begin_event *event) {
+ if (seat->seatop_impl->pinch_begin) {
+ seat->seatop_impl->pinch_begin(seat, event);
+ }
+}
+
+void seatop_pinch_update(struct sway_seat *seat,
+ struct wlr_pointer_pinch_update_event *event) {
+ if (seat->seatop_impl->pinch_update) {
+ seat->seatop_impl->pinch_update(seat, event);
+ }
+}
+
+void seatop_pinch_end(struct sway_seat *seat,
+ struct wlr_pointer_pinch_end_event *event) {
+ if (seat->seatop_impl->pinch_end) {
+ seat->seatop_impl->pinch_end(seat, event);
+ }
+}
+
+void seatop_swipe_begin(struct sway_seat *seat,
+ struct wlr_pointer_swipe_begin_event *event) {
+ if (seat->seatop_impl->swipe_begin) {
+ seat->seatop_impl->swipe_begin(seat, event);
+ }
+}
+
+void seatop_swipe_update(struct sway_seat *seat,
+ struct wlr_pointer_swipe_update_event *event) {
+ if (seat->seatop_impl->swipe_update) {
+ seat->seatop_impl->swipe_update(seat, event);
+ }
+}
+
+void seatop_swipe_end(struct sway_seat *seat,
+ struct wlr_pointer_swipe_end_event *event) {
+ if (seat->seatop_impl->swipe_end) {
+ seat->seatop_impl->swipe_end(seat, event);
+ }
+}
+
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec) {
if (seat->seatop_impl->rebase) {
seat->seatop_impl->rebase(seat, time_msec);
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c
index 4320a3b4..84acefdf 100644
--- a/sway/input/seatop_default.c
+++ b/sway/input/seatop_default.c
@@ -4,6 +4,7 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_xcursor_manager.h>
+#include "gesture.h"
#include "sway/desktop/transaction.h"
#include "sway/input/cursor.h"
#include "sway/input/seat.h"
@@ -20,6 +21,7 @@ struct seatop_default_event {
struct sway_node *previous_node;
uint32_t pressed_buttons[SWAY_CURSOR_PRESSED_BUTTONS_CAP];
size_t pressed_button_count;
+ struct gesture_tracker gestures;
};
/*-----------------------------------------\
@@ -427,13 +429,31 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
}
}
+ // Handle changing focus when clicking on a container
+ if (cont && state == WLR_BUTTON_PRESSED) {
+ // Default case: focus the container that was just clicked.
+ node = &cont->node;
+
+ // If the container is a tab/stacked container and the click happened
+ // on a tab, switch to the tab. If the tab contents were already
+ // focused, focus the tab container itself. If the tab container was
+ // already focused, cycle back to focusing the tab contents.
+ if (on_titlebar) {
+ struct sway_container *focus = seat_get_focused_container(seat);
+ if (focus == cont || !container_has_ancestor(focus, cont)) {
+ node = seat_get_focus_inactive(seat, &cont->node);
+ }
+ }
+
+ seat_set_focus(seat, node);
+ transaction_commit_dirty();
+ }
+
// Handle beginning floating move
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
state == WLR_BUTTON_PRESSED) {
uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
if (button == btn_move && (mod_pressed || on_titlebar)) {
- seat_set_focus_container(seat,
- seat_get_focus_inactive_view(seat, &cont->node));
seatop_begin_move_floating(seat, container_toplevel_ancestor(cont));
return;
}
@@ -444,6 +464,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
state == WLR_BUTTON_PRESSED) {
// Via border
if (button == BTN_LEFT && resize_edge != WLR_EDGE_NONE) {
+ seat_set_focus_container(seat, cont);
seatop_begin_resize_floating(seat, cont, resize_edge);
return;
}
@@ -458,6 +479,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ?
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
+ seat_set_focus_container(seat, floater);
seatop_begin_resize_floating(seat, floater, edge);
return;
}
@@ -467,25 +489,18 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
if (config->tiling_drag && (mod_pressed || on_titlebar) &&
state == WLR_BUTTON_PRESSED && !is_floating_or_child &&
cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
- 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);
- }
-
- // If moving a container by it's title bar, use a threshold for the drag
+ // If moving a container by its title bar, use a threshold for the drag
if (!mod_pressed && config->tiling_drag_threshold > 0) {
seatop_begin_move_tiling_threshold(seat, cont);
} else {
seatop_begin_move_tiling(seat, cont);
}
+
return;
}
// Handle mousedown on a container surface
if (surface && cont && state == WLR_BUTTON_PRESSED) {
- seat_set_focus_container(seat, cont);
seatop_begin_down(seat, cont, time_msec, sx, sy);
seat_pointer_notify_button(seat, time_msec, button, WLR_BUTTON_PRESSED);
return;
@@ -493,9 +508,6 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
// Handle clicking a container surface or decorations
if (cont && state == WLR_BUTTON_PRESSED) {
- node = seat_get_focus_inactive(seat, &cont->node);
- seat_set_focus(seat, node);
- transaction_commit_dirty();
seat_pointer_notify_button(seat, time_msec, button, state);
return;
}
@@ -645,7 +657,7 @@ static void handle_tablet_tool_motion(struct sway_seat *seat,
* Functions used by handle_pointer_axis /
*--------------------------------------*/
-static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
+static uint32_t wl_axis_to_button(struct wlr_pointer_axis_event *event) {
switch (event->orientation) {
case WLR_AXIS_ORIENTATION_VERTICAL:
return event->delta < 0 ? SWAY_SCROLL_UP : SWAY_SCROLL_DOWN;
@@ -658,9 +670,9 @@ static uint32_t wl_axis_to_button(struct wlr_event_pointer_axis *event) {
}
static void handle_pointer_axis(struct sway_seat *seat,
- struct wlr_event_pointer_axis *event) {
+ struct wlr_pointer_axis_event *event) {
struct sway_input_device *input_device =
- event->device ? event->device->data : NULL;
+ event->pointer ? event->pointer->base.data : NULL;
struct input_config *ic =
input_device ? input_device_get_config(input_device) : NULL;
struct sway_cursor *cursor = seat->cursor;
@@ -706,6 +718,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
// Scrolling on a tabbed or stacked title bar (handled as press event)
if (!handled && (on_titlebar || on_titlebar_border)) {
+ struct sway_node *new_focus;
enum sway_container_layout layout = container_parent_layout(cont);
if (layout == L_TABBED || layout == L_STACKED) {
struct sway_node *tabcontainer = node_get_parent(node);
@@ -713,7 +726,7 @@ static void handle_pointer_axis(struct sway_seat *seat,
seat_get_active_tiling_child(seat, tabcontainer);
list_t *siblings = container_get_siblings(cont);
int desired = list_find(siblings, active->sway_container) +
- round(scroll_factor * event->delta_discrete);
+ round(scroll_factor * event->delta_discrete / WLR_POINTER_AXIS_DISCRETE_STEP);
if (desired < 0) {
desired = 0;
} else if (desired >= siblings->length) {
@@ -722,14 +735,16 @@ static void handle_pointer_axis(struct sway_seat *seat,
struct sway_container *new_sibling_con = siblings->items[desired];
struct sway_node *new_sibling = &new_sibling_con->node;
- struct sway_node *new_focus =
- seat_get_focus_inactive(seat, new_sibling);
// Use the focused child of the tabbed/stacked container, not the
// container the user scrolled on.
- seat_set_focus(seat, new_focus);
- transaction_commit_dirty();
- handled = true;
+ new_focus = seat_get_focus_inactive(seat, new_sibling);
+ } else {
+ new_focus = seat_get_focus_inactive(seat, &cont->node);
}
+
+ seat_set_focus(seat, new_focus);
+ transaction_commit_dirty();
+ handled = true;
}
// Handle mouse bindings - x11 mouse buttons 4-7 - release event
@@ -750,6 +765,304 @@ static void handle_pointer_axis(struct sway_seat *seat,
}
}
+/*------------------------------------\
+ * Functions used by gesture support /
+ *----------------------------------*/
+
+/**
+ * Check gesture binding for a specific gesture type and finger count.
+ * Returns true if binding is present, false otherwise
+ */
+static bool gesture_binding_check(list_t *bindings, enum gesture_type type,
+ uint8_t fingers, struct sway_input_device *device) {
+ char *input =
+ device ? input_device_get_identifier(device->wlr_device) : strdup("*");
+
+ for (int i = 0; i < bindings->length; ++i) {
+ struct sway_gesture_binding *binding = bindings->items[i];
+
+ // Check type and finger count
+ if (!gesture_check(&binding->gesture, type, fingers)) {
+ continue;
+ }
+
+ // Check that input matches
+ if (strcmp(binding->input, "*") != 0 &&
+ strcmp(binding->input, input) != 0) {
+ continue;
+ }
+
+ free(input);
+
+ return true;
+ }
+
+ free(input);
+
+ return false;
+}
+
+/**
+ * Return the gesture binding which matches gesture type, finger count
+ * and direction, otherwise return null.
+ */
+static struct sway_gesture_binding* gesture_binding_match(
+ list_t *bindings, struct gesture *gesture, const char *input) {
+ struct sway_gesture_binding *current = NULL;
+
+ // Find best matching binding
+ for (int i = 0; i < bindings->length; ++i) {
+ struct sway_gesture_binding *binding = bindings->items[i];
+ bool exact = binding->flags & BINDING_EXACT;
+
+ // Check gesture matching
+ if (!gesture_match(&binding->gesture, gesture, exact)) {
+ continue;
+ }
+
+ // Check input matching
+ if (strcmp(binding->input, "*") != 0 &&
+ strcmp(binding->input, input) != 0) {
+ continue;
+ }
+
+ // If we already have a match ...
+ if (current) {
+ // ... check if input matching is equivalent
+ if (strcmp(current->input, binding->input) == 0) {
+
+ // ... - do not override an exact binding
+ if (!exact && current->flags & BINDING_EXACT) {
+ continue;
+ }
+
+ // ... - and ensure direction matching is better or equal
+ if (gesture_compare(&current->gesture, &binding->gesture) > 0) {
+ continue;
+ }
+ } else if (strcmp(binding->input, "*") == 0) {
+ // ... do not accept worse input match
+ continue;
+ }
+ }
+
+ // Accept newer or better match
+ current = binding;
+
+ // If exact binding and input is found, quit search
+ if (strcmp(current->input, input) == 0 &&
+ gesture_compare(&current->gesture, gesture) == 0) {
+ break;
+ }
+ } // for all gesture bindings
+
+ return current;
+}
+
+// Wrapper around gesture_tracker_end to use tracker with sway bindings
+static struct sway_gesture_binding* gesture_tracker_end_and_match(
+ struct gesture_tracker *tracker, struct sway_input_device* device) {
+ // Determine name of input that received gesture
+ char *input = device
+ ? input_device_get_identifier(device->wlr_device)
+ : strdup("*");
+
+ // Match tracking result to binding
+ struct gesture *gesture = gesture_tracker_end(tracker);
+ struct sway_gesture_binding *binding = gesture_binding_match(
+ config->current_mode->gesture_bindings, gesture, input);
+ free(gesture);
+ free(input);
+
+ return binding;
+}
+
+// Small wrapper around seat_execute_command to work on gesture bindings
+static void gesture_binding_execute(struct sway_seat *seat,
+ struct sway_gesture_binding *binding) {
+ struct sway_binding *dummy_binding =
+ calloc(1, sizeof(struct sway_binding));
+ dummy_binding->type = BINDING_GESTURE;
+ dummy_binding->command = binding->command;
+
+ char *description = gesture_to_string(&binding->gesture);
+ sway_log(SWAY_DEBUG, "executing gesture binding: %s", description);
+ free(description);
+
+ seat_execute_command(seat, dummy_binding);
+
+ free(dummy_binding);
+}
+
+static void handle_hold_begin(struct sway_seat *seat,
+ struct wlr_pointer_hold_begin_event *event) {
+ // Start tracking gesture if there is a matching binding ...
+ struct sway_input_device *device =
+ event->pointer ? event->pointer->base.data : NULL;
+ list_t *bindings = config->current_mode->gesture_bindings;
+ if (gesture_binding_check(bindings, GESTURE_TYPE_HOLD, event->fingers, device)) {
+ struct seatop_default_event *seatop = seat->seatop_data;
+ gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_HOLD, event->fingers);
+ } else {
+ // ... otherwise forward to client
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_hold_begin(
+ cursor->pointer_gestures, cursor->seat->wlr_seat,
+ event->time_msec, event->fingers);
+ }
+}
+
+static void handle_hold_end(struct sway_seat *seat,
+ struct wlr_pointer_hold_end_event *event) {
+ // Ensure that gesture is being tracked and was not cancelled
+ struct seatop_default_event *seatop = seat->seatop_data;
+ if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_HOLD)) {
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_hold_end(
+ cursor->pointer_gestures, cursor->seat->wlr_seat,
+ event->time_msec, event->cancelled);
+ return;
+ }
+ if (event->cancelled) {
+ gesture_tracker_cancel(&seatop->gestures);
+ return;
+ }
+
+ // End gesture tracking and execute matched binding
+ struct sway_input_device *device =
+ event->pointer ? event->pointer->base.data : NULL;
+ struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
+ &seatop->gestures, device);
+
+ if (binding) {
+ gesture_binding_execute(seat, binding);
+ }
+}
+
+static void handle_pinch_begin(struct sway_seat *seat,
+ struct wlr_pointer_pinch_begin_event *event) {
+ // Start tracking gesture if there is a matching binding ...
+ struct sway_input_device *device =
+ event->pointer ? event->pointer->base.data : NULL;
+ list_t *bindings = config->current_mode->gesture_bindings;
+ if (gesture_binding_check(bindings, GESTURE_TYPE_PINCH, event->fingers, device)) {
+ struct seatop_default_event *seatop = seat->seatop_data;
+ gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_PINCH, event->fingers);
+ } else {
+ // ... otherwise forward to client
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_pinch_begin(
+ cursor->pointer_gestures, cursor->seat->wlr_seat,
+ event->time_msec, event->fingers);
+ }
+}
+
+static void handle_pinch_update(struct sway_seat *seat,
+ struct wlr_pointer_pinch_update_event *event) {
+ // Update any ongoing tracking ...
+ struct seatop_default_event *seatop = seat->seatop_data;
+ if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
+ gesture_tracker_update(&seatop->gestures, event->dx, event->dy,
+ event->scale, event->rotation);
+ } else {
+ // ... otherwise forward to client
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_pinch_update(
+ cursor->pointer_gestures,
+ cursor->seat->wlr_seat,
+ event->time_msec, event->dx, event->dy,
+ event->scale, event->rotation);
+ }
+}
+
+static void handle_pinch_end(struct sway_seat *seat,
+ struct wlr_pointer_pinch_end_event *event) {
+ // Ensure that gesture is being tracked and was not cancelled
+ struct seatop_default_event *seatop = seat->seatop_data;
+ if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_PINCH)) {
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_pinch_end(
+ cursor->pointer_gestures, cursor->seat->wlr_seat,
+ event->time_msec, event->cancelled);
+ return;
+ }
+ if (event->cancelled) {
+ gesture_tracker_cancel(&seatop->gestures);
+ return;
+ }
+
+ // End gesture tracking and execute matched binding
+ struct sway_input_device *device =
+ event->pointer ? event->pointer->base.data : NULL;
+ struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
+ &seatop->gestures, device);
+
+ if (binding) {
+ gesture_binding_execute(seat, binding);
+ }
+}
+
+static void handle_swipe_begin(struct sway_seat *seat,
+ struct wlr_pointer_swipe_begin_event *event) {
+ // Start tracking gesture if there is a matching binding ...
+ struct sway_input_device *device =
+ event->pointer ? event->pointer->base.data : NULL;
+ list_t *bindings = config->current_mode->gesture_bindings;
+ if (gesture_binding_check(bindings, GESTURE_TYPE_SWIPE, event->fingers, device)) {
+ struct seatop_default_event *seatop = seat->seatop_data;
+ gesture_tracker_begin(&seatop->gestures, GESTURE_TYPE_SWIPE, event->fingers);
+ } else {
+ // ... otherwise forward to client
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_swipe_begin(
+ cursor->pointer_gestures, cursor->seat->wlr_seat,
+ event->time_msec, event->fingers);
+ }
+}
+
+static void handle_swipe_update(struct sway_seat *seat,
+ struct wlr_pointer_swipe_update_event *event) {
+
+ // Update any ongoing tracking ...
+ struct seatop_default_event *seatop = seat->seatop_data;
+ if (gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
+ gesture_tracker_update(&seatop->gestures,
+ event->dx, event->dy, NAN, NAN);
+ } else {
+ // ... otherwise forward to client
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_swipe_update(
+ cursor->pointer_gestures, cursor->seat->wlr_seat,
+ event->time_msec, event->dx, event->dy);
+ }
+}
+
+static void handle_swipe_end(struct sway_seat *seat,
+ struct wlr_pointer_swipe_end_event *event) {
+ // Ensure gesture is being tracked and was not cancelled
+ struct seatop_default_event *seatop = seat->seatop_data;
+ if (!gesture_tracker_check(&seatop->gestures, GESTURE_TYPE_SWIPE)) {
+ struct sway_cursor *cursor = seat->cursor;
+ wlr_pointer_gestures_v1_send_swipe_end(cursor->pointer_gestures,
+ cursor->seat->wlr_seat, event->time_msec, event->cancelled);
+ return;
+ }
+ if (event->cancelled) {
+ gesture_tracker_cancel(&seatop->gestures);
+ return;
+ }
+
+ // End gesture tracking and execute matched binding
+ struct sway_input_device *device =
+ event->pointer ? event->pointer->base.data : NULL;
+ struct sway_gesture_binding *binding = gesture_tracker_end_and_match(
+ &seatop->gestures, device);
+
+ if (binding) {
+ gesture_binding_execute(seat, binding);
+ }
+}
+
/*----------------------------------\
* Functions used by handle_rebase /
*--------------------------------*/
@@ -779,6 +1092,14 @@ static const struct sway_seatop_impl seatop_impl = {
.pointer_axis = handle_pointer_axis,
.tablet_tool_tip = handle_tablet_tool_tip,
.tablet_tool_motion = handle_tablet_tool_motion,
+ .hold_begin = handle_hold_begin,
+ .hold_end = handle_hold_end,
+ .pinch_begin = handle_pinch_begin,
+ .pinch_update = handle_pinch_update,
+ .pinch_end = handle_pinch_end,
+ .swipe_begin = handle_swipe_begin,
+ .swipe_update = handle_swipe_update,
+ .swipe_end = handle_swipe_end,
.rebase = handle_rebase,
.allow_set_cursor = true,
};
@@ -789,8 +1110,8 @@ void seatop_begin_default(struct sway_seat *seat) {
struct seatop_default_event *e =
calloc(1, sizeof(struct seatop_default_event));
sway_assert(e, "Unable to allocate seatop_default_event");
+
seat->seatop_impl = &seatop_impl;
seat->seatop_data = e;
-
seatop_rebase(seat, 0);
}
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c
index ecc34fea..b40773d0 100644
--- a/sway/input/seatop_down.c
+++ b/sway/input/seatop_down.c
@@ -18,9 +18,9 @@ struct seatop_down_event {
};
static void handle_pointer_axis(struct sway_seat *seat,
- struct wlr_event_pointer_axis *event) {
+ struct wlr_pointer_axis_event *event) {
struct sway_input_device *input_device =
- event->device ? event->device->data : NULL;
+ event->pointer ? event->pointer->base.data : NULL;
struct input_config *ic =
input_device ? input_device_get_config(input_device) : NULL;
float scroll_factor =
diff --git a/sway/input/switch.c b/sway/input/switch.c
index 9ea87a1a..fc7dfaff 100644
--- a/sway/input/switch.c
+++ b/sway/input/switch.c
@@ -11,6 +11,7 @@ struct sway_switch *sway_switch_create(struct sway_seat *seat,
return NULL;
}
device->switch_device = switch_device;
+ switch_device->wlr = wlr_switch_from_input_device(device->input_device->wlr_device);
switch_device->seat_device = device;
switch_device->state = WLR_SWITCH_STATE_OFF;
wl_list_init(&switch_device->switch_toggle.link);
@@ -19,9 +20,23 @@ struct sway_switch *sway_switch_create(struct sway_seat *seat,
return switch_device;
}
+static bool sway_switch_trigger_test(enum sway_switch_trigger trigger,
+ enum wlr_switch_state state) {
+ switch (trigger) {
+ case SWAY_SWITCH_TRIGGER_ON:
+ return state == WLR_SWITCH_STATE_ON;
+ case SWAY_SWITCH_TRIGGER_OFF:
+ return state == WLR_SWITCH_STATE_OFF;
+ case SWAY_SWITCH_TRIGGER_TOGGLE:
+ return true;
+ }
+ abort(); // unreachable
+}
+
static void execute_binding(struct sway_switch *sway_switch) {
struct sway_seat* seat = sway_switch->seat_device->sway_seat;
- bool input_inhibited = seat->exclusive_client != NULL;
+ bool input_inhibited = seat->exclusive_client != NULL ||
+ server.session_lock.locked;
list_t *bindings = config->current_mode->switch_bindings;
struct sway_switch_binding *matched_binding = NULL;
@@ -30,11 +45,10 @@ static void execute_binding(struct sway_switch *sway_switch) {
if (binding->type != sway_switch->type) {
continue;
}
- if (binding->state != WLR_SWITCH_STATE_TOGGLE &&
- binding->state != sway_switch->state) {
+ if (!sway_switch_trigger_test(binding->trigger, sway_switch->state)) {
continue;
}
- if (config->reloading && (binding->state == WLR_SWITCH_STATE_TOGGLE
+ if (config->reloading && (binding->trigger == SWAY_SWITCH_TRIGGER_TOGGLE
|| (binding->flags & BINDING_RELOAD) == 0)) {
continue;
}
@@ -65,7 +79,7 @@ static void execute_binding(struct sway_switch *sway_switch) {
static void handle_switch_toggle(struct wl_listener *listener, void *data) {
struct sway_switch *sway_switch =
wl_container_of(listener, sway_switch, switch_toggle);
- struct wlr_event_switch_toggle *event = data;
+ struct wlr_switch_toggle_event *event = data;
struct sway_seat *seat = sway_switch->seat_device->sway_seat;
seat_idle_notify_activity(seat, IDLE_SOURCE_SWITCH);
@@ -82,10 +96,8 @@ static void handle_switch_toggle(struct wl_listener *listener, void *data) {
}
void sway_switch_configure(struct sway_switch *sway_switch) {
- struct wlr_input_device *wlr_device =
- sway_switch->seat_device->input_device->wlr_device;
wl_list_remove(&sway_switch->switch_toggle.link);
- wl_signal_add(&wlr_device->switch_device->events.toggle,
+ wl_signal_add(&sway_switch->wlr->events.toggle,
&sway_switch->switch_toggle);
sway_switch->switch_toggle.notify = handle_switch_toggle;
sway_log(SWAY_DEBUG, "Configured switch for device");
diff --git a/sway/input/tablet.c b/sway/input/tablet.c
index 26e86e36..92ede3fa 100644
--- a/sway/input/tablet.c
+++ b/sway/input/tablet.c
@@ -196,7 +196,7 @@ static void handle_tablet_pad_attach(struct wl_listener *listener,
static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) {
struct sway_tablet_pad *pad = wl_container_of(listener, pad, ring);
- struct wlr_event_tablet_pad_ring *event = data;
+ struct wlr_tablet_pad_ring_event *event = data;
if (!pad->current_surface) {
return;
@@ -210,7 +210,7 @@ static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) {
static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) {
struct sway_tablet_pad *pad = wl_container_of(listener, pad, strip);
- struct wlr_event_tablet_pad_strip *event = data;
+ struct wlr_tablet_pad_strip_event *event = data;
if (!pad->current_surface) {
return;
@@ -224,7 +224,7 @@ static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) {
static void handle_tablet_pad_button(struct wl_listener *listener, void *data) {
struct sway_tablet_pad *pad = wl_container_of(listener, pad, button);
- struct wlr_event_tablet_pad_button *event = data;
+ struct wlr_tablet_pad_button_event *event = data;
if (!pad->current_surface) {
return;
@@ -246,6 +246,7 @@ struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
return NULL;
}
+ tablet_pad->wlr = wlr_tablet_pad_from_input_device(device->input_device->wlr_device);
tablet_pad->seat_device = device;
wl_list_init(&tablet_pad->attach.link);
wl_list_init(&tablet_pad->button.link);
@@ -260,40 +261,40 @@ struct sway_tablet_pad *sway_tablet_pad_create(struct sway_seat *seat,
}
void sway_configure_tablet_pad(struct sway_tablet_pad *tablet_pad) {
- struct wlr_input_device *device =
+ struct wlr_input_device *wlr_device =
tablet_pad->seat_device->input_device->wlr_device;
struct sway_seat *seat = tablet_pad->seat_device->sway_seat;
if (!tablet_pad->tablet_v2_pad) {
tablet_pad->tablet_v2_pad =
- wlr_tablet_pad_create(server.tablet_v2, seat->wlr_seat, device);
+ wlr_tablet_pad_create(server.tablet_v2, seat->wlr_seat, wlr_device);
}
wl_list_remove(&tablet_pad->attach.link);
tablet_pad->attach.notify = handle_tablet_pad_attach;
- wl_signal_add(&device->tablet_pad->events.attach_tablet,
+ wl_signal_add(&tablet_pad->wlr->events.attach_tablet,
&tablet_pad->attach);
wl_list_remove(&tablet_pad->button.link);
tablet_pad->button.notify = handle_tablet_pad_button;
- wl_signal_add(&device->tablet_pad->events.button, &tablet_pad->button);
+ wl_signal_add(&tablet_pad->wlr->events.button, &tablet_pad->button);
wl_list_remove(&tablet_pad->strip.link);
tablet_pad->strip.notify = handle_tablet_pad_strip;
- wl_signal_add(&device->tablet_pad->events.strip, &tablet_pad->strip);
+ wl_signal_add(&tablet_pad->wlr->events.strip, &tablet_pad->strip);
wl_list_remove(&tablet_pad->ring.link);
tablet_pad->ring.notify = handle_tablet_pad_ring;
- wl_signal_add(&device->tablet_pad->events.ring, &tablet_pad->ring);
+ wl_signal_add(&tablet_pad->wlr->events.ring, &tablet_pad->ring);
/* Search for a sibling tablet */
- if (!wlr_input_device_is_libinput(device)) {
+ if (!wlr_input_device_is_libinput(wlr_device)) {
/* We can only do this on libinput devices */
return;
}
struct libinput_device_group *group =
- libinput_device_get_device_group(wlr_libinput_get_device_handle(device));
+ libinput_device_get_device_group(wlr_libinput_get_device_handle(wlr_device));
struct sway_tablet *tool;
wl_list_for_each(tool, &seat->cursor->tablets, link) {
struct wlr_input_device *tablet =
diff --git a/sway/input/text_input.c b/sway/input/text_input.c
index b8c19c17..58911c2d 100644
--- a/sway/input/text_input.c
+++ b/sway/input/text_input.c
@@ -77,8 +77,6 @@ static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) {
struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat);
wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
active_keyboard);
- wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab,
- &active_keyboard->modifiers);
wl_signal_add(&keyboard_grab->events.destroy,
&relay->input_method_keyboard_grab_destroy);
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 1b64f86e..d757f21f 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -112,12 +112,43 @@ static const char *ipc_json_output_adaptive_sync_status_description(
return "disabled";
case WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED:
return "enabled";
- case WLR_OUTPUT_ADAPTIVE_SYNC_UNKNOWN:
- return "unknown";
}
return NULL;
}
+static const char *ipc_json_output_mode_aspect_ratio_description(
+ enum wlr_output_mode_aspect_ratio aspect_ratio) {
+ switch (aspect_ratio) {
+ case WLR_OUTPUT_MODE_ASPECT_RATIO_NONE:
+ return "none";
+ case WLR_OUTPUT_MODE_ASPECT_RATIO_4_3:
+ return "4:3";
+ case WLR_OUTPUT_MODE_ASPECT_RATIO_16_9:
+ return "16:9";
+ case WLR_OUTPUT_MODE_ASPECT_RATIO_64_27:
+ return "64:27";
+ case WLR_OUTPUT_MODE_ASPECT_RATIO_256_135:
+ return "256:135";
+ }
+ return NULL;
+}
+
+static json_object *ipc_json_output_mode_description(
+ const struct wlr_output_mode *mode) {
+ const char *pic_ar =
+ ipc_json_output_mode_aspect_ratio_description(mode->picture_aspect_ratio);
+ json_object *mode_object = json_object_new_object();
+ json_object_object_add(mode_object, "width",
+ json_object_new_int(mode->width));
+ json_object_object_add(mode_object, "height",
+ json_object_new_int(mode->height));
+ json_object_object_add(mode_object, "refresh",
+ json_object_new_int(mode->refresh));
+ json_object_object_add(mode_object, "picture_aspect_ratio",
+ json_object_new_string(pic_ar));
+ return mode_object;
+}
+
#if HAVE_XWAYLAND
static const char *ipc_json_xwindow_type_description(struct sway_view *view) {
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
@@ -242,23 +273,50 @@ static json_object *ipc_json_create_node(int id, const char* type, char *name,
return object;
}
+static void ipc_json_describe_wlr_output(struct wlr_output *wlr_output, json_object *object) {
+ json_object_object_add(object, "primary", json_object_new_boolean(false));
+ json_object_object_add(object, "make",
+ json_object_new_string(wlr_output->make ? wlr_output->make : "Unknown"));
+ json_object_object_add(object, "model",
+ json_object_new_string(wlr_output->model ? wlr_output->model : "Unknown"));
+ json_object_object_add(object, "serial",
+ json_object_new_string(wlr_output->serial ? wlr_output->serial : "Unknown"));
+
+ json_object *modes_array = json_object_new_array();
+ struct wlr_output_mode *mode;
+ wl_list_for_each(mode, &wlr_output->modes, link) {
+ json_object *mode_object = json_object_new_object();
+ json_object_object_add(mode_object, "width",
+ json_object_new_int(mode->width));
+ json_object_object_add(mode_object, "height",
+ json_object_new_int(mode->height));
+ json_object_object_add(mode_object, "refresh",
+ json_object_new_int(mode->refresh));
+ json_object_array_add(modes_array, mode_object);
+ }
+ json_object_object_add(object, "modes", modes_array);
+}
+
static void ipc_json_describe_output(struct sway_output *output,
json_object *object) {
+ ipc_json_describe_wlr_output(output->wlr_output, object);
+}
+
+static void ipc_json_describe_enabled_output(struct sway_output *output,
+ json_object *object) {
+ ipc_json_describe_output(output, object);
+
struct wlr_output *wlr_output = output->wlr_output;
+ json_object_object_add(object, "non_desktop", json_object_new_boolean(false));
json_object_object_add(object, "active", json_object_new_boolean(true));
json_object_object_add(object, "dpms",
json_object_new_boolean(wlr_output->enabled));
- json_object_object_add(object, "primary", json_object_new_boolean(false));
+ json_object_object_add(object, "power",
+ json_object_new_boolean(wlr_output->enabled));
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_object_add(object, "make",
- json_object_new_string(wlr_output->make));
- json_object_object_add(object, "model",
- json_object_new_string(wlr_output->model));
- json_object_object_add(object, "serial",
- json_object_new_string(wlr_output->serial));
json_object_object_add(object, "scale",
json_object_new_double(wlr_output->scale));
json_object_object_add(object, "scale_filter",
@@ -283,25 +341,26 @@ static void ipc_json_describe_output(struct sway_output *output,
json_object *modes_array = json_object_new_array();
struct wlr_output_mode *mode;
wl_list_for_each(mode, &wlr_output->modes, link) {
- json_object *mode_object = json_object_new_object();
- json_object_object_add(mode_object, "width",
- json_object_new_int(mode->width));
- json_object_object_add(mode_object, "height",
- json_object_new_int(mode->height));
- json_object_object_add(mode_object, "refresh",
- json_object_new_int(mode->refresh));
+ json_object *mode_object =
+ ipc_json_output_mode_description(mode);
json_object_array_add(modes_array, mode_object);
}
json_object_object_add(object, "modes", modes_array);
- json_object *current_mode_object = json_object_new_object();
- json_object_object_add(current_mode_object, "width",
- json_object_new_int(wlr_output->width));
- json_object_object_add(current_mode_object, "height",
- json_object_new_int(wlr_output->height));
- json_object_object_add(current_mode_object, "refresh",
- json_object_new_int(wlr_output->refresh));
+ json_object *current_mode_object;
+ if (wlr_output->current_mode != NULL) {
+ current_mode_object =
+ ipc_json_output_mode_description(wlr_output->current_mode);
+ } else {
+ current_mode_object = json_object_new_object();
+ json_object_object_add(current_mode_object, "width",
+ json_object_new_int(wlr_output->width));
+ json_object_object_add(current_mode_object, "height",
+ json_object_new_int(wlr_output->height));
+ json_object_object_add(current_mode_object, "refresh",
+ json_object_new_int(wlr_output->refresh));
+ }
json_object_object_add(object, "current_mode", current_mode_object);
struct sway_node *parent = node_get_parent(&output->node);
@@ -325,33 +384,15 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
json_object *object = json_object_new_object();
+ ipc_json_describe_output(output, object);
+
+ json_object_object_add(object, "non_desktop", json_object_new_boolean(false));
json_object_object_add(object, "type", json_object_new_string("output"));
json_object_object_add(object, "name",
json_object_new_string(wlr_output->name));
json_object_object_add(object, "active", json_object_new_boolean(false));
json_object_object_add(object, "dpms", json_object_new_boolean(false));
- json_object_object_add(object, "primary", json_object_new_boolean(false));
- json_object_object_add(object, "make",
- json_object_new_string(wlr_output->make));
- json_object_object_add(object, "model",
- json_object_new_string(wlr_output->model));
- json_object_object_add(object, "serial",
- json_object_new_string(wlr_output->serial));
-
- json_object *modes_array = json_object_new_array();
- struct wlr_output_mode *mode;
- wl_list_for_each(mode, &wlr_output->modes, link) {
- json_object *mode_object = json_object_new_object();
- json_object_object_add(mode_object, "width",
- json_object_new_int(mode->width));
- json_object_object_add(mode_object, "height",
- json_object_new_int(mode->height));
- json_object_object_add(mode_object, "refresh",
- json_object_new_int(mode->refresh));
- json_object_array_add(modes_array, mode_object);
- }
-
- json_object_object_add(object, "modes", modes_array);
+ json_object_object_add(object, "power", json_object_new_boolean(false));
json_object_object_add(object, "current_workspace", NULL);
@@ -367,6 +408,21 @@ json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
return object;
}
+json_object *ipc_json_describe_non_desktop_output(struct sway_output_non_desktop *output) {
+ struct wlr_output *wlr_output = output->wlr_output;
+
+ json_object *object = json_object_new_object();
+
+ ipc_json_describe_wlr_output(wlr_output, object);
+
+ json_object_object_add(object, "non_desktop", json_object_new_boolean(true));
+ json_object_object_add(object, "type", json_object_new_string("output"));
+ json_object_object_add(object, "name",
+ json_object_new_string(wlr_output->name));
+
+ return object;
+}
+
static json_object *ipc_json_describe_scratchpad_output(void) {
struct wlr_box box;
root_get_box(root, &box);
@@ -453,7 +509,9 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace,
static void get_deco_rect(struct sway_container *c, struct wlr_box *deco_rect) {
enum sway_container_layout parent_layout = container_parent_layout(c);
- bool tab_or_stack = parent_layout == L_TABBED || parent_layout == L_STACKED;
+ list_t *siblings = container_get_siblings(c);
+ bool tab_or_stack = (parent_layout == L_TABBED || parent_layout == L_STACKED)
+ && ((siblings && siblings->length > 1) || !config->hide_lone_tab);
if (((!tab_or_stack || container_is_floating(c)) &&
c->current.border != B_NORMAL) ||
c->pending.fullscreen_mode != FULLSCREEN_NONE ||
@@ -706,7 +764,7 @@ json_object *ipc_json_describe_node(struct sway_node *node) {
case N_ROOT:
break;
case N_OUTPUT:
- ipc_json_describe_output(node->sway_output, object);
+ ipc_json_describe_enabled_output(node->sway_output, object);
break;
case N_CONTAINER:
ipc_json_describe_container(node->sway_container, object);
@@ -942,6 +1000,19 @@ static json_object *describe_libinput_device(struct libinput_device *device) {
json_object_object_add(object, "dwt", json_object_new_string(dwt));
}
+ if (libinput_device_config_dwtp_is_available(device)) {
+ const char *dwtp = "unknown";
+ switch (libinput_device_config_dwtp_get_enabled(device)) {
+ case LIBINPUT_CONFIG_DWTP_ENABLED:
+ dwtp = "enabled";
+ break;
+ case LIBINPUT_CONFIG_DWTP_DISABLED:
+ dwtp = "disabled";
+ break;
+ }
+ json_object_object_add(object, "dwtp", json_object_new_string(dwtp));
+ }
+
if (libinput_device_config_calibration_has_matrix(device)) {
float matrix[6];
libinput_device_config_calibration_get_matrix(device, matrix);
@@ -977,10 +1048,16 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
input_device_get_type(device)));
if (device->wlr_device->type == WLR_INPUT_DEVICE_KEYBOARD) {
- struct wlr_keyboard *keyboard = device->wlr_device->keyboard;
+ struct wlr_keyboard *keyboard =
+ wlr_keyboard_from_input_device(device->wlr_device);
struct xkb_keymap *keymap = keyboard->keymap;
struct xkb_state *state = keyboard->xkb_state;
+ json_object_object_add(object, "repeat_delay",
+ json_object_new_int(keyboard->repeat_info.delay));
+ json_object_object_add(object, "repeat_rate",
+ json_object_new_int(keyboard->repeat_info.rate));
+
json_object *layouts_arr = json_object_new_array();
json_object_object_add(object, "xkb_layout_names", layouts_arr);
@@ -1005,11 +1082,11 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
if (device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) {
struct input_config *ic = input_device_get_config(device);
float scroll_factor = 1.0f;
- if (ic != NULL && !isnan(ic->scroll_factor) &&
+ if (ic != NULL && !isnan(ic->scroll_factor) &&
ic->scroll_factor != FLT_MIN) {
scroll_factor = ic->scroll_factor;
}
- json_object_object_add(object, "scroll_factor",
+ json_object_object_add(object, "scroll_factor",
json_object_new_double(scroll_factor));
}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 1bf5a05f..00b01d7d 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -150,7 +150,6 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
(void) fd;
struct sway_server *server = data;
- sway_log(SWAY_DEBUG, "Event on IPC listening socket");
assert(mask == WL_EVENT_READABLE);
int client_fd = accept(ipc_socket, NULL, NULL);
@@ -211,13 +210,10 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
}
if (mask & WL_EVENT_HANGUP) {
- sway_log(SWAY_DEBUG, "Client %d hung up", client->fd);
ipc_client_disconnect(client);
return 0;
}
- sway_log(SWAY_DEBUG, "Client %d readable", client->fd);
-
int read_available;
if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
sway_log_errno(SWAY_INFO, "Unable to read IPC socket buffer size");
@@ -523,7 +519,6 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
}
if (mask & WL_EVENT_HANGUP) {
- sway_log(SWAY_DEBUG, "Client %d hung up", client->fd);
ipc_client_disconnect(client);
return 0;
}
@@ -532,8 +527,6 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
return 0;
}
- sway_log(SWAY_DEBUG, "Client %d writable", client->fd);
-
ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
if (written == -1 && errno == EAGAIN) {
@@ -692,6 +685,12 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
ipc_json_describe_disabled_output(output));
}
}
+
+ for (int i = 0; i < root->non_desktop_outputs->length; i++) {
+ struct sway_output_non_desktop *non_desktop_output = root->non_desktop_outputs->items[i];
+ json_object_array_add(outputs, ipc_json_describe_non_desktop_output(non_desktop_output));
+ }
+
const char *json_string = json_object_to_json_string(outputs);
ipc_send_reply(client, payload_type, json_string,
(uint32_t)strlen(json_string));
@@ -955,7 +954,5 @@ bool ipc_send_reply(struct ipc_client *client, enum ipc_command_type payload_typ
ipc_client_handle_writable, client);
}
- sway_log(SWAY_DEBUG, "Added IPC reply of type 0x%x to client %d queue: %s",
- payload_type, client->fd, payload);
return true;
}
diff --git a/sway/lock.c b/sway/lock.c
new file mode 100644
index 00000000..bf7d5de8
--- /dev/null
+++ b/sway/lock.c
@@ -0,0 +1,225 @@
+#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include "log.h"
+#include "sway/input/keyboard.h"
+#include "sway/input/seat.h"
+#include "sway/output.h"
+#include "sway/server.h"
+
+struct sway_session_lock_surface {
+ struct wlr_session_lock_surface_v1 *lock_surface;
+ struct sway_output *output;
+ struct wlr_surface *surface;
+ struct wl_listener map;
+ struct wl_listener destroy;
+ struct wl_listener surface_commit;
+ struct wl_listener output_mode;
+ struct wl_listener output_commit;
+ struct wl_listener output_destroy;
+};
+
+static void set_lock_focused_surface(struct wlr_surface *focused) {
+ server.session_lock.focused = focused;
+
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat_set_focus_surface(seat, focused, false);
+ }
+}
+
+static void handle_surface_map(struct wl_listener *listener, void *data) {
+ struct sway_session_lock_surface *surf = wl_container_of(listener, surf, map);
+ if (server.session_lock.focused == NULL) {
+ set_lock_focused_surface(surf->surface);
+ }
+ output_damage_whole(surf->output);
+}
+
+static void handle_surface_commit(struct wl_listener *listener, void *data) {
+ struct sway_session_lock_surface *surf = wl_container_of(listener, surf, surface_commit);
+ output_damage_surface(surf->output, 0, 0, surf->surface, false);
+}
+
+static void handle_output_mode(struct wl_listener *listener, void *data) {
+ struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_mode);
+ wlr_session_lock_surface_v1_configure(surf->lock_surface,
+ surf->output->width, surf->output->height);
+}
+
+static void handle_output_commit(struct wl_listener *listener, void *data) {
+ struct wlr_output_event_commit *event = data;
+ struct sway_session_lock_surface *surf = wl_container_of(listener, surf, output_commit);
+ if (event->committed & (
+ WLR_OUTPUT_STATE_MODE |
+ WLR_OUTPUT_STATE_SCALE |
+ WLR_OUTPUT_STATE_TRANSFORM)) {
+ wlr_session_lock_surface_v1_configure(surf->lock_surface,
+ surf->output->width, surf->output->height);
+ }
+}
+
+static void destroy_lock_surface(struct sway_session_lock_surface *surf) {
+ // Move the seat focus to another surface if one is available
+ if (server.session_lock.focused == surf->surface) {
+ struct wlr_surface *next_focus = NULL;
+
+ struct wlr_session_lock_surface_v1 *other;
+ wl_list_for_each(other, &server.session_lock.lock->surfaces, link) {
+ if (other != surf->lock_surface && other->mapped) {
+ next_focus = other->surface;
+ break;
+ }
+ }
+ set_lock_focused_surface(next_focus);
+ }
+
+ wl_list_remove(&surf->map.link);
+ wl_list_remove(&surf->destroy.link);
+ wl_list_remove(&surf->surface_commit.link);
+ wl_list_remove(&surf->output_mode.link);
+ wl_list_remove(&surf->output_commit.link);
+ wl_list_remove(&surf->output_destroy.link);
+ output_damage_whole(surf->output);
+ free(surf);
+}
+
+static void handle_surface_destroy(struct wl_listener *listener, void *data) {
+ struct sway_session_lock_surface *surf = wl_container_of(listener, surf, destroy);
+ destroy_lock_surface(surf);
+}
+
+static void handle_output_destroy(struct wl_listener *listener, void *data) {
+ struct sway_session_lock_surface *surf =
+ wl_container_of(listener, surf, output_destroy);
+ destroy_lock_surface(surf);
+}
+
+static void handle_new_surface(struct wl_listener *listener, void *data) {
+ struct wlr_session_lock_surface_v1 *lock_surface = data;
+ struct sway_session_lock_surface *surf = calloc(1, sizeof(*surf));
+ if (surf == NULL) {
+ return;
+ }
+
+ sway_log(SWAY_DEBUG, "new lock layer surface");
+
+ struct sway_output *output = lock_surface->output->data;
+ wlr_session_lock_surface_v1_configure(lock_surface, output->width, output->height);
+
+ surf->lock_surface = lock_surface;
+ surf->surface = lock_surface->surface;
+ surf->output = output;
+ surf->map.notify = handle_surface_map;
+ wl_signal_add(&lock_surface->events.map, &surf->map);
+ surf->destroy.notify = handle_surface_destroy;
+ wl_signal_add(&lock_surface->events.destroy, &surf->destroy);
+ surf->surface_commit.notify = handle_surface_commit;
+ wl_signal_add(&surf->surface->events.commit, &surf->surface_commit);
+ surf->output_mode.notify = handle_output_mode;
+ wl_signal_add(&output->wlr_output->events.mode, &surf->output_mode);
+ surf->output_commit.notify = handle_output_commit;
+ wl_signal_add(&output->wlr_output->events.commit, &surf->output_commit);
+ surf->output_destroy.notify = handle_output_destroy;
+ wl_signal_add(&output->node.events.destroy, &surf->output_destroy);
+}
+
+static void handle_unlock(struct wl_listener *listener, void *data) {
+ sway_log(SWAY_DEBUG, "session unlocked");
+ server.session_lock.locked = false;
+ server.session_lock.lock = NULL;
+ server.session_lock.focused = NULL;
+
+ wl_list_remove(&server.session_lock.lock_new_surface.link);
+ wl_list_remove(&server.session_lock.lock_unlock.link);
+ wl_list_remove(&server.session_lock.lock_destroy.link);
+
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat_set_exclusive_client(seat, NULL);
+ // copied from seat_set_focus_layer -- deduplicate?
+ struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
+ if (previous) {
+ // Hack to get seat to re-focus the return value of get_focus
+ seat_set_focus(seat, NULL);
+ seat_set_focus(seat, previous);
+ }
+ }
+
+ // redraw everything
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole(output);
+ }
+}
+
+static void handle_abandon(struct wl_listener *listener, void *data) {
+ sway_log(SWAY_INFO, "session lock abandoned");
+ server.session_lock.lock = NULL;
+ server.session_lock.focused = NULL;
+
+ wl_list_remove(&server.session_lock.lock_new_surface.link);
+ wl_list_remove(&server.session_lock.lock_unlock.link);
+ wl_list_remove(&server.session_lock.lock_destroy.link);
+
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat->exclusive_client = NULL;
+ }
+
+ // redraw everything
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole(output);
+ }
+}
+
+static void handle_session_lock(struct wl_listener *listener, void *data) {
+ struct wlr_session_lock_v1 *lock = data;
+ struct wl_client *client = wl_resource_get_client(lock->resource);
+
+ if (server.session_lock.lock) {
+ wlr_session_lock_v1_destroy(lock);
+ return;
+ }
+
+ sway_log(SWAY_DEBUG, "session locked");
+ server.session_lock.locked = true;
+ server.session_lock.lock = lock;
+
+ struct sway_seat *seat;
+ wl_list_for_each(seat, &server.input->seats, link) {
+ seat_set_exclusive_client(seat, client);
+ }
+
+ wl_signal_add(&lock->events.new_surface, &server.session_lock.lock_new_surface);
+ wl_signal_add(&lock->events.unlock, &server.session_lock.lock_unlock);
+ wl_signal_add(&lock->events.destroy, &server.session_lock.lock_destroy);
+
+ wlr_session_lock_v1_send_locked(lock);
+
+ // redraw everything
+ for (int i = 0; i < root->outputs->length; ++i) {
+ struct sway_output *output = root->outputs->items[i];
+ output_damage_whole(output);
+ }
+}
+
+static void handle_session_lock_destroy(struct wl_listener *listener, void *data) {
+ assert(server.session_lock.lock == NULL);
+ wl_list_remove(&server.session_lock.new_lock.link);
+ wl_list_remove(&server.session_lock.manager_destroy.link);
+}
+
+void sway_session_lock_init(void) {
+ server.session_lock.manager = wlr_session_lock_manager_v1_create(server.wl_display);
+
+ server.session_lock.lock_new_surface.notify = handle_new_surface;
+ server.session_lock.lock_unlock.notify = handle_unlock;
+ server.session_lock.lock_destroy.notify = handle_abandon;
+ server.session_lock.new_lock.notify = handle_session_lock;
+ server.session_lock.manager_destroy.notify = handle_session_lock_destroy;
+ wl_signal_add(&server.session_lock.manager->events.new_lock,
+ &server.session_lock.new_lock);
+ wl_signal_add(&server.session_lock.manager->events.destroy,
+ &server.session_lock.manager_destroy);
+}
diff --git a/sway/main.c b/sway/main.c
index b6f8a8bf..85bc2f1c 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -150,27 +150,17 @@ static void log_kernel(void) {
pclose(f);
}
-
-static bool drop_permissions(void) {
- if (getuid() != geteuid() || getgid() != getegid()) {
- sway_log(SWAY_ERROR, "!!! DEPRECATION WARNING: "
- "SUID privilege drop will be removed in a future release, please migrate to seatd-launch");
-
- // Set the gid and uid in the correct order.
- if (setgid(getgid()) != 0) {
- sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start");
- return false;
- }
- if (setuid(getuid()) != 0) {
- sway_log(SWAY_ERROR, "Unable to drop root user, refusing to start");
- return false;
- }
+static bool detect_suid(void) {
+ if (geteuid() != 0 && getegid() != 0) {
+ return false;
}
- if (setgid(0) != -1 || setuid(0) != -1) {
- sway_log(SWAY_ERROR, "Unable to drop root (we shouldn't be able to "
- "restore it after setuid), refusing to start");
+
+ if (getuid() == geteuid() && getgid() == getegid()) {
return false;
}
+
+ sway_log(SWAY_ERROR, "SUID operation is no longer supported, refusing to start. "
+ "This check will be removed in a future release.");
return true;
}
@@ -240,35 +230,35 @@ static void handle_wlr_log(enum wlr_log_importance importance,
_sway_vlog(convert_wlr_log_importance(importance), sway_fmt, args);
}
+static const struct option long_options[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"config", required_argument, NULL, 'c'},
+ {"validate", no_argument, NULL, 'C'},
+ {"debug", no_argument, NULL, 'd'},
+ {"version", no_argument, NULL, 'v'},
+ {"verbose", no_argument, NULL, 'V'},
+ {"get-socketpath", no_argument, NULL, 'p'},
+ {"unsupported-gpu", no_argument, NULL, 'u'},
+ {0, 0, 0, 0}
+};
+
+static const char usage[] =
+ "Usage: sway [options] [command]\n"
+ "\n"
+ " -h, --help Show help message and quit.\n"
+ " -c, --config <config> Specify a config file.\n"
+ " -C, --validate Check the validity of the config file, then exit.\n"
+ " -d, --debug Enables full logging, including debug information.\n"
+ " -v, --version Show the version number and quit.\n"
+ " -V, --verbose Enables more verbose logging.\n"
+ " --get-socketpath Gets the IPC socket path and prints it, then exits.\n"
+ "\n";
+
int main(int argc, char **argv) {
- static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0;
-
- static const struct option long_options[] = {
- {"help", no_argument, NULL, 'h'},
- {"config", required_argument, NULL, 'c'},
- {"validate", no_argument, NULL, 'C'},
- {"debug", no_argument, NULL, 'd'},
- {"version", no_argument, NULL, 'v'},
- {"verbose", no_argument, NULL, 'V'},
- {"get-socketpath", no_argument, NULL, 'p'},
- {"unsupported-gpu", no_argument, NULL, 'u'},
- {0, 0, 0, 0}
- };
+ static bool verbose = false, debug = false, validate = false, allow_unsupported_gpu = false;
char *config_path = NULL;
- const char* usage =
- "Usage: sway [options] [command]\n"
- "\n"
- " -h, --help Show help message and quit.\n"
- " -c, --config <config> Specify a config file.\n"
- " -C, --validate Check the validity of the config file, then exit.\n"
- " -d, --debug Enables full logging, including debug information.\n"
- " -v, --version Show the version number and quit.\n"
- " -V, --verbose Enables more verbose logging.\n"
- " --get-socketpath Gets the IPC socket path and prints it, then exits.\n"
- "\n";
-
int c;
while (1) {
int option_index = 0;
@@ -286,25 +276,25 @@ int main(int argc, char **argv) {
config_path = strdup(optarg);
break;
case 'C': // validate
- validate = 1;
+ validate = true;
break;
case 'd': // debug
- debug = 1;
+ debug = true;
break;
case 'D': // extended debug options
enable_debug_flag(optarg);
break;
case 'u':
- allow_unsupported_gpu = 1;
+ allow_unsupported_gpu = true;
break;
case 'v': // version
printf("sway version " SWAY_VERSION "\n");
exit(EXIT_SUCCESS);
break;
case 'V': // verbose
- verbose = 1;
+ verbose = true;
break;
- case 'p': ; // --get-socketpath
+ case 'p': // --get-socketpath
if (getenv("SWAYSOCK")) {
printf("%s\n", getenv("SWAYSOCK"));
exit(EXIT_SUCCESS);
@@ -319,6 +309,11 @@ int main(int argc, char **argv) {
}
}
+ // SUID operation is deprecated, so block it for now.
+ if (detect_suid()) {
+ exit(EXIT_FAILURE);
+ }
+
// Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the
// clear error message (when not running as an IPC client).
if (!getenv("XDG_RUNTIME_DIR") && optind == argc) {
@@ -357,9 +352,6 @@ int main(int argc, char **argv) {
"`sway -d 2>sway.log`.");
exit(EXIT_FAILURE);
}
- if (!drop_permissions()) {
- exit(EXIT_FAILURE);
- }
char *socket_path = getenv("SWAYSOCK");
if (!socket_path) {
sway_log(SWAY_ERROR, "Unable to retrieve socket path");
@@ -372,16 +364,6 @@ int main(int argc, char **argv) {
}
detect_proprietary(allow_unsupported_gpu);
-
- if (!server_privileged_prepare(&server)) {
- return 1;
- }
-
- if (!drop_permissions()) {
- server_fini(&server);
- exit(EXIT_FAILURE);
- }
-
increase_nofile_limit();
// handle SIGTERM signals
@@ -413,6 +395,8 @@ int main(int argc, char **argv) {
goto shutdown;
}
+ set_rr_scheduling();
+
if (!server_start(&server)) {
sway_terminate(EXIT_FAILURE);
goto shutdown;
diff --git a/sway/meson.build b/sway/meson.build
index ac3d408d..12362fcd 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -1,245 +1,252 @@
sway_sources = files(
- 'commands.c',
- 'config.c',
- 'criteria.c',
- 'decoration.c',
- 'ipc-json.c',
- 'ipc-server.c',
- 'main.c',
- 'server.c',
- 'swaynag.c',
- 'xdg_activation_v1.c',
- 'xdg_decoration.c',
+ 'commands.c',
+ 'config.c',
+ 'criteria.c',
+ 'decoration.c',
+ 'ipc-json.c',
+ 'ipc-server.c',
+ 'lock.c',
+ 'main.c',
+ 'realtime.c',
+ 'server.c',
+ 'swaynag.c',
+ 'xdg_activation_v1.c',
+ 'xdg_decoration.c',
- 'desktop/desktop.c',
- 'desktop/fx_renderer.c',
- 'desktop/idle_inhibit_v1.c',
- 'desktop/layer_shell.c',
- 'desktop/output.c',
- 'desktop/render.c',
- 'desktop/surface.c',
- 'desktop/transaction.c',
- 'desktop/xdg_shell.c',
+ 'desktop/desktop.c',
+ 'desktop/fx_renderer.c',
+ 'desktop/idle_inhibit_v1.c',
+ 'desktop/layer_shell.c',
+ 'desktop/output.c',
+ 'desktop/render.c',
+ 'desktop/surface.c',
+ 'desktop/transaction.c',
+ 'desktop/xdg_shell.c',
+ 'desktop/launcher.c',
+ 'input/input-manager.c',
+ 'input/cursor.c',
+ 'input/keyboard.c',
+ 'input/libinput.c',
+ 'input/seat.c',
+ 'input/seatop_default.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/switch.c',
+ 'input/tablet.c',
+ 'input/text_input.c',
- 'input/input-manager.c',
- 'input/cursor.c',
- 'input/keyboard.c',
- 'input/libinput.c',
- 'input/seat.c',
- 'input/seatop_default.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/switch.c',
- 'input/tablet.c',
- 'input/text_input.c',
+ 'config/bar.c',
+ 'config/output.c',
+ 'config/seat.c',
+ 'config/input.c',
- 'config/bar.c',
- 'config/output.c',
- 'config/seat.c',
- 'config/input.c',
+ 'commands/assign.c',
+ 'commands/bar.c',
+ 'commands/bind.c',
+ 'commands/border.c',
+ 'commands/client.c',
+ 'commands/corner_radius.c',
+ 'commands/create_output.c',
+ 'commands/default_border.c',
+ 'commands/default_floating_border.c',
+ 'commands/default_orientation.c',
+ 'commands/dim_inactive.c',
+ 'commands/dim_inactive_colors.c',
+ 'commands/exit.c',
+ 'commands/exec.c',
+ 'commands/exec_always.c',
+ 'commands/floating.c',
+ 'commands/floating_minmax_size.c',
+ 'commands/floating_modifier.c',
+ 'commands/focus.c',
+ 'commands/focus_follows_mouse.c',
+ 'commands/focus_on_window_activation.c',
+ 'commands/focus_wrapping.c',
+ 'commands/font.c',
+ 'commands/for_window.c',
+ 'commands/force_display_urgency_hint.c',
+ 'commands/force_focus_wrapping.c',
+ 'commands/fullscreen.c',
+ 'commands/gaps.c',
+ 'commands/gesture.c',
+ 'commands/hide_edge_borders.c',
+ 'commands/inhibit_idle.c',
+ 'commands/kill.c',
+ 'commands/mark.c',
+ 'commands/max_render_time.c',
+ 'commands/opacity.c',
+ 'commands/include.c',
+ 'commands/input.c',
+ 'commands/layout.c',
+ 'commands/mode.c',
+ 'commands/mouse_warping.c',
+ 'commands/move.c',
+ 'commands/new_float.c',
+ 'commands/new_window.c',
+ 'commands/no_focus.c',
+ 'commands/nop.c',
+ 'commands/output.c',
+ 'commands/popup_during_fullscreen.c',
+ 'commands/reload.c',
+ 'commands/rename.c',
+ 'commands/resize.c',
+ 'commands/saturation.c',
+ 'commands/scratchpad.c',
+ 'commands/seat.c',
+ 'commands/seat/attach.c',
+ 'commands/seat/cursor.c',
+ 'commands/seat/fallback.c',
+ 'commands/seat/hide_cursor.c',
+ 'commands/seat/idle.c',
+ 'commands/seat/keyboard_grouping.c',
+ 'commands/seat/pointer_constraint.c',
+ 'commands/seat/shortcuts_inhibitor.c',
+ 'commands/seat/xcursor_theme.c',
+ 'commands/set.c',
+ 'commands/show_marks.c',
+ 'commands/shortcuts_inhibitor.c',
+ 'commands/smart_borders.c',
+ 'commands/smart_gaps.c',
+ 'commands/split.c',
+ 'commands/sticky.c',
+ 'commands/swaybg_command.c',
+ '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',
+ 'commands/workspace_layout.c',
+ 'commands/ws_auto_back_and_forth.c',
+ 'commands/xwayland.c',
- 'commands/assign.c',
- 'commands/bar.c',
- 'commands/bind.c',
- 'commands/border.c',
- 'commands/client.c',
- 'commands/corner_radius.c',
- 'commands/create_output.c',
- 'commands/default_border.c',
- 'commands/default_floating_border.c',
- 'commands/default_orientation.c',
- 'commands/dim_inactive.c',
- 'commands/dim_inactive_colors.c',
- 'commands/exit.c',
- 'commands/exec.c',
- 'commands/exec_always.c',
- 'commands/floating.c',
- 'commands/floating_minmax_size.c',
- 'commands/floating_modifier.c',
- 'commands/focus.c',
- 'commands/focus_follows_mouse.c',
- 'commands/focus_on_window_activation.c',
- 'commands/focus_wrapping.c',
- 'commands/font.c',
- 'commands/for_window.c',
- 'commands/force_display_urgency_hint.c',
- 'commands/force_focus_wrapping.c',
- 'commands/fullscreen.c',
- 'commands/gaps.c',
- 'commands/hide_edge_borders.c',
- 'commands/inhibit_idle.c',
- 'commands/kill.c',
- 'commands/mark.c',
- 'commands/max_render_time.c',
- 'commands/opacity.c',
- 'commands/saturation.c',
- 'commands/include.c',
- 'commands/input.c',
- 'commands/layout.c',
- 'commands/mode.c',
- 'commands/mouse_warping.c',
- 'commands/move.c',
- 'commands/new_float.c',
- 'commands/new_window.c',
- 'commands/no_focus.c',
- 'commands/nop.c',
- 'commands/output.c',
- 'commands/popup_during_fullscreen.c',
- 'commands/reload.c',
- 'commands/rename.c',
- 'commands/resize.c',
- 'commands/scratchpad.c',
- 'commands/seat.c',
- 'commands/seat/attach.c',
- 'commands/seat/cursor.c',
- 'commands/seat/fallback.c',
- 'commands/seat/hide_cursor.c',
- 'commands/seat/idle.c',
- 'commands/seat/keyboard_grouping.c',
- 'commands/seat/pointer_constraint.c',
- 'commands/seat/shortcuts_inhibitor.c',
- 'commands/seat/xcursor_theme.c',
- 'commands/set.c',
- 'commands/show_marks.c',
- 'commands/shortcuts_inhibitor.c',
- 'commands/smart_borders.c',
- 'commands/smart_gaps.c',
- 'commands/split.c',
- 'commands/sticky.c',
- 'commands/swaybg_command.c',
- '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',
- 'commands/workspace_layout.c',
- 'commands/ws_auto_back_and_forth.c',
- 'commands/xwayland.c',
+ 'commands/bar/bind.c',
+ 'commands/bar/binding_mode_indicator.c',
+ 'commands/bar/colors.c',
+ 'commands/bar/font.c',
+ 'commands/bar/gaps.c',
+ 'commands/bar/height.c',
+ 'commands/bar/hidden_state.c',
+ 'commands/bar/icon_theme.c',
+ 'commands/bar/id.c',
+ 'commands/bar/mode.c',
+ 'commands/bar/modifier.c',
+ 'commands/bar/output.c',
+ 'commands/bar/pango_markup.c',
+ 'commands/bar/position.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_bind.c',
+ 'commands/bar/tray_output.c',
+ 'commands/bar/tray_padding.c',
+ 'commands/bar/workspace_buttons.c',
+ 'commands/bar/workspace_min_width.c',
+ 'commands/bar/wrap_scroll.c',
- 'commands/bar/bind.c',
- 'commands/bar/binding_mode_indicator.c',
- 'commands/bar/colors.c',
- 'commands/bar/font.c',
- 'commands/bar/gaps.c',
- 'commands/bar/height.c',
- 'commands/bar/hidden_state.c',
- 'commands/bar/icon_theme.c',
- 'commands/bar/id.c',
- 'commands/bar/mode.c',
- 'commands/bar/modifier.c',
- 'commands/bar/output.c',
- 'commands/bar/pango_markup.c',
- 'commands/bar/position.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_bind.c',
- 'commands/bar/tray_output.c',
- 'commands/bar/tray_padding.c',
- 'commands/bar/workspace_buttons.c',
- 'commands/bar/workspace_min_width.c',
- 'commands/bar/wrap_scroll.c',
+ 'commands/input/accel_profile.c',
+ 'commands/input/calibration_matrix.c',
+ 'commands/input/click_method.c',
+ 'commands/input/drag.c',
+ 'commands/input/drag_lock.c',
+ 'commands/input/dwt.c',
+ 'commands/input/dwtp.c',
+ 'commands/input/events.c',
+ 'commands/input/left_handed.c',
+ 'commands/input/map_from_region.c',
+ 'commands/input/map_to_output.c',
+ 'commands/input/map_to_region.c',
+ 'commands/input/middle_emulation.c',
+ 'commands/input/natural_scroll.c',
+ 'commands/input/pointer_accel.c',
+ 'commands/input/repeat_delay.c',
+ 'commands/input/repeat_rate.c',
+ 'commands/input/scroll_button.c',
+ 'commands/input/scroll_factor.c',
+ 'commands/input/scroll_method.c',
+ 'commands/input/tap.c',
+ 'commands/input/tap_button_map.c',
+ 'commands/input/tool_mode.c',
+ 'commands/input/xkb_capslock.c',
+ 'commands/input/xkb_file.c',
+ 'commands/input/xkb_layout.c',
+ 'commands/input/xkb_model.c',
+ 'commands/input/xkb_numlock.c',
+ 'commands/input/xkb_options.c',
+ 'commands/input/xkb_rules.c',
+ 'commands/input/xkb_switch_layout.c',
+ 'commands/input/xkb_variant.c',
- 'commands/input/accel_profile.c',
- 'commands/input/calibration_matrix.c',
- 'commands/input/click_method.c',
- 'commands/input/drag.c',
- 'commands/input/drag_lock.c',
- 'commands/input/dwt.c',
- 'commands/input/events.c',
- 'commands/input/left_handed.c',
- 'commands/input/map_from_region.c',
- 'commands/input/map_to_output.c',
- 'commands/input/map_to_region.c',
- 'commands/input/middle_emulation.c',
- 'commands/input/natural_scroll.c',
- 'commands/input/pointer_accel.c',
- 'commands/input/repeat_delay.c',
- 'commands/input/repeat_rate.c',
- 'commands/input/scroll_button.c',
- 'commands/input/scroll_factor.c',
- 'commands/input/scroll_method.c',
- 'commands/input/tap.c',
- 'commands/input/tap_button_map.c',
- 'commands/input/tool_mode.c',
- 'commands/input/xkb_capslock.c',
- 'commands/input/xkb_file.c',
- 'commands/input/xkb_layout.c',
- 'commands/input/xkb_model.c',
- 'commands/input/xkb_numlock.c',
- 'commands/input/xkb_options.c',
- 'commands/input/xkb_rules.c',
- 'commands/input/xkb_switch_layout.c',
- 'commands/input/xkb_variant.c',
+ 'commands/output/adaptive_sync.c',
+ 'commands/output/background.c',
+ 'commands/output/disable.c',
+ 'commands/output/dpms.c',
+ 'commands/output/enable.c',
+ 'commands/output/max_render_time.c',
+ 'commands/output/mode.c',
+ 'commands/output/position.c',
+ 'commands/output/power.c',
+ 'commands/output/render_bit_depth.c',
+ 'commands/output/scale.c',
+ 'commands/output/scale_filter.c',
+ 'commands/output/subpixel.c',
+ 'commands/output/toggle.c',
+ 'commands/output/transform.c',
+ 'commands/output/unplug.c',
- 'commands/output/adaptive_sync.c',
- 'commands/output/background.c',
- 'commands/output/disable.c',
- 'commands/output/dpms.c',
- 'commands/output/enable.c',
- 'commands/output/max_render_time.c',
- 'commands/output/mode.c',
- 'commands/output/position.c',
- 'commands/output/render_bit_depth.c',
- 'commands/output/scale.c',
- 'commands/output/scale_filter.c',
- 'commands/output/subpixel.c',
- 'commands/output/toggle.c',
- 'commands/output/transform.c',
-
- 'tree/arrange.c',
- 'tree/container.c',
- 'tree/node.c',
- 'tree/root.c',
- 'tree/view.c',
- 'tree/workspace.c',
- 'tree/output.c',
+ 'tree/arrange.c',
+ 'tree/container.c',
+ 'tree/node.c',
+ 'tree/root.c',
+ 'tree/view.c',
+ 'tree/workspace.c',
+ 'tree/output.c',
)
subdir('desktop/shaders')
sway_deps = [
- cairo,
- drm,
- jsonc,
- libevdev,
- libinput,
- libudev,
- math,
- pango,
- pcre,
- glesv2,
- pixman,
- server_protos,
- wayland_server,
- wlroots,
- xkbcommon,
- egl,
+ cairo,
+ drm,
+ jsonc,
+ libevdev,
+ libinput,
+ libudev,
+ math,
+ pango,
+ pcre2,
+ glesv2,
+ pixman,
+ threads,
+ wayland_server,
+ wlroots,
+ xkbcommon,
+ xcb_icccm,
+ egl,
]
if have_xwayland
- sway_sources += 'desktop/xwayland.c'
- sway_deps += xcb
+ sway_sources += 'desktop/xwayland.c'
+ sway_deps += xcb
endif
executable(
- 'sway',
- sway_sources,
- include_directories: [sway_inc],
- dependencies: sway_deps,
- link_with: [lib_sway_common],
- install: true
+ 'sway',
+ sway_sources + wl_protos_src,
+ include_directories: [sway_inc],
+ dependencies: sway_deps,
+ link_with: [lib_sway_common],
+ install: true
)
diff --git a/sway/realtime.c b/sway/realtime.c
new file mode 100644
index 00000000..11154af0
--- /dev/null
+++ b/sway/realtime.c
@@ -0,0 +1,40 @@
+#include <sys/resource.h>
+#include <sched.h>
+#include <unistd.h>
+#include <pthread.h>
+#include "sway/server.h"
+#include "log.h"
+
+static void child_fork_callback(void) {
+ struct sched_param param;
+
+ param.sched_priority = 0;
+
+ int ret = pthread_setschedparam(pthread_self(), SCHED_OTHER, &param);
+ if (ret != 0) {
+ sway_log(SWAY_ERROR, "Failed to reset scheduler policy on fork");
+ }
+}
+
+void set_rr_scheduling(void) {
+ int prio = sched_get_priority_min(SCHED_RR);
+ int old_policy;
+ int ret;
+ struct sched_param param;
+
+ ret = pthread_getschedparam(pthread_self(), &old_policy, &param);
+ if (ret != 0) {
+ sway_log(SWAY_DEBUG, "Failed to get old scheduling priority");
+ return;
+ }
+
+ param.sched_priority = prio;
+
+ ret = pthread_setschedparam(pthread_self(), SCHED_RR, &param);
+ if (ret != 0) {
+ sway_log(SWAY_INFO, "Failed to set scheduling priority to %d", prio);
+ return;
+ }
+
+ pthread_atfork(NULL, NULL, child_fork_callback);
+}
diff --git a/sway/server.c b/sway/server.c
index 3fab3431..90b2e042 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -18,13 +18,16 @@
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle.h>
+#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#include <wlr/types/wlr_screencopy_v1.h>
+#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_server_decoration.h>
+#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_tablet_v2.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_xcursor_manager.h>
@@ -48,19 +51,6 @@
#include "sway/xwayland.h"
#endif
-bool server_privileged_prepare(struct sway_server *server) {
- sway_log(SWAY_DEBUG, "Preparing Wayland server initialization");
- server->wl_display = wl_display_create();
- server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
- server->backend = wlr_backend_autocreate(server->wl_display);
-
- if (!server->backend) {
- sway_log(SWAY_ERROR, "Unable to create backend");
- return false;
- }
- return true;
-}
-
static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
/* We only offer non-desktop outputs, but in the future we might want to do
* more logic here. */
@@ -73,8 +63,18 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
}
}
+#define SWAY_XDG_SHELL_VERSION 2
+
bool server_init(struct sway_server *server) {
sway_log(SWAY_DEBUG, "Initializing Wayland server");
+ server->wl_display = wl_display_create();
+ server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
+ server->backend = wlr_backend_autocreate(server->wl_display);
+
+ if (!server->backend) {
+ sway_log(SWAY_ERROR, "Unable to create backend");
+ return false;
+ }
server->wlr_renderer = wlr_renderer_autocreate(server->backend);
if (!server->wlr_renderer) {
@@ -109,6 +109,8 @@ bool server_init(struct sway_server *server) {
wl_signal_add(&server->compositor->events.new_surface,
&server->compositor_new_surface);
+ wlr_subcompositor_create(server->wl_display);
+
server->data_device_manager =
wlr_data_device_manager_create(server->wl_display);
@@ -123,6 +125,7 @@ bool server_init(struct sway_server *server) {
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
server->idle = wlr_idle_create(server->wl_display);
+ server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display);
server->idle_inhibit_manager_v1 =
sway_idle_inhibit_manager_v1_create(server->wl_display, server->idle);
@@ -131,7 +134,8 @@ bool server_init(struct sway_server *server) {
&server->layer_shell_surface);
server->layer_shell_surface.notify = handle_layer_shell_surface;
- server->xdg_shell = wlr_xdg_shell_create(server->wl_display);
+ server->xdg_shell = wlr_xdg_shell_create(server->wl_display,
+ SWAY_XDG_SHELL_VERSION);
wl_signal_add(&server->xdg_shell->events.new_surface,
&server->xdg_shell_surface);
server->xdg_shell_surface.notify = handle_xdg_shell_surface;
@@ -188,6 +192,8 @@ bool server_init(struct sway_server *server) {
server->foreign_toplevel_manager =
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
+ sway_session_lock_init();
+
server->drm_lease_manager=
wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
if (server->drm_lease_manager) {
@@ -204,6 +210,7 @@ bool server_init(struct sway_server *server) {
wlr_data_control_manager_v1_create(server->wl_display);
wlr_primary_selection_v1_device_manager_create(server->wl_display);
wlr_viewporter_create(server->wl_display);
+ wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
struct wlr_xdg_foreign_registry *foreign_registry =
wlr_xdg_foreign_registry_create(server->wl_display);
@@ -216,10 +223,12 @@ bool server_init(struct sway_server *server) {
wl_signal_add(&server->xdg_activation_v1->events.request_activate,
&server->xdg_activation_v1_request_activate);
+ wl_list_init(&server->pending_launcher_ctxs);
+
// Avoid using "wayland-0" as display socket
char name_candidate[16];
- for (int i = 1; i <= 32; ++i) {
- sprintf(name_candidate, "wayland-%d", i);
+ for (unsigned int i = 1; i <= 32; ++i) {
+ snprintf(name_candidate, sizeof(name_candidate), "wayland-%u", i);
if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) {
server->socket = strdup(name_candidate);
break;
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index 8b702b77..e073c45d 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -147,6 +147,10 @@ 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> dwtp enabled|disabled
+ Enables or disables disable-while-trackpointing for the specified input
+ device.
+
*input* <identifier> events enabled|disabled|disabled_on_external_mouse|toggle [<toggle-modes>]
Enables or disables send_events for specified input device. Disabling
send_events disables the input device.
diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd
index d90fe97a..9121f679 100644
--- a/sway/sway-ipc.7.scd
+++ b/sway/sway-ipc.7.scd
@@ -213,7 +213,10 @@ following properties:
: Whether this output is active/enabled
|- dpms
: boolean
-: Whether this output is on/off (via DPMS)
+: (Deprecated, use _power_ instead) Whether this output is on/off (via DPMS)
+|- power
+: boolean
+: Whether this output is on/off
|- primary
: boolean
: For i3 compatibility, this will be false. It does not make sense in Wayland
@@ -370,7 +373,7 @@ node and will have the following properties:
that can be used as an aid in submitting reproduction steps for bug reports
|- fullscreen_mode
: integer
-: (Only containers and views) The fullscreen mode of the node. 0 means none, 1 means
+: (Only containers and views) The fullscreen mode of the node. 0 means none, 1 means
full workspace, and 2 means global fullscreen
|- app_id
: string
@@ -1194,6 +1197,10 @@ following properties will be included for devices that support them:
|- dwt
: string
: Whether disable-while-typing is enabled. It can be _enabled_ or _disabled_
+|- dwtp
+: string
+: Whether disable-while-trackpointing is enabled. It can be _enabled_ or
+ _disabled_
|- calibration_matrix
: array
: An array of 6 floats representing the calibration matrix for absolute
@@ -1233,7 +1240,8 @@ following properties will be included for devices that support them:
"click_method": "button_areas",
"middle_emulation": "disabled",
"scroll_method": "edge",
- "dwt": "enabled"
+ "dwt": "enabled",
+ "dwtp": "enabled"
}
},
{
@@ -1360,7 +1368,8 @@ one seat. Each object has the following properties:
"click_method": "button_areas",
"middle_emulation": "disabled",
"scroll_method": "edge",
- "dwt": "enabled"
+ "dwt": "enabled",
+ "dwtp": "enabled"
}
},
{
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 4159a851..b7d5e577 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -24,7 +24,7 @@ must be separated by one space. For example:
# COMMANDS
-*output* <name> mode|resolution|res [--custom] <WIDTHxHEIGHT>[@<RATE>Hz]
+*output* <name> mode|resolution|res [--custom] <width>x<height>[@<rate>Hz]
Configures the specified output to use the given mode. Modes are a
combination of width and height (in pixels) and a refresh rate that your
display can be configured to use. For a list of available modes for each
@@ -119,12 +119,20 @@ must be separated by one space. For example:
Enables or disables the specified output (all outputs are enabled by
default).
+ As opposed to the _power_ command, the output will loose its current
+ workspace and windows.
+
*output* <name> toggle
Toggle the specified output.
+*output* <name> power on|off|toggle
+ Turns on or off the specified output.
+
+ As opposed to the _enable_ and _disable_ commands, the output keeps its
+ current workspaces and windows.
+
*output* <name> dpms on|off|toggle
- Enables or disables the specified output via DPMS. To turn an output off
- (ie. blank the screen but keep workspaces as-is), one can set DPMS to off.
+ Deprecated. Alias for _power_.
*output* <name> max_render_time off|<msec>
Controls when sway composites the output, as a positive number of
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index bf936a27..15e60844 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -176,6 +176,12 @@ set|plus|minus|toggle <amount>
*layout* default|splith|splitv|stacking|tabbed
Sets the layout mode of the focused container.
+ When using the _stacking_ layout, only the focused window in the container is
+ displayed, with the opened windows' list on the top of the container.
+
+ The _tabbed_ layout is similar to _stacking_, but the windows’ list is vertically
+ split.
+
*layout* toggle [split|all]
Cycles the layout mode of the focused container though a preset list of
layouts. If no argument is given, then it cycles through stacking, tabbed
@@ -210,15 +216,14 @@ set|plus|minus|toggle <amount>
further details.
*move* left|right|up|down [<px> px]
- Moves the focused container in the direction specified. If the container,
- the optional _px_ argument specifies how many pixels to move the container.
- If unspecified, the default is 10 pixels. Pixels are ignored when moving
- tiled containers.
+ Moves the focused container in the direction specified. The optional _px_
+ argument specifies how many pixels to move the container. If unspecified,
+ the default is 10 pixels. Pixels are ignored when moving tiled containers.
*move* [absolute] position <pos_x> [px|ppt] <pos_y> [px|ppt]
Moves the focused container to the specified position in the workspace.
The position can be specified in pixels or percentage points, omitting
- the unit defaults to pixels. If _absolute_ is used, the position is
+ the unit defaults to pixels. If _absolute_ is used, the position is
relative to all outputs. _absolute_ can not be used with percentage points.
*move* [absolute] position center
@@ -482,6 +487,62 @@ runtime.
bindswitch lid:toggle exec echo "Lid moved"
```
+*bindgesture* [--exact] [--input-device=<device>] [--no-warn] \
+<gesture>[:<fingers>][:directions] <command>
+ Binds _gesture_ to execute the sway command _command_ when detected.
+ Currently supports the _hold_, _pinch_ or _swipe_ gesture. Optionally
+ can be limited to bind to a certain number of _fingers_ or, for a
+ _pinch_ or _swipe_ gesture, to certain _directions_.
+
+[[ *type*
+:[ *fingers*
+:< *direction*
+| hold
+:- 1 - 5
+: none
+| swipe
+: 3 - 5
+: up, down, left, right
+| pinch
+: 2 - 5
+: all above + inward, outward, clockwise, counterclockwise
+
+ The _fingers_ can be limited to any sensible number or left empty to accept
+ any finger counts.
+ Valid directions are _up_, _down_, _left_ and _right_, as well as _inward_,
+ _outward_, _clockwise_, _counterclockwise_ for the _pinch_ gesture.
+ Multiple directions can be combined by a plus.
+
+ If a _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. By default, if you overwrite a binding,
+ swaynag will give you a warning. To silence this, use the _--no-warn_ flag.
+
+ The _--exact_ flag can be used to ensure a binding only matches when exactly
+ all specified directions are matched and nothing more. If there is matching
+ binding with _--exact_, it will be preferred.
+
+ The priority for matching bindings is as follows: input device, then
+ exact matches followed by matches with the highest number of matching
+ directions.
+
+ Gestures executed while the pointer is above a bar are not handled by sway.
+ See the respective documentation, e.g. *bindgesture* in *sway-bar*(5).
+
+ Example:
+```
+ # Allow switching between workspaces with left and right swipes
+ bindgesture swipe:right workspace prev
+ bindgesture swipe:left workspace next
+
+ # Allow container movements by pinching them
+ bindgesture pinch:inward+up move up
+ bindgesture pinch:inward+down move down
+ bindgesture pinch:inward+left move left
+ bindgesture pinch:inward+right move right
+
+```
+
*client.background* <color>
This command is ignored and is only present for i3 compatibility.
@@ -632,11 +693,11 @@ The default colors are:
after switching between workspaces.
*focus_on_window_activation* smart|urgent|focus|none
- This option determines what to do when an xwayland client requests
- window activation. If set to _urgent_, the urgent state will be set
- for that window. If set to _focus_, the window will become focused.
- If set to _smart_, the window will become focused only if it is already
- visible, otherwise the urgent state will be set. Default is _urgent_.
+ This option determines what to do when a client requests window activation.
+ If set to _urgent_, the urgent state will be set for that window. If set to
+ _focus_, the window will become focused. If set to _smart_, the window will
+ become focused only if it is already visible, otherwise the urgent state
+ will be set. Default is _urgent_.
*focus_wrapping* yes|no|force|workspace
This option determines what to do when attempting to focus over the edge
@@ -805,6 +866,11 @@ The default colors are:
*unbindswitch* <switch>:<state>
Removes a binding for when <switch> changes to <state>.
+*unbindgesture* [--exact] [--input-device=<device>] \
+<gesture>[:<fingers>][:directions]
+ Removes a binding for the specified _gesture_, _fingers_
+ and _directions_ combination.
+
*unbindsym* [--whole-window] [--border] [--exclude-titlebar] [--release] [--locked] \
[--to-code] [--input-device=<device>] <key combo>
Removes the binding for _key combo_ that was previously bound with the
@@ -918,7 +984,8 @@ The following attributes may be matched with:
*class*
Compare value against the window class. Can be a regular expression. If
value is \_\_focused\_\_, then the window class must be the same as that of
- the currently focused window. _class_ are specific to X11 applications.
+ the currently focused window. _class_ are specific to X11 applications and
+ require XWayland.
*con_id*
Compare against the internal container ID, which you can find via IPC. If
@@ -932,12 +999,14 @@ The following attributes may be matched with:
Matches floating windows.
*id*
- Compare value against the X11 window ID. Must be numeric.
+ Compare value against the X11 window ID. Must be numeric. id is specific to
+ X11 applications and requires XWayland.
*instance*
Compare value against the window instance. Can be a regular expression. If
value is \_\_focused\_\_, then the window instance must be the same as that
- of the currently focused window.
+ of the currently focused window. instance is specific to X11 applications and
+ requires XWayland.
*pid*
Compare value against the window's process ID. Must be numeric.
@@ -962,12 +1031,14 @@ The following attributes may be matched with:
*window_role*
Compare against the window role (WM_WINDOW_ROLE). Can be a regular
expression. If value is \_\_focused\_\_, then the window role must be the
- same as that of the currently focused window.
+ same as that of the currently focused window. window_role is specific to X11
+ applications and requires XWayland.
*window_type*
Compare against the window type (\_NET_WM_WINDOW_TYPE). Possible values
are normal, dialog, utility, toolbar, splash, menu, dropdown_menu,
- popup_menu, tooltip and notification.
+ popup_menu, tooltip and notification. window_type is specific to X11
+ applications and requires XWayland.
*workspace*
Compare against the workspace name for this view. Can be a regular
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c
index 4aa82c35..9c1a11e5 100644
--- a/sway/tree/arrange.c
+++ b/sway/tree/arrange.c
@@ -311,12 +311,13 @@ void arrange_output(struct sway_output *output) {
if (config->reloading) {
return;
}
- const struct wlr_box *output_box = wlr_output_layout_get_box(
- root->output_layout, output->wlr_output);
- output->lx = output_box->x;
- output->ly = output_box->y;
- output->width = output_box->width;
- output->height = output_box->height;
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout,
+ output->wlr_output, &output_box);
+ output->lx = output_box.x;
+ output->ly = output_box.y;
+ output->width = output_box.width;
+ output->height = output_box.height;
for (int i = 0; i < output->workspaces->length; ++i) {
struct sway_workspace *workspace = output->workspaces->items[i];
@@ -328,12 +329,12 @@ void arrange_root(void) {
if (config->reloading) {
return;
}
- const struct wlr_box *layout_box =
- wlr_output_layout_get_box(root->output_layout, NULL);
- root->x = layout_box->x;
- root->y = layout_box->y;
- root->width = layout_box->width;
- root->height = layout_box->height;
+ struct wlr_box layout_box;
+ wlr_output_layout_get_box(root->output_layout, NULL, &layout_box);
+ root->x = layout_box.x;
+ root->y = layout_box.y;
+ root->width = layout_box.width;
+ root->height = layout_box.height;
if (root->fullscreen_global) {
struct sway_container *fs = root->fullscreen_global;
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 73bb865c..29a1e226 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -9,6 +9,7 @@
#include <wayland-server-core.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_output_layout.h>
+#include <wlr/types/wlr_subcompositor.h>
#include <wlr/render/drm_format_set.h>
#include "linux-dmabuf-unstable-v1-protocol.h"
#include "cairo_util.h"
@@ -51,7 +52,7 @@ struct sway_container *container_create(struct sway_view *view) {
c->outputs = create_list();
wl_signal_init(&c->events.destroy);
- wl_signal_emit(&root->events.new_node, &c->node);
+ wl_signal_emit_mutable(&root->events.new_node, &c->node);
return c;
}
@@ -106,7 +107,7 @@ void container_begin_destroy(struct sway_container *con) {
container_fullscreen_disable(con);
}
- wl_signal_emit(&con->node.events.destroy, &con->node);
+ wl_signal_emit_mutable(&con->node.events.destroy, &con->node);
container_end_mouse_operation(con);
@@ -196,7 +197,7 @@ static struct sway_container *surface_at_view(struct sway_container *con, double
#endif
case SWAY_VIEW_XDG_SHELL:
_surface = wlr_xdg_surface_surface_at(
- view->wlr_xdg_surface,
+ view->wlr_xdg_toplevel->base,
view_sx, view_sy, &_sx, &_sy);
break;
}
@@ -522,7 +523,7 @@ static void render_titlebar_text_texture(struct sway_output *output,
to_cairo_subpixel_order(output->wlr_output->subpixel));
}
cairo_set_font_options(c, fo);
- get_text_size(c, config->font, &width, NULL, &baseline, scale,
+ get_text_size(c, config->font_description, &width, NULL, &baseline, scale,
config->pango_markup, "%s", text);
cairo_surface_destroy(dummy_surface);
cairo_destroy(c);
@@ -556,7 +557,7 @@ static void render_titlebar_text_texture(struct sway_output *output,
class->text[2], class->text[3]);
cairo_move_to(cairo, 0, config->font_baseline * scale - baseline);
- render_text(cairo, config->font, scale, pango_markup, "%s", text);
+ render_text(cairo, config->font_description, scale, pango_markup, "%s", text);
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
@@ -697,12 +698,13 @@ void floating_calculate_constraints(int *min_width, int *max_width,
*min_height = config->floating_minimum_height;
}
- struct wlr_box *box = wlr_output_layout_get_box(root->output_layout, NULL);
+ struct wlr_box box;
+ wlr_output_layout_get_box(root->output_layout, NULL, &box);
if (config->floating_maximum_width == -1) { // no maximum
*max_width = INT_MAX;
} else if (config->floating_maximum_width == 0) { // automatic
- *max_width = box->width;
+ *max_width = box.width;
} else {
*max_width = config->floating_maximum_width;
}
@@ -710,7 +712,7 @@ void floating_calculate_constraints(int *min_width, int *max_width,
if (config->floating_maximum_height == -1) { // no maximum
*max_height = INT_MAX;
} else if (config->floating_maximum_height == 0) { // automatic
- *max_height = box->height;
+ *max_height = box.height;
} else {
*max_height = config->floating_maximum_height;
}
@@ -742,9 +744,9 @@ void container_floating_resize_and_center(struct sway_container *con) {
return;
}
- struct wlr_box *ob = wlr_output_layout_get_box(root->output_layout,
- ws->output->wlr_output);
- if (!ob) {
+ struct wlr_box ob;
+ wlr_output_layout_get_box(root->output_layout, ws->output->wlr_output, &ob);
+ if (wlr_box_empty(&ob)) {
// On NOOP output. Will be called again when moved to an output
con->pending.x = 0;
con->pending.y = 0;
@@ -756,8 +758,8 @@ void container_floating_resize_and_center(struct sway_container *con) {
floating_natural_resize(con);
if (!con->view) {
if (con->pending.width > ws->width || con->pending.height > ws->height) {
- con->pending.x = ob->x + (ob->width - con->pending.width) / 2;
- con->pending.y = ob->y + (ob->height - con->pending.height) / 2;
+ con->pending.x = ob.x + (ob.width - con->pending.width) / 2;
+ con->pending.y = ob.y + (ob.height - con->pending.height) / 2;
} else {
con->pending.x = ws->x + (ws->width - con->pending.width) / 2;
con->pending.y = ws->y + (ws->height - con->pending.height) / 2;
@@ -765,8 +767,8 @@ void container_floating_resize_and_center(struct sway_container *con) {
} else {
if (con->pending.content_width > ws->width
|| con->pending.content_height > ws->height) {
- con->pending.content_x = ob->x + (ob->width - con->pending.content_width) / 2;
- con->pending.content_y = ob->y + (ob->height - con->pending.content_height) / 2;
+ con->pending.content_x = ob.x + (ob.width - con->pending.content_width) / 2;
+ con->pending.content_y = ob.y + (ob.height - con->pending.content_height) / 2;
} else {
con->pending.content_x = ws->x + (ws->width - con->pending.content_width) / 2;
con->pending.content_y = ws->y + (ws->height - con->pending.content_height) / 2;
@@ -788,11 +790,11 @@ void container_floating_set_default_size(struct sway_container *con) {
int min_width, max_width, min_height, max_height;
floating_calculate_constraints(&min_width, &max_width,
&min_height, &max_height);
- struct wlr_box *box = calloc(1, sizeof(struct wlr_box));
- workspace_get_box(con->pending.workspace, box);
+ struct wlr_box box;
+ workspace_get_box(con->pending.workspace, &box);
- double width = fmax(min_width, fmin(box->width * 0.5, max_width));
- double height = fmax(min_height, fmin(box->height * 0.75, max_height));
+ double width = fmax(min_width, fmin(box.width * 0.5, max_width));
+ double height = fmax(min_height, fmin(box.height * 0.75, max_height));
if (!con->view) {
con->pending.width = width;
con->pending.height = height;
@@ -801,8 +803,6 @@ void container_floating_set_default_size(struct sway_container *con) {
con->pending.content_height = height;
container_set_geometry_from_content(con);
}
-
- free(box);
}
@@ -1413,6 +1413,9 @@ list_t *container_get_siblings(struct sway_container *container) {
if (container_is_scratchpad_hidden(container)) {
return NULL;
}
+ if (!container->pending.workspace) {
+ return NULL;
+ }
if (list_find(container->pending.workspace->tiling, container) != -1) {
return container->pending.workspace->tiling;
}
@@ -1707,7 +1710,7 @@ static void update_marks_texture(struct sway_container *con,
for (int i = 0; i < con->marks->length; ++i) {
char *mark = con->marks->items[i];
if (mark[0] != '_') {
- sprintf(part, "[%s]", mark);
+ snprintf(part, len + 1, "[%s]", mark);
strcat(buffer, part);
}
}
diff --git a/sway/tree/node.c b/sway/tree/node.c
index bc7e2aa5..12361c75 100644
--- a/sway/tree/node.c
+++ b/sway/tree/node.c
@@ -18,13 +18,13 @@ void node_init(struct sway_node *node, enum sway_node_type type, void *thing) {
const char *node_type_to_str(enum sway_node_type type) {
switch (type) {
case N_ROOT:
- return "N_ROOT";
+ return "root";
case N_OUTPUT:
- return "N_OUTPUT";
+ return "output";
case N_WORKSPACE:
- return "N_WORKSPACE";
+ return "workspace";
case N_CONTAINER:
- return "N_CONTAINER";
+ return "container";
}
return "";
}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index ad8d2482..eccab2f7 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -3,12 +3,12 @@
#include <ctype.h>
#include <string.h>
#include <strings.h>
-#include <wlr/types/wlr_output_damage.h>
#include "sway/ipc-server.h"
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/tree/arrange.h"
#include "sway/tree/workspace.h"
+#include "sway/server.h"
#include "log.h"
#include "util.h"
@@ -146,7 +146,7 @@ void output_enable(struct sway_output *output) {
input_manager_configure_xcursor();
- wl_signal_emit(&root->events.new_node, &output->node);
+ wl_signal_emit_mutable(&root->events.new_node, &output->node);
arrange_layers(output);
arrange_root();
@@ -262,7 +262,7 @@ void output_disable(struct sway_output *output) {
}
sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name);
- wl_signal_emit(&output->events.disable, output);
+ wl_signal_emit_mutable(&output->events.disable, output);
output_evacuate(output);
@@ -286,7 +286,7 @@ void output_begin_destroy(struct sway_output *output) {
return;
}
sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name);
- wl_signal_emit(&output->node.events.destroy, &output->node);
+ wl_signal_emit_mutable(&output->node.events.destroy, &output->node);
output->node.destroying = true;
node_set_dirty(&output->node);
@@ -301,10 +301,10 @@ struct sway_output *output_get_in_direction(struct sway_output *reference,
if (!sway_assert(direction, "got invalid direction: %d", direction)) {
return NULL;
}
- struct wlr_box *output_box =
- wlr_output_layout_get_box(root->output_layout, reference->wlr_output);
- int lx = output_box->x + output_box->width / 2;
- int ly = output_box->y + output_box->height / 2;
+ struct wlr_box output_box;
+ wlr_output_layout_get_box(root->output_layout, reference->wlr_output, &output_box);
+ int lx = output_box.x + output_box.width / 2;
+ int ly = output_box.y + output_box.height / 2;
struct wlr_output *wlr_adjacent = wlr_output_layout_adjacent_output(
root->output_layout, direction, reference->wlr_output, lx, ly);
if (!wlr_adjacent) {
@@ -390,6 +390,33 @@ void output_get_box(struct sway_output *output, struct wlr_box *box) {
box->height = output->height;
}
+static void handle_destroy_non_desktop(struct wl_listener *listener, void *data) {
+ struct sway_output_non_desktop *output =
+ wl_container_of(listener, output, destroy);
+
+ sway_log(SWAY_DEBUG, "Destroying non-desktop output '%s'", output->wlr_output->name);
+
+ int index = list_find(root->non_desktop_outputs, output);
+ list_del(root->non_desktop_outputs, index);
+
+ wl_list_remove(&output->destroy.link);
+
+ free(output);
+}
+
+struct sway_output_non_desktop *output_non_desktop_create(
+ struct wlr_output *wlr_output) {
+ struct sway_output_non_desktop *output =
+ calloc(1, sizeof(struct sway_output_non_desktop));
+
+ output->wlr_output = wlr_output;
+
+ wl_signal_add(&wlr_output->events.destroy, &output->destroy);
+ output->destroy.notify = handle_destroy_non_desktop;
+
+ return output;
+}
+
enum sway_container_layout output_get_default_layout(
struct sway_output *output) {
if (config->default_orientation != L_NONE) {
diff --git a/sway/tree/root.c b/sway/tree/root.c
index 73f3993c..8934721f 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -38,6 +38,7 @@ struct sway_root *root_create(void) {
wl_list_init(&root->drag_icons);
wl_signal_init(&root->events.new_node);
root->outputs = create_list();
+ root->non_desktop_outputs = create_list();
root->scratchpad = create_list();
root->output_layout_change.notify = output_layout_handle_change;
@@ -183,172 +184,6 @@ void root_scratchpad_hide(struct sway_container *con) {
ipc_event_window(con, "move");
}
-struct pid_workspace {
- pid_t pid;
- char *workspace;
- struct timespec time_added;
-
- struct sway_output *output;
- struct wl_listener output_destroy;
-
- struct wl_list link;
-};
-
-static struct wl_list pid_workspaces;
-
-/**
- * Get the pid of a parent process given the pid of a child process.
- *
- * Returns the parent pid or NULL if the parent pid cannot be determined.
- */
-static pid_t get_parent_pid(pid_t child) {
- pid_t parent = -1;
- char file_name[100];
- char *buffer = NULL;
- const char *sep = " ";
- FILE *stat = NULL;
- size_t buf_size = 0;
-
- sprintf(file_name, "/proc/%d/stat", child);
-
- if ((stat = fopen(file_name, "r"))) {
- if (getline(&buffer, &buf_size, stat) != -1) {
- strtok(buffer, sep); // pid
- strtok(NULL, sep); // executable name
- strtok(NULL, sep); // state
- char *token = strtok(NULL, sep); // parent pid
- parent = strtol(token, NULL, 10);
- }
- free(buffer);
- fclose(stat);
- }
-
- if (parent) {
- return (parent == child) ? -1 : parent;
- }
-
- return -1;
-}
-
-static void pid_workspace_destroy(struct pid_workspace *pw) {
- wl_list_remove(&pw->output_destroy.link);
- wl_list_remove(&pw->link);
- free(pw->workspace);
- free(pw);
-}
-
-struct sway_workspace *root_workspace_for_pid(pid_t pid) {
- if (!pid_workspaces.prev && !pid_workspaces.next) {
- wl_list_init(&pid_workspaces);
- return NULL;
- }
-
- struct sway_workspace *ws = NULL;
- struct pid_workspace *pw = NULL;
-
- sway_log(SWAY_DEBUG, "Looking up workspace for pid %d", pid);
-
- do {
- struct pid_workspace *_pw = NULL;
- wl_list_for_each(_pw, &pid_workspaces, link) {
- if (pid == _pw->pid) {
- pw = _pw;
- sway_log(SWAY_DEBUG,
- "found pid_workspace for pid %d, workspace %s",
- pid, pw->workspace);
- goto found;
- }
- }
- pid = get_parent_pid(pid);
- } while (pid > 1);
-found:
-
- if (pw && pw->workspace) {
- ws = workspace_by_name(pw->workspace);
-
- if (!ws) {
- sway_log(SWAY_DEBUG,
- "Creating workspace %s for pid %d because it disappeared",
- pw->workspace, pid);
-
- struct sway_output *output = pw->output;
- if (pw->output && !pw->output->enabled) {
- sway_log(SWAY_DEBUG,
- "Workspace output %s is disabled, trying another one",
- pw->output->wlr_output->name);
- output = NULL;
- }
-
- ws = workspace_create(output, pw->workspace);
- }
-
- pid_workspace_destroy(pw);
- }
-
- return ws;
-}
-
-static void pw_handle_output_destroy(struct wl_listener *listener, void *data) {
- struct pid_workspace *pw = wl_container_of(listener, pw, output_destroy);
- pw->output = NULL;
- wl_list_remove(&pw->output_destroy.link);
- wl_list_init(&pw->output_destroy.link);
-}
-
-void root_record_workspace_pid(pid_t pid) {
- sway_log(SWAY_DEBUG, "Recording workspace for process %d", pid);
- if (!pid_workspaces.prev && !pid_workspaces.next) {
- wl_list_init(&pid_workspaces);
- }
-
- struct sway_seat *seat = input_manager_current_seat();
- struct sway_workspace *ws = seat_get_focused_workspace(seat);
- if (!ws) {
- sway_log(SWAY_DEBUG, "Bailing out, no workspace");
- return;
- }
- struct sway_output *output = ws->output;
- if (!output) {
- sway_log(SWAY_DEBUG, "Bailing out, no output");
- return;
- }
-
- struct timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- // Remove expired entries
- static const int timeout = 60;
- struct pid_workspace *old, *_old;
- wl_list_for_each_safe(old, _old, &pid_workspaces, link) {
- if (now.tv_sec - old->time_added.tv_sec >= timeout) {
- pid_workspace_destroy(old);
- }
- }
-
- struct pid_workspace *pw = calloc(1, sizeof(struct pid_workspace));
- pw->workspace = strdup(ws->name);
- pw->output = output;
- pw->pid = pid;
- memcpy(&pw->time_added, &now, sizeof(struct timespec));
- pw->output_destroy.notify = pw_handle_output_destroy;
- wl_signal_add(&output->wlr_output->events.destroy, &pw->output_destroy);
- wl_list_insert(&pid_workspaces, &pw->link);
-}
-
-void root_remove_workspace_pid(pid_t pid) {
- if (!pid_workspaces.prev || !pid_workspaces.next) {
- return;
- }
-
- struct pid_workspace *pw, *tmp;
- wl_list_for_each_safe(pw, tmp, &pid_workspaces, link) {
- if (pid == pw->pid) {
- pid_workspace_destroy(pw);
- return;
- }
- }
-}
-
void root_for_each_workspace(void (*f)(struct sway_workspace *ws, void *data),
void *data) {
for (int i = 0; i < root->outputs->length; ++i) {
@@ -443,17 +278,3 @@ void root_get_box(struct sway_root *root, struct wlr_box *box) {
box->width = root->width;
box->height = root->height;
}
-
-void root_rename_pid_workspaces(const char *old_name, const char *new_name) {
- if (!pid_workspaces.prev && !pid_workspaces.next) {
- wl_list_init(&pid_workspaces);
- }
-
- struct pid_workspace *pw = NULL;
- wl_list_for_each(pw, &pid_workspaces, link) {
- if (strcmp(pw->workspace, old_name) == 0) {
- free(pw->workspace);
- pw->workspace = strdup(new_name);
- }
- }
-}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index 8b7061ba..9d7b68d1 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -6,6 +6,7 @@
#include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_server_decoration.h>
+#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include "config.h"
#if HAVE_XWAYLAND
@@ -18,6 +19,7 @@
#include "sway/desktop.h"
#include "sway/desktop/transaction.h"
#include "sway/desktop/idle_inhibit_v1.h"
+#include "sway/desktop/launcher.h"
#include "sway/input/cursor.h"
#include "sway/ipc-server.h"
#include "sway/output.h"
@@ -62,6 +64,8 @@ void view_destroy(struct sway_view *view) {
}
list_free(view->executed_criteria);
+ view_assign_ctx(view, NULL);
+
free(view->title_format);
if (view->impl->destroy) {
@@ -532,6 +536,20 @@ static void view_populate_pid(struct sway_view *view) {
view->pid = pid;
}
+void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx) {
+ if (view->ctx) {
+ // This ctx has been replaced
+ launcher_ctx_destroy(view->ctx);
+ view->ctx = NULL;
+ }
+ if (ctx == NULL) {
+ return;
+ }
+ launcher_ctx_consume(ctx);
+
+ view->ctx = ctx;
+}
+
static struct sway_workspace *select_workspace(struct sway_view *view) {
struct sway_seat *seat = input_manager_current_seat();
@@ -567,13 +585,14 @@ static struct sway_workspace *select_workspace(struct sway_view *view) {
}
list_free(criterias);
if (ws) {
- root_remove_workspace_pid(view->pid);
+ view_assign_ctx(view, NULL);
return ws;
}
// Check if there's a PID mapping
- ws = root_workspace_for_pid(view->pid);
+ ws = view->ctx ? launcher_ctx_get_workspace(view->ctx) : NULL;
if (ws) {
+ view_assign_ctx(view, NULL);
return ws;
}
@@ -739,6 +758,13 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
view_populate_pid(view);
view->container = container_create(view);
+ if (view->ctx == NULL) {
+ struct launcher_ctx *ctx = launcher_ctx_find_pid(view->pid);
+ if (ctx != NULL) {
+ view_assign_ctx(view, ctx);
+ }
+ }
+
// If there is a request to be opened fullscreen on a specific output, try
// to honor that request. Otherwise, fallback to assigns, pid mappings,
// focused workspace, etc
@@ -873,7 +899,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
}
void view_unmap(struct sway_view *view) {
- wl_signal_emit(&view->events.unmap, view);
+ wl_signal_emit_mutable(&view->events.unmap, view);
wl_list_remove(&view->surface_new_subsurface.link);
@@ -1308,21 +1334,23 @@ void view_update_title(struct sway_view *view, bool force) {
free(view->container->title);
free(view->container->formatted_title);
- if (title) {
- size_t len = parse_title_format(view, NULL);
+
+ size_t len = parse_title_format(view, NULL);
+
+ if (len) {
char *buffer = calloc(len + 1, sizeof(char));
if (!sway_assert(buffer, "Unable to allocate title string")) {
return;
}
- parse_title_format(view, buffer);
- view->container->title = strdup(title);
+ parse_title_format(view, buffer);
view->container->formatted_title = buffer;
} else {
- view->container->title = NULL;
view->container->formatted_title = NULL;
}
+ view->container->title = title ? strdup(title) : NULL;
+
// Update title after the global font height is updated
container_update_title_textures(view->container);
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index c84320bd..ee940466 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -56,6 +56,8 @@ struct sway_output *workspace_get_initial_output(const char *name) {
struct sway_workspace *workspace_create(struct sway_output *output,
const char *name) {
+ sway_assert(name, "NULL name given to workspace_create");
+
if (output == NULL) {
output = workspace_get_initial_output(name);
}
@@ -69,7 +71,7 @@ struct sway_workspace *workspace_create(struct sway_output *output,
return NULL;
}
node_init(&ws->node, N_WORKSPACE, ws);
- ws->name = name ? strdup(name) : NULL;
+ ws->name = strdup(name);
ws->prev_split_layout = L_NONE;
ws->layout = output_get_default_layout(output);
ws->floating = create_list();
@@ -114,7 +116,7 @@ struct sway_workspace *workspace_create(struct sway_output *output,
output_sort_workspaces(output);
ipc_event_workspace(NULL, ws, "init");
- wl_signal_emit(&root->events.new_node, &ws->node);
+ wl_signal_emit_mutable(&root->events.new_node, &ws->node);
return ws;
}
@@ -142,7 +144,7 @@ void workspace_destroy(struct sway_workspace *workspace) {
void workspace_begin_destroy(struct sway_workspace *workspace) {
sway_log(SWAY_DEBUG, "Destroying workspace '%s'", workspace->name);
ipc_event_workspace(NULL, workspace, "empty"); // intentional
- wl_signal_emit(&workspace->node.events.destroy, &workspace->node);
+ wl_signal_emit_mutable(&workspace->node.events.destroy, &workspace->node);
if (workspace->output) {
workspace_detach(workspace);
diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c
index 6c70c785..2b94136c 100644
--- a/sway/xdg_activation_v1.c
+++ b/sway/xdg_activation_v1.c
@@ -1,4 +1,5 @@
#include <wlr/types/wlr_xdg_activation_v1.h>
+#include "sway/desktop/launcher.h"
#include "sway/tree/view.h"
void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
@@ -11,8 +12,26 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener,
struct wlr_xdg_surface *xdg_surface =
wlr_xdg_surface_from_wlr_surface(event->surface);
+ if (xdg_surface == NULL) {
+ return;
+ }
struct sway_view *view = xdg_surface->data;
- if (!xdg_surface->mapped || view == NULL) {
+ if (view == NULL) {
+ return;
+ }
+
+ if (!xdg_surface->mapped) {
+ // This is a startup notification. If we are tracking it, the data
+ // field is a launcher_ctx.
+ struct launcher_ctx *ctx = event->token->data;
+ if (!ctx || ctx->activated) {
+ // This ctx has already been activated and cannot be used again
+ // for a startup notification. It will be destroyed
+ return;
+ } else {
+ ctx->activated = true;
+ view_assign_ctx(view, ctx);
+ }
return;
}