DisplayServer (Linux): be compatible with KDE 6.7

This PR also removes usage of `kde-output-order-v1-protocol`, which disables detection of primary monitor for old KDE versions
This commit is contained in:
Carter Li
2026-06-18 10:31:37 +08:00
parent d6a4946511
commit e9c0d886d1
6 changed files with 60 additions and 222 deletions
-5
View File
@@ -602,7 +602,6 @@ if(LINUX)
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -763,7 +762,6 @@ elseif(FreeBSD)
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -859,7 +857,6 @@ elseif(NetBSD)
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -944,7 +941,6 @@ elseif(OpenBSD)
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -1189,7 +1185,6 @@ elseif(SunOS)
src/detection/displayserver/linux/wayland/wl-output-protocol.c
src/detection/displayserver/linux/wayland/wp-color-management-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c
src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
@@ -1,134 +0,0 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H
#define KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include "wayland-client.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @page page_kde_output_order_v1 The kde_output_order_v1 protocol
* @section page_ifaces_kde_output_order_v1 Interfaces
* - @subpage page_iface_kde_output_order_v1 - announce order of outputs
* @section page_copyright_kde_output_order_v1 Copyright
* <pre>
*
* SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
*
* SPDX-License-Identifier: MIT-CMU
* </pre>
*/
struct kde_output_order_v1;
#ifndef KDE_OUTPUT_ORDER_V1_INTERFACE
#define KDE_OUTPUT_ORDER_V1_INTERFACE
/**
* @page page_iface_kde_output_order_v1 kde_output_order_v1
* @section page_iface_kde_output_order_v1_desc Description
*
* Announce the order in which desktop environment components should be placed on outputs.
* The compositor will send the list of outputs when the global is bound and whenever there is a change.
* @section page_iface_kde_output_order_v1_api API
* See @ref iface_kde_output_order_v1.
*/
/**
* @defgroup iface_kde_output_order_v1 The kde_output_order_v1 interface
*
* Announce the order in which desktop environment components should be placed on outputs.
* The compositor will send the list of outputs when the global is bound and whenever there is a change.
*/
extern const struct wl_interface kde_output_order_v1_interface;
#endif
/**
* @ingroup iface_kde_output_order_v1
* @struct kde_output_order_v1_listener
*/
struct kde_output_order_v1_listener {
/**
* output name
*
* Specifies the output identified by their wl_output.name.
* @param output_name the name of the output
*/
void (*output)(void* data,
struct kde_output_order_v1* kde_output_order_v1,
const char* output_name);
/**
* done
*
* Specifies that the output list is complete. On the next output
* event, a new list begins.
*/
void (*done)(void* data,
struct kde_output_order_v1* kde_output_order_v1);
};
/**
* @ingroup iface_kde_output_order_v1
*/
static inline int
kde_output_order_v1_add_listener(struct kde_output_order_v1* kde_output_order_v1,
const struct kde_output_order_v1_listener* listener,
void* data) {
return wl_proxy_add_listener((struct wl_proxy*) kde_output_order_v1,
(void (**)(void)) listener,
data);
}
#define KDE_OUTPUT_ORDER_V1_DESTROY 0
/**
* @ingroup iface_kde_output_order_v1
*/
#define KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION 1
/**
* @ingroup iface_kde_output_order_v1
*/
#define KDE_OUTPUT_ORDER_V1_DONE_SINCE_VERSION 1
/**
* @ingroup iface_kde_output_order_v1
*/
#define KDE_OUTPUT_ORDER_V1_DESTROY_SINCE_VERSION 1
// /** @ingroup iface_kde_output_order_v1 */
// static inline void
// kde_output_order_v1_set_user_data(struct kde_output_order_v1 *kde_output_order_v1, void *user_data)
// {
// wl_proxy_set_user_data((struct wl_proxy *) kde_output_order_v1, user_data);
// }
// /** @ingroup iface_kde_output_order_v1 */
// static inline void *
// kde_output_order_v1_get_user_data(struct kde_output_order_v1 *kde_output_order_v1)
// {
// return wl_proxy_get_user_data((struct wl_proxy *) kde_output_order_v1);
// }
// static inline uint32_t
// kde_output_order_v1_get_version(struct kde_output_order_v1 *kde_output_order_v1)
// {
// return wl_proxy_get_version((struct wl_proxy *) kde_output_order_v1);
// }
// /**
// * @ingroup iface_kde_output_order_v1
// */
// static inline void
// kde_output_order_v1_destroy(struct kde_output_order_v1 *kde_output_order_v1)
// {
// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_order_v1,
// KDE_OUTPUT_ORDER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_order_v1), WL_MARSHAL_FLAG_DESTROY);
// }
#ifdef __cplusplus
}
#endif
#endif
@@ -1,37 +0,0 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.22.0 */
/*
* SPDX-FileCopyrightText: 2022 Xaver Hugl <xaver.hugl@gmail.com>
*
* SPDX-License-Identifier: MIT-CMU
*/
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
static const struct wl_interface* kde_output_order_v1_types[] = {
NULL,
};
static const struct wl_message kde_output_order_v1_requests[] = {
{ "destroy", "", kde_output_order_v1_types + 0 },
};
static const struct wl_message kde_output_order_v1_events[] = {
{ "output", "s", kde_output_order_v1_types + 0 },
{ "done", "", kde_output_order_v1_types + 0 },
};
WL_EXPORT const struct wl_interface kde_output_order_v1_interface = {
"kde_output_order_v1",
1,
1,
kde_output_order_v1_requests,
2,
kde_output_order_v1_events,
};
#endif
@@ -2,7 +2,6 @@
#include "wayland.h"
#include "kde-output-device-v2-client-protocol.h"
#include "kde-output-order-v1-client-protocol.h"
#include "common/edidHelper.h"
#include "common/base64.h"
@@ -142,6 +141,11 @@ static void waylandKdeMaxBitsPerColorListener(void* data, FF_A_UNUSED struct kde
display->bitDepth = (uint8_t) max_bpc;
}
static void waylandKdePriorityListener(void* data, FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, uint32_t priority) {
WaylandDisplay* display = data;
display->primary = priority == 1;
}
static struct kde_output_device_v2_listener outputListener = {
.geometry = waylandKdeGeometryListener,
.current_mode = waylandKdeCurrentModeListener,
@@ -176,15 +180,16 @@ static struct kde_output_device_v2_listener outputListener = {
.max_bits_per_color_range = (void*) stubListener,
.automatic_max_bits_per_color_limit = (void*) stubListener,
.edr_policy = (void*) stubListener,
.sharpness = (void*) stubListener,
.priority = waylandKdePriorityListener,
.auto_brightness = (void*) stubListener,
.removed = (void*) stubListener,
.hdr_icc_profile_path = (void*) stubListener,
.hdr_color_profile_source = (void*) stubListener,
.abm_level = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create kde_output_device_v2";
}
static const char* waylandKdeHandleOutput(WaylandData* wldata, struct wl_proxy* output) {
FF_LIST_AUTO_DESTROY modes = ffListCreate();
WaylandDisplay display = {
.parent = wldata,
@@ -236,7 +241,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
? &display.edidName
: &display.name,
display.type,
false,
display.primary,
display.id,
(uint32_t) display.physicalWidth,
(uint32_t) display.physicalHeight,
@@ -265,35 +270,42 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
return NULL;
}
static void waylandKdeOutputOrderListener(void* data, FF_A_UNUSED struct kde_output_order_v1* _, const char* output_name) {
uint64_t* id = (uint64_t*) data;
if (*id == 0) {
*id = ffWaylandGenerateIdFromName(output_name);
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
// TODO: remove this in future versions
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_PRIORITY_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create kde_output_device_v2";
}
return waylandKdeHandleOutput(wldata, output);
}
static const struct kde_output_order_v1_listener orderListener = {
.output = waylandKdeOutputOrderListener,
.done = (void*) stubListener,
static void waylandKdeOutputListener(void* data, FF_A_UNUSED struct kde_output_device_registry_v2* kde_output_device_registry_v2, struct kde_output_device_v2* output) {
waylandKdeHandleOutput((WaylandData*) data, (struct wl_proxy*) output);
}
static struct kde_output_device_registry_v2_listener registryListener = {
.output = waylandKdeOutputListener,
.finished = (void*) stubListener,
};
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION);
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_order_v1_interface, bindVersion, name, kde_output_order_v1_interface.name, bindVersion, NULL);
if (output == NULL) {
return "Failed to create kde_output_order_v1";
const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_REGISTRY_V2_OUTPUT_SINCE_VERSION);
struct wl_proxy* outputRegistry = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_registry_v2_interface, bindVersion, name, kde_output_device_registry_v2_interface.name, bindVersion, NULL);
if (outputRegistry == NULL) {
return "Failed to create kde_output_device_registry_v2";
}
if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &orderListener, &wldata->primaryDisplayId) < 0) {
wldata->ffwl_proxy_destroy(output);
return "Failed to add listener to kde_output_order_v1";
if (wldata->ffwl_proxy_add_listener(outputRegistry, (void (**)(void)) &registryListener, wldata) < 0) {
wldata->ffwl_proxy_destroy(outputRegistry);
return "Failed to add listener to kde_output_device_registry_v2";
}
if (wldata->ffwl_display_roundtrip(wldata->display) < 0) {
wldata->ffwl_proxy_destroy(output);
return "Failed to roundtrip kde_output_order_v1";
wldata->ffwl_proxy_destroy(outputRegistry);
return "Failed to roundtrip kde_output_device_registry_v2";
}
wldata->ffwl_proxy_destroy(output);
wldata->ffwl_proxy_destroy(outputRegistry);
return NULL;
}
@@ -14,7 +14,6 @@
#include "wayland.h"
#include "kde-output-device-v2-client-protocol.h"
#include "kde-output-order-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "wp-color-management-v1-client-protocol.h"
@@ -86,13 +85,16 @@ static void waylandGlobalAddListener(void* data, struct wl_registry* registry, u
if (ffWaylandHandleGlobalOutput(wldata, registry, name, version) != NULL) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE) && ffStrEquals(interface, kde_output_device_v2_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE;
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, kde_output_device_registry_v2_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY;
if (ffWaylandHandleKdeOutputRegistry(wldata, registry, name, version) != NULL) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED) && ffStrEquals(interface, kde_output_device_v2_interface.name)) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED;
if (ffWaylandHandleKdeOutput(wldata, registry, name, version) != NULL) {
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_NONE;
}
} else if (ffStrEquals(interface, kde_output_order_v1_interface.name)) {
ffWaylandHandleKdeOutputOrder(wldata, registry, name, version);
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, zxdg_output_manager_v1_interface.name)) {
ffWaylandHandleZxdgOutput(wldata, registry, name, version);
} else if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE) && ffStrEquals(interface, wp_color_manager_v1_interface.name)) {
@@ -259,7 +261,7 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
data.ffwl_proxy_destroy(registry);
ffwl_display_disconnect(data.display);
if (data.primaryDisplayId == 0 && result->wmProcessName.length > 0) {
{
const char* fileName = ffStrbufEqualS(&result->wmProcessName, "gnome-shell")
? "monitors.xml"
: ffStrbufEqualS(&result->wmProcessName, "cinnamon")
@@ -306,7 +308,14 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
if (end < monitorsXml.length) {
ffStrbufSubstrBefore(&monitorsXml, end);
const char* name = monitorsXml.chars + start + strlen("<connector>");
data.primaryDisplayId = ffWaylandGenerateIdFromName(name);
uint64_t primaryDisplayId = ffWaylandGenerateIdFromName(name);
FF_LIST_FOR_EACH (FFDisplayResult, d, data.result->displays) {
if (d->id == primaryDisplayId) {
d->primary = true;
break;
}
}
}
}
}
@@ -314,15 +323,6 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
}
}
if (data.primaryDisplayId) {
FF_LIST_FOR_EACH (FFDisplayResult, d, data.result->displays) {
if (d->id == data.primaryDisplayId) {
d->primary = true;
break;
}
}
}
// We successfully connected to wayland and detected the display.
// So we can set set the session type to wayland.
// This is used as an indicator that we are running wayland by the x11 backends.
@@ -16,7 +16,8 @@ static inline uint32_t min(uint32_t a, uint32_t b) {
typedef enum FF_A_PACKED WaylandProtocolType {
FF_WAYLAND_PROTOCOL_TYPE_NONE,
FF_WAYLAND_PROTOCOL_TYPE_GLOBAL,
FF_WAYLAND_PROTOCOL_TYPE_KDE,
FF_WAYLAND_PROTOCOL_TYPE_KDE_DEPRECATED,
FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY,
} WaylandProtocolType;
typedef struct WaylandData {
@@ -27,7 +28,6 @@ typedef struct WaylandData {
FF_LIBRARY_SYMBOL(wl_display_roundtrip)
struct wl_display* display;
WaylandProtocolType protocolType;
uint64_t primaryDisplayId;
struct wl_proxy* zxdgOutputManager;
struct wl_proxy* wpColorManager;
} WaylandData;
@@ -57,6 +57,7 @@ typedef struct WaylandDisplay {
uint16_t mweek;
uint32_t serial;
uint8_t bitDepth;
bool primary;
} WaylandDisplay;
inline static void stubListener(void* data, ...) {
@@ -80,6 +81,7 @@ void ffWaylandOutputDescriptionListener(void* data, FF_A_UNUSED void* output, co
uint32_t ffWaylandHandleRotation(WaylandDisplay* display);
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);