aboutsummaryrefslogtreecommitdiffstats
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;
278sway_cmd seat_cmd_fallback; 278sway_cmd seat_cmd_fallback;
279sway_cmd seat_cmd_hide_cursor; 279sway_cmd seat_cmd_hide_cursor;
280sway_cmd seat_cmd_pointer_constraint; 280sway_cmd seat_cmd_pointer_constraint;
281sway_cmd seat_cmd_xcursor_theme;
281 282
282sway_cmd cmd_ipc_cmd; 283sway_cmd cmd_ipc_cmd;
283sway_cmd cmd_ipc_events; 284sway_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 {
165 list_t *attachments; // list of seat_attachment configs 165 list_t *attachments; // list of seat_attachment configs
166 int hide_cursor_timeout; 166 int hide_cursor_timeout;
167 enum seat_config_allow_constrain allow_constrain; 167 enum seat_config_allow_constrain allow_constrain;
168 struct {
169 char *name;
170 int size;
171 } xcursor_theme;
168}; 172};
169 173
170enum config_dpms { 174enum 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[] = {
13 { "fallback", seat_cmd_fallback }, 13 { "fallback", seat_cmd_fallback },
14 { "hide_cursor", seat_cmd_hide_cursor }, 14 { "hide_cursor", seat_cmd_hide_cursor },
15 { "pointer_constraint", seat_cmd_pointer_constraint }, 15 { "pointer_constraint", seat_cmd_pointer_constraint },
16 { "xcursor_theme", seat_cmd_xcursor_theme },
16}; 17};
17 18
18struct cmd_results *cmd_seat(int argc, char **argv) { 19struct 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 @@
1#define _POSIX_C_SOURCE 200809L
2#include <string.h>
3#include "sway/commands.h"
4#include "sway/config.h"
5
6struct cmd_results *seat_cmd_xcursor_theme(int argc, char **argv) {
7 struct cmd_results *error = NULL;
8 if ((error = checkarg(argc, "xcursor_theme", EXPECTED_AT_LEAST, 1)) ||
9 (error = checkarg(argc, "xcursor_theme", EXPECTED_AT_MOST, 2))) {
10 return error;
11 }
12 if (!config->handler_context.seat_config) {
13 return cmd_results_new(CMD_FAILURE, "No seat defined");
14 }
15
16 const char *theme_name = argv[0];
17 unsigned size = 24;
18
19 if (argc == 2) {
20 char *end;
21 size = strtoul(argv[1], &end, 10);
22 if (*end) {
23 return cmd_results_new(
24 CMD_INVALID, "Expected a positive integer size");
25 }
26 }
27
28 free(config->handler_context.seat_config->xcursor_theme.name);
29 config->handler_context.seat_config->xcursor_theme.name = strdup(theme_name);
30 config->handler_context.seat_config->xcursor_theme.size = size;
31
32 return cmd_results_new(CMD_SUCCESS, NULL);
33}
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) {
27 } 27 }
28 seat->hide_cursor_timeout = -1; 28 seat->hide_cursor_timeout = -1;
29 seat->allow_constrain = CONSTRAIN_DEFAULT; 29 seat->allow_constrain = CONSTRAIN_DEFAULT;
30 seat->xcursor_theme.name = NULL;
31 seat->xcursor_theme.size = 24;
30 32
31 return seat; 33 return seat;
32} 34}
@@ -147,6 +149,12 @@ void merge_seat_config(struct seat_config *dest, struct seat_config *source) {
147 if (source->allow_constrain != CONSTRAIN_DEFAULT) { 149 if (source->allow_constrain != CONSTRAIN_DEFAULT) {
148 dest->allow_constrain = source->allow_constrain; 150 dest->allow_constrain = source->allow_constrain;
149 } 151 }
152
153 if (source->xcursor_theme.name != NULL) {
154 free(dest->xcursor_theme.name);
155 dest->xcursor_theme.name = strdup(source->xcursor_theme.name);
156 dest->xcursor_theme.size = source->xcursor_theme.size;
157 }
150} 158}
151 159
152struct seat_config *copy_seat_config(struct seat_config *seat) { 160struct seat_config *copy_seat_config(struct seat_config *seat) {
@@ -170,6 +178,7 @@ void free_seat_config(struct seat_config *seat) {
170 seat_attachment_config_free(seat->attachments->items[i]); 178 seat_attachment_config_free(seat->attachments->items[i]);
171 } 179 }
172 list_free(seat->attachments); 180 list_free(seat->attachments);
181 free(seat->xcursor_theme.name);
173 free(seat); 182 free(seat);
174} 183}
175 184
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 @@
19#include "sway/ipc-server.h" 19#include "sway/ipc-server.h"
20#include "sway/layers.h" 20#include "sway/layers.h"
21#include "sway/output.h" 21#include "sway/output.h"
22#include "sway/server.h"
22#include "sway/tree/arrange.h" 23#include "sway/tree/arrange.h"
23#include "sway/tree/container.h" 24#include "sway/tree/container.h"
24#include "sway/tree/root.h" 25#include "sway/tree/root.h"
@@ -722,17 +723,72 @@ void seat_remove_device(struct sway_seat *seat,
722 seat_update_capabilities(seat); 723 seat_update_capabilities(seat);
723} 724}
724 725
726static bool xcursor_manager_is_named(const struct wlr_xcursor_manager *manager,
727 const char *name) {
728 return (!manager->name && !name) ||
729 (name && manager->name && strcmp(name, manager->name) == 0);
730}
731
725void seat_configure_xcursor(struct sway_seat *seat) { 732void seat_configure_xcursor(struct sway_seat *seat) {
726 // TODO configure theme and size 733 unsigned cursor_size = 24;
727 const char *cursor_theme = NULL; 734 const char *cursor_theme = NULL;
728 735
729 if (!seat->cursor->xcursor_manager) { 736 const struct seat_config *seat_config = seat_get_config(seat);
730 seat->cursor->xcursor_manager = 737 if (!seat_config) {
731 wlr_xcursor_manager_create(cursor_theme, 24); 738 seat_config = seat_get_config_by_name("*");
732 if (sway_assert(seat->cursor->xcursor_manager, 739 }
733 "Cannot create XCursor manager for theme")) { 740 if (seat_config) {
734 return; 741 cursor_size = seat_config->xcursor_theme.size;
742 cursor_theme = seat_config->xcursor_theme.name;
743 }
744
745 if (seat == input_manager_get_default_seat()) {
746 char cursor_size_fmt[16];
747 snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%d", cursor_size);
748 setenv("XCURSOR_SIZE", cursor_size_fmt, 1);
749 if (cursor_theme != NULL) {
750 setenv("XCURSOR_THEME", cursor_theme, 1);
735 } 751 }
752
753#if HAVE_XWAYLAND
754 if (!server.xwayland.xcursor_manager ||
755 !xcursor_manager_is_named(server.xwayland.xcursor_manager,
756 cursor_theme) ||
757 server.xwayland.xcursor_manager->size != cursor_size) {
758
759 wlr_xcursor_manager_destroy(server.xwayland.xcursor_manager);
760
761 server.xwayland.xcursor_manager =
762 wlr_xcursor_manager_create(cursor_theme, cursor_size);
763 sway_assert(server.xwayland.xcursor_manager,
764 "Cannot create XCursor manager for theme");
765
766 wlr_xcursor_manager_load(server.xwayland.xcursor_manager, 1);
767 struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
768 server.xwayland.xcursor_manager, "left_ptr", 1);
769 if (xcursor != NULL) {
770 struct wlr_xcursor_image *image = xcursor->images[0];
771 wlr_xwayland_set_cursor(
772 server.xwayland.wlr_xwayland, image->buffer,
773 image->width * 4, image->width, image->height,
774 image->hotspot_x, image->hotspot_y);
775 }
776 }
777#endif
778 }
779
780 /* Create xcursor manager if we don't have one already, or if the
781 * theme has changed */
782 if (!seat->cursor->xcursor_manager ||
783 !xcursor_manager_is_named(
784 seat->cursor->xcursor_manager, cursor_theme) ||
785 seat->cursor->xcursor_manager->size != cursor_size) {
786
787 wlr_xcursor_manager_destroy(seat->cursor->xcursor_manager);
788 seat->cursor->xcursor_manager =
789 wlr_xcursor_manager_create(cursor_theme, cursor_size);
790 sway_assert(seat->cursor->xcursor_manager,
791 "Cannot create XCursor manager for theme");
736 } 792 }
737 793
738 for (int i = 0; i < root->outputs->length; ++i) { 794 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(
89 'commands/seat/fallback.c', 89 'commands/seat/fallback.c',
90 'commands/seat/hide_cursor.c', 90 'commands/seat/hide_cursor.c',
91 'commands/seat/pointer_constraint.c', 91 'commands/seat/pointer_constraint.c',
92 'commands/seat/xcursor_theme.c',
92 'commands/set.c', 93 'commands/set.c',
93 'commands/show_marks.c', 94 'commands/show_marks.c',
94 'commands/smart_borders.c', 95 '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) {
168} 168}
169 169
170bool server_start(struct sway_server *server) { 170bool server_start(struct sway_server *server) {
171 // TODO: configurable cursor theme and size
172 int cursor_size = 24;
173 const char *cursor_theme = NULL;
174
175 char cursor_size_fmt[16];
176 snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), "%d", cursor_size);
177 setenv("XCURSOR_SIZE", cursor_size_fmt, 1);
178 if (cursor_theme != NULL) {
179 setenv("XCURSOR_THEME", cursor_theme, 1);
180 }
181
182#if HAVE_XWAYLAND 171#if HAVE_XWAYLAND
183 if (config->xwayland) { 172 if (config->xwayland) {
184 sway_log(SWAY_DEBUG, "Initializing Xwayland"); 173 sway_log(SWAY_DEBUG, "Initializing Xwayland");
@@ -193,17 +182,7 @@ bool server_start(struct sway_server *server) {
193 182
194 setenv("DISPLAY", server->xwayland.wlr_xwayland->display_name, true); 183 setenv("DISPLAY", server->xwayland.wlr_xwayland->display_name, true);
195 184
196 server->xwayland.xcursor_manager = 185 /* xcursor configured by the default seat */
197 wlr_xcursor_manager_create(cursor_theme, cursor_size);
198 wlr_xcursor_manager_load(server->xwayland.xcursor_manager, 1);
199 struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor(
200 server->xwayland.xcursor_manager, "left_ptr", 1);
201 if (xcursor != NULL) {
202 struct wlr_xcursor_image *image = xcursor->images[0];
203 wlr_xwayland_set_cursor(server->xwayland.wlr_xwayland, image->buffer,
204 image->width * 4, image->width, image->height, image->hotspot_x,
205 image->hotspot_y);
206 }
207 } 186 }
208#endif 187#endif
209 188
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.
206 by default) for the seat. This is primarily useful for video games. The 206 by default) for the seat. This is primarily useful for video games. The
207 "escape" command can be used at runtime to escape from a captured client. 207 "escape" command can be used at runtime to escape from a captured client.
208 208
209*seat* <name> xcursor_theme <theme> [<size>]
210 Override the system default XCursor theme. The default seat's
211 (_seat0_) theme is also used as the default cursor theme in
212 XWayland, and exported through the _XCURSOR_THEME_ and
213 _XCURSOR_SIZE_ environment variables.
214
209# SEE ALSO 215# SEE ALSO
210 216
211*sway*(5) *sway-output*(5) *xkeyboard-config*(7) 217*sway*(5) *sway-output*(5) *xkeyboard-config*(7)