aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h4
-rw-r--r--sway/commands/seat.c1
-rw-r--r--sway/commands/seat/xcursor_theme.c33
-rw-r--r--sway/config/seat.c9
-rw-r--r--sway/input/seat.c70
-rw-r--r--sway/meson.build1
-rw-r--r--sway/server.c23
-rw-r--r--sway/sway-input.5.scd6
9 files changed, 119 insertions, 29 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index c4903788..927296b0 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -278,6 +278,7 @@ sway_cmd seat_cmd_cursor;
sway_cmd seat_cmd_fallback;
sway_cmd seat_cmd_hide_cursor;
sway_cmd seat_cmd_pointer_constraint;
+sway_cmd seat_cmd_xcursor_theme;
sway_cmd cmd_ipc_cmd;
sway_cmd cmd_ipc_events;
diff --git a/include/sway/config.h b/include/sway/config.h
index b94a35f3..311adb16 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -165,6 +165,10 @@ struct seat_config {
list_t *attachments; // list of seat_attachment configs
int hide_cursor_timeout;
enum seat_config_allow_constrain allow_constrain;
+ struct {
+ char *name;
+ int size;
+ } xcursor_theme;
};
enum config_dpms {
diff --git a/sway/commands/seat.c b/sway/commands/seat.c
index aa36ba95..a827bf74 100644
--- a/sway/commands/seat.c
+++ b/sway/commands/seat.c
@@ -13,6 +13,7 @@ static struct cmd_handler seat_handlers[] = {
{ "fallback", seat_cmd_fallback },
{ "hide_cursor", seat_cmd_hide_cursor },
{ "pointer_constraint", seat_cmd_pointer_constraint },
+ { "xcursor_theme", seat_cmd_xcursor_theme },
};
struct cmd_results *cmd_seat(int argc, char **argv) {
diff --git a/sway/commands/seat/xcursor_theme.c b/sway/commands/seat/xcursor_theme.c
new file mode 100644
index 00000000..202f35b9
--- /dev/null
+++ b/sway/commands/seat/xcursor_theme.c
@@ -0,0 +1,33 @@
+#define _POSIX_C_SOURCE 200809L
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *seat_cmd_xcursor_theme(int argc, char **argv) {
+ struct cmd_results *error = NULL;
+ if ((error = checkarg(argc, "xcursor_theme", EXPECTED_AT_LEAST, 1)) ||
+ (error = checkarg(argc, "xcursor_theme", EXPECTED_AT_MOST, 2))) {
+ return error;
+ }
+ if (!config->handler_context.seat_config) {
+ return cmd_results_new(CMD_FAILURE, "No seat defined");
+ }
+
+ const char *theme_name = argv[0];
+ unsigned size = 24;
+
+ if (argc == 2) {
+ char *end;
+ size = strtoul(argv[1], &end, 10);
+ if (*end) {
+ return cmd_results_new(
+ CMD_INVALID, "Expected a positive integer size");
+ }
+ }
+
+ free(config->handler_context.seat_config->xcursor_theme.name);
+ config->handler_context.seat_config->xcursor_theme.name = strdup(theme_name);
+ config->handler_context.seat_config->xcursor_theme.size = size;
+
+ return cmd_results_new(CMD_SUCCESS, NULL);
+}
diff --git a/sway/config/seat.c b/sway/config/seat.c
index 04a44e3a..d4190cec 100644
--- a/sway/config/seat.c
+++ b/sway/config/seat.c
@@ -27,6 +27,8 @@ struct seat_config *new_seat_config(const char* name) {
}
seat->hide_cursor_timeout = -1;
seat->allow_constrain = CONSTRAIN_DEFAULT;
+ seat->xcursor_theme.name = NULL;
+ seat->xcursor_theme.size = 24;
return seat;
}
@@ -147,6 +149,12 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
if (source->allow_constrain != CONSTRAIN_DEFAULT) {
dest->allow_constrain = source->allow_constrain;
}
+
+ if (source->xcursor_theme.name != NULL) {
+ free(dest->xcursor_theme.name);
+ dest->xcursor_theme.name = strdup(source->xcursor_theme.name);
+ dest->xcursor_theme.size = source->xcursor_theme.size;
+ }
}
struct seat_config *copy_seat_config(struct seat_config *seat) {
@@ -170,6 +178,7 @@ void free_seat_config(struct seat_config *seat) {
seat_attachment_config_free(seat->attachments->items[i]);
}
list_free(seat->attachments);
+ free(seat->xcursor_theme.name);
free(seat);
}
diff --git a/sway/input/seat.c b/sway/input/seat.c
index ce009d7e..2e386d2c 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -19,6 +19,7 @@
#include "sway/ipc-server.h"
#include "sway/layers.h"
#include "sway/output.h"
+#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
@@ -722,17 +723,72 @@ void seat_remove_device(struct sway_seat *seat,
seat_update_capabilities(seat);
}
+static bool xcursor_manager_is_named(const struct wlr_xcursor_manager *manager,
+ const char *name) {
+ return (!manager->name && !name) ||
+ (name && manager->name && strcmp(name, manager->name) == 0);
+}
+
void seat_configure_xcursor(struct sway_seat *seat) {
- // TODO configure theme and size
+ unsigned cursor_size = 24;
const char *cursor_theme = NULL;
- if (!seat->cursor->xcursor_manager) {
- seat->cursor->xcursor_manager =
- wlr_xcursor_manager_create(cursor_theme, 24);
- if (sway_assert(seat->cursor->xcursor_manager,
- "Cannot create XCursor manager for theme")) {
- return;
+ const struct seat_config *seat_config = seat_get_config(seat);
+ if (!seat_config) {
+ seat_config = seat_get_config_by_name("*");
+ }
+ if (seat_config) {
+ cursor_size = seat_config->xcursor_theme.size;
+ cursor_theme = seat_config->xcursor_theme.name;
+ }
+
+ if (seat == input_manager_get_default_seat()) {
+ char cursor_size_fmt[16];
+ snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%d", cursor_size);
+ setenv("XCURSOR_SIZE", cursor_size_fmt, 1);
+ if (cursor_theme != NULL) {
+ setenv("XCURSOR_THEME", cursor_theme, 1);
}
+
+#if HAVE_XWAYLAND
+ if (!server.xwayland.xcursor_manager ||
+ !xcursor_manager_is_named(server.xwayland.xcursor_manager,
+ cursor_theme) ||
+ server.xwayland.xcursor_manager->size != cursor_size) {
+
+ wlr_xcursor_manager_destroy(server.xwayland.xcursor_manager);
+
+ server.xwayland.xcursor_manager =
+ wlr_xcursor_manager_create(cursor_theme, cursor_size);
+ sway_assert(server.xwayland.xcursor_manager,
+ "Cannot create XCursor manager for theme");
+
+ wlr_xcursor_manager_load(server.xwayland.xcursor_manager, 1);
+ struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
+ server.xwayland.xcursor_manager, "left_ptr", 1);
+ if (xcursor != NULL) {
+ struct wlr_xcursor_image *image = xcursor->images[0];
+ wlr_xwayland_set_cursor(
+ server.xwayland.wlr_xwayland, image->buffer,
+ image->width * 4, image->width, image->height,
+ image->hotspot_x, image->hotspot_y);
+ }
+ }
+#endif
+ }
+
+ /* Create xcursor manager if we don't have one already, or if the
+ * theme has changed */
+ if (!seat->cursor->xcursor_manager ||
+ !xcursor_manager_is_named(
+ seat->cursor->xcursor_manager, cursor_theme) ||
+ seat->cursor->xcursor_manager->size != cursor_size) {
+
+ wlr_xcursor_manager_destroy(seat->cursor->xcursor_manager);
+ seat->cursor->xcursor_manager =
+ wlr_xcursor_manager_create(cursor_theme, cursor_size);
+ sway_assert(seat->cursor->xcursor_manager,
+ "Cannot create XCursor manager for theme");
}
for (int i = 0; i < root->outputs->length; ++i) {
diff --git a/sway/meson.build b/sway/meson.build
index 05cece7a..262d7057 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -89,6 +89,7 @@ sway_sources = files(
'commands/seat/fallback.c',
'commands/seat/hide_cursor.c',
'commands/seat/pointer_constraint.c',
+ 'commands/seat/xcursor_theme.c',
'commands/set.c',
'commands/show_marks.c',
'commands/smart_borders.c',
diff --git a/sway/server.c b/sway/server.c
index a403d8b3..b50e3ccc 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -168,17 +168,6 @@ void server_fini(struct sway_server *server) {
}
bool server_start(struct sway_server *server) {
- // TODO: configurable cursor theme and size
- int cursor_size = 24;
- const char *cursor_theme = NULL;
-
- char cursor_size_fmt[16];
- snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%d", cursor_size);
- setenv("XCURSOR_SIZE", cursor_size_fmt, 1);
- if (cursor_theme != NULL) {
- setenv("XCURSOR_THEME", cursor_theme, 1);
- }
-
#if HAVE_XWAYLAND
if (config->xwayland) {
sway_log(SWAY_DEBUG, "Initializing Xwayland");
@@ -193,17 +182,7 @@ bool server_start(struct sway_server *server) {
setenv("DISPLAY", server->xwayland.wlr_xwayland->display_name, true);
- server->xwayland.xcursor_manager =
- wlr_xcursor_manager_create(cursor_theme, cursor_size);
- wlr_xcursor_manager_load(server->xwayland.xcursor_manager, 1);
- struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
- server->xwayland.xcursor_manager, "left_ptr", 1);
- if (xcursor != NULL) {
- struct wlr_xcursor_image *image = xcursor->images[0];
- wlr_xwayland_set_cursor(server->xwayland.wlr_xwayland, image->buffer,
- image->width * 4, image->width, image->height, image->hotspot_x,
- image->hotspot_y);
- }
+ /* xcursor configured by the default seat */
}
#endif
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index efd3d1af..3191bddf 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -206,6 +206,12 @@ correct seat.
by default) for the seat. This is primarily useful for video games. The
"escape" command can be used at runtime to escape from a captured client.
+*seat* <name> xcursor_theme <theme> [<size>]
+ Override the system default XCursor theme. The default seat's
+ (_seat0_) theme is also used as the default cursor theme in
+ XWayland, and exported through the _XCURSOR_THEME_ and
+ _XCURSOR_SIZE_ environment variables.
+
# SEE ALSO
*sway*(5) *sway-output*(5) *xkeyboard-config*(7)