From 796898519be183adcffd09f1dca71d13c376488f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 18 May 2024 13:48:17 +0200 Subject: [PATCH 01/32] build: disable wayland-protocols subproject tests by default --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 1043e4ba..1d143110 100644 --- a/meson.build +++ b/meson.build @@ -68,7 +68,7 @@ pcre2 = dependency('libpcre2-8') wayland_server = dependency('wayland-server', version: '>=1.21.0') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') -wayland_protos = dependency('wayland-protocols', version: '>=1.24') +wayland_protos = dependency('wayland-protocols', version: '>=1.24', default_options: ['tests=false']) xkbcommon = dependency('xkbcommon', version: '>=1.5.0') cairo = dependency('cairo') pango = dependency('pango') From fd3b643d15618fe608c8ed0fed0956d1e2526574 Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Sat, 18 May 2024 16:13:08 +0200 Subject: [PATCH 02/32] sway/config/output.c: fix null deref on output config If there's no config for the output, oc is null, but some screens might have a default rotation, causing the log call to dereference a null pointer. Signed-off-by: Anna (navi) Figueiredo Gomes --- sway/config/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/config/output.c b/sway/config/output.c index fb1956df..e7299459 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -448,7 +448,7 @@ static void queue_output_config(struct output_config *oc, #endif } if (wlr_output->transform != tr) { - sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr); + sway_log(SWAY_DEBUG, "Set %s transform to %d", wlr_output->name, tr); wlr_output_state_set_transform(pending, tr); } From 970415241497ceccfb013b6f8cb2395abee74e5c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 18 May 2024 14:02:14 +0200 Subject: [PATCH 03/32] build: drop xwayland option Instead of having a build-time option to enable/disable xwayland support, just use the wlroots build config: enable xwayland in Sway if it was enabled when building wlroots. I don't see any use-case for disabling xwayland in Sway when enabled in wlroots: Sway doesn't pull in any additional dependency (just pulls in dependencies that wlroots already needs). We have a config command to disable xwayland at runtime anyways. This makes it so xwayland behaves the same way as other features such as libinput backend and session support. This also reduces the build matrix (less combinations of build options). I think we originally introduced the xwayland option when we didn't have a good way to figure out the wlroots build config from the Sway build system. --- .builds/alpine.yml | 7 ++++++- include/sway/criteria.h | 2 +- include/sway/server.h | 6 +++--- include/sway/tree/root.h | 4 ++-- include/sway/tree/view.h | 13 +++++++------ meson.build | 12 ++---------- meson_options.txt | 1 - sway/commands/swap.c | 4 ++-- sway/commands/xwayland.c | 2 +- sway/criteria.c | 18 +++++++++--------- sway/desktop/transaction.c | 2 +- sway/input/cursor.c | 2 +- sway/input/seat.c | 4 ++-- sway/input/seatop_default.c | 8 ++++---- sway/ipc-json.c | 4 ++-- sway/meson.build | 2 +- sway/server.c | 8 ++++---- sway/tree/root.c | 2 +- sway/tree/view.c | 14 +++++++------- 19 files changed, 56 insertions(+), 59 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 59df7737..055e5ffa 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -38,9 +38,14 @@ tasks: cd sway ninja -C build - build-no-xwayland: | - cd sway + cd wlroots meson configure build -Dxwayland=disabled ninja -C build + sudo ninja -C build install + + cd ../sway + meson configure build --clearcache + ninja -C build - build-static: | cd sway mkdir subprojects diff --git a/include/sway/criteria.h b/include/sway/criteria.h index 8da345ea..758d70ed 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -36,7 +36,7 @@ struct criteria { struct pattern *app_id; struct pattern *con_mark; uint32_t con_id; // internal ID -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct pattern *class; uint32_t id; // X11 window ID struct pattern *instance; diff --git a/include/sway/server.h b/include/sway/server.h index c71851f6..90f187fd 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -5,7 +5,7 @@ #include "config.h" #include "list.h" #include "sway/desktop/idle_inhibit_v1.h" -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND #include "sway/xwayland.h" #endif @@ -59,7 +59,7 @@ struct sway_server { struct wlr_tablet_manager_v2 *tablet_v2; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct sway_xwayland xwayland; struct wl_listener xwayland_surface; struct wl_listener xwayland_ready; @@ -165,7 +165,7 @@ void sway_session_lock_add_output(struct sway_session_lock *lock, bool sway_session_lock_has_surface(struct sway_session_lock *lock, struct wlr_surface *surface); void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data); -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND void handle_xwayland_surface(struct wl_listener *listener, void *data); #endif void handle_server_decoration(struct wl_listener *listener, void *data); diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index 15df0f55..7de0abcd 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -2,12 +2,12 @@ #define _SWAY_ROOT_H #include #include +#include #include #include #include #include "sway/tree/container.h" #include "sway/tree/node.h" -#include "config.h" #include "list.h" extern struct sway_root *root; @@ -47,7 +47,7 @@ struct sway_root { struct wlr_scene_tree *shell_top; struct wlr_scene_tree *fullscreen; struct wlr_scene_tree *fullscreen_global; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct wlr_scene_tree *unmanaged; #endif struct wlr_scene_tree *shell_overlay; diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 7faacdcc..3ae8cf22 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -1,10 +1,11 @@ #ifndef _SWAY_VIEW_H #define _SWAY_VIEW_H #include +#include #include #include #include "sway/config.h" -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND #include #endif #include "sway/input/input-manager.h" @@ -15,7 +16,7 @@ struct sway_xdg_decoration; enum sway_view_type { SWAY_VIEW_XDG_SHELL, -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND SWAY_VIEW_XWAYLAND, #endif }; @@ -27,7 +28,7 @@ enum sway_view_prop { VIEW_PROP_INSTANCE, VIEW_PROP_WINDOW_TYPE, VIEW_PROP_WINDOW_ROLE, -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND VIEW_PROP_X11_WINDOW_ID, VIEW_PROP_X11_PARENT_ID, #endif @@ -98,7 +99,7 @@ struct sway_view { union { struct wlr_xdg_toplevel *wlr_xdg_toplevel; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct wlr_xwayland_surface *wlr_xwayland_surface; #endif }; @@ -127,7 +128,7 @@ struct sway_xdg_shell_view { struct wl_listener unmap; struct wl_listener destroy; }; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct sway_xwayland_view { struct sway_view view; @@ -293,7 +294,7 @@ void view_center_and_clip_surface(struct sway_view *view); struct sway_view *view_from_wlr_xdg_surface( struct wlr_xdg_surface *xdg_surface); -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct sway_view *view_from_wlr_xwayland_surface( struct wlr_xwayland_surface *xsurface); #endif diff --git a/meson.build b/meson.build index 1d143110..3c444e07 100644 --- a/meson.build +++ b/meson.build @@ -57,10 +57,6 @@ foreach name, _ : wlroots_features wlroots_features += { name: have } endforeach -if get_option('xwayland').enabled() and not wlroots_features['xwayland'] - error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support') -endif - null_dep = dependency('', required: false) jsonc = dependency('json-c', version: '>=0.13') @@ -77,16 +73,14 @@ gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) pixman = dependency('pixman-1') libevdev = dependency('libevdev') libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep -xcb = dependency('xcb', required: get_option('xwayland')) +xcb = wlroots_features['xwayland'] ? dependency('xcb') : null_dep drm = dependency('libdrm') libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_dep math = cc.find_library('m') rt = cc.find_library('rt') -xcb_icccm = dependency('xcb-icccm', required: get_option('xwayland')) +xcb_icccm = wlroots_features['xwayland'] ? dependency('xcb-icccm') : null_dep threads = dependency('threads') # for pthread_setschedparam -have_xwayland = xcb.found() and xcb_icccm.found() and wlroots_features['xwayland'] - if get_option('sd-bus-provider') == 'auto' if not get_option('tray').disabled() assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto') @@ -110,7 +104,6 @@ have_tray = (not get_option('tray').disabled()) and tray_deps_found conf_data = configuration_data() -conf_data.set10('HAVE_XWAYLAND', have_xwayland) conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found()) conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd') conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind') @@ -271,7 +264,6 @@ endif subdir('completions') summary({ - 'xwayland': have_xwayland, 'gdk-pixbuf': gdk_pixbuf.found(), 'tray': have_tray, 'man-pages': scdoc.found(), diff --git a/meson_options.txt b/meson_options.txt index 8d0d6509..506ecc9a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,7 +4,6 @@ option('bash-completions', type: 'boolean', value: true, description: 'Install b option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions.') option('swaybar', type: 'boolean', value: true, description: 'Enable support for swaybar') option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag') -option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray') option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybar tray') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') diff --git a/sway/commands/swap.c b/sway/commands/swap.c index e142eede..c0b0d0b9 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -18,7 +18,7 @@ static bool test_con_id(struct sway_container *container, void *data) { return container->node.id == *con_id; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND static bool test_id(struct sway_container *container, void *data) { xcb_window_t *wid = data; return (container->view && container->view->type == SWAY_VIEW_XWAYLAND @@ -53,7 +53,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { char *value = join_args(argv + 3, argc - 3); if (strcasecmp(argv[2], "id") == 0) { -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND xcb_window_t id = strtol(value, NULL, 0); other = root_find_container(test_id, &id); #endif diff --git a/sway/commands/xwayland.c b/sway/commands/xwayland.c index 584a8e3a..c0b175fc 100644 --- a/sway/commands/xwayland.c +++ b/sway/commands/xwayland.c @@ -10,7 +10,7 @@ struct cmd_results *cmd_xwayland(int argc, char **argv) { return error; } -#ifdef HAVE_XWAYLAND +#ifdef WLR_HAS_XWAYLAND enum xwayland_mode xwayland; if (strcmp(argv[0], "force") == 0) { xwayland = XWAYLAND_MODE_IMMEDIATE; diff --git a/sway/criteria.c b/sway/criteria.c index e16b4fa8..13f0530e 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -22,7 +22,7 @@ bool criteria_is_empty(struct criteria *criteria) { && !criteria->app_id && !criteria->con_mark && !criteria->con_id -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND && !criteria->class && !criteria->id && !criteria->instance @@ -90,7 +90,7 @@ void criteria_destroy(struct criteria *criteria) { pattern_destroy(criteria->title); pattern_destroy(criteria->shell); pattern_destroy(criteria->app_id); -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND pattern_destroy(criteria->class); pattern_destroy(criteria->instance); pattern_destroy(criteria->window_role); @@ -110,7 +110,7 @@ static int regex_cmp(const char *item, const pcre2_code *regex) { return result; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND static bool view_has_window_type(struct sway_view *view, enum atom_name name) { if (view->type != SWAY_VIEW_XWAYLAND) { return false; @@ -251,7 +251,7 @@ static bool criteria_matches_view(struct criteria *criteria, return false; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND if (criteria->id) { // X11 window ID uint32_t x11_window_id = view_get_x11_window_id(view); if (!x11_window_id || x11_window_id != criteria->id) { @@ -428,7 +428,7 @@ list_t *criteria_get_containers(struct criteria *criteria) { return matches; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND static enum atom_name parse_window_type(const char *type) { if (strcasecmp(type, "normal") == 0) { return NET_WM_WINDOW_TYPE_NORMAL; @@ -461,7 +461,7 @@ enum criteria_token { T_CON_ID, T_CON_MARK, T_FLOATING, -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND T_CLASS, T_ID, T_INSTANCE, @@ -487,7 +487,7 @@ static enum criteria_token token_from_name(char *name) { return T_CON_ID; } else if (strcmp(name, "con_mark") == 0) { return T_CON_MARK; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND } else if (strcmp(name, "class") == 0) { return T_CLASS; } else if (strcmp(name, "id") == 0) { @@ -566,7 +566,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) { case T_CON_MARK: pattern_create(&criteria->con_mark, value); break; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND case T_CLASS: pattern_create(&criteria->class, value); break; @@ -674,7 +674,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) { ++head; struct criteria *criteria = calloc(1, sizeof(struct criteria)); -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND criteria->window_type = ATOM_LAST; // default value #endif char *name = NULL, *value = NULL; diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 042141ab..e464ff1a 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -761,7 +761,7 @@ static bool should_configure(struct sway_node *node, } struct sway_container_state *cstate = &node->sway_container->current; struct sway_container_state *istate = &instruction->container_state; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND // Xwayland views are position-aware and need to be reconfigured // when their position changes. if (node->sway_container->view->type == SWAY_VIEW_XWAYLAND) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 3d04826c..0b4a36d9 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -107,7 +107,7 @@ struct sway_node *node_at_coords( return NULL; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND if (scene_descriptor_try_get(current, SWAY_SCENE_DESC_XWAYLAND_UNMANAGED)) { return NULL; } diff --git a/sway/input/seat.c b/sway/input/seat.c index 0c5672bc..da4bb12a 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -190,7 +190,7 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) { node->sway_container->view : NULL; if (view && seat_is_input_allowed(seat, view->surface)) { -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND if (view->type == SWAY_VIEW_XWAYLAND) { struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; wlr_xwayland_set_seat(xwayland, seat->wlr_seat); @@ -1002,7 +1002,7 @@ void seat_configure_xcursor(struct sway_seat *seat) { setenv("XCURSOR_THEME", cursor_theme, 1); } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND if (server.xwayland.wlr_xwayland && (!server.xwayland.xcursor_manager || !xcursor_manager_is_named(server.xwayland.xcursor_manager, cursor_theme) || diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index 0c6f7c5e..e01fa933 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -15,7 +15,7 @@ #include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "log.h" -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND #include "sway/xwayland.h" #endif @@ -234,7 +234,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, node->sway_container : NULL; struct wlr_layer_surface_v1 *layer; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct wlr_xwayland_surface *xsurface; #endif if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface)) && @@ -268,7 +268,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, seat_set_focus_container(seat, cont); seatop_begin_down(seat, node->sway_container, sx, sy); } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND // Handle tapping on an xwayland unmanaged view else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) && xsurface->override_redirect && @@ -514,7 +514,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, return; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND // Handle clicking on xwayland unmanaged view struct wlr_xwayland_surface *xsurface; if (surface && diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 81ca3483..b7370aa6 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -154,7 +154,7 @@ static json_object *ipc_json_output_mode_description( return mode_object; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND static const char *ipc_json_xwindow_type_description(struct sway_view *view) { struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; struct sway_xwayland *xwayland = &server.xwayland; @@ -633,7 +633,7 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_new_string(ipc_json_content_type_description(content_type))); } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND if (c->view->type == SWAY_VIEW_XWAYLAND) { json_object_object_add(object, "window", json_object_new_int(view_get_x11_window_id(c->view))); diff --git a/sway/meson.build b/sway/meson.build index d937e425..47b51d0c 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -231,7 +231,7 @@ sway_deps = [ xcb_icccm, ] -if have_xwayland +if wlroots_features['xwayland'] sway_sources += 'desktop/xwayland.c' endif diff --git a/sway/server.c b/sway/server.c index 180d3a6b..4b48e8e5 100644 --- a/sway/server.c +++ b/sway/server.c @@ -56,7 +56,7 @@ #include "sway/input/cursor.h" #include "sway/tree/root.h" -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND #include #include "sway/xwayland.h" #endif @@ -118,7 +118,7 @@ static bool is_privileged(const struct wl_global *global) { static bool filter_global(const struct wl_client *client, const struct wl_global *global, void *data) { -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; if (xwayland && global == xwayland->shell_v1->global) { return xwayland->server != NULL && client == xwayland->server->client; @@ -437,7 +437,7 @@ bool server_init(struct sway_server *server) { void server_fini(struct sway_server *server) { // TODO: free sway-specific resources -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND wlr_xwayland_destroy(server->xwayland.wlr_xwayland); #endif wl_display_destroy_clients(server->wl_display); @@ -447,7 +447,7 @@ void server_fini(struct sway_server *server) { } bool server_start(struct sway_server *server) { -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND if (config->xwayland != XWAYLAND_MODE_DISABLED) { sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)", config->xwayland == XWAYLAND_MODE_LAZY); diff --git a/sway/tree/root.c b/sway/tree/root.c index ae3c3cb2..20fcfa59 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -53,7 +53,7 @@ struct sway_root *root_create(struct wl_display *wl_display) { root->layers.shell_top = alloc_scene_tree(root->layer_tree, &failed); root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed); root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed); -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND root->layers.unmanaged = alloc_scene_tree(root->layer_tree, &failed); #endif root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed); diff --git a/sway/tree/view.c b/sway/tree/view.c index 35b4b73f..9a87d9e2 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -9,8 +10,7 @@ #include #include #include -#include "config.h" -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND #include #endif #include "list.h" @@ -126,7 +126,7 @@ const char *view_get_instance(struct sway_view *view) { } return NULL; } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND uint32_t view_get_x11_window_id(struct sway_view *view) { if (view->impl->get_int_prop) { return view->impl->get_int_prop(view, VIEW_PROP_X11_WINDOW_ID); @@ -159,7 +159,7 @@ const char *view_get_shell(struct sway_view *view) { switch(view->type) { case SWAY_VIEW_XDG_SHELL: return "xdg_shell"; -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND case SWAY_VIEW_XWAYLAND: return "xwayland"; #endif @@ -499,7 +499,7 @@ void view_execute_criteria(struct sway_view *view) { static void view_populate_pid(struct sway_view *view) { pid_t pid; switch (view->type) { -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND case SWAY_VIEW_XWAYLAND:; struct wlr_xwayland_surface *surf = wlr_xwayland_surface_try_from_wlr_surface(view->surface); @@ -838,7 +838,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, bool set_focus = should_focus(view); -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct wlr_xwayland_surface *xsurface; if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) { set_focus &= wlr_xwayland_icccm_input_model(xsurface) != @@ -954,7 +954,7 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(wlr_surface))) { return view_from_wlr_xdg_surface(xdg_surface); } -#if HAVE_XWAYLAND +#if WLR_HAS_XWAYLAND struct wlr_xwayland_surface *xsurface; if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) { return view_from_wlr_xwayland_surface(xsurface); From a168b2029932d2a76341d91b3c6d8463de568213 Mon Sep 17 00:00:00 2001 From: thal Date: Sat, 2 Mar 2024 17:17:51 -0600 Subject: [PATCH 04/32] tree/view: Do not clip to geometry if using CSD If a floating window is using CSD, the geometry should not be used to define the clipping region. Otherwise drop shadows and such may be clipped excessively. --- sway/tree/view.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index 9a87d9e2..1c1c8ee8 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -927,11 +927,14 @@ void view_update_size(struct sway_view *view) { void view_center_and_clip_surface(struct sway_view *view) { struct sway_container *con = view->container; + bool clip_to_geometry = true; + if (container_is_floating(con)) { // We always center the current coordinates rather than the next, as the // geometry immediately affects the currently active rendering. int x = (int) fmax(0, (con->current.content_width - view->geometry.width) / 2); int y = (int) fmax(0, (con->current.content_height - view->geometry.height) / 2); + clip_to_geometry = !view->using_csd; wlr_scene_node_set_position(&view->content_tree->node, x, y); } else { @@ -940,12 +943,16 @@ void view_center_and_clip_surface(struct sway_view *view) { // only make sure to clip the content if there is content to clip if (!wl_list_empty(&con->view->content_tree->children)) { - wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &(struct wlr_box){ - .x = con->view->geometry.x, - .y = con->view->geometry.y, - .width = con->current.content_width, - .height = con->current.content_height, - }); + struct wlr_box clip = {0}; + if (clip_to_geometry) { + clip = (struct wlr_box){ + .x = con->view->geometry.x, + .y = con->view->geometry.y, + .width = con->current.content_width, + .height = con->current.content_height, + }; + } + wlr_scene_subsurface_tree_set_clip(&con->view->content_tree->node, &clip); } } From 700f4805bc3ca86b3c2a46aa96bcee9d8e20f599 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 24 May 2024 23:49:32 +0200 Subject: [PATCH 05/32] server: hide xdg_output from unprivileged clients Regular Wayland clients shouldn't care about the position or size of outputs. Hide xdg_output from unprivileged clients to make sure they're not doing shenanigans with this information. --- include/sway/server.h | 2 ++ sway/server.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/sway/server.h b/include/sway/server.h index 90f187fd..3a63df34 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -81,6 +81,8 @@ struct sway_server { struct wlr_pointer_constraints_v1 *pointer_constraints; struct wl_listener pointer_constraint; + struct wlr_xdg_output_manager_v1 *xdg_output_manager_v1; + struct wlr_output_manager_v1 *output_manager_v1; struct wl_listener output_manager_apply; struct wl_listener output_manager_test; diff --git a/sway/server.c b/sway/server.c index 4b48e8e5..edbc1a4b 100644 --- a/sway/server.c +++ b/sway/server.c @@ -113,7 +113,8 @@ static bool is_privileged(const struct wl_global *global) { global == server.input->keyboard_shortcuts_inhibit->global || global == server.input->virtual_keyboard->global || global == server.input->virtual_pointer->global || - global == server.input->transient_seat_manager->global; + global == server.input->transient_seat_manager->global || + global == server.xdg_output_manager_v1->global; } static bool filter_global(const struct wl_client *client, @@ -275,7 +276,8 @@ bool server_init(struct sway_server *server) { wl_signal_add(&root->output_layout->events.change, &server->output_layout_change); - wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); + server->xdg_output_manager_v1 = + wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); sway_idle_inhibit_manager_v1_init(); From df69367d927e6d4fde70d61611c9317b70537261 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 24 May 2024 23:53:46 +0200 Subject: [PATCH 06/32] input/text_input: ensure keyboard is set before sending modifiers Clients get confused when modifier events are sent before the keymap. --- sway/input/text_input.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sway/input/text_input.c b/sway/input/text_input.c index c38a3bb2..ba8c0b99 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -66,11 +66,13 @@ static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void * struct sway_input_method_relay *relay = wl_container_of(listener, relay, input_method_keyboard_grab_destroy); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; + struct wlr_seat *wlr_seat = keyboard_grab->input_method->seat; wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); if (keyboard_grab->keyboard) { // send modifier state to original client - wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, + wlr_seat_set_keyboard(wlr_seat, keyboard_grab->keyboard); + wlr_seat_keyboard_notify_modifiers(wlr_seat, &keyboard_grab->keyboard->modifiers); } } From d0bd591ee70b706182b6bfff45a68bc5404ea89b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 25 May 2024 00:02:48 +0200 Subject: [PATCH 07/32] Drop server.h include from input/input-manager.h The only reason it's included there is for a declaration of struct sway_server, but we can just forward-declare it. This avoids rebuilding almost all of Sway when touching server.h. All other server.h includes are from source files, not headers. --- include/sway/criteria.h | 4 ++++ include/sway/input/input-manager.h | 3 ++- sway/commands/input/events.c | 1 + sway/commands/input/xkb_switch_layout.c | 1 + sway/commands/move.c | 1 + sway/commands/seat/cursor.c | 1 + sway/commands/seat/pointer_constraint.c | 1 + sway/commands/seat/shortcuts_inhibitor.c | 1 + sway/commands/shortcuts_inhibitor.c | 1 + sway/config.c | 1 + sway/config/bar.c | 1 + sway/config/input.c | 1 + sway/config/output.c | 1 + sway/criteria.c | 1 + sway/desktop/launcher.c | 1 + sway/desktop/transaction.c | 1 + sway/input/cursor.c | 1 + sway/input/keyboard.c | 1 + sway/input/seatop_default.c | 1 + sway/input/switch.c | 1 + sway/input/tablet.c | 1 + sway/input/text_input.c | 2 ++ sway/ipc-json.c | 1 + sway/tree/workspace.c | 1 + 24 files changed, 29 insertions(+), 1 deletion(-) diff --git a/include/sway/criteria.h b/include/sway/criteria.h index 758d70ed..ae546821 100644 --- a/include/sway/criteria.h +++ b/include/sway/criteria.h @@ -7,6 +7,10 @@ #include "list.h" #include "tree/view.h" +#if WLR_HAS_XWAYLAND +#include "sway/xwayland.h" +#endif + enum criteria_type { CT_COMMAND = 1 << 0, CT_ASSIGN_OUTPUT = 1 << 1, diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 45c75199..b014e18f 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -5,10 +5,11 @@ #include #include #include -#include "sway/server.h" #include "sway/config.h" #include "list.h" +struct sway_server; + struct sway_input_device { char *identifier; struct wlr_input_device *wlr_device; diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c index 08d99bf0..3cea026e 100644 --- a/sway/commands/input/events.c +++ b/sway/commands/input/events.c @@ -5,6 +5,7 @@ #include "sway/config.h" #include "sway/commands.h" #include "sway/input/input-manager.h" +#include "sway/server.h" #include "log.h" #if WLR_HAS_LIBINPUT_BACKEND diff --git a/sway/commands/input/xkb_switch_layout.c b/sway/commands/input/xkb_switch_layout.c index ecac8e6c..8d600fca 100644 --- a/sway/commands/input/xkb_switch_layout.c +++ b/sway/commands/input/xkb_switch_layout.c @@ -3,6 +3,7 @@ #include "sway/config.h" #include "sway/commands.h" #include "sway/input/input-manager.h" +#include "sway/server.h" #include "log.h" struct xkb_switch_layout_action { diff --git a/sway/commands/move.c b/sway/commands/move.c index 8addf26e..ff656cfb 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -11,6 +11,7 @@ #include "sway/input/seat.h" #include "sway/ipc-server.h" #include "sway/output.h" +#include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/root.h" diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index df7c379d..434e6bbb 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -5,6 +5,7 @@ #include #include "sway/commands.h" #include "sway/input/cursor.h" +#include "sway/server.h" static struct cmd_results *press_or_release(struct sway_cursor *cursor, char *action, char *button_str); diff --git a/sway/commands/seat/pointer_constraint.c b/sway/commands/seat/pointer_constraint.c index 3890ebde..38f85bcd 100644 --- a/sway/commands/seat/pointer_constraint.c +++ b/sway/commands/seat/pointer_constraint.c @@ -4,6 +4,7 @@ #include "sway/config.h" #include "sway/input/cursor.h" #include "sway/input/seat.h" +#include "sway/server.h" enum operation { OP_ENABLE, diff --git a/sway/commands/seat/shortcuts_inhibitor.c b/sway/commands/seat/shortcuts_inhibitor.c index 7c7f99cf..df68618d 100644 --- a/sway/commands/seat/shortcuts_inhibitor.c +++ b/sway/commands/seat/shortcuts_inhibitor.c @@ -2,6 +2,7 @@ #include "sway/commands.h" #include "sway/input/seat.h" #include "sway/input/input-manager.h" +#include "sway/server.h" #include "util.h" static struct cmd_results *handle_action(struct seat_config *sc, diff --git a/sway/commands/shortcuts_inhibitor.c b/sway/commands/shortcuts_inhibitor.c index ffa1a5c9..2dfd1b9f 100644 --- a/sway/commands/shortcuts_inhibitor.c +++ b/sway/commands/shortcuts_inhibitor.c @@ -3,6 +3,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/input/seat.h" +#include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/view.h" diff --git a/sway/config.c b/sway/config.c index f9131e0f..5058efcc 100644 --- a/sway/config.c +++ b/sway/config.c @@ -23,6 +23,7 @@ #include "sway/config.h" #include "sway/criteria.h" #include "sway/desktop/transaction.h" +#include "sway/server.h" #include "sway/swaynag.h" #include "sway/tree/arrange.h" #include "sway/tree/root.h" diff --git a/sway/config/bar.c b/sway/config/bar.c index 908b2865..ecefb61a 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -12,6 +12,7 @@ #include "sway/config.h" #include "sway/input/keyboard.h" #include "sway/output.h" +#include "sway/server.h" #include "config.h" #include "list.h" #include "log.h" diff --git a/sway/config/input.c b/sway/config/input.c index de3b21ed..613270df 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -3,6 +3,7 @@ #include #include "sway/config.h" #include "sway/input/keyboard.h" +#include "sway/server.h" #include "log.h" struct input_config *new_input_config(const char* identifier) { diff --git a/sway/config/output.c b/sway/config/output.c index e7299459..9a447388 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -13,6 +13,7 @@ #include "sway/config.h" #include "sway/input/cursor.h" #include "sway/output.h" +#include "sway/server.h" #include "sway/tree/root.h" #include "log.h" #include "util.h" diff --git a/sway/criteria.c b/sway/criteria.c index 13f0530e..2b7290c0 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -7,6 +7,7 @@ #include "sway/criteria.h" #include "sway/tree/container.h" #include "sway/config.h" +#include "sway/server.h" #include "sway/tree/root.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" diff --git a/sway/desktop/launcher.c b/sway/desktop/launcher.c index 28043d19..2362e1ba 100644 --- a/sway/desktop/launcher.c +++ b/sway/desktop/launcher.c @@ -4,6 +4,7 @@ #include "sway/input/seat.h" #include "sway/output.h" #include "sway/desktop/launcher.h" +#include "sway/server.h" #include "sway/tree/node.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index e464ff1a..d1898843 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -10,6 +10,7 @@ #include "sway/input/cursor.h" #include "sway/input/input-manager.h" #include "sway/output.h" +#include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/node.h" #include "sway/tree/view.h" diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 0b4a36d9..235951d4 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -25,6 +25,7 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/scene_descriptor.h" +#include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/root.h" #include "sway/tree/view.h" diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index f74d0658..9ac21664 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -13,6 +13,7 @@ #include "sway/input/seat.h" #include "sway/input/cursor.h" #include "sway/ipc-server.h" +#include "sway/server.h" #include "log.h" #if WLR_HAS_SESSION diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index e01fa933..f4a0f463 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c @@ -11,6 +11,7 @@ #include "sway/input/tablet.h" #include "sway/layers.h" #include "sway/output.h" +#include "sway/server.h" #include "sway/scene_descriptor.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" diff --git a/sway/input/switch.c b/sway/input/switch.c index 831f4dbf..6aab4ad0 100644 --- a/sway/input/switch.c +++ b/sway/input/switch.c @@ -1,5 +1,6 @@ #include "sway/config.h" #include "sway/input/switch.h" +#include "sway/server.h" #include "log.h" struct sway_switch *sway_switch_create(struct sway_seat *seat, diff --git a/sway/input/tablet.c b/sway/input/tablet.c index 2863642a..ec1e4f68 100644 --- a/sway/input/tablet.c +++ b/sway/input/tablet.c @@ -7,6 +7,7 @@ #include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/input/tablet.h" +#include "sway/server.h" #if WLR_HAS_LIBINPUT_BACKEND #include diff --git a/sway/input/text_input.c b/sway/input/text_input.c index ba8c0b99..580a9f54 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -9,6 +9,8 @@ #include "sway/input/text_input.h" #include "sway/input/text_input_popup.h" #include "sway/layers.h" +#include "sway/server.h" + static void input_popup_update(struct sway_input_popup *popup); static struct sway_text_input *relay_get_focusable_text_input( diff --git a/sway/ipc-json.c b/sway/ipc-json.c index b7370aa6..1ee39124 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -11,6 +11,7 @@ #include "log.h" #include "sway/config.h" #include "sway/ipc-json.h" +#include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index a68dc927..52e48ad5 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -10,6 +10,7 @@ #include "sway/input/seat.h" #include "sway/ipc-server.h" #include "sway/output.h" +#include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" #include "sway/tree/node.h" From 2e9139df664f1e2dbe14b5df4a9646411b924c66 Mon Sep 17 00:00:00 2001 From: Violet Purcell Date: Sun, 17 Mar 2024 13:27:34 -0400 Subject: [PATCH 08/32] Update for versioned wlroots files References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4614 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3c444e07..eb66506a 100644 --- a/meson.build +++ b/meson.build @@ -45,7 +45,7 @@ subproject( required: false, version: wlroots_version, ) -wlroots = dependency('wlroots', version: wlroots_version) +wlroots = dependency('wlroots-0.18', version: wlroots_version, fallback: 'wlroots') wlroots_features = { 'xwayland': false, 'libinput_backend': false, From 40ca4150b27a5b94938b6c3d744f74bb26d347f7 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Mon, 17 Jul 2023 21:40:28 -0400 Subject: [PATCH 09/32] sway/commands/output: Add command to set color profile This makes it possible to render output buffers in a different color space, by specifying an ICC profile for the output. --- .builds/alpine.yml | 1 + .builds/archlinux.yml | 1 + .builds/freebsd.yml | 1 + include/sway/commands.h | 1 + include/sway/config.h | 3 + include/sway/output.h | 2 + sway/commands/output.c | 1 + sway/commands/output/color_profile.c | 101 +++++++++++++++++++++++++++ sway/config/output.c | 18 +++++ sway/desktop/output.c | 5 +- sway/meson.build | 1 + sway/sway-output.5.scd | 12 ++++ sway/tree/output.c | 1 + 13 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 sway/commands/output/color_profile.c diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 055e5ffa..7a1fa58e 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -4,6 +4,7 @@ packages: - eudev-dev - gdk-pixbuf-dev - json-c-dev + - lcms2-dev - libdisplay-info-dev - libevdev-dev - libinput-dev diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 9972c01a..e249571e 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -3,6 +3,7 @@ packages: - cairo - gdk-pixbuf2 - json-c + - lcms2 - libdisplay-info - libegl - libinput diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 29c6312a..8084574c 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -8,6 +8,7 @@ packages: - devel/pkgconf - graphics/cairo - graphics/gdk-pixbuf2 +- graphics/lcms2 - graphics/wayland - graphics/wayland-protocols - textproc/scdoc diff --git a/include/sway/commands.h b/include/sway/commands.h index 27058587..0a9fdc70 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -283,6 +283,7 @@ sway_cmd input_cmd_xkb_variant; sway_cmd output_cmd_adaptive_sync; sway_cmd output_cmd_background; +sway_cmd output_cmd_color_profile; sway_cmd output_cmd_disable; sway_cmd output_cmd_dpms; sway_cmd output_cmd_enable; diff --git a/include/sway/config.h b/include/sway/config.h index 5ccc3e77..3e3a104e 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include "../include/config.h" @@ -285,6 +286,8 @@ struct output_config { int max_render_time; // In milliseconds int adaptive_sync; enum render_bit_depth render_bit_depth; + bool set_color_transform; + struct wlr_color_transform *color_transform; char *background; char *background_option; diff --git a/include/sway/output.h b/include/sway/output.h index d546d488..2189c6e8 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -66,6 +66,8 @@ struct sway_output { struct wl_signal disable; } events; + struct wlr_color_transform *color_transform; + struct timespec last_presentation; uint32_t refresh_nsec; int max_render_time; // In milliseconds diff --git a/sway/commands/output.c b/sway/commands/output.c index 5e5d31b3..b822e770 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -10,6 +10,7 @@ static const struct cmd_handler output_handlers[] = { { "adaptive_sync", output_cmd_adaptive_sync }, { "background", output_cmd_background }, { "bg", output_cmd_background }, + { "color_profile", output_cmd_color_profile }, { "disable", output_cmd_disable }, { "dpms", output_cmd_dpms }, { "enable", output_cmd_enable }, diff --git a/sway/commands/output/color_profile.c b/sway/commands/output/color_profile.c new file mode 100644 index 00000000..792bd55f --- /dev/null +++ b/sway/commands/output/color_profile.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include "sway/commands.h" +#include "sway/config.h" + +static bool read_file_into_buf(const char *path, void **buf, size_t *size) { + /* Why not use fopen/fread directly? glibc will succesfully open directories, + * not just files, and supports seeking on them. Instead, we directly + * work with file descriptors and use the more consistent open/fstat/read. */ + int fd = open(path, O_RDONLY | O_NOCTTY | O_CLOEXEC); + if (fd == -1) { + return false; + } + char *b = NULL; + struct stat info; + if (fstat(fd, &info) == -1) { + goto fail; + } + // only regular files, to avoid issues with e.g. opening pipes + if (!S_ISREG(info.st_mode)) { + goto fail; + } + off_t s = info.st_size; + if (s <= 0) { + goto fail; + } + b = calloc(1, s); + if (!b) { + goto fail; + } + size_t nread = 0; + while (nread < (size_t)s) { + size_t to_read = (size_t)s - nread; + ssize_t r = read(fd, b + nread, to_read); + if ((r == -1 && errno != EINTR) || r == 0) { + goto fail; + } + nread += (size_t)r; + } + close(fd); + *buf = b; + *size = (size_t)s; + return true; // success +fail: + free(b); + close(fd); + return false; +} + +struct cmd_results *output_cmd_color_profile(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 color_profile first argument."); + } + + if (strcmp(*argv, "srgb") == 0) { + wlr_color_transform_unref(config->handler_context.output_config->color_transform); + config->handler_context.output_config->color_transform = NULL; + config->handler_context.output_config->set_color_transform = true; + + config->handler_context.leftovers.argc = argc - 1; + config->handler_context.leftovers.argv = argv + 1; + } else if (strcmp(*argv, "icc") == 0) { + if (argc < 2) { + return cmd_results_new(CMD_INVALID, + "Invalid color profile specification: icc type requires a file"); + } + void *data = NULL; + size_t size = 0; + if (!read_file_into_buf(argv[1], &data, &size)) { + return cmd_results_new(CMD_FAILURE, + "Failed to load color profile: could not read ICC file"); + } + + struct wlr_color_transform *tmp = + wlr_color_transform_init_linear_to_icc(data, size); + if (!tmp) { + free(data); + return cmd_results_new(CMD_FAILURE, + "Failed to load color profile: failed to initialize transform from ICC"); + } + free(data); + + wlr_color_transform_unref(config->handler_context.output_config->color_transform); + config->handler_context.output_config->color_transform = tmp; + config->handler_context.output_config->set_color_transform = true; + + config->handler_context.leftovers.argc = argc - 2; + config->handler_context.leftovers.argv = argv + 2; + } else { + return cmd_results_new(CMD_INVALID, + "Invalid color profile specification: first argument should be icc|srgb"); + } + + return NULL; +} diff --git a/sway/config/output.c b/sway/config/output.c index 9a447388..bcd21b9b 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -76,6 +76,8 @@ 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->set_color_transform = false; + oc->color_transform = NULL; oc->power = -1; return oc; } @@ -191,6 +193,14 @@ static void merge_output_config(struct output_config *dst, struct output_config if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { dst->render_bit_depth = src->render_bit_depth; } + if (src->set_color_transform) { + if (src->color_transform) { + wlr_color_transform_ref(src->color_transform); + } + wlr_color_transform_unref(dst->color_transform); + dst->set_color_transform = true; + dst->color_transform = src->color_transform; + } if (src->background) { free(dst->background); dst->background = strdup(src->background); @@ -557,6 +567,13 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output output->max_render_time = oc->max_render_time; } + if (oc && oc->set_color_transform) { + if (oc->color_transform) { + wlr_color_transform_ref(oc->color_transform); + } + wlr_color_transform_unref(output->color_transform); + output->color_transform = oc->color_transform; + } return true; } @@ -997,6 +1014,7 @@ void free_output_config(struct output_config *oc) { free(oc->name); free(oc->background); free(oc->background_option); + wlr_color_transform_unref(oc->color_transform); free(oc); } diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 2722e556..cfa53021 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -269,7 +269,10 @@ static int output_repaint_timer_handler(void *data) { return 0; } - wlr_scene_output_commit(output->scene_output, NULL); + struct wlr_scene_output_state_options opts = { + .color_transform = output->color_transform, + }; + wlr_scene_output_commit(output->scene_output, &opts); return 0; } diff --git a/sway/meson.build b/sway/meson.build index 47b51d0c..a189fe9a 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -202,6 +202,7 @@ sway_sources = files( 'commands/output/toggle.c', 'commands/output/transform.c', 'commands/output/unplug.c', + 'commands/output/color_profile.c', 'tree/arrange.c', 'tree/container.c', diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 7d088d5d..6d7c0860 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -178,6 +178,18 @@ must be separated by one space. For example: updated to work with different bit depths. This command is experimental, and may be removed or changed in the future. +*output* color_profile srgb|[icc ] + Sets the color profile for an output. The default is _srgb_. should be a + path to a display ICC profile. + + Not all renderers support this feature; currently it only works with the + the Vulkan renderer. Even where supported, the application of the color + profile may be inaccurate. + + This command is experimental, and may be removed or changed in the future. It + may have no effect or produce unexpected output when used together with future + HDR support features. + # SEE ALSO *sway*(5) *sway-input*(5) diff --git a/sway/tree/output.c b/sway/tree/output.c index 2d11195e..6c8dd6dc 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -279,6 +279,7 @@ void output_destroy(struct sway_output *output) { list_free(output->workspaces); list_free(output->current.workspaces); wl_event_source_remove(output->repaint_timer); + wlr_color_transform_unref(output->color_transform); free(output); } From cc342107690631cf1ff003fed0b1cdb072491c63 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 8 Jun 2024 11:28:42 +0200 Subject: [PATCH 10/32] Set color transform when calling wlr_scene_output_build_state() We were only passing the color transform when calling wlr_scene_output_commit(). However when modesetting or pushing a new gamma LUT we render via wlr_scene_output_build_state(). Pass the color transform there as well. --- sway/config/output.c | 1 + sway/desktop/output.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index bcd21b9b..16be49c8 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -927,6 +927,7 @@ bool apply_output_configs(struct matched_output_config *configs, struct wlr_scene_output_state_options opts = { .swapchain = wlr_output_swapchain_manager_get_swapchain( &swapchain_mgr, backend_state->output), + .color_transform = cfg->output->color_transform, }; struct wlr_scene_output *scene_output = cfg->output->scene_output; struct wlr_output_state *state = &backend_state->base; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index cfa53021..6bf77d17 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -243,10 +243,14 @@ static int output_repaint_timer_handler(void *data) { output_configure_scene(output, &root->root_scene->tree.node, 1.0f); + struct wlr_scene_output_state_options opts = { + .color_transform = output->color_transform, + }; + if (output->gamma_lut_changed) { struct wlr_output_state pending; wlr_output_state_init(&pending); - if (!wlr_scene_output_build_state(output->scene_output, &pending, NULL)) { + if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) { return 0; } @@ -269,9 +273,6 @@ static int output_repaint_timer_handler(void *data) { return 0; } - struct wlr_scene_output_state_options opts = { - .color_transform = output->color_transform, - }; wlr_scene_output_commit(output->scene_output, &opts); return 0; } From 5f15c5e91defe8afc6c0f5105b7a51625676a685 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 24 Jun 2024 09:29:31 +0200 Subject: [PATCH 11/32] =?UTF-8?q?tree/view:=20set=20default=20min=20size?= =?UTF-8?q?=20to=201=C3=971?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not possible to have a surface with a smaller size. --- sway/tree/view.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index 1c1c8ee8..884beec8 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -173,9 +173,9 @@ void view_get_constraints(struct sway_view *view, double *min_width, view->impl->get_constraints(view, min_width, max_width, min_height, max_height); } else { - *min_width = DBL_MIN; + *min_width = 1; *max_width = DBL_MAX; - *min_height = DBL_MIN; + *min_height = 1; *max_height = DBL_MAX; } } From fce8de0f672e3c205dbbb0eb9a55d4bc05ff66ad Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 24 Jun 2024 09:29:59 +0200 Subject: [PATCH 12/32] tree/view: ensure content_{width,height} is positive The size computations may result in a zero or negative size, which are not valid wl_surface sizes. --- sway/tree/view.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index 884beec8..e9624094 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -365,8 +365,8 @@ void view_autoconfigure(struct sway_view *view) { con->pending.content_x = x; con->pending.content_y = y; - con->pending.content_width = width; - con->pending.content_height = height; + con->pending.content_width = fmax(width, 1); + con->pending.content_height = fmax(height, 1); } void view_set_activated(struct sway_view *view, bool activated) { From 74cc02d60f221deeed800454ba3cf68a55001430 Mon Sep 17 00:00:00 2001 From: bretello Date: Thu, 27 Jun 2024 15:41:48 +0200 Subject: [PATCH 13/32] fix crash when setting urgency on an hidden scratchpad container --- sway/tree/view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index e9624094..086a8ff3 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1185,7 +1185,7 @@ void view_set_urgent(struct sway_view *view, bool enable) { ipc_event_window(view->container, "urgent"); - if (!container_is_scratchpad_hidden(view->container)) { + if (!container_is_scratchpad_hidden_or_child(view->container)) { workspace_detect_urgent(view->container->pending.workspace); } } From 8f6bc5bb36d1451dd51d91feabf2c91bf5bc1026 Mon Sep 17 00:00:00 2001 From: bretello Date: Thu, 27 Jun 2024 16:16:33 +0200 Subject: [PATCH 14/32] prevent workspace_find_container from crashing with NULL workspaces --- sway/tree/workspace.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 52e48ad5..f8709a4c 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -708,6 +708,11 @@ void workspace_for_each_container(struct sway_workspace *ws, struct sway_container *workspace_find_container(struct sway_workspace *ws, bool (*test)(struct sway_container *con, void *data), void *data) { struct sway_container *result = NULL; + if (ws == NULL){ + sway_log(SWAY_ERROR, "Cannot find container with no workspace."); + return NULL; + } + // Tiling for (int i = 0; i < ws->tiling->length; ++i) { struct sway_container *child = ws->tiling->items[i]; From cdde0165dad94e4522f8f6f040e9d30145fbb14f Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 27 Jun 2024 21:01:19 +0300 Subject: [PATCH 15/32] protocols: use tablet-v2 xml from stable/ --- protocols/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/meson.build b/protocols/meson.build index 81edb584..6eac8542 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -7,10 +7,10 @@ wayland_scanner = find_program( ) protocols = [ + wl_protocol_dir / 'stable/tablet/tablet-v2.xml', wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml', wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml', wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml', - wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.xml', wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml', wl_protocol_dir / 'staging/content-type/content-type-v1.xml', wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml', From 5d237679f5d433b6a6c3b489298c42d40f217db4 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 31 Jul 2023 12:20:07 -0700 Subject: [PATCH 16/32] view: send scale notification when the output is known --- sway/tree/view.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sway/tree/view.c b/sway/tree/view.c index 086a8ff3..4f757acf 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -741,6 +742,14 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, ws = select_workspace(view); } + if (ws && ws->output) { + // Once the output is determined, we can notify the client early about + // scale to reduce startup jitter. + float scale = ws->output->wlr_output->scale; + wlr_fractional_scale_v1_notify_scale(wlr_surface, scale); + wlr_surface_set_preferred_buffer_scale(wlr_surface, ceil(scale)); + } + struct sway_seat *seat = input_manager_current_seat(); struct sway_node *node = seat_get_focus_inactive(seat, ws ? &ws->node : &root->node); From 1e0031781fc9283db7096aba34deca5503c2ab91 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 1 Jul 2024 09:21:53 +0200 Subject: [PATCH 17/32] desktop/output: unify page-flip codepath Instead of having a special codepath for applying gamma LUTs, have a single codepath for regular page-flips and gamma LUT updates. Should make it easier to add more logic on top e.g. for tearing page-flips. --- sway/desktop/output.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 6bf77d17..4c9d0b63 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -247,13 +247,13 @@ static int output_repaint_timer_handler(void *data) { .color_transform = output->color_transform, }; - if (output->gamma_lut_changed) { - struct wlr_output_state pending; - wlr_output_state_init(&pending); - if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) { - return 0; - } + struct wlr_output_state pending; + wlr_output_state_init(&pending); + if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) { + return 0; + } + if (output->gamma_lut_changed) { output->gamma_lut_changed = false; struct wlr_gamma_control_v1 *gamma_control = wlr_gamma_control_manager_v1_get_control( @@ -263,17 +263,16 @@ static int output_repaint_timer_handler(void *data) { return 0; } - if (!wlr_output_commit_state(output->wlr_output, &pending)) { + if (!wlr_output_test_state(output->wlr_output, &pending)) { wlr_gamma_control_v1_send_failed_and_destroy(gamma_control); - wlr_output_state_finish(&pending); - return 0; + wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL); } - - wlr_output_state_finish(&pending); - return 0; } - wlr_scene_output_commit(output->scene_output, &opts); + if (!wlr_output_commit_state(output->wlr_output, &pending)) { + sway_log(SWAY_ERROR, "Page-flip failed on output %s", output->wlr_output->name); + } + wlr_output_state_finish(&pending); return 0; } From 4e38f93f367dfb7f1ec66060e6262b806cecf3a7 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Jul 2024 00:39:21 +0200 Subject: [PATCH 18/32] config/output: Skip VRR tests when not supported Adaptive sync is a "soft" setting which we degrade of off when not supported. Some outputs types do not support turning it off (Wayland, X11), which makes for an awkward three-way test where we first enable, disable and finally unset the setting. wlr_output.adaptive_sync_supported tells us whether the output definitely does not support making changes (backend without support, connector without the feature), or whether it might work. Use this to avoid wasting time on adaptive sync test that can never succeed, and to avoid the Wayland/X11-backend specific unset step. --- sway/config/output.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/sway/config/output.c b/sway/config/output.c index 16be49c8..e64efb7f 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -721,21 +721,18 @@ static bool search_adaptive_sync(struct search_context *ctx, size_t output_idx) struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; struct wlr_output_state *state = &backend_state->base; + if (!backend_state->output->adaptive_sync_supported) { + return search_finish(ctx, output_idx); + } + if (cfg->config && cfg->config->adaptive_sync == 1) { wlr_output_state_set_adaptive_sync_enabled(state, true); if (search_finish(ctx, output_idx)) { return true; } } - if (!cfg->config || cfg->config->adaptive_sync != -1) { - wlr_output_state_set_adaptive_sync_enabled(state, false); - if (search_finish(ctx, output_idx)) { - return true; - } - } - // If adaptive sync has not been set, or fallback in case we are on a - // backend that cannot disable adaptive sync such as the wayland backend. - state->committed &= ~WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; + + wlr_output_state_set_adaptive_sync_enabled(state, false); return search_finish(ctx, output_idx); } From dfbcd1fbaa5148e537a1c29dc3cbe8ea21ee5eac Mon Sep 17 00:00:00 2001 From: llyyr Date: Mon, 27 May 2024 15:43:56 +0530 Subject: [PATCH 19/32] input/keyboard: don't send key release if we don't have focused surface "The compositor must not send this event if the wl_keyboard did not have an active surface immediately before this event. The compositor must not send this event if state is pressed (resp. released) and the key was already logically down (resp. was not logically down) immediately before this event." From https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/382 --- sway/input/keyboard.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 9ac21664..e33dbe0b 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -509,12 +509,13 @@ static void handle_key_event(struct sway_keyboard *keyboard, } if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { - // If the pressed event was sent to a client, also send the released + // If the pressed event was sent to a client and we have a focused + // surface immediately before this event, also send the released // event. In particular, don't send the released event to the IM grab. bool pressed_sent = update_shortcut_state( &keyboard->state_pressed_sent, event->keycode, event->state, keyinfo.keycode, 0); - if (pressed_sent) { + if (pressed_sent && seat->wlr_seat->keyboard_state.focused_surface) { wlr_seat_set_keyboard(wlr_seat, keyboard->wlr); wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, event->keycode, event->state); From 0386b2afcb88f0ceba144c1f2bbb4b6fc6f13518 Mon Sep 17 00:00:00 2001 From: llyyr Date: Sat, 25 May 2024 22:30:20 +0530 Subject: [PATCH 20/32] input/seat: don't send redundant leave/enter on device creation Fixes: #8143 #8173 Upstream issue: https://github.com/fcitx/fcitx5/issues/1044 --- sway/input/seat.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index da4bb12a..9a00a3e2 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -802,11 +802,10 @@ static void seat_configure_keyboard(struct sway_seat *seat, return; } - // force notify reenter to pick up the new configuration. This reuses + // 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, surface); } } From 4c3c0602116c12c2821e1e505e7248b3c642b4ca Mon Sep 17 00:00:00 2001 From: llyyr Date: Sun, 26 May 2024 00:59:44 +0530 Subject: [PATCH 21/32] input/keyboard: refactor into sway_keyboard_set_layout --- sway/input/keyboard.c | 80 ++++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index e33dbe0b..91a4f866 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -961,16 +961,8 @@ cleanup: free(sway_group); } -void sway_keyboard_configure(struct sway_keyboard *keyboard) { - struct input_config *input_config = - input_device_get_config(keyboard->seat_device->input_device); - - 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; - } - +static void sway_keyboard_set_layout(struct sway_keyboard *keyboard, + struct input_config *input_config) { struct xkb_keymap *keymap = sway_keyboard_compile_keymap(input_config, NULL); if (!keymap) { sway_log(SWAY_ERROR, "Failed to compile keymap. Attempting defaults"); @@ -986,31 +978,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { !wlr_keyboard_keymaps_match(keyboard->keymap, keymap) : true; bool effective_layout_changed = keyboard->effective_layout != 0; - int repeat_rate = 25; - if (input_config && input_config->repeat_rate != INT_MIN) { - repeat_rate = input_config->repeat_rate; - } - int repeat_delay = 600; - if (input_config && input_config->repeat_delay != INT_MIN) { - repeat_delay = input_config->repeat_delay; - } - - bool repeat_info_changed = keyboard->repeat_rate != repeat_rate || - keyboard->repeat_delay != repeat_delay; - - if (keymap_changed || repeat_info_changed || config->reloading) { + if (keymap_changed || config->reloading) { xkb_keymap_unref(keyboard->keymap); keyboard->keymap = keymap; keyboard->effective_layout = 0; - keyboard->repeat_rate = repeat_rate; - keyboard->repeat_delay = repeat_delay; sway_keyboard_group_remove_invalid(keyboard); - wlr_keyboard_set_keymap(keyboard->wlr, keyboard->keymap); - wlr_keyboard_set_repeat_info(keyboard->wlr, - keyboard->repeat_rate, keyboard->repeat_delay); - if (!keyboard->wlr->group) { sway_keyboard_group_add(keyboard); } @@ -1061,6 +1035,47 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { wlr_seat_set_keyboard(seat, keyboard->wlr); } + if (keymap_changed) { + ipc_event_input("xkb_keymap", + keyboard->seat_device->input_device); + } else if (effective_layout_changed) { + ipc_event_input("xkb_layout", + keyboard->seat_device->input_device); + } +} + +void sway_keyboard_configure(struct sway_keyboard *keyboard) { + struct input_config *input_config = + input_device_get_config(keyboard->seat_device->input_device); + + 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; + } + + int repeat_rate = 25; + if (input_config && input_config->repeat_rate != INT_MIN) { + repeat_rate = input_config->repeat_rate; + } + int repeat_delay = 600; + if (input_config && input_config->repeat_delay != INT_MIN) { + repeat_delay = input_config->repeat_delay; + } + + bool repeat_info_changed = keyboard->repeat_rate != repeat_rate || + keyboard->repeat_delay != repeat_delay; + + if (repeat_info_changed || config->reloading) { + keyboard->repeat_rate = repeat_rate; + keyboard->repeat_delay = repeat_delay; + + wlr_keyboard_set_repeat_info(keyboard->wlr, + keyboard->repeat_rate, keyboard->repeat_delay); + } + + sway_keyboard_set_layout(keyboard, input_config); + wl_list_remove(&keyboard->keyboard_key.link); wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key); keyboard->keyboard_key.notify = handle_keyboard_key; @@ -1070,13 +1085,6 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { &keyboard->keyboard_modifiers); keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; - if (keymap_changed) { - ipc_event_input("xkb_keymap", - keyboard->seat_device->input_device); - } else if (effective_layout_changed) { - ipc_event_input("xkb_layout", - keyboard->seat_device->input_device); - } } void sway_keyboard_destroy(struct sway_keyboard *keyboard) { From e32bdaa7bead5052dd32c12917ea8f74a9b14405 Mon Sep 17 00:00:00 2001 From: llyyr Date: Sun, 26 May 2024 01:46:34 +0530 Subject: [PATCH 22/32] input/keyboard: don't set layout for virtual keyboard device This prevents us from recompiling keymap every time a virtual device is created by clients like fcitx5 --- sway/input/keyboard.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 91a4f866..efb9ac39 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -1074,7 +1074,9 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { keyboard->repeat_rate, keyboard->repeat_delay); } - sway_keyboard_set_layout(keyboard, input_config); + if (!keyboard->seat_device->input_device->is_virtual) { + sway_keyboard_set_layout(keyboard, input_config); + } wl_list_remove(&keyboard->keyboard_key.link); wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key); From b04f4136bc6163246d7e24454b84a950c8137ffc Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 28 Mar 2024 00:34:30 +0100 Subject: [PATCH 23/32] desktop/output: Debounce modesets Output changes often happen in rapid succession. Instead of doing the modesets one by one, set a 10 millisecond debounce timer. --- include/sway/server.h | 2 ++ sway/desktop/output.c | 32 +++++++++++++++++++++++--------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/sway/server.h b/include/sway/server.h index 3a63df34..abf1b6b4 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -135,6 +135,8 @@ struct sway_server { // Stores the nodes that have been marked as "dirty" and will be put into // the pending transaction. list_t *dirty_nodes; + + struct wl_event_source *delayed_modeset; }; extern struct sway_server server; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 4c9d0b63..f936b2a8 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -365,6 +365,26 @@ static void update_output_manager_config(struct sway_server *server) { ipc_event_output(); } +static int timer_modeset_handle(void *data) { + struct sway_server *server = data; + wl_event_source_remove(server->delayed_modeset); + server->delayed_modeset = NULL; + + apply_all_output_configs(); + transaction_commit_dirty(); + update_output_manager_config(server); + + return 0; +} + +static void request_modeset(struct sway_server *server) { + if (server->delayed_modeset == NULL) { + server->delayed_modeset = wl_event_loop_add_timer(server->wl_event_loop, + timer_modeset_handle, server); + wl_event_source_timer_update(server->delayed_modeset, 10); + } +} + static void begin_destroy(struct sway_output *output) { struct sway_server *server = output->server; @@ -388,9 +408,7 @@ static void begin_destroy(struct sway_output *output) { output->wlr_output->data = NULL; output->wlr_output = NULL; - transaction_commit_dirty(); - - update_output_manager_config(server); + request_modeset(server); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -524,11 +542,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { sway_session_lock_add_output(server->session_lock.lock, output); } - apply_all_output_configs(); - - transaction_commit_dirty(); - - update_output_manager_config(server); + request_modeset(server); } void handle_output_layout_change(struct wl_listener *listener, @@ -680,5 +694,5 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener, break; } store_output_config(oc); - apply_all_output_configs(); + request_modeset(output->server); } From a0a078f75e977bff85ba6723fe54a4e982e9df52 Mon Sep 17 00:00:00 2001 From: novenary Date: Wed, 3 Jul 2024 16:37:49 +0300 Subject: [PATCH 24/32] transaction: fix missing top border with hide_lone_tab Regressed by scene graph. --- sway/desktop/transaction.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index d1898843..7568990b 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -314,7 +314,7 @@ static void arrange_children(enum sway_container_layout layout, list_t *children if (activated) { arrange_container(child, width, height - title_bar_height, - false, 0); + title_bar_height == 0, 0); } else { disable_container(child); } @@ -343,7 +343,7 @@ static void arrange_children(enum sway_container_layout layout, list_t *children if (activated) { arrange_container(child, width, height - title_height, - false, 0); + title_bar_height == 0, 0); } else { disable_container(child); } From 5233a0bd2ef84ab6d1eeb2ebcde3d0c73794cdb9 Mon Sep 17 00:00:00 2001 From: novenary Date: Thu, 28 Dec 2023 23:28:27 +0200 Subject: [PATCH 25/32] ipc: properly check for titlebars This fixes incorrect values for rect.y when using `hide_edge_borders --i3`. --- sway/ipc-json.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 1ee39124..91e31a29 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -578,9 +578,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object bool visible = view_is_visible(c->view); json_object_object_add(object, "visible", json_object_new_boolean(visible)); + bool has_titlebar = c->title_bar.tree->node.enabled; struct wlr_box window_box = { c->pending.content_x - c->pending.x, - (c->current.border == B_PIXEL) ? c->pending.content_y - c->pending.y : 0, + has_titlebar ? 0 : c->pending.content_y - c->pending.y, c->pending.content_width, c->pending.content_height }; From fdcfe00781d3ee31df99acb43ccd3873d2229809 Mon Sep 17 00:00:00 2001 From: llyyr Date: Thu, 4 Jul 2024 03:01:25 +0530 Subject: [PATCH 26/32] xdg_shell: don't send configure events to uninitialized surfaces the surface isn't initialized yet when we first handle it in `handle_xdg_shell_toplevel`, move setting WM capabilities to handle_commit instead. Fixes warnings from wlroots about a configure being scheduled for uninitialized surface --- sway/desktop/xdg_shell.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 7c417891..fdfa7b65 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -289,6 +289,8 @@ static void handle_commit(struct wl_listener *listener, void *data) { } // XXX: https://github.com/swaywm/sway/issues/2176 wlr_xdg_surface_schedule_configure(xdg_surface); + wlr_xdg_toplevel_set_wm_capabilities(view->wlr_xdg_toplevel, + XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); // TODO: wlr_xdg_toplevel_set_bounds() return; } @@ -575,7 +577,4 @@ void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) { wlr_scene_xdg_surface_create(xdg_shell_view->view.content_tree, xdg_toplevel->base); xdg_toplevel->base->data = xdg_shell_view; - - wlr_xdg_toplevel_set_wm_capabilities(xdg_toplevel, - XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN); } From d8c4a2d5fe5c2fb5f3941a5daf9edb679242bb11 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 3 Jul 2024 23:48:03 +0200 Subject: [PATCH 27/32] tree/container: drop decl for container_update_textures_recursive() This function doesn't exist anymore. --- include/sway/tree/container.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 93f6bfbb..8bf1955d 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -175,8 +175,6 @@ struct sway_container *container_obstructing_fullscreen_container(struct sway_co bool container_has_ancestor(struct sway_container *container, struct sway_container *ancestor); -void container_update_textures_recursive(struct sway_container *con); - void container_reap_empty(struct sway_container *con); struct sway_container *container_flatten(struct sway_container *container); From 818ea17389326901093c0469a5225aab61ccc1ec Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 4 Jul 2024 00:06:21 +0200 Subject: [PATCH 28/32] sway_text_node: avoid unnecessary redraws When a floating container has a titlebar, render_backing_buffer() ends up being called each time the container is moved. Add some more checks for no-op changes in sway_text_node_set_max_width() and sway_text_node_set_background(). This makes the move smoother. --- sway/sway_text_node.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sway/sway_text_node.c b/sway/sway_text_node.c index 4b7ee999..7c781355 100644 --- a/sway/sway_text_node.c +++ b/sway/sway_text_node.c @@ -294,6 +294,9 @@ void sway_text_node_set_text(struct sway_text_node *node, char *text) { void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) { struct text_buffer *buffer = wl_container_of(node, buffer, props); + if (max_width == buffer->props.max_width) { + return; + } buffer->props.max_width = max_width; wlr_scene_buffer_set_dest_size(buffer->buffer_node, get_text_width(&buffer->props), buffer->props.height); @@ -303,6 +306,9 @@ void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) { void sway_text_node_set_background(struct sway_text_node *node, float background[4]) { struct text_buffer *buffer = wl_container_of(node, buffer, props); + if (memcmp(&node->background, background, sizeof(*background) * 4) == 0) { + return; + } memcpy(&node->background, background, sizeof(*background) * 4); render_backing_buffer(buffer); } From 5be5a5005164d3ccff844f4c72836cb49cbf784a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarc=C3=ADsio=20Eduardo=20Moreira=20Crocomo?= Date: Wed, 10 Apr 2024 18:01:50 -0300 Subject: [PATCH 29/32] Implement clickfinger_button_map support. --- include/sway/commands.h | 1 + include/sway/config.h | 1 + sway/commands/input.c | 1 + sway/commands/input/clickfinger_button_map.c | 27 ++++++++++++++++++++ sway/config/input.c | 4 +++ sway/input/libinput.c | 15 +++++++++++ sway/ipc-json.c | 16 ++++++++++-- sway/meson.build | 1 + sway/sway-input.5.scd | 6 +++++ sway/sway-ipc.7.scd | 5 +++- 10 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 sway/commands/input/clickfinger_button_map.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 0a9fdc70..15cd8698 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -249,6 +249,7 @@ sway_cmd input_cmd_seat; sway_cmd input_cmd_accel_profile; sway_cmd input_cmd_calibration_matrix; sway_cmd input_cmd_click_method; +sway_cmd input_cmd_clickfinger_button_map; sway_cmd input_cmd_drag; sway_cmd input_cmd_drag_lock; sway_cmd input_cmd_dwt; diff --git a/include/sway/config.h b/include/sway/config.h index 3e3a104e..dfa3c1b7 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -149,6 +149,7 @@ struct input_config { int accel_profile; struct calibration_matrix calibration_matrix; int click_method; + int clickfinger_button_map; int drag; int drag_lock; int dwt; diff --git a/sway/commands/input.c b/sway/commands/input.c index 306c40f7..35846b1c 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -11,6 +11,7 @@ static const struct cmd_handler input_handlers[] = { { "accel_profile", input_cmd_accel_profile }, { "calibration_matrix", input_cmd_calibration_matrix }, { "click_method", input_cmd_click_method }, + { "clickfinger_button_map", input_cmd_clickfinger_button_map }, { "drag", input_cmd_drag }, { "drag_lock", input_cmd_drag_lock }, { "dwt", input_cmd_dwt }, diff --git a/sway/commands/input/clickfinger_button_map.c b/sway/commands/input/clickfinger_button_map.c new file mode 100644 index 00000000..57d6e39a --- /dev/null +++ b/sway/commands/input/clickfinger_button_map.c @@ -0,0 +1,27 @@ +#include +#include +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_clickfinger_button_map(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "clickfinger_button_map", 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 (strcasecmp(argv[0], "lrm") == 0) { + ic->clickfinger_button_map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM; + } else if (strcasecmp(argv[0], "lmr") == 0) { + ic->clickfinger_button_map = LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR; + } else { + return cmd_results_new(CMD_INVALID, + "Expected 'clickfinger_button_map '"); + } + + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config/input.c b/sway/config/input.c index 613270df..e5694eff 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -28,6 +28,7 @@ struct input_config *new_input_config(const char* identifier) { input->dwtp = INT_MIN; input->send_events = INT_MIN; input->click_method = INT_MIN; + input->clickfinger_button_map = INT_MIN; input->middle_emulation = INT_MIN; input->natural_scroll = INT_MIN; input->accel_profile = INT_MIN; @@ -55,6 +56,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { if (src->click_method != INT_MIN) { dst->click_method = src->click_method; } + if (src->clickfinger_button_map != INT_MIN) { + dst->clickfinger_button_map = src->clickfinger_button_map; + } if (src->drag != INT_MIN) { dst->drag = src->drag; } diff --git a/sway/input/libinput.c b/sway/input/libinput.c index 0266c7a9..2fec290e 100644 --- a/sway/input/libinput.c +++ b/sway/input/libinput.c @@ -132,6 +132,16 @@ static bool set_click_method(struct libinput_device *device, return true; } +static bool set_clickfinger_button_map(struct libinput_device *device, + enum libinput_config_clickfinger_button_map map) { + if (libinput_device_config_click_get_clickfinger_button_map(device) == map) { + return false; + } + sway_log(SWAY_DEBUG, "clickfinger_set_button_map(%d)", map); + log_status(libinput_device_config_click_set_clickfinger_button_map(device, map)); + return true; +} + static bool set_middle_emulation(struct libinput_device *dev, enum libinput_config_middle_emulation_state mid) { if (!libinput_device_config_middle_emulation_is_available(dev) || @@ -281,6 +291,9 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device if (ic->click_method != INT_MIN) { changed |= set_click_method(device, ic->click_method); } + if (ic->clickfinger_button_map != INT_MIN) { + changed |= set_clickfinger_button_map(device, ic->clickfinger_button_map); + } if (ic->middle_emulation != INT_MIN) { changed |= set_middle_emulation(device, ic->middle_emulation); } @@ -356,6 +369,8 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) { libinput_device_config_left_handed_get_default(device)); changed |= set_click_method(device, libinput_device_config_click_get_default_method(device)); + changed |= set_clickfinger_button_map(device, + libinput_device_config_click_get_default_clickfinger_button_map(device)); changed |= set_middle_emulation(device, libinput_device_config_middle_emulation_get_default_enabled(device)); changed |= set_scroll_method(device, diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 91e31a29..e512a223 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -992,6 +992,18 @@ static json_object *describe_libinput_device(struct libinput_device *device) { } json_object_object_add(object, "click_method", json_object_new_string(click_method)); + + const char *button_map = "unknown"; + switch (libinput_device_config_click_get_clickfinger_button_map(device)) { + case LIBINPUT_CONFIG_CLICKFINGER_MAP_LRM: + button_map = "lrm"; + break; + case LIBINPUT_CONFIG_CLICKFINGER_MAP_LMR: + button_map = "lmr"; + break; + } + json_object_object_add(object, "clickfinger_button_map", + json_object_new_string(button_map)); } if (libinput_device_config_middle_emulation_is_available(device)) { @@ -1109,9 +1121,9 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { struct xkb_keymap *keymap = keyboard->keymap; struct xkb_state *state = keyboard->xkb_state; - json_object_object_add(object, "repeat_delay", + json_object_object_add(object, "repeat_delay", json_object_new_int(keyboard->repeat_info.delay)); - json_object_object_add(object, "repeat_rate", + json_object_object_add(object, "repeat_rate", json_object_new_int(keyboard->repeat_info.rate)); json_object *layouts_arr = json_object_new_array(); diff --git a/sway/meson.build b/sway/meson.build index a189fe9a..2f4406ab 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -154,6 +154,7 @@ sway_sources = files( 'commands/input/accel_profile.c', 'commands/input/calibration_matrix.c', 'commands/input/click_method.c', + 'commands/input/clickfinger_button_map.c', 'commands/input/drag.c', 'commands/input/drag_lock.c', 'commands/input/dwt.c', diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 442311bb..fbef2a32 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -143,6 +143,12 @@ The following commands may only be used in the configuration file. *input* click_method none|button_areas|clickfinger Changes the click method for the specified device. +*input* clickfinger_button_map lrm|lmr + Specifies which button mapping to use for clickfinger. _lrm_ treats 1 finger as + left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_ + treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as + right click. + *input* drag enabled|disabled Enables or disables tap-and-drag for specified input device. diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 2f697248..e90abcbb 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd @@ -1168,7 +1168,7 @@ following properties will be included for devices that support them: : Whether tap to click is enabled. It can be _enabled_ or _disabled_ |- tap_button_map : string -: The finger to button mapping in use. It can be _lmr_ or _lrm_ +: The finger to button mapping in use for tapping. It can be _lmr_ or _lrm_ |- tap_drag : string : Whether tap-and-drag is enabled. It can be _enabled_ or _disabled_ @@ -1190,6 +1190,9 @@ following properties will be included for devices that support them: |- click_method : string : The click method in use. It can be _none_, _button_areas_, or _clickfinger_ +|- click_button_map +: string +: The finger to button mapping in use for clickfinger. It can be _lmr_ or _lrm_ |- middle_emulation : string : Whether middle emulation is enabled. It can be _enabled_ or _disabled_ From 3d0055203583d576ec1dec5a22f25ddf9a53b8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tarc=C3=ADsio=20Eduardo=20Moreira=20Crocomo?= Date: Thu, 4 Jul 2024 18:00:47 -0300 Subject: [PATCH 30/32] build: bump libinput version required --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index eb66506a..c602d008 100644 --- a/meson.build +++ b/meson.build @@ -72,7 +72,7 @@ pangocairo = dependency('pangocairo') gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) pixman = dependency('pixman-1') libevdev = dependency('libevdev') -libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep +libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.26.0') : null_dep xcb = wlroots_features['xwayland'] ? dependency('xcb') : null_dep drm = dependency('libdrm') libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_dep From 28fd73589df0e73e1d15e165acd90651a5f805d6 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Wed, 28 Feb 2024 14:22:09 -0700 Subject: [PATCH 31/32] xdg-activation: launcher tokens are activation requests If the launched client decides to pass it's token along as an activation request, allow that. This will make the behavior match tokens provided by an external launcher client. --- sway/xdg_activation_v1.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c index b7c80dd4..fd604874 100644 --- a/sway/xdg_activation_v1.c +++ b/sway/xdg_activation_v1.c @@ -38,14 +38,14 @@ void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, } // This is an activation request. If this context is internal we have ctx->seat. - struct sway_seat *seat = ctx->seat; - if (!seat) { - // Otherwise, use the seat indicated by the launcher client in set_serial - seat = ctx->token->seat ? ctx->token->seat->data : NULL; + if (ctx->seat) { + view_request_activate(view, ctx->seat); + return; } - if (seat && ctx->had_focused_surface) { - view_request_activate(view, seat); + // Otherwise, activate if passed from another focused client + if (ctx->token->seat && ctx->had_focused_surface) { + view_request_activate(view, ctx->token->seat->data); } else { // The token is valid, but cannot be used to activate a window view_request_urgent(view); From 8c5b23e592d2334b3324227dd9d1311e46c5fd69 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 11 Jul 2024 00:33:19 +0200 Subject: [PATCH 32/32] common/pango: Disable glyph position rounding Pango rounds glyph position and widths to nearest integer, which leads to font dimensions jumping around when rendering with a scale, causing text geometry to jump around when changing scale. This is disturbing when text buffers change scale, and also mean that the text geometry calculations in sway_text_node are incorrect. Disable this rounding to make the geometry stable. --- common/pango.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/pango.c b/common/pango.c index 288569b3..e52b52b9 100644 --- a/common/pango.c +++ b/common/pango.c @@ -53,6 +53,8 @@ size_t escape_markup_text(const char *src, char *dest) { PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc, const char *text, double scale, bool markup) { PangoLayout *layout = pango_cairo_create_layout(cairo); + pango_context_set_round_glyph_positions(pango_layout_get_context(layout), false); + PangoAttrList *attrs; if (markup) { char *buf; @@ -104,6 +106,7 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, void get_text_metrics(const PangoFontDescription *description, int *height, int *baseline) { cairo_t *cairo = cairo_create(NULL); PangoContext *pango = pango_cairo_create_context(cairo); + pango_context_set_round_glyph_positions(pango, false); // When passing NULL as a language, pango uses the current locale. PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL);