From 9ef934cf547cfc7e923c681be7b261ea2ba0ab4a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 15 Jan 2026 09:53:09 +0530 Subject: [PATCH] Wayland: Remove usage of the Wayland color management protocol to inform compositors of the color space used by kitty As is typical with Wayland, the protocol is poorly designed and implemented even worse. Hyprland 0.53 has completely broken color management. https://github.com/hyprwm/Hyprland/discussions/12788 In addition it and mangowc crash when using color management with nouveau drivers. https://github.com/kovidgoyal/kitty/issues/9030 KDE kwin does not support the sRGB transfer function. And the geniuses at Wayland are any way planning to deprecate sRGB as a transfer function. Only GNOME mutter seems to get it right. Then there are people that are likely going to shoehorn this into EGL instead of leaving it under application control via the protocol anyway. https://github.com/KhronosGroup/EGL-Registry/issues/197 Sigh. Wayland. --- docs/changelog.rst | 3 ++ glfw/source-info.json | 1 - glfw/wl_init.c | 92 ------------------------------------------- glfw/wl_platform.h | 11 ------ glfw/wl_window.c | 20 ---------- 5 files changed, 3 insertions(+), 124 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index d6c87410f..287127d13 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -192,6 +192,9 @@ Detailed list of changes with frames that dispose onto background with non-zero delay using the native engine (:iss:`9376`) +- Wayland: Remove usage of the wayland color management protocol to inform + compositors of the color space used by kitty + 0.45.0 [2025-12-24] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/glfw/source-info.json b/glfw/source-info.json index c74fa5901..a4534895f 100644 --- a/glfw/source-info.json +++ b/glfw/source-info.json @@ -88,7 +88,6 @@ "staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml", "staging/xdg-system-bell/xdg-system-bell-v1.xml", "staging/xdg-toplevel-tag/xdg-toplevel-tag-v1.xml", - "staging/color-management/color-management-v1.xml", "kwin-blur-v1.xml", "wlr-layer-shell-unstable-v1.xml" diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 917b56d32..edd2401a5 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -502,53 +502,6 @@ static const struct wl_seat_listener seatListener = { seatHandleCapabilities, seatHandleName, }; - -static void -ignored_color_manager_event(void *data UNUSED, struct wp_color_manager_v1 *wp_color_manager_v1 UNUSED, uint32_t x UNUSED) {} - -static void -on_color_manger_features_done(void *data UNUSED, struct wp_color_manager_v1 *wp_color_manager_v1 UNUSED) { - _glfw.wl.color_manager.capabilities_reported = true; -} - -static void -on_supported_color_primaries(void *data UNUSED, struct wp_color_manager_v1 *wp_color_manager_v1 UNUSED, uint32_t x) { - switch(x) { - case WP_COLOR_MANAGER_V1_PRIMARIES_SRGB: - _glfw.wl.color_manager.supported_primaries.srgb = true; break; - } -} - -static void -on_supported_color_feature(void *data UNUSED, struct wp_color_manager_v1 *wp_color_manager_v1 UNUSED, uint32_t x) { - switch(x) { - case WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC: - _glfw.wl.color_manager.supported_features.parametric = true; break; - case WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES: - _glfw.wl.color_manager.supported_features.set_primaries = true; break; - } -} - -static void -on_supported_color_transfer_function(void *data UNUSED, struct wp_color_manager_v1 *wp_color_manager_v1 UNUSED, uint32_t x) { - switch(x) { - case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB: - _glfw.wl.color_manager.supported_transfer_functions.srgb = true; break; - case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22: - _glfw.wl.color_manager.supported_transfer_functions.gamma22 = true; break; - case WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR: - _glfw.wl.color_manager.supported_transfer_functions.ext_linear = true; break; - } -} - -static const struct wp_color_manager_v1_listener color_manager_listener = { - .supported_intent = ignored_color_manager_event, - .supported_feature = on_supported_color_feature, - .supported_primaries_named = on_supported_color_primaries, - .supported_tf_named = on_supported_color_transfer_function, - .done = on_color_manger_features_done, -}; - static void wmBaseHandlePing(void* data UNUSED, struct xdg_wm_base* wmBase, uint32_t serial) @@ -709,9 +662,6 @@ static void registryHandleGlobal(void* data UNUSED, _glfw.wl.xdg_system_bell_v1 = wl_registry_bind(registry, name, &xdg_system_bell_v1_interface, 1); } else if (is(xdg_toplevel_tag_manager_v1)) { _glfw.wl.xdg_toplevel_tag_manager_v1 = wl_registry_bind(registry, name, &xdg_toplevel_tag_manager_v1_interface, 1); - } else if (is(wp_color_manager_v1)) { - _glfw.wl.wp_color_manager_v1 = wl_registry_bind(registry, name, &wp_color_manager_v1_interface, 1); - wp_color_manager_v1_add_listener(_glfw.wl.wp_color_manager_v1, &color_manager_listener, NULL); } #undef is } @@ -827,7 +777,6 @@ get_compositor_missing_capabilities(void) { #define P(x) p += snprintf(p, sizeof(buf) - (p - buf), "%s ", x); if (_glfw.wl.xdg_wm_base_version < 6) P("window-state-suspended"); if (_glfw.wl.xdg_wm_base_version < 5) P("window-capabilities"); - if (!_glfw.wl.color_manager.has_needed_capabilities) P("color-manager"); #undef P #undef C while (p > buf && (p - 1)[0] == ' ') { p--; *p = 0; } @@ -836,25 +785,6 @@ get_compositor_missing_capabilities(void) { GLFWAPI const char* glfwWaylandMissingCapabilities(void) { return get_compositor_missing_capabilities(); } -static void -image_description_failed(void *data UNUSED, struct wp_image_description_v1 *d, uint32_t cause, const char *msg) { - wp_image_description_v1_destroy(d); - _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create color mamagement profile description with cause: %d and error: %s", cause, msg); - _glfw.wl.color_manager.image_description_done = true; -} - -static void -image_description_ready(void *data UNUSED, struct wp_image_description_v1 *d, uint32_t identity UNUSED) { - _glfw.wl.color_manager.image_description_done = true; - _glfw.wl.color_manager.image_description = d; -} - -static const struct wp_image_description_v1_listener image_description_listener = { - .failed = image_description_failed, - .ready = image_description_ready, -}; - - int _glfwPlatformInit(bool *supports_window_occlusion) { int i; @@ -915,23 +845,6 @@ int _glfwPlatformInit(bool *supports_window_occlusion) // Sync so we got all initial output events wl_display_roundtrip(_glfw.wl.display); - // Sync so we get all color manager capabilities - if (_glfw.wl.wp_color_manager_v1) { - while (!_glfw.wl.color_manager.capabilities_reported) wl_display_roundtrip(_glfw.wl.display); - _glfw.wl.color_manager.has_needed_capabilities = \ - _glfw.wl.color_manager.supported_transfer_functions.srgb && - _glfw.wl.color_manager.supported_features.parametric && - _glfw.wl.color_manager.supported_features.set_primaries; - if (_glfw.wl.color_manager.has_needed_capabilities) { - struct wp_image_description_creator_params_v1 *c = wp_color_manager_v1_create_parametric_creator( - _glfw.wl.wp_color_manager_v1); - wp_image_description_creator_params_v1_set_tf_named(c, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB); - wp_image_description_creator_params_v1_set_primaries_named(c, WP_COLOR_MANAGER_V1_PRIMARIES_SRGB); - wp_image_description_v1_add_listener(wp_image_description_creator_params_v1_create(c), - &image_description_listener, NULL); - } - } - for (i = 0; i < _glfw.monitorCount; ++i) { monitor = _glfw.monitors[i]; @@ -1045,11 +958,6 @@ void _glfwPlatformTerminate(void) xdg_system_bell_v1_destroy(_glfw.wl.xdg_system_bell_v1); if (_glfw.wl.xdg_toplevel_tag_manager_v1) xdg_toplevel_tag_manager_v1_destroy(_glfw.wl.xdg_toplevel_tag_manager_v1); - if (_glfw.wl.wp_color_manager_v1) { - if (_glfw.wl.color_manager.image_description) - wp_image_description_v1_destroy(_glfw.wl.color_manager.image_description); - wp_color_manager_v1_destroy(_glfw.wl.wp_color_manager_v1); - } if (_glfw.wl.wp_single_pixel_buffer_manager_v1) wp_single_pixel_buffer_manager_v1_destroy(_glfw.wl.wp_single_pixel_buffer_manager_v1); if (_glfw.wl.wp_cursor_shape_manager_v1) diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 4341569e1..6f7e1ecf8 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -70,7 +70,6 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #include "wayland-xdg-toplevel-icon-v1-client-protocol.h" #include "wayland-xdg-system-bell-v1-client-protocol.h" #include "wayland-xdg-toplevel-tag-v1-client-protocol.h" -#include "wayland-color-management-v1-client-protocol.h" #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL) #define _glfw_dlclose(handle) dlclose(handle) @@ -172,7 +171,6 @@ typedef struct _GLFWwindowWayland bool hovered; bool transparent; struct wl_surface* surface; - struct wp_color_management_surface_v1 *color_management; bool waiting_for_swap_to_commit; struct wl_egl_window* native; struct wl_callback* callback; @@ -348,7 +346,6 @@ typedef struct _GLFWlibraryWayland struct xdg_toplevel_icon_manager_v1* xdg_toplevel_icon_manager_v1; struct xdg_system_bell_v1* xdg_system_bell_v1; struct xdg_toplevel_tag_manager_v1* xdg_toplevel_tag_manager_v1; - struct wp_color_manager_v1* wp_color_manager_v1; struct wp_cursor_shape_manager_v1* wp_cursor_shape_manager_v1; struct wp_cursor_shape_device_v1* wp_cursor_shape_device_v1; struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1; @@ -399,14 +396,6 @@ typedef struct _GLFWlibraryWayland PFN_wl_egl_window_resize window_resize; } egl; - struct { - struct { bool gamma22, ext_linear, srgb; } supported_transfer_functions; - struct { bool srgb; } supported_primaries; - struct { bool parametric, set_primaries; } supported_features; - bool capabilities_reported, image_description_done, has_needed_capabilities; - struct wp_image_description_v1 *image_description; - } color_manager; - struct { glfw_wl_xdg_activation_request *array; size_t capacity, sz; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 8cd724a9b..d5c658e73 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -573,13 +573,6 @@ static const struct wp_fractional_scale_v1_listener fractional_scale_listener = .preferred_scale = &fractional_scale_preferred_scale, }; -static void -ensure_color_manager_ready(void) { - if (_glfw.wl.wp_color_manager_v1 && !_glfw.wl.color_manager.image_description_done) { - while (!_glfw.wl.color_manager.image_description_done) wl_display_roundtrip(_glfw.wl.display); - } -} - static bool create_surface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { window->wl.surface = wl_compositor_create_surface(_glfw.wl.compositor); @@ -587,16 +580,6 @@ create_surface(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) { wl_surface_add_listener(window->wl.surface, &surfaceListener, window); wl_surface_set_user_data(window->wl.surface, window); - if (_glfw.wl.color_manager.has_needed_capabilities) { - ensure_color_manager_ready(); - if (_glfw.wl.color_manager.image_description && !window->wl.color_management) { - window->wl.color_management = wp_color_manager_v1_get_surface( - _glfw.wl.wp_color_manager_v1, window->wl.surface); - wp_color_management_surface_v1_set_image_description( - window->wl.color_management, _glfw.wl.color_manager.image_description, WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL); - } - } - // If we already have been notified of the primary monitor scale, assume // the window will be created on it and so avoid a rescale roundtrip in the common // case of the window being shown on the primary monitor or all monitors having the same scale. @@ -1548,9 +1531,6 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window) if (window->wl.layer_shell.zwlr_layer_surface_v1) zwlr_layer_surface_v1_destroy(window->wl.layer_shell.zwlr_layer_surface_v1); - if (window->wl.color_management) - wp_color_management_surface_v1_destroy(window->wl.color_management); - if (window->wl.surface) wl_surface_destroy(window->wl.surface);