From 76424950e373d3b04ac3dd13019151bfba3e8423 Mon Sep 17 00:00:00 2001 From: sumuel Date: Mon, 17 Aug 2026 20:44:55 +0000 Subject: Add the files --- .../displayserver/linux/wayland/global-output.c | 173 +++ .../wayland/kde-output-device-v2-client-protocol.h | 1384 ++++++++++++++++++++ .../linux/wayland/kde-output-device-v2-protocol.c | 128 ++ .../wayland/kde-output-order-v1-client-protocol.h | 134 ++ .../linux/wayland/kde-output-order-v1-protocol.c | 37 + .../displayserver/linux/wayland/kde-output.c | 300 +++++ .../displayserver/linux/wayland/wayland.c | 340 +++++ .../displayserver/linux/wayland/wayland.h | 89 ++ ...output-management-unstable-v1-client-protocol.h | 1292 ++++++++++++++++++ .../wlr-output-management-unstable-v1-protocol.c | 176 +++ .../xdg-output-unstable-v1-client-protocol.h | 414 ++++++ .../wayland/xdg-output-unstable-v1-protocol.c | 76 ++ .../displayserver/linux/wayland/zwlr-output.c | 212 +++ 13 files changed, 4755 insertions(+) create mode 100644 src/detection/displayserver/linux/wayland/global-output.c create mode 100644 src/detection/displayserver/linux/wayland/kde-output-device-v2-client-protocol.h create mode 100644 src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c create mode 100644 src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h create mode 100644 src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c create mode 100644 src/detection/displayserver/linux/wayland/kde-output.c create mode 100644 src/detection/displayserver/linux/wayland/wayland.c create mode 100644 src/detection/displayserver/linux/wayland/wayland.h create mode 100644 src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h create mode 100644 src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c create mode 100644 src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-client-protocol.h create mode 100644 src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c create mode 100644 src/detection/displayserver/linux/wayland/zwlr-output.c (limited to 'src/detection/displayserver/linux/wayland') diff --git a/src/detection/displayserver/linux/wayland/global-output.c b/src/detection/displayserver/linux/wayland/global-output.c new file mode 100644 index 0000000..51fb425 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/global-output.c @@ -0,0 +1,173 @@ +#ifdef FF_HAVE_WAYLAND + + #include "wayland.h" + #include "common/strutil.h" + #include "xdg-output-unstable-v1-client-protocol.h" + +static void waylandOutputModeListener(void* data, FF_A_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate) { + WaylandDisplay* display = data; + + if (flags & WL_OUTPUT_MODE_CURRENT) { + display->width = width; + display->height = height; + display->refreshRate = refreshRate; + } + if (flags & WL_OUTPUT_MODE_PREFERRED) { + display->preferredWidth = width; + display->preferredHeight = height; + display->preferredRefreshRate = refreshRate; + } +} + +static void waylandOutputScaleListener(void* data, FF_A_UNUSED struct wl_output* output, int32_t scale) { + WaylandDisplay* display = data; + display->dpi = 96 * (uint32_t) scale; +} + +static void waylandOutputGeometryListener(void* data, + FF_A_UNUSED struct wl_output* output, + FF_A_UNUSED int32_t x, + FF_A_UNUSED int32_t y, + int32_t physical_width, + int32_t physical_height, + FF_A_UNUSED int32_t subpixel, + FF_A_UNUSED const char* make, + FF_A_UNUSED const char* model, + int32_t transform) { + WaylandDisplay* display = data; + display->physicalWidth = physical_width; + display->physicalHeight = physical_height; + display->transform = (enum wl_output_transform) transform; +} + +static void handleXdgLogicalSize(void* data, FF_A_UNUSED struct zxdg_output_v1* _, int32_t width, FF_A_UNUSED int32_t height) { + WaylandDisplay* display = data; + // Seems the values are only useful when ractional scale is enabled + if (width < display->width) { + display->dpi = (uint32_t) (display->width * 96 / width); + } +} + +// Dirty hack for #477 +// The order of these callbacks MUST follow `struct wl_output_listener` +static void* outputListener[] = { + waylandOutputGeometryListener, // geometry + waylandOutputModeListener, // mode + stubListener, // done + waylandOutputScaleListener, // scale + ffWaylandOutputNameListener, // name + ffWaylandOutputDescriptionListener, // description +}; +static_assert( + sizeof(outputListener) >= sizeof(struct wl_output_listener), + "sizeof(outputListener) is too small. Please report it to fastfetch github issue"); + +static struct zxdg_output_v1_listener zxdgOutputListener = { + .logical_position = (void*) stubListener, + .logical_size = handleXdgLogicalSize, + .done = (void*) stubListener, + .name = (void*) ffWaylandOutputNameListener, + .description = (void*) ffWaylandOutputDescriptionListener, +}; + +const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { + const char* api = "wayland-global"; + uint32_t bindVersion = min(version, WL_OUTPUT_DESCRIPTION_SINCE_VERSION); + struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, bindVersion, name, wldata->ffwl_output_interface->name, bindVersion, NULL); + if (output == NULL) { + return "Failed to create wl_output"; + } + + WaylandDisplay display = { + .parent = wldata, + .transform = WL_OUTPUT_TRANSFORM_NORMAL, + .type = FF_DISPLAY_TYPE_UNKNOWN, + .name = ffStrbufCreate(), + .description = ffStrbufCreate(), + .edidName = ffStrbufCreate(), + }; + + if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &outputListener, &display) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to add listener to wl_output"; + } + if (wldata->ffwl_display_roundtrip(wldata->display) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to roundtrip wl_output"; + } + + if (wldata->zxdgOutputManager) { + uint32_t bindVersion = min(version, ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION); + struct wl_proxy* zxdgOutput = wldata->ffwl_proxy_marshal_constructor_versioned(wldata->zxdgOutputManager, ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, bindVersion, NULL, output); + + if (zxdgOutput) { + wldata->ffwl_proxy_add_listener(zxdgOutput, (void (**)(void)) &zxdgOutputListener, &display); + wldata->ffwl_display_roundtrip(wldata->display); + wldata->ffwl_proxy_destroy(zxdgOutput); + api = "wayland-global-zxdg"; + } + } + + wldata->ffwl_proxy_destroy(output); + + if (display.width <= 0 || display.height <= 0) { + return "Failed to get display information from wl_output"; + } + + uint32_t rotation = ffWaylandHandleRotation(&display); + + FFDisplayResult* item = ffdsAppendDisplay(wldata->result, + (uint32_t) display.width, + (uint32_t) display.height, + display.refreshRate / 1000.0, + display.dpi, + (uint32_t) display.preferredWidth, + (uint32_t) display.preferredHeight, + display.preferredRefreshRate / 1000.0, + rotation, + display.edidName.length + ? &display.edidName + // Try ignoring `eDP-1-unknown`, where `unknown` is localized + : display.description.length && !ffStrbufContain(&display.description, &display.name) + ? &display.description + : &display.name, + display.type, + false, + display.id, + (uint32_t) display.physicalWidth, + (uint32_t) display.physicalHeight, + api); + if (item) { + if (display.hdrSupported) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; + } else if (display.hdrInfoAvailable) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + } else { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + } + + item->manufactureYear = display.myear; + item->manufactureWeek = display.mweek; + item->serial = display.serial; + } + + ffStrbufDestroy(&display.description); + ffStrbufDestroy(&display.name); + ffStrbufDestroy(&display.edidName); + + return NULL; +} + +const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { + uint32_t bindVersion = min(version, ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION); + struct wl_proxy* manager = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zxdg_output_manager_v1_interface, bindVersion, name, zxdg_output_manager_v1_interface.name, bindVersion, NULL); + if (manager == NULL) { + return "Failed to create zxdg_output_manager_v1"; + } + + wldata->zxdgOutputManager = manager; + + return NULL; +} + +#endif diff --git a/src/detection/displayserver/linux/wayland/kde-output-device-v2-client-protocol.h b/src/detection/displayserver/linux/wayland/kde-output-device-v2-client-protocol.h new file mode 100644 index 0000000..44ab8ab --- /dev/null +++ b/src/detection/displayserver/linux/wayland/kde-output-device-v2-client-protocol.h @@ -0,0 +1,1384 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H +#define KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_kde_output_device_v2 The kde_output_device_v2 protocol + * @section page_ifaces_kde_output_device_v2 Interfaces + * - @subpage page_iface_kde_output_device_registry_v2 - output devices + * - @subpage page_iface_kde_output_device_v2 - output configuration representation + * - @subpage page_iface_kde_output_device_mode_v2 - output mode + * @section page_copyright_kde_output_device_v2 Copyright + *
+ *
+ * SPDX-FileCopyrightText: 2008-2011 Kristian Høgsberg
+ * SPDX-FileCopyrightText: 2010-2011 Intel Corporation
+ * SPDX-FileCopyrightText: 2012-2013 Collabora, Ltd.
+ * SPDX-FileCopyrightText: 2015 Sebastian Kügler 
+ * SPDX-FileCopyrightText: 2021 Méven Car 
+ *
+ * SPDX-License-Identifier: MIT-CMU
+ * 
+ */ +struct kde_output_device_mode_v2; +struct kde_output_device_registry_v2; +struct kde_output_device_v2; + +#ifndef KDE_OUTPUT_DEVICE_REGISTRY_V2_INTERFACE + #define KDE_OUTPUT_DEVICE_REGISTRY_V2_INTERFACE +/** + * @page page_iface_kde_output_device_registry_v2 kde_output_device_registry_v2 + * @section page_iface_kde_output_device_registry_v2_desc Description + * + * This interface can be used to list output devices. + * + * If this global is bound with a version less than 21, the unsupported_version + * protocol error will be posted. + * @section page_iface_kde_output_device_registry_v2_api API + * See @ref iface_kde_output_device_registry_v2. + */ +/** + * @defgroup iface_kde_output_device_registry_v2 The kde_output_device_registry_v2 interface + * + * This interface can be used to list output devices. + * + * If this global is bound with a version less than 21, the unsupported_version + * protocol error will be posted. + */ +extern const struct wl_interface kde_output_device_registry_v2_interface; +#endif +#ifndef KDE_OUTPUT_DEVICE_V2_INTERFACE + #define KDE_OUTPUT_DEVICE_V2_INTERFACE +/** + * @page page_iface_kde_output_device_v2 kde_output_device_v2 + * @section page_iface_kde_output_device_v2_desc Description + * + * An output device describes a display device available to the compositor. + * output_device is similar to wl_output, but focuses on output + * configuration management. + * + * A client can query all global output_device objects to enlist all + * available display devices, even those that may currently not be + * represented by the compositor as a wl_output. + * + * The client sends configuration changes to the server through the + * outputconfiguration interface, and the server applies the configuration + * changes to the hardware and signals changes to the output devices + * accordingly. + * + * This object is published as global during start up for every available + * display devices, or when one later becomes available, for example by + * being hotplugged via a physical connector. + * + * Warning! The protocol described in this file is a desktop environment + * implementation detail. Regular clients must not use this protocol. + * Backward incompatible changes may be added without bumping the major + * version of the extension. + * @section page_iface_kde_output_device_v2_api API + * See @ref iface_kde_output_device_v2. + */ +/** + * @defgroup iface_kde_output_device_v2 The kde_output_device_v2 interface + * + * An output device describes a display device available to the compositor. + * output_device is similar to wl_output, but focuses on output + * configuration management. + * + * A client can query all global output_device objects to enlist all + * available display devices, even those that may currently not be + * represented by the compositor as a wl_output. + * + * The client sends configuration changes to the server through the + * outputconfiguration interface, and the server applies the configuration + * changes to the hardware and signals changes to the output devices + * accordingly. + * + * This object is published as global during start up for every available + * display devices, or when one later becomes available, for example by + * being hotplugged via a physical connector. + * + * Warning! The protocol described in this file is a desktop environment + * implementation detail. Regular clients must not use this protocol. + * Backward incompatible changes may be added without bumping the major + * version of the extension. + */ +extern const struct wl_interface kde_output_device_v2_interface; +#endif +#ifndef KDE_OUTPUT_DEVICE_MODE_V2_INTERFACE + #define KDE_OUTPUT_DEVICE_MODE_V2_INTERFACE +/** + * @page page_iface_kde_output_device_mode_v2 kde_output_device_mode_v2 + * @section page_iface_kde_output_device_mode_v2_desc Description + * + * This object describes an output mode. + * + * Some heads don't support output modes, in which case modes won't be + * advertised. + * + * Properties sent via this interface are applied atomically via the + * kde_output_device.done event. No guarantees are made regarding the order + * in which properties are sent. + * @section page_iface_kde_output_device_mode_v2_api API + * See @ref iface_kde_output_device_mode_v2. + */ +/** + * @defgroup iface_kde_output_device_mode_v2 The kde_output_device_mode_v2 interface + * + * This object describes an output mode. + * + * Some heads don't support output modes, in which case modes won't be + * advertised. + * + * Properties sent via this interface are applied atomically via the + * kde_output_device.done event. No guarantees are made regarding the order + * in which properties are sent. + */ +extern const struct wl_interface kde_output_device_mode_v2_interface; +#endif + +#ifndef KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_ENUM + #define KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_ENUM +/** + * @ingroup iface_kde_output_device_registry_v2 + * kde_output_device_registry_v2 error values + * + * These errors can be emitted in response to some requests. + */ +enum kde_output_device_registry_v2_error { + /** + * the registry was bound with an unsupported version + */ + KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_UNSUPPORTED_VERSION = 0, +}; +#endif /* KDE_OUTPUT_DEVICE_REGISTRY_V2_ERROR_ENUM */ + +/** + * @ingroup iface_kde_output_device_registry_v2 + * @struct kde_output_device_registry_v2_listener + */ +struct kde_output_device_registry_v2_listener { + /** + * no new output announcements + * + * This event is sent in response to the stop request. The + * compositor will immediately destroy the object after sending + * this event. + * @since 21 + */ + void (*finished)(void* data, + struct kde_output_device_registry_v2* kde_output_device_registry_v2); + /** + * new available output + * + * This event is sent when a new output is connected or after + * binding this global to list all available outputs. + * @since 21 + */ + void (*output)(void* data, + struct kde_output_device_registry_v2* kde_output_device_registry_v2, + struct kde_output_device_v2* output); +}; + +/** + * @ingroup iface_kde_output_device_registry_v2 + */ +static inline int +kde_output_device_registry_v2_add_listener(struct kde_output_device_registry_v2* kde_output_device_registry_v2, + const struct kde_output_device_registry_v2_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) kde_output_device_registry_v2, + (void (**)(void)) listener, + data); +} + +#define KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP 0 + +/** + * @ingroup iface_kde_output_device_registry_v2 + */ +#define KDE_OUTPUT_DEVICE_REGISTRY_V2_FINISHED_SINCE_VERSION 21 +/** + * @ingroup iface_kde_output_device_registry_v2 + */ +#define KDE_OUTPUT_DEVICE_REGISTRY_V2_OUTPUT_SINCE_VERSION 21 + +/** + * @ingroup iface_kde_output_device_registry_v2 + */ +#define KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP_SINCE_VERSION 21 + +/** @ingroup iface_kde_output_device_registry_v2 */ +static inline void +kde_output_device_registry_v2_set_user_data(struct kde_output_device_registry_v2* kde_output_device_registry_v2, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) kde_output_device_registry_v2, user_data); +} + +/** @ingroup iface_kde_output_device_registry_v2 */ +static inline void* +kde_output_device_registry_v2_get_user_data(struct kde_output_device_registry_v2* kde_output_device_registry_v2) { + return wl_proxy_get_user_data((struct wl_proxy*) kde_output_device_registry_v2); +} + +static inline uint32_t +kde_output_device_registry_v2_get_version(struct kde_output_device_registry_v2* kde_output_device_registry_v2) { + return wl_proxy_get_version((struct wl_proxy*) kde_output_device_registry_v2); +} + +/** @ingroup iface_kde_output_device_registry_v2 */ +static inline void +kde_output_device_registry_v2_destroy(struct kde_output_device_registry_v2* kde_output_device_registry_v2) { + wl_proxy_destroy((struct wl_proxy*) kde_output_device_registry_v2); +} + +/** + * @ingroup iface_kde_output_device_registry_v2 + * + * This request indicates that the client no longer wants to receive new + * output announcements. The compositor will send the + * kde_output_device_registry_v2.finished event in response to this request. + * The compositor may still send new output announcements after calling this + * request until the kde_output_device_registry_v2.finished event is sent. + */ +// static inline void +// kde_output_device_registry_v2_stop(struct kde_output_device_registry_v2* kde_output_device_registry_v2) { +// wl_proxy_marshal_flags((struct wl_proxy*) kde_output_device_registry_v2, +// KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP, +// NULL, +// wl_proxy_get_version((struct wl_proxy*) kde_output_device_registry_v2), +// 0); +// } + +#ifndef KDE_OUTPUT_DEVICE_V2_SUBPIXEL_ENUM + #define KDE_OUTPUT_DEVICE_V2_SUBPIXEL_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * subpixel geometry information + * + * This enumeration describes how the physical pixels on an output are + * laid out. + */ +enum kde_output_device_v2_subpixel { + KDE_OUTPUT_DEVICE_V2_SUBPIXEL_UNKNOWN = 0, + KDE_OUTPUT_DEVICE_V2_SUBPIXEL_NONE = 1, + KDE_OUTPUT_DEVICE_V2_SUBPIXEL_HORIZONTAL_RGB = 2, + KDE_OUTPUT_DEVICE_V2_SUBPIXEL_HORIZONTAL_BGR = 3, + KDE_OUTPUT_DEVICE_V2_SUBPIXEL_VERTICAL_RGB = 4, + KDE_OUTPUT_DEVICE_V2_SUBPIXEL_VERTICAL_BGR = 5, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_SUBPIXEL_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_TRANSFORM_ENUM + #define KDE_OUTPUT_DEVICE_V2_TRANSFORM_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * transform from framebuffer to output + * + * This describes the transform, that a compositor will apply to a + * surface to compensate for the rotation or mirroring of an + * output device. + * + * The flipped values correspond to an initial flip around a + * vertical axis followed by rotation. + * + * The purpose is mainly to allow clients to render accordingly and + * tell the compositor, so that for fullscreen surfaces, the + * compositor is still able to scan out directly client surfaces. + */ +enum kde_output_device_v2_transform { + KDE_OUTPUT_DEVICE_V2_TRANSFORM_NORMAL = 0, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_90 = 1, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_180 = 2, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_270 = 3, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_FLIPPED = 4, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_FLIPPED_90 = 5, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_FLIPPED_180 = 6, + KDE_OUTPUT_DEVICE_V2_TRANSFORM_FLIPPED_270 = 7, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_TRANSFORM_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * describes capabilities of the outputdevice + * + * Describes what capabilities this device has. + */ +enum kde_output_device_v2_capability { + /** + * if this output_device can use overscan + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_OVERSCAN = 0x1, + /** + * if this outputdevice supports variable refresh rate + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_VRR = 0x2, + /** + * if setting the rgb range is possible + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_RGB_RANGE = 0x4, + /** + * if this outputdevice supports high dynamic range + * @since 3 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_HIGH_DYNAMIC_RANGE = 0x8, + /** + * if this outputdevice supports a wide color gamut + * @since 3 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_WIDE_COLOR_GAMUT = 0x10, + /** + * if this outputdevice supports autorotation + * @since 4 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_AUTO_ROTATE = 0x20, + /** + * if this outputdevice supports icc profiles + * @since 5 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_ICC_PROFILE = 0x40, + /** + * if this outputdevice supports the brightness setting + * @since 9 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80, + /** + * if this outputdevice supports the built-in color profile + * @since 12 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR = 0x100, + /** + * if this outputdevice supports DDC/CI + * @since 14 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI = 0x200, + /** + * if this outputdevice supports setting max bpc + * @since 15 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR = 0x400, + /** + * if this outputdevice supports EDR + * @since 16 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800, + /** + * if this outputdevice supports the sharpness setting + * @since 17 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_SHARPNESS = 0x1000, + /** + * if this outputdevice supports custom modes + * @since 18 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_CUSTOM_MODES = 0x2000, + /** + * @since 19 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_AUTO_BRIGHTNESS = 0x4000, + /** + * if this outputdevice supports HDR ICC profiles + * @since 22 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_HDR_ICC_PROFILE = 0x8000, + /** + * if this outputdevice supports the abm level setting + * @since 23 + */ + KDE_OUTPUT_DEVICE_V2_CAPABILITY_ABM_LEVEL = 0x10000, +}; + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_HIGH_DYNAMIC_RANGE_SINCE_VERSION 3 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_WIDE_COLOR_GAMUT_SINCE_VERSION 3 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_AUTO_ROTATE_SINCE_VERSION 4 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_ICC_PROFILE_SINCE_VERSION 5 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR_SINCE_VERSION 12 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI_SINCE_VERSION 14 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR_SINCE_VERSION 15 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_SHARPNESS_SINCE_VERSION 17 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_CUSTOM_MODES_SINCE_VERSION 18 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_AUTO_BRIGHTNESS_SINCE_VERSION 19 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_HDR_ICC_PROFILE_SINCE_VERSION 22 + /** + * @ingroup iface_kde_output_device_v2 + */ + #define KDE_OUTPUT_DEVICE_V2_CAPABILITY_ABM_LEVEL_SINCE_VERSION 23 +#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM + #define KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * describes vrr policy + * + * Describes when the compositor may employ variable refresh rate + */ +enum kde_output_device_v2_vrr_policy { + KDE_OUTPUT_DEVICE_V2_VRR_POLICY_NEVER = 0, + KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ALWAYS = 1, + KDE_OUTPUT_DEVICE_V2_VRR_POLICY_AUTOMATIC = 2, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_RGB_RANGE_ENUM + #define KDE_OUTPUT_DEVICE_V2_RGB_RANGE_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * describes RGB range policy + * + * Whether full or limited color range should be used + */ +enum kde_output_device_v2_rgb_range { + KDE_OUTPUT_DEVICE_V2_RGB_RANGE_AUTOMATIC = 0, + KDE_OUTPUT_DEVICE_V2_RGB_RANGE_FULL = 1, + KDE_OUTPUT_DEVICE_V2_RGB_RANGE_LIMITED = 2, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_RGB_RANGE_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_ENUM + #define KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * describes when auto rotate should be used + */ +enum kde_output_device_v2_auto_rotate_policy { + KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_NEVER = 0, + KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_IN_TABLET_MODE = 1, + KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_ALWAYS = 2, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_ENUM + #define KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * which source the compositor should use for the color profile on an output + */ +enum kde_output_device_v2_color_profile_source { + KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_SRGB = 0, + KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_ICC = 1, + KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_EDID = 2, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM + #define KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * tradeoff between power and accuracy + * + * The compositor can do a lot of things that trade between + * performance, power and color accuracy. This setting describes + * a high level preference from the user about in which direction + * that tradeoff should be made. + */ +enum kde_output_device_v2_color_power_tradeoff { + /** + * prefer efficiency and performance + */ + KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_EFFICIENCY = 0, + /** + * prefer accuracy + */ + KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ACCURACY = 1, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */ + +#ifndef KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM + #define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM +/** + * @ingroup iface_kde_output_device_v2 + * when the compositor may make use of EDR + */ +enum kde_output_device_v2_edr_policy { + KDE_OUTPUT_DEVICE_V2_EDR_POLICY_NEVER = 0, + KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ALWAYS = 1, +}; +#endif /* KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM */ + +/** + * @ingroup iface_kde_output_device_v2 + * @struct kde_output_device_v2_listener + */ +struct kde_output_device_v2_listener { + /** + * geometric properties of the output + * + * The geometry event describes geometric properties of the + * output. The event is sent when binding to the output object and + * whenever any of the properties change. + * @param x x position within the global compositor space + * @param y y position within the global compositor space + * @param physical_width width in millimeters of the output + * @param physical_height height in millimeters of the output + * @param subpixel subpixel orientation of the output + * @param make textual description of the manufacturer + * @param model textual description of the model + * @param transform transform that maps framebuffer to output + */ + void (*geometry)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + int32_t x, + int32_t y, + int32_t physical_width, + int32_t physical_height, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform); + /** + * current mode + * + * This event describes the mode currently in use for this head. + * It is only sent if the output is enabled. + */ + void (*current_mode)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + struct kde_output_device_mode_v2* mode); + /** + * advertise available output modes and current one + * + * The mode event describes an available mode for the output. + * + * When the client binds to the output_device object, the server + * sends this event once for every available mode the output_device + * can be operated by. + * + * There will always be at least one event sent out on initial + * binding, which represents the current mode. + * + * Later if an output changes, its mode event is sent again for the + * eventual added modes and lastly the current mode. In other + * words, the current mode is always represented by the latest + * event sent with the current flag set. + * + * The size of a mode is given in physical hardware units of the + * output device. This is not necessarily the same as the output + * size in the global compositor space. For instance, the output + * may be scaled, as described in kde_output_device_v2.scale, or + * transformed, as described in kde_output_device_v2.transform. + */ + void (*mode)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + struct kde_output_device_mode_v2* mode); + /** + * sent all information about output + * + * This event is sent after all other properties have been sent + * on binding to the output object as well as after any other + * output property change have been applied later on. This allows + * to see changes to the output properties as atomic, even if + * multiple events successively announce them. + */ + void (*done)(void* data, + struct kde_output_device_v2* kde_output_device_v2); + /** + * output scaling properties + * + * This event contains scaling geometry information that is not + * in the geometry event. It may be sent after binding the output + * object or if the output scale changes later. If it is not sent, + * the client should assume a scale of 1. + * + * A scale larger than 1 means that the compositor will + * automatically scale surface buffers by this amount when + * rendering. This is used for high resolution displays where + * applications rendering at the native resolution would be too + * small to be legible. + * + * It is intended that scaling aware clients track the current + * output of a surface, and if it is on a scaled output it should + * use wl_surface.set_buffer_scale with the scale of the output. + * That way the compositor can avoid scaling the surface, and the + * client can supply a higher detail image. + * @param factor scaling factor of output + */ + void (*scale)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + wl_fixed_t factor); + /** + * advertise EDID data for the output + * + * The edid event encapsulates the EDID data for the + * outputdevice. + * + * The event is sent when binding to the output object. The EDID + * data may be empty, in which case this event is sent anyway. If + * the EDID information is empty, you can fall back to the name et + * al. properties of the outputdevice. + * @param raw base64-encoded EDID string + */ + void (*edid)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* raw); + /** + * output is enabled or disabled + * + * The enabled event notifies whether this output is currently + * enabled and used for displaying content by the server. The event + * is sent when binding to the output object and whenever later on + * an output changes its state by becoming enabled or disabled. + * @param enabled output enabled state + */ + void (*enabled)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + int32_t enabled); + /** + * A unique id for this outputdevice + * + * The uuid can be used to identify the output. It's controlled + * by the server entirely. The server should make sure the uuid is + * persistent across restarts. An empty uuid is considered invalid. + * @param uuid output devices ID + */ + void (*uuid)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* uuid); + /** + * Serial Number + * + * Serial ID of the monitor, sent on startup before the first + * done event. + * @param serialNumber textual representation of serial number + */ + void (*serial_number)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* serialNumber); + /** + * EISA ID + * + * EISA ID of the monitor, sent on startup before the first done + * event. + * @param eisaId textual representation of EISA identifier + */ + void (*eisa_id)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* eisaId); + /** + * capability flags + * + * What capabilities this device has, sent on startup before the + * first done event. + */ + void (*capabilities)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t flags); + /** + * overscan + * + * Overscan value of the monitor in percent, sent on startup + * before the first done event. + * @param overscan amount of overscan of the monitor + */ + void (*overscan)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t overscan); + /** + * Variable Refresh Rate Policy + * + * What policy the compositor will employ regarding its use of + * variable refresh rate. + */ + void (*vrr_policy)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t vrr_policy); + /** + * RGB range + * + * What rgb range the compositor is using for this output + */ + void (*rgb_range)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t rgb_range); + /** + * Output's name + * + * Name of the output, it's useful to cross-reference to an + * zxdg_output_v1 and ultimately QScreen + * @since 2 + */ + void (*name)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* name); + /** + * if HDR is enabled + * + * Whether or not high dynamic range is enabled for this output + * @param hdr_enabled 1 if enabled, 0 if disabled + * @since 3 + */ + void (*high_dynamic_range)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t hdr_enabled); + /** + * the brightness of sdr if hdr is enabled + * + * If high dynamic range is used, this value defines the + * brightness in nits for content that's in standard dynamic range + * format. Note that while the value is in nits, that doesn't + * necessarily translate to the same brightness on the screen. + * @since 3 + */ + void (*sdr_brightness)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t sdr_brightness); + /** + * if WCG is enabled + * + * Whether or not the use of a wide color gamut is enabled for + * this output + * @param wcg_enabled 1 if enabled, 0 if disabled + * @since 3 + */ + void (*wide_color_gamut)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t wcg_enabled); + /** + * describes when auto rotate is used + * + * + * @since 4 + */ + void (*auto_rotate_policy)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t policy); + /** + * describes the path to the ICC profile used in SDR mode + * + * + * @since 5 + */ + void (*icc_profile_path)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* profile_path); + /** + * metadata about the screen's brightness limits + * + * + * @param max_peak_brightness in nits + * @param max_frame_average_brightness in nits + * @param min_brightness in 0.0001 nits + * @since 6 + */ + void (*brightness_metadata)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t max_peak_brightness, + uint32_t max_frame_average_brightness, + uint32_t min_brightness); + /** + * overrides for the screen's brightness limits + * + * + * @param max_peak_brightness -1 for no override, positive values are the brightness in nits + * @param max_average_brightness -1 for no override, positive values are the brightness in nits + * @param min_brightness -1 for no override, positive values are the brightness in 0.0001 nits + * @since 6 + */ + void (*brightness_overrides)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + int32_t max_peak_brightness, + int32_t max_average_brightness, + int32_t min_brightness); + /** + * describes which gamut is assumed for sRGB applications + * + * This can be used to provide the colors users assume sRGB + * applications should have based on the default experience on many + * modern sRGB screens. + * @param gamut_wideness 0 means rec.709 primaries, 10000 means native primaries + * @since 6 + */ + void (*sdr_gamut_wideness)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t gamut_wideness); + /** + * describes which source the compositor uses for the color profile on an output in SDR mode + * + * + * @since 7 + */ + void (*color_profile_source)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t source); + /** + * brightness multiplier + * + * This is the brightness modifier of the output. It doesn't + * specify any absolute values, but is merely a multiplier on top + * of other brightness values, like sdr_brightness and + * brightness_metadata. 0 is the minimum brightness (not completely + * dark) and 10000 is the maximum brightness. This is currently + * only supported / meaningful while HDR is active. + * @param brightness brightness in 0-10000 + * @since 8 + */ + void (*brightness)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t brightness); + /** + * the preferred color/power tradeoff + * + * + * @since 10 + */ + void (*color_power_tradeoff)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t preference); + /** + * dimming multiplier + * + * This is the dimming multiplier of the output. This is similar + * to the brightness setting, except it's meant to be a temporary + * setting only, not persistent and may be implemented differently + * depending on the display. 0 is the minimum dimming factor (not + * completely dark) and 10000 means the output is not dimmed. + * @param multiplier multiplier in 0-10000 + * @since 11 + */ + void (*dimming)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t multiplier); + /** + * source output for mirroring + * + * + * @param source uuid of the source output + * @since 13 + */ + void (*replication_source)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* source); + /** + * if DDC/CI should be used to control brightness etc. + * + * If the ddc_ci capability is present, this determines if + * settings such as brightness, contrast or others should be set + * using DDC/CI. + * @param allowed 1 if allowed, 0 if disabled + * @since 14 + */ + void (*ddc_ci_allowed)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t allowed); + /** + * override max bpc + * + * This limits the amount of bits per color that are sent to the + * display. + * @param max_bpc 0 for the default / automatic + * @since 15 + */ + void (*max_bits_per_color)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t max_bpc); + /** + * range of max bits per color value + * + * + * @param min_value the minimum supported by the driver + * @param max_value the maximum supported by the driver + * @since 15 + */ + void (*max_bits_per_color_range)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t min_value, + uint32_t max_value); + /** + * if and to what value automatic max bpc is limited + * + * + * @param max_bpc_limit which value automatic bpc gets limited to. 0 if not limited + * @since 15 + */ + void (*automatic_max_bits_per_color_limit)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t max_bpc_limit); + /** + * when the compositor may apply EDR + * + * When EDR is enabled, the compositor may increase the backlight + * beyond the user-specified setting, in order to present HDR + * content on displays without native HDR support. This will + * usually result in better visuals, but also increases battery + * usage. + * @since 16 + */ + void (*edr_policy)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t policy); + /** + * sharpness strength + * + * This is the sharpness modifier of the output. 0 is sharpness + * disabled and 10000 is the maximum sharpness + * @param sharpness sharpness in 0-10000 + * @since 17 + */ + void (*sharpness)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t sharpness); + /** + * output priority + * + * Describes the position of the output in the output order list, + * with lower values being earlier in the list. There's no specific + * value the list has to start at, this value is only used in + * sorting outputs. + * + * Note that the output order protocol is not sufficient for this, + * as an output may not be in the output order if it's disabled or + * mirroring another screen. + * @param priority priority + * @since 18 + */ + void (*priority)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t priority); + /** + * whether or not automatic brightness is enabled + * + * + * @param enabled 1 for enabled, 0 for disabled + * @since 20 + */ + void (*auto_brightness)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t enabled); + /** + * the output has been removed + * + * This event is sent when the output device is disconnected and + * no new updates will be sent. The client should call the + * kde_output_device_v2.release request after receiving this event. + * @since 21 + */ + void (*removed)(void* data, + struct kde_output_device_v2* kde_output_device_v2); + /** + * describes the path to the ICC profile used in HDR mode + * + * + * @since 22 + */ + void (*hdr_icc_profile_path)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + const char* profile_path); + /** + * describes which source the compositor uses for the color profile on an output in HDR mode + * + * + * @since 22 + */ + void (*hdr_color_profile_source)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t source); + /** + * allowed level of adaptive backlight modulation + * + * Adaptive backlight modulation is a feature that reduces the + * backlight and increases contrast of colors on the screen to + * improve power usage. + * @param level 0 is off, 4 is the maximum level + * @since 23 + */ + void (*abm_level)(void* data, + struct kde_output_device_v2* kde_output_device_v2, + uint32_t level); +}; + +/** + * @ingroup iface_kde_output_device_v2 + */ +static inline int +kde_output_device_v2_add_listener(struct kde_output_device_v2* kde_output_device_v2, + const struct kde_output_device_v2_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) kde_output_device_v2, + (void (**)(void)) listener, + data); +} + +#define KDE_OUTPUT_DEVICE_V2_RELEASE 0 + +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_GEOMETRY_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_CURRENT_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_SCALE_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_EDID_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_ENABLED_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_UUID_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_SERIAL_NUMBER_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_EISA_ID_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_CAPABILITIES_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_OVERSCAN_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_VRR_POLICY_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_RGB_RANGE_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_NAME_SINCE_VERSION 2 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_HIGH_DYNAMIC_RANGE_SINCE_VERSION 3 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_SDR_BRIGHTNESS_SINCE_VERSION 3 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_WIDE_COLOR_GAMUT_SINCE_VERSION 3 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_AUTO_ROTATE_POLICY_SINCE_VERSION 4 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_ICC_PROFILE_PATH_SINCE_VERSION 5 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_METADATA_SINCE_VERSION 6 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_OVERRIDES_SINCE_VERSION 6 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_SDR_GAMUT_WIDENESS_SINCE_VERSION 6 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_COLOR_PROFILE_SOURCE_SINCE_VERSION 7 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_SINCE_VERSION 8 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_SINCE_VERSION 10 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_REPLICATION_SOURCE_SINCE_VERSION 13 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_DDC_CI_ALLOWED_SINCE_VERSION 14 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION 15 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_RANGE_SINCE_VERSION 15 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_AUTOMATIC_MAX_BITS_PER_COLOR_LIMIT_SINCE_VERSION 15 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_SHARPNESS_SINCE_VERSION 17 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_PRIORITY_SINCE_VERSION 18 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_AUTO_BRIGHTNESS_SINCE_VERSION 20 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_REMOVED_SINCE_VERSION 21 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_HDR_ICC_PROFILE_PATH_SINCE_VERSION 22 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_HDR_COLOR_PROFILE_SOURCE_SINCE_VERSION 22 +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_ABM_LEVEL_SINCE_VERSION 23 + +/** + * @ingroup iface_kde_output_device_v2 + */ +#define KDE_OUTPUT_DEVICE_V2_RELEASE_SINCE_VERSION 21 + +/** @ingroup iface_kde_output_device_v2 */ +static inline void +kde_output_device_v2_set_user_data(struct kde_output_device_v2* kde_output_device_v2, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) kde_output_device_v2, user_data); +} + +/** @ingroup iface_kde_output_device_v2 */ +static inline void* +kde_output_device_v2_get_user_data(struct kde_output_device_v2* kde_output_device_v2) { + return wl_proxy_get_user_data((struct wl_proxy*) kde_output_device_v2); +} + +static inline uint32_t +kde_output_device_v2_get_version(struct kde_output_device_v2* kde_output_device_v2) { + return wl_proxy_get_version((struct wl_proxy*) kde_output_device_v2); +} + +/** @ingroup iface_kde_output_device_v2 */ +static inline void +kde_output_device_v2_destroy(struct kde_output_device_v2* kde_output_device_v2) { + wl_proxy_destroy((struct wl_proxy*) kde_output_device_v2); +} + +/** + * @ingroup iface_kde_output_device_v2 + * + * This notifies the compositor that the client no longer wishes to use + * the kde_output_device_v2 object. + */ +// static inline void +// kde_output_device_v2_release(struct kde_output_device_v2* kde_output_device_v2) { +// wl_proxy_marshal_flags((struct wl_proxy*) kde_output_device_v2, +// KDE_OUTPUT_DEVICE_V2_RELEASE, +// NULL, +// wl_proxy_get_version((struct wl_proxy*) kde_output_device_v2), +// WL_MARSHAL_FLAG_DESTROY); +// } + +#ifndef KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_ENUM + #define KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_ENUM +/** + * @ingroup iface_kde_output_device_mode_v2 + * mode flags + */ +enum kde_output_device_mode_v2_flags { + KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_CUSTOM = 0x1, + KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_REDUCED_BLANKING = 0x2, +}; +#endif /* KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_ENUM */ + +/** + * @ingroup iface_kde_output_device_mode_v2 + * @struct kde_output_device_mode_v2_listener + */ +struct kde_output_device_mode_v2_listener { + /** + * mode size + * + * This event describes the mode size. The size is given in + * physical hardware units of the output device. This is not + * necessarily the same as the output size in the global compositor + * space. For instance, the output may be scaled or transformed. + * @param width width of the mode in hardware units + * @param height height of the mode in hardware units + */ + void (*size)(void* data, + struct kde_output_device_mode_v2* kde_output_device_mode_v2, + int32_t width, + int32_t height); + /** + * mode refresh rate + * + * This event describes the mode's fixed vertical refresh rate. + * It is only sent if the mode has a fixed refresh rate. + * @param refresh vertical refresh rate in mHz + */ + void (*refresh)(void* data, + struct kde_output_device_mode_v2* kde_output_device_mode_v2, + int32_t refresh); + /** + * mode is preferred + * + * This event advertises this mode as preferred. + */ + void (*preferred)(void* data, + struct kde_output_device_mode_v2* kde_output_device_mode_v2); + /** + * the mode has been destroyed + * + * The compositor will destroy the object immediately after + * sending this event, so it will become invalid and the client + * should release any resources associated with it. + */ + void (*removed)(void* data, + struct kde_output_device_mode_v2* kde_output_device_mode_v2); + /** + * mode flags + * + * This event describes the mode's flags. + * @since 19 + */ + void (*flags)(void* data, + struct kde_output_device_mode_v2* kde_output_device_mode_v2, + uint32_t flags); +}; + +/** + * @ingroup iface_kde_output_device_mode_v2 + */ +static inline int +kde_output_device_mode_v2_add_listener(struct kde_output_device_mode_v2* kde_output_device_mode_v2, + const struct kde_output_device_mode_v2_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) kde_output_device_mode_v2, + (void (**)(void)) listener, + data); +} + +/** + * @ingroup iface_kde_output_device_mode_v2 + */ +#define KDE_OUTPUT_DEVICE_MODE_V2_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_mode_v2 + */ +#define KDE_OUTPUT_DEVICE_MODE_V2_REFRESH_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_mode_v2 + */ +#define KDE_OUTPUT_DEVICE_MODE_V2_PREFERRED_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_mode_v2 + */ +#define KDE_OUTPUT_DEVICE_MODE_V2_REMOVED_SINCE_VERSION 1 +/** + * @ingroup iface_kde_output_device_mode_v2 + */ +#define KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_SINCE_VERSION 19 + +/** @ingroup iface_kde_output_device_mode_v2 */ +static inline void +kde_output_device_mode_v2_set_user_data(struct kde_output_device_mode_v2* kde_output_device_mode_v2, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) kde_output_device_mode_v2, user_data); +} + +/** @ingroup iface_kde_output_device_mode_v2 */ +static inline void* +kde_output_device_mode_v2_get_user_data(struct kde_output_device_mode_v2* kde_output_device_mode_v2) { + return wl_proxy_get_user_data((struct wl_proxy*) kde_output_device_mode_v2); +} + +static inline uint32_t +kde_output_device_mode_v2_get_version(struct kde_output_device_mode_v2* kde_output_device_mode_v2) { + return wl_proxy_get_version((struct wl_proxy*) kde_output_device_mode_v2); +} + +/** @ingroup iface_kde_output_device_mode_v2 */ +static inline void +kde_output_device_mode_v2_destroy(struct kde_output_device_mode_v2* kde_output_device_mode_v2) { + wl_proxy_destroy((struct wl_proxy*) kde_output_device_mode_v2); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c b/src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c new file mode 100644 index 0000000..9dd7556 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c @@ -0,0 +1,128 @@ +#ifdef FF_HAVE_WAYLAND + +/* Generated by wayland-scanner 1.24.0 */ + +/* + * SPDX-FileCopyrightText: 2008-2011 Kristian Høgsberg + * SPDX-FileCopyrightText: 2010-2011 Intel Corporation + * SPDX-FileCopyrightText: 2012-2013 Collabora, Ltd. + * SPDX-FileCopyrightText: 2015 Sebastian Kügler + * SPDX-FileCopyrightText: 2021 Méven Car + * + * SPDX-License-Identifier: MIT-CMU + */ + + #include + #include + #include + #include + +extern const struct wl_interface kde_output_device_mode_v2_interface; +extern const struct wl_interface kde_output_device_v2_interface; + +static const struct wl_interface* kde_output_device_v2_types[] = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &kde_output_device_v2_interface, + &kde_output_device_mode_v2_interface, + &kde_output_device_mode_v2_interface, +}; + +static const struct wl_message kde_output_device_registry_v2_requests[] = { + { "stop", "21", kde_output_device_v2_types + 0 }, +}; + +static const struct wl_message kde_output_device_registry_v2_events[] = { + { "finished", "21", kde_output_device_v2_types + 0 }, + { "output", "21n", kde_output_device_v2_types + 8 }, +}; + +WL_EXPORT const struct wl_interface kde_output_device_registry_v2_interface = { + "kde_output_device_registry_v2", + 23, + 1, + kde_output_device_registry_v2_requests, + 2, + kde_output_device_registry_v2_events, +}; + +static const struct wl_message kde_output_device_v2_requests[] = { + { "release", "21", kde_output_device_v2_types + 0 }, +}; + +static const struct wl_message kde_output_device_v2_events[] = { + { "geometry", "iiiiissi", kde_output_device_v2_types + 0 }, + { "current_mode", "o", kde_output_device_v2_types + 9 }, + { "mode", "n", kde_output_device_v2_types + 10 }, + { "done", "", kde_output_device_v2_types + 0 }, + { "scale", "f", kde_output_device_v2_types + 0 }, + { "edid", "s", kde_output_device_v2_types + 0 }, + { "enabled", "i", kde_output_device_v2_types + 0 }, + { "uuid", "s", kde_output_device_v2_types + 0 }, + { "serial_number", "s", kde_output_device_v2_types + 0 }, + { "eisa_id", "s", kde_output_device_v2_types + 0 }, + { "capabilities", "u", kde_output_device_v2_types + 0 }, + { "overscan", "u", kde_output_device_v2_types + 0 }, + { "vrr_policy", "u", kde_output_device_v2_types + 0 }, + { "rgb_range", "u", kde_output_device_v2_types + 0 }, + { "name", "2s", kde_output_device_v2_types + 0 }, + { "high_dynamic_range", "3u", kde_output_device_v2_types + 0 }, + { "sdr_brightness", "3u", kde_output_device_v2_types + 0 }, + { "wide_color_gamut", "3u", kde_output_device_v2_types + 0 }, + { "auto_rotate_policy", "4u", kde_output_device_v2_types + 0 }, + { "icc_profile_path", "5s", kde_output_device_v2_types + 0 }, + { "brightness_metadata", "6uuu", kde_output_device_v2_types + 0 }, + { "brightness_overrides", "6iii", kde_output_device_v2_types + 0 }, + { "sdr_gamut_wideness", "6u", kde_output_device_v2_types + 0 }, + { "color_profile_source", "7u", kde_output_device_v2_types + 0 }, + { "brightness", "8u", kde_output_device_v2_types + 0 }, + { "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 }, + { "dimming", "11u", kde_output_device_v2_types + 0 }, + { "replication_source", "13s", kde_output_device_v2_types + 0 }, + { "ddc_ci_allowed", "14u", kde_output_device_v2_types + 0 }, + { "max_bits_per_color", "15u", kde_output_device_v2_types + 0 }, + { "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 }, + { "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 }, + { "edr_policy", "16u", kde_output_device_v2_types + 0 }, + { "sharpness", "17u", kde_output_device_v2_types + 0 }, + { "priority", "18u", kde_output_device_v2_types + 0 }, + { "auto_brightness", "20u", kde_output_device_v2_types + 0 }, + { "removed", "21", kde_output_device_v2_types + 0 }, + { "hdr_icc_profile_path", "22s", kde_output_device_v2_types + 0 }, + { "hdr_color_profile_source", "22u", kde_output_device_v2_types + 0 }, + { "abm_level", "23u", kde_output_device_v2_types + 0 }, +}; + +WL_EXPORT const struct wl_interface kde_output_device_v2_interface = { + "kde_output_device_v2", + 23, + 1, + kde_output_device_v2_requests, + 40, + kde_output_device_v2_events, +}; + +static const struct wl_message kde_output_device_mode_v2_events[] = { + { "size", "ii", kde_output_device_v2_types + 0 }, + { "refresh", "i", kde_output_device_v2_types + 0 }, + { "preferred", "", kde_output_device_v2_types + 0 }, + { "removed", "", kde_output_device_v2_types + 0 }, + { "flags", "19u", kde_output_device_v2_types + 0 }, +}; + +WL_EXPORT const struct wl_interface kde_output_device_mode_v2_interface = { + "kde_output_device_mode_v2", + 22, + 0, + NULL, + 5, + kde_output_device_mode_v2_events, +}; + +#endif diff --git a/src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h new file mode 100644 index 0000000..b9928c3 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/kde-output-order-v1-client-protocol.h @@ -0,0 +1,134 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H +#define KDE_OUTPUT_ORDER_V1_CLIENT_PROTOCOL_H + +#include +#include +#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 + *
+ *
+ * SPDX-FileCopyrightText: 2022 Xaver Hugl 
+ *
+ * SPDX-License-Identifier: MIT-CMU
+ * 
+ */ +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 diff --git a/src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c b/src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c new file mode 100644 index 0000000..00db32a --- /dev/null +++ b/src/detection/displayserver/linux/wayland/kde-output-order-v1-protocol.c @@ -0,0 +1,37 @@ +#ifdef FF_HAVE_WAYLAND + +/* Generated by wayland-scanner 1.22.0 */ + +/* + * SPDX-FileCopyrightText: 2022 Xaver Hugl + * + * SPDX-License-Identifier: MIT-CMU + */ + + #include + #include + #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 diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c new file mode 100644 index 0000000..90d5770 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -0,0 +1,300 @@ +#ifdef FF_HAVE_WAYLAND + + #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" + +typedef struct WaylandKdeMode { + int32_t width; + int32_t height; + int32_t refreshRate; + bool preferred; + struct kde_output_device_mode_v2* pMode; +} WaylandKdeMode; + +static void waylandKdeModeSizeListener(void* data, FF_A_UNUSED struct kde_output_device_mode_v2* _, int32_t width, int32_t height) { + WaylandKdeMode* mode = (WaylandKdeMode*) data; + mode->width = width; + mode->height = height; +} + +static void waylandKdeModeRefreshListener(void* data, FF_A_UNUSED struct kde_output_device_mode_v2* _, int32_t rate) { + WaylandKdeMode* mode = (WaylandKdeMode*) data; + mode->refreshRate = rate; +} + +static void waylandKdeModePreferredListener(void* data, FF_A_UNUSED struct kde_output_device_mode_v2* _) { + WaylandKdeMode* mode = (WaylandKdeMode*) data; + mode->preferred = true; +} + +static const struct kde_output_device_mode_v2_listener modeListener = { + .size = waylandKdeModeSizeListener, + .refresh = waylandKdeModeRefreshListener, + .preferred = waylandKdeModePreferredListener, + .removed = (void*) stubListener, + .flags = (void*) stubListener, +}; + +static void waylandKdeModeListener(void* data, FF_A_UNUSED struct kde_output_device_v2* _, struct kde_output_device_mode_v2* mode) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!wldata->internal) { + return; + } + + WaylandKdeMode* newMode = FF_LIST_ADD(WaylandKdeMode, *(FFlist*) wldata->internal); + *newMode = (WaylandKdeMode) { .pMode = mode }; + + // Strangely, the listener is called only in this function, but not in `waylandKdeCurrentModeListener` + wldata->parent->ffwl_proxy_add_listener((struct wl_proxy*) mode, (void (**)(void)) &modeListener, newMode); +} + +static void waylandKdeCurrentModeListener(void* data, FF_A_UNUSED struct kde_output_device_v2* _, struct kde_output_device_mode_v2* mode) { + // waylandKdeModeListener is always run before this + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!wldata->internal) { + return; + } + + int set = 0; + FF_LIST_FOR_EACH (WaylandKdeMode, m, *(FFlist*) wldata->internal) { + if (m->pMode == mode) { + wldata->width = m->width; + wldata->height = m->height; + wldata->refreshRate = m->refreshRate; + if (++set == 2) { + break; + } + } + if (m->preferred) { + wldata->preferredWidth = m->width; + wldata->preferredHeight = m->height; + wldata->preferredRefreshRate = m->refreshRate; + if (++set == 2) { + break; + } + } + } +} + +static void waylandKdeScaleListener(void* data, FF_A_UNUSED struct kde_output_device_v2* _, wl_fixed_t scale) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + wldata->dpi = (uint32_t) scale * 3 / 8; // wl_fixed_to_double(scale) * 96; +} + +static void waylandKdeEdidListener(void* data, FF_A_UNUSED struct kde_output_device_v2* _, const char* raw) { + if (!*raw) { + return; + } + WaylandDisplay* wldata = (WaylandDisplay*) data; + FF_STRBUF_AUTO_DESTROY b64 = ffStrbufCreateStatic(raw); + FF_STRBUF_AUTO_DESTROY edid = ffBase64DecodeStrbuf(&b64); + if (edid.length < 128) { + return; + } + ffEdidGetName((const uint8_t*) edid.chars, &wldata->edidName); + wldata->hdrSupported = ffEdidGetHdrCompatible((const uint8_t*) edid.chars, edid.length); + ffEdidGetSerialAndManufactureDate((const uint8_t*) edid.chars, &wldata->serial, &wldata->myear, &wldata->mweek); + wldata->hdrInfoAvailable = true; +} + +static void waylandKdeEnabledListener(void* data, FF_A_UNUSED struct kde_output_device_v2* _, int32_t enabled) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!enabled) { + wldata->internal = NULL; + } +} + +static void waylandKdeGeometryListener(void* data, + FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, + FF_A_UNUSED int32_t x, + FF_A_UNUSED int32_t y, + int32_t physical_width, + int32_t physical_height, + FF_A_UNUSED int32_t subpixel, + FF_A_UNUSED const char* make, + FF_A_UNUSED const char* model, + int32_t transform) { + WaylandDisplay* display = data; + display->physicalWidth = physical_width; + display->physicalHeight = physical_height; + display->transform = (enum wl_output_transform) transform; +} + +static void waylandKdeNameListener(void* data, FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, const char* name) { + WaylandDisplay* display = data; + display->type = ffdsGetDisplayType(name); + // As display->id is used as an internal identifier, we don't need it to be NUL terminated + strncpy((char*) &display->id, name, sizeof(display->id)); + + ffStrbufAppendS(&display->name, name); +} + +static void waylandKdeHdrListener(void* data, FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, uint32_t hdr_enabled) { + WaylandDisplay* display = data; + display->hdrEnabled = !!hdr_enabled; +} + +static void waylandKdeMaxBitsPerColorListener(void* data, FF_A_UNUSED struct kde_output_device_v2* kde_output_device_v2, uint32_t max_bpc) { + WaylandDisplay* display = data; + display->bitDepth = (uint8_t) max_bpc; +} + +static struct kde_output_device_v2_listener outputListener = { + .geometry = waylandKdeGeometryListener, + .current_mode = waylandKdeCurrentModeListener, + .mode = waylandKdeModeListener, + .done = (void*) stubListener, + .scale = waylandKdeScaleListener, + .edid = waylandKdeEdidListener, + .enabled = waylandKdeEnabledListener, + .uuid = (void*) stubListener, + .serial_number = (void*) stubListener, + .eisa_id = (void*) stubListener, + .capabilities = (void*) stubListener, + .overscan = (void*) stubListener, + .vrr_policy = (void*) stubListener, + .rgb_range = (void*) stubListener, + .name = waylandKdeNameListener, + .high_dynamic_range = waylandKdeHdrListener, + .sdr_brightness = (void*) stubListener, + .wide_color_gamut = (void*) stubListener, + .auto_rotate_policy = (void*) stubListener, + .icc_profile_path = (void*) stubListener, + .brightness_metadata = (void*) stubListener, + .brightness_overrides = (void*) stubListener, + .sdr_gamut_wideness = (void*) stubListener, + .color_profile_source = (void*) stubListener, + .brightness = (void*) stubListener, + .color_power_tradeoff = (void*) stubListener, + .dimming = (void*) stubListener, + .replication_source = (void*) stubListener, + .ddc_ci_allowed = (void*) stubListener, + .max_bits_per_color = (void*) waylandKdeMaxBitsPerColorListener, + .max_bits_per_color_range = (void*) stubListener, + .automatic_max_bits_per_color_limit = (void*) stubListener, + .edr_policy = (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"; + } + + FF_LIST_AUTO_DESTROY modes = ffListCreate(); + WaylandDisplay display = { + .parent = wldata, + .transform = WL_OUTPUT_TRANSFORM_NORMAL, + .type = FF_DISPLAY_TYPE_UNKNOWN, + .name = ffStrbufCreate(), + .description = ffStrbufCreate(), + .edidName = ffStrbufCreate(), + .internal = &modes, + }; + + if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &outputListener, &display) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to add listener to kde_output_device_v2"; + } + + if (wldata->ffwl_display_roundtrip(wldata->display) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to roundtrip kde_output_device_v2"; + } + // Destroy any mode proxies that were created during the listeners. + // wl proxies created for modes are not automatically freed by destroying + // the parent output proxy, so destroy them explicitly to avoid leaks. + FF_LIST_FOR_EACH (WaylandKdeMode, m, modes) { + if (m->pMode) { + wldata->ffwl_proxy_destroy((struct wl_proxy*) m->pMode); + m->pMode = NULL; + } + } + + wldata->ffwl_proxy_destroy(output); + + if (display.width <= 0 || display.height <= 0 || !display.internal) { + return "Failed to get display information from kde_output_device_v2"; + } + + uint32_t rotation = ffWaylandHandleRotation(&display); + + FFDisplayResult* item = ffdsAppendDisplay(wldata->result, + (uint32_t) display.width, + (uint32_t) display.height, + display.refreshRate / 1000.0, + display.dpi, + (uint32_t) display.preferredWidth, + (uint32_t) display.preferredHeight, + display.preferredRefreshRate / 1000.0, + rotation, + display.edidName.length + ? &display.edidName + : &display.name, + display.type, + false, + display.id, + (uint32_t) display.physicalWidth, + (uint32_t) display.physicalHeight, + "wayland-kde"); + if (item) { + if (display.hdrEnabled) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED; + } else if (display.hdrSupported) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; + } else if (display.hdrInfoAvailable) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + } else { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + } + + item->manufactureYear = display.myear; + item->manufactureWeek = display.mweek; + item->serial = display.serial; + item->bitDepth = display.bitDepth; + } + + ffStrbufDestroy(&display.description); + ffStrbufDestroy(&display.name); + ffStrbufDestroy(&display.edidName); + + 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); + } +} + +static const struct kde_output_order_v1_listener orderListener = { + .output = waylandKdeOutputOrderListener, + .done = (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"; + } + + 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_display_roundtrip(wldata->display) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to roundtrip kde_output_order_v1"; + } + wldata->ffwl_proxy_destroy(output); + + return NULL; +} + +#endif diff --git a/src/detection/displayserver/linux/wayland/wayland.c b/src/detection/displayserver/linux/wayland/wayland.c new file mode 100644 index 0000000..064c239 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wayland.c @@ -0,0 +1,340 @@ +#include "../displayserver_linux.h" +#include "common/io.h" +#include "common/edidHelper.h" +#include "common/strutil.h" + +#include +#include + +#ifdef FF_HAVE_WAYLAND + + #include + + #include "common/properties.h" + + #include "wayland.h" + #include "wlr-output-management-unstable-v1-client-protocol.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" + + #if __FreeBSD__ + #include + #include + #include + #endif + +static bool waylandDetectWM(int fd, FFDisplayServerResult* result) { + #if __linux__ || __GNU__ || (__FreeBSD__ && !__DragonFly__) + + #if __linux__ || __GNU__ + struct ucred ucred = {}; + socklen_t len = sizeof(ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1 || ucred.pid <= 0) { + return false; + } + + FF_STRBUF_AUTO_DESTROY procPath = ffStrbufCreate(); + ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); // We check the cmdline for the process name, because it is not trimmed. + if (!ffReadFileBuffer(procPath.chars, &result->wmProcessName)) { + return false; + } + #else + struct xucred ucred = {}; + socklen_t len = sizeof(ucred); + if (getsockopt(fd, AF_UNSPEC, LOCAL_PEERCRED, &ucred, &len) == -1 || ucred.cr_pid <= 0) { + return false; + } + + size_t size = 4096; + ffStrbufEnsureFixedLengthFree(&result->wmProcessName, (uint32_t) size); + + if (sysctl((int[]) { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, ucred.cr_pid }, 4, result->wmProcessName.chars, &size, NULL, 0) != 0) { + return false; + } + result->wmProcessName.length = (uint32_t) size - 1; + #endif + + // #1135: wl-restart is a special case + const char* filename = strrchr(result->wmProcessName.chars, '/'); + if (filename) { + filename++; + } else { + filename = result->wmProcessName.chars; + } + + if (ffStrEquals(filename, "wl-restart")) { + ffStrbufSubstrAfterLastC(&result->wmProcessName, '\0'); + } + + ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); // Trim the arguments + ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); // Trim the path + + return true; + + #else + FF_UNUSED(fd, result); + return false; + #endif +} + +static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) { + WaylandData* wldata = data; + + if ((wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_NONE || wldata->protocolType == FF_WAYLAND_PROTOCOL_TYPE_GLOBAL) && ffStrEquals(interface, wldata->ffwl_output_interface->name)) { + wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_GLOBAL; + 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_ZWLR) && ffStrEquals(interface, zwlr_output_manager_v1_interface.name)) { + wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_ZWLR; + if (ffWaylandHandleZwlrOutput(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; + 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); + } +} + +static FF_A_UNUSED bool matchDrmConnector(const char* connName, WaylandDisplay* wldata) { + // https://wayland.freedesktop.org/docs/html/apa.html#protocol-spec-wl_output-event-name + // The doc says that "do not assume that the name is a reflection of an underlying DRM connector, X11 connection, etc." + // However I can't find a better method to get the edid data + const char* drmDirPath = "/sys/class/drm/"; + + FF_AUTO_CLOSE_DIR DIR* dirp = opendir(drmDirPath); + if (dirp == NULL) { + return false; + } + + struct dirent* entry; + while ((entry = readdir(dirp)) != NULL) { + const char* plainName = entry->d_name; + if (ffStrStartsWith(plainName, "card")) { + const char* tmp = strchr(plainName + strlen("card"), '-'); + if (tmp) { + plainName = tmp + 1; + } + } + if (ffStrEquals(plainName, connName)) { + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateF("%s%s/edid", drmDirPath, entry->d_name); + + uint8_t edidData[512]; + ssize_t edidLength = ffReadFileData(path.chars, ARRAY_SIZE(edidData), edidData); + if (edidLength > 0 && edidLength % 128 == 0) { + ffEdidGetName(edidData, &wldata->edidName); + ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength); + ffEdidGetSerialAndManufactureDate(edidData, &wldata->serial, &wldata->myear, &wldata->mweek); + wldata->hdrInfoAvailable = true; + return true; + } + break; + } + } + return false; +} + +void ffWaylandOutputNameListener(void* data, FF_A_UNUSED void* output, const char* name) { + WaylandDisplay* display = data; + if (display->id) { + return; + } + + display->type = ffdsGetDisplayType(name); + #if __linux__ + if (!display->edidName.length) { + matchDrmConnector(name, display); + } + #endif + display->id = ffWaylandGenerateIdFromName(name); + ffStrbufAppendS(&display->name, name); +} + +void ffWaylandOutputDescriptionListener(void* data, FF_A_UNUSED void* output, const char* description) { + WaylandDisplay* display = data; + if (display->description.length) { + return; + } + + while (*description == ' ') { + ++description; + } + if (!ffStrEquals(description, "Unknown Display") && !ffStrContains(description, "(null)")) { + ffStrbufAppendS(&display->description, description); + } +} + +uint32_t ffWaylandHandleRotation(WaylandDisplay* display) { + uint32_t rotation; + switch (display->transform) { + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_90: + rotation = 90; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + case WL_OUTPUT_TRANSFORM_180: + rotation = 180; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + case WL_OUTPUT_TRANSFORM_270: + rotation = 270; + break; + default: + rotation = 0; + break; + } + + switch (rotation) { + case 90: + case 270: { + int32_t temp = display->width; + display->width = display->height; + display->height = temp; + + temp = display->physicalWidth; + display->physicalWidth = display->physicalHeight; + display->physicalHeight = temp; + break; + } + default: + break; + } + return rotation; +} + +const char* ffdsConnectWayland(FFDisplayServerResult* result) { + if (getenv("XDG_RUNTIME_DIR") == NULL) { + return "Wayland requires $XDG_RUNTIME_DIR being set"; + } + + FF_LIBRARY_LOAD_MESSAGE(wayland, "libwayland-client" FF_LIBRARY_EXTENSION, 1) + + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_connect) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_get_fd) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_proxy_marshal_constructor) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_disconnect) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_registry_interface) + + WaylandData data = {}; + + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_marshal_constructor_versioned) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_add_listener) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_destroy) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_display_roundtrip) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_output_interface) + + data.display = ffwl_display_connect(NULL); + if (data.display == NULL) { + return "wl_display_connect returned NULL"; + } + + waylandDetectWM(ffwl_display_get_fd(data.display), result); + + struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL); + if (registry == NULL) { + ffwl_display_disconnect(data.display); + return "wl_display_get_registry returned NULL"; + } + + data.result = result; + + struct wl_registry_listener registry_listener = { + .global = waylandGlobalAddListener, + .global_remove = (void*) stubListener + }; + + data.ffwl_proxy_add_listener(registry, (void (**)(void)) ®istry_listener, &data); + data.ffwl_display_roundtrip(data.display); + + if (data.zxdgOutputManager) { + data.ffwl_proxy_destroy(data.zxdgOutputManager); + } + + 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") + ? "cinnamon-monitors.xml" + : NULL; + if (fileName) { + FF_STRBUF_AUTO_DESTROY monitorsXml = ffStrbufCreate(); + FF_LIST_FOR_EACH (FFstrbuf, basePath, instance.state.platform.configDirs) { + char path[1024]; + snprintf(path, ARRAY_SIZE(path), "%s%s", basePath->chars, fileName); + if (ffReadFileBuffer(path, &monitorsXml)) { + break; + } + } + if (monitorsXml.length) { + // + // + // + // 0 + // 0 + // 1.7489879131317139 + // yes + // + // + // Virtual-1 + // unknown + // unknown + // unknown + // + // + // 3456 + // 2160 + // 60.000068664550781 + // + // + // + // + // + uint32_t start = ffStrbufFirstIndexS(&monitorsXml, "yes"); + if (start < monitorsXml.length) { + start = ffStrbufNextIndexS(&monitorsXml, start, ""); + if (start < monitorsXml.length) { + uint32_t end = ffStrbufNextIndexS(&monitorsXml, start, ""); + if (end < monitorsXml.length) { + ffStrbufSubstrBefore(&monitorsXml, end); + const char* name = monitorsXml.chars + start + strlen(""); + data.primaryDisplayId = ffWaylandGenerateIdFromName(name); + } + } + } + } + } + } + + 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. + ffStrbufSetStatic(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND); + return NULL; +} + +#else + +const char* ffdsConnectWayland(FF_A_UNUSED FFDisplayServerResult* result) { + return "Fastfetch was compiled without Wayland support"; +} + +#endif diff --git a/src/detection/displayserver/linux/wayland/wayland.h b/src/detection/displayserver/linux/wayland/wayland.h new file mode 100644 index 0000000..b103ab9 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wayland.h @@ -0,0 +1,89 @@ +#pragma once + +#ifdef FF_HAVE_WAYLAND + + #include "common/library.h" + #include "common/strutil.h" + + #include + + #include "../displayserver_linux.h" + +static inline uint32_t min(uint32_t a, uint32_t b) { + return a < b ? a : b; +} + +typedef enum FF_A_PACKED WaylandProtocolType { + FF_WAYLAND_PROTOCOL_TYPE_NONE, + FF_WAYLAND_PROTOCOL_TYPE_GLOBAL, + FF_WAYLAND_PROTOCOL_TYPE_ZWLR, + FF_WAYLAND_PROTOCOL_TYPE_KDE, +} WaylandProtocolType; + +typedef struct WaylandData { + FFDisplayServerResult* result; + FF_LIBRARY_SYMBOL(wl_proxy_marshal_constructor_versioned) + FF_LIBRARY_SYMBOL(wl_proxy_add_listener) + FF_LIBRARY_SYMBOL(wl_proxy_destroy) + FF_LIBRARY_SYMBOL(wl_display_roundtrip) + struct wl_display* display; + const struct wl_interface* ffwl_output_interface; + WaylandProtocolType protocolType; + uint64_t primaryDisplayId; + struct wl_proxy* zxdgOutputManager; +} WaylandData; + +typedef struct WaylandDisplay { + WaylandData* parent; + void* internal; + int32_t width; + int32_t height; + int32_t refreshRate; + int32_t preferredWidth; + int32_t preferredHeight; + int32_t preferredRefreshRate; + int32_t physicalWidth; + int32_t physicalHeight; + uint32_t dpi; + enum wl_output_transform transform; + FFDisplayType type; + FFstrbuf name; + FFstrbuf description; + FFstrbuf edidName; + uint64_t id; + bool hdrInfoAvailable; + bool hdrSupported; + bool hdrEnabled; + uint16_t myear; + uint16_t mweek; + uint32_t serial; + uint8_t bitDepth; +} WaylandDisplay; + +inline static void stubListener(void* data, ...) { + (void) data; +} + +inline static uint64_t ffWaylandGenerateIdFromName(const char* name) { + uint64_t id = 0; + size_t len = strlen(name); + if (len > sizeof(id)) { + memcpy(&id, name + (len - sizeof(id)), sizeof(id)); // copy the last 8 bytes + } else if (len > 0) { + memcpy(&id, name, len); + } + return id; +} + +void ffWaylandOutputNameListener(void* data, FF_A_UNUSED void* output, const char* name); +void ffWaylandOutputDescriptionListener(void* data, FF_A_UNUSED void* output, const char* description); +// Modifies content of display. Don't call this function when calling ffdsAppendDisplay +uint32_t ffWaylandHandleRotation(WaylandDisplay* display); + +const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version); +const char* ffWaylandHandleZwlrOutput(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); + +#endif diff --git a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h new file mode 100644 index 0000000..2b0584d --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-client-protocol.h @@ -0,0 +1,1292 @@ +/* Generated by wayland-scanner 1.24.0 */ + +#ifndef WLR_OUTPUT_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define WLR_OUTPUT_MANAGEMENT_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_wlr_output_management_unstable_v1 The wlr_output_management_unstable_v1 protocol + * protocol to configure output devices + * + * @section page_desc_wlr_output_management_unstable_v1 Description + * + * This protocol exposes interfaces to obtain and modify output device + * configuration. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible changes + * may be added together with the corresponding interface version bump. + * Backward incompatible changes are done by bumping the version number in + * the protocol and interface names and resetting the interface version. + * Once the protocol is to be declared stable, the 'z' prefix and the + * version number in the protocol and interface names are removed and the + * interface version number is reset. + * + * @section page_ifaces_wlr_output_management_unstable_v1 Interfaces + * - @subpage page_iface_zwlr_output_manager_v1 - output device configuration manager + * - @subpage page_iface_zwlr_output_head_v1 - output device + * - @subpage page_iface_zwlr_output_mode_v1 - output mode + * - @subpage page_iface_zwlr_output_configuration_v1 - output configuration + * - @subpage page_iface_zwlr_output_configuration_head_v1 - head configuration + * @section page_copyright_wlr_output_management_unstable_v1 Copyright + *
+ *
+ * Copyright © 2019 Purism SPC
+ *
+ * Permission to use, copy, modify, distribute, and sell this
+ * software and its documentation for any purpose is hereby granted
+ * without fee, provided that the above copyright notice appear in
+ * all copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of
+ * the copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+ * THIS SOFTWARE.
+ * 
+ */ +struct zwlr_output_configuration_head_v1; +struct zwlr_output_configuration_v1; +struct zwlr_output_head_v1; +struct zwlr_output_manager_v1; +struct zwlr_output_mode_v1; + +#ifndef ZWLR_OUTPUT_MANAGER_V1_INTERFACE + #define ZWLR_OUTPUT_MANAGER_V1_INTERFACE +/** + * @page page_iface_zwlr_output_manager_v1 zwlr_output_manager_v1 + * @section page_iface_zwlr_output_manager_v1_desc Description + * + * This interface is a manager that allows reading and writing the current + * output device configuration. + * + * Output devices that display pixels (e.g. a physical monitor or a virtual + * output in a window) are represented as heads. Heads cannot be created nor + * destroyed by the client, but they can be enabled or disabled and their + * properties can be changed. Each head may have one or more available modes. + * + * Whenever a head appears (e.g. a monitor is plugged in), it will be + * advertised via the head event. Immediately after the output manager is + * bound, all current heads are advertised. + * + * Whenever a head's properties change, the relevant wlr_output_head events + * will be sent. Not all head properties will be sent: only properties that + * have changed need to. + * + * Whenever a head disappears (e.g. a monitor is unplugged), a + * wlr_output_head.finished event will be sent. + * + * After one or more heads appear, change or disappear, the done event will + * be sent. It carries a serial which can be used in a create_configuration + * request to update heads properties. + * + * The information obtained from this protocol should only be used for output + * configuration purposes. This protocol is not designed to be a generic + * output property advertisement protocol for regular clients. Instead, + * protocols such as xdg-output should be used. + * @section page_iface_zwlr_output_manager_v1_api API + * See @ref iface_zwlr_output_manager_v1. + */ +/** + * @defgroup iface_zwlr_output_manager_v1 The zwlr_output_manager_v1 interface + * + * This interface is a manager that allows reading and writing the current + * output device configuration. + * + * Output devices that display pixels (e.g. a physical monitor or a virtual + * output in a window) are represented as heads. Heads cannot be created nor + * destroyed by the client, but they can be enabled or disabled and their + * properties can be changed. Each head may have one or more available modes. + * + * Whenever a head appears (e.g. a monitor is plugged in), it will be + * advertised via the head event. Immediately after the output manager is + * bound, all current heads are advertised. + * + * Whenever a head's properties change, the relevant wlr_output_head events + * will be sent. Not all head properties will be sent: only properties that + * have changed need to. + * + * Whenever a head disappears (e.g. a monitor is unplugged), a + * wlr_output_head.finished event will be sent. + * + * After one or more heads appear, change or disappear, the done event will + * be sent. It carries a serial which can be used in a create_configuration + * request to update heads properties. + * + * The information obtained from this protocol should only be used for output + * configuration purposes. This protocol is not designed to be a generic + * output property advertisement protocol for regular clients. Instead, + * protocols such as xdg-output should be used. + */ +extern const struct wl_interface zwlr_output_manager_v1_interface; +#endif +#ifndef ZWLR_OUTPUT_HEAD_V1_INTERFACE + #define ZWLR_OUTPUT_HEAD_V1_INTERFACE +/** + * @page page_iface_zwlr_output_head_v1 zwlr_output_head_v1 + * @section page_iface_zwlr_output_head_v1_desc Description + * + * A head is an output device. The difference between a wl_output object and + * a head is that heads are advertised even if they are turned off. A head + * object only advertises properties and cannot be used directly to change + * them. + * + * A head has some read-only properties: modes, name, description and + * physical_size. These cannot be changed by clients. + * + * Other properties can be updated via a wlr_output_configuration object. + * + * Properties sent via this interface are applied atomically via the + * wlr_output_manager.done event. No guarantees are made regarding the order + * in which properties are sent. + * @section page_iface_zwlr_output_head_v1_api API + * See @ref iface_zwlr_output_head_v1. + */ +/** + * @defgroup iface_zwlr_output_head_v1 The zwlr_output_head_v1 interface + * + * A head is an output device. The difference between a wl_output object and + * a head is that heads are advertised even if they are turned off. A head + * object only advertises properties and cannot be used directly to change + * them. + * + * A head has some read-only properties: modes, name, description and + * physical_size. These cannot be changed by clients. + * + * Other properties can be updated via a wlr_output_configuration object. + * + * Properties sent via this interface are applied atomically via the + * wlr_output_manager.done event. No guarantees are made regarding the order + * in which properties are sent. + */ +extern const struct wl_interface zwlr_output_head_v1_interface; +#endif +#ifndef ZWLR_OUTPUT_MODE_V1_INTERFACE + #define ZWLR_OUTPUT_MODE_V1_INTERFACE +/** + * @page page_iface_zwlr_output_mode_v1 zwlr_output_mode_v1 + * @section page_iface_zwlr_output_mode_v1_desc Description + * + * This object describes an output mode. + * + * Some heads don't support output modes, in which case modes won't be + * advertised. + * + * Properties sent via this interface are applied atomically via the + * wlr_output_manager.done event. No guarantees are made regarding the order + * in which properties are sent. + * @section page_iface_zwlr_output_mode_v1_api API + * See @ref iface_zwlr_output_mode_v1. + */ +/** + * @defgroup iface_zwlr_output_mode_v1 The zwlr_output_mode_v1 interface + * + * This object describes an output mode. + * + * Some heads don't support output modes, in which case modes won't be + * advertised. + * + * Properties sent via this interface are applied atomically via the + * wlr_output_manager.done event. No guarantees are made regarding the order + * in which properties are sent. + */ +extern const struct wl_interface zwlr_output_mode_v1_interface; +#endif +#ifndef ZWLR_OUTPUT_CONFIGURATION_V1_INTERFACE + #define ZWLR_OUTPUT_CONFIGURATION_V1_INTERFACE +/** + * @page page_iface_zwlr_output_configuration_v1 zwlr_output_configuration_v1 + * @section page_iface_zwlr_output_configuration_v1_desc Description + * + * This object is used by the client to describe a full output configuration. + * + * First, the client needs to setup the output configuration. Each head can + * be either enabled (and configured) or disabled. It is a protocol error to + * send two enable_head or disable_head requests with the same head. It is a + * protocol error to omit a head in a configuration. + * + * Then, the client can apply or test the configuration. The compositor will + * then reply with a succeeded, failed or cancelled event. Finally the client + * should destroy the configuration object. + * @section page_iface_zwlr_output_configuration_v1_api API + * See @ref iface_zwlr_output_configuration_v1. + */ +/** + * @defgroup iface_zwlr_output_configuration_v1 The zwlr_output_configuration_v1 interface + * + * This object is used by the client to describe a full output configuration. + * + * First, the client needs to setup the output configuration. Each head can + * be either enabled (and configured) or disabled. It is a protocol error to + * send two enable_head or disable_head requests with the same head. It is a + * protocol error to omit a head in a configuration. + * + * Then, the client can apply or test the configuration. The compositor will + * then reply with a succeeded, failed or cancelled event. Finally the client + * should destroy the configuration object. + */ +extern const struct wl_interface zwlr_output_configuration_v1_interface; +#endif +#ifndef ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_INTERFACE + #define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_INTERFACE +/** + * @page page_iface_zwlr_output_configuration_head_v1 zwlr_output_configuration_head_v1 + * @section page_iface_zwlr_output_configuration_head_v1_desc Description + * + * This object is used by the client to update a single head's configuration. + * + * It is a protocol error to set the same property twice. + * @section page_iface_zwlr_output_configuration_head_v1_api API + * See @ref iface_zwlr_output_configuration_head_v1. + */ +/** + * @defgroup iface_zwlr_output_configuration_head_v1 The zwlr_output_configuration_head_v1 interface + * + * This object is used by the client to update a single head's configuration. + * + * It is a protocol error to set the same property twice. + */ +extern const struct wl_interface zwlr_output_configuration_head_v1_interface; +#endif + +/** + * @ingroup iface_zwlr_output_manager_v1 + * @struct zwlr_output_manager_v1_listener + */ +struct zwlr_output_manager_v1_listener { + /** + * introduce a new head + * + * This event introduces a new head. This happens whenever a new + * head appears (e.g. a monitor is plugged in) or after the output + * manager is bound. + */ + void (*head)(void* data, + struct zwlr_output_manager_v1* zwlr_output_manager_v1, + struct zwlr_output_head_v1* head); + /** + * sent all information about current configuration + * + * This event is sent after all information has been sent after + * binding to the output manager object and after any subsequent + * changes. This applies to child head and mode objects as well. In + * other words, this event is sent whenever a head or mode is + * created or destroyed and whenever one of their properties has + * been changed. Not all state is re-sent each time the current + * configuration changes: only the actual changes are sent. + * + * This allows changes to the output configuration to be seen as + * atomic, even if they happen via multiple events. + * + * A serial is sent to be used in a future create_configuration + * request. + * @param serial current configuration serial + */ + void (*done)(void* data, + struct zwlr_output_manager_v1* zwlr_output_manager_v1, + uint32_t serial); + /** + * the compositor has finished with the manager + * + * This event indicates that the compositor is done sending + * manager events. The compositor will destroy the object + * immediately after sending this event, so it will become invalid + * and the client should release any resources associated with it. + */ + void (*finished)(void* data, + struct zwlr_output_manager_v1* zwlr_output_manager_v1); +}; + +/** + * @ingroup iface_zwlr_output_manager_v1 + */ +static inline int +zwlr_output_manager_v1_add_listener(struct zwlr_output_manager_v1* zwlr_output_manager_v1, + const struct zwlr_output_manager_v1_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_manager_v1, + (void (**)(void)) listener, + data); +} + +#define ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION 0 +#define ZWLR_OUTPUT_MANAGER_V1_STOP 1 + +/** + * @ingroup iface_zwlr_output_manager_v1 + */ +#define ZWLR_OUTPUT_MANAGER_V1_HEAD_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_manager_v1 + */ +#define ZWLR_OUTPUT_MANAGER_V1_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_manager_v1 + */ +#define ZWLR_OUTPUT_MANAGER_V1_FINISHED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_output_manager_v1 + */ +#define ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_manager_v1 + */ +#define ZWLR_OUTPUT_MANAGER_V1_STOP_SINCE_VERSION 1 + +/** @ingroup iface_zwlr_output_manager_v1 */ +static inline void +zwlr_output_manager_v1_set_user_data(struct zwlr_output_manager_v1* zwlr_output_manager_v1, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_manager_v1, user_data); +} + +/** @ingroup iface_zwlr_output_manager_v1 */ +static inline void* +zwlr_output_manager_v1_get_user_data(struct zwlr_output_manager_v1* zwlr_output_manager_v1) { + return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_manager_v1); +} + +static inline uint32_t +zwlr_output_manager_v1_get_version(struct zwlr_output_manager_v1* zwlr_output_manager_v1) { + return wl_proxy_get_version((struct wl_proxy*) zwlr_output_manager_v1); +} + +/** @ingroup iface_zwlr_output_manager_v1 */ +static inline void +zwlr_output_manager_v1_destroy(struct zwlr_output_manager_v1* zwlr_output_manager_v1) { + wl_proxy_destroy((struct wl_proxy*) zwlr_output_manager_v1); +} + +// /** +// * @ingroup iface_zwlr_output_manager_v1 +// * +// * Create a new output configuration object. This allows to update head +// * properties. +// */ +// static inline struct zwlr_output_configuration_v1 * +// zwlr_output_manager_v1_create_configuration(struct zwlr_output_manager_v1 *zwlr_output_manager_v1, uint32_t serial) +// { +// struct wl_proxy *id; + +// id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_manager_v1, +// ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION, &zwlr_output_configuration_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_output_manager_v1), 0, NULL, serial); + +// return (struct zwlr_output_configuration_v1 *) id; +// } + +// /** +// * @ingroup iface_zwlr_output_manager_v1 +// * +// * Indicates the client no longer wishes to receive events for output +// * configuration changes. However the compositor may emit further events, +// * until the finished event is emitted. +// * +// * The client must not send any more requests after this one. +// */ +// static inline void +// zwlr_output_manager_v1_stop(struct zwlr_output_manager_v1 *zwlr_output_manager_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_manager_v1, +// ZWLR_OUTPUT_MANAGER_V1_STOP, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_manager_v1), 0); +// } + +#ifndef ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENUM + #define ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENUM +enum zwlr_output_head_v1_adaptive_sync_state { + /** + * adaptive sync is disabled + */ + ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED = 0, + /** + * adaptive sync is enabled + */ + ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED = 1, +}; +#endif /* ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENUM */ + +/** + * @ingroup iface_zwlr_output_head_v1 + * @struct zwlr_output_head_v1_listener + */ +struct zwlr_output_head_v1_listener { + /** + * head name + * + * This event describes the head name. + * + * The naming convention is compositor defined, but limited to + * alphanumeric characters and dashes (-). Each name is unique + * among all wlr_output_head objects, but if a wlr_output_head + * object is destroyed the same name may be reused later. The names + * will also remain consistent across sessions with the same + * hardware and software configuration. + * + * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. + * However, do not assume that the name is a reflection of an + * underlying DRM connector, X11 connection, etc. + * + * If this head matches a wl_output, the wl_output.name event must + * report the same name. + * + * The name event is sent after a wlr_output_head object is + * created. This event is only sent once per object, and the name + * does not change over the lifetime of the wlr_output_head object. + */ + void (*name)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + const char* name); + /** + * head description + * + * This event describes a human-readable description of the head. + * + * The description is a UTF-8 string with no convention defined for + * its contents. Examples might include 'Foocorp 11" Display' or + * 'Virtual X11 output via :1'. However, do not assume that the + * name is a reflection of the make, model, serial of the + * underlying DRM connector or the display name of the underlying + * X11 connection, etc. + * + * If this head matches a wl_output, the wl_output.description + * event must report the same name. + * + * The description event is sent after a wlr_output_head object is + * created. This event is only sent once per object, and the + * description does not change over the lifetime of the + * wlr_output_head object. + */ + void (*description)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + const char* description); + /** + * head physical size + * + * This event describes the physical size of the head. This event + * is only sent if the head has a physical size (e.g. is not a + * projector or a virtual device). + * + * The physical size event is sent after a wlr_output_head object + * is created. This event is only sent once per object, and the + * physical size does not change over the lifetime of the + * wlr_output_head object. + * @param width width in millimeters of the output + * @param height height in millimeters of the output + */ + void (*physical_size)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + int32_t width, + int32_t height); + /** + * introduce a mode + * + * This event introduces a mode for this head. It is sent once + * per supported mode. + */ + void (*mode)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + struct zwlr_output_mode_v1* mode); + /** + * head is enabled or disabled + * + * This event describes whether the head is enabled. A disabled + * head is not mapped to a region of the global compositor space. + * + * When a head is disabled, some properties (current_mode, + * position, transform and scale) are irrelevant. + * @param enabled zero if disabled, non-zero if enabled + */ + void (*enabled)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + int32_t enabled); + /** + * current mode + * + * This event describes the mode currently in use for this head. + * It is only sent if the output is enabled. + */ + void (*current_mode)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + struct zwlr_output_mode_v1* mode); + /** + * current position + * + * This events describes the position of the head in the global + * compositor space. It is only sent if the output is enabled. + * @param x x position within the global compositor space + * @param y y position within the global compositor space + */ + void (*position)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + int32_t x, + int32_t y); + /** + * current transformation + * + * This event describes the transformation currently applied to + * the head. It is only sent if the output is enabled. + */ + void (*transform)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + int32_t transform); + /** + * current scale + * + * This events describes the scale of the head in the global + * compositor space. It is only sent if the output is enabled. + */ + void (*scale)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + wl_fixed_t scale); + /** + * the head has disappeared + * + * This event indicates that the head is no longer available. The + * head object becomes inert. Clients should send a destroy request + * and release any resources associated with it. + */ + void (*finished)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1); + /** + * head manufacturer + * + * This event describes the manufacturer of the head. + * + * Together with the model and serial_number events the purpose is + * to allow clients to recognize heads from previous sessions and + * for example load head-specific configurations back. + * + * It is not guaranteed this event will be ever sent. A reason for + * that can be that the compositor does not have information about + * the make of the head or the definition of a make is not sensible + * in the current setup, for example in a virtual session. Clients + * can still try to identify the head by available information from + * other events but should be aware that there is an increased risk + * of false positives. + * + * If sent, the make event is sent after a wlr_output_head object + * is created and only sent once per object. The make does not + * change over the lifetime of the wlr_output_head object. + * + * It is not recommended to display the make string in UI to users. + * For that the string provided by the description event should be + * preferred. + * @since 2 + */ + void (*make)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + const char* make); + /** + * head model + * + * This event describes the model of the head. + * + * Together with the make and serial_number events the purpose is + * to allow clients to recognize heads from previous sessions and + * for example load head-specific configurations back. + * + * It is not guaranteed this event will be ever sent. A reason for + * that can be that the compositor does not have information about + * the model of the head or the definition of a model is not + * sensible in the current setup, for example in a virtual session. + * Clients can still try to identify the head by available + * information from other events but should be aware that there is + * an increased risk of false positives. + * + * If sent, the model event is sent after a wlr_output_head object + * is created and only sent once per object. The model does not + * change over the lifetime of the wlr_output_head object. + * + * It is not recommended to display the model string in UI to + * users. For that the string provided by the description event + * should be preferred. + * @since 2 + */ + void (*model)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + const char* model); + /** + * head serial number + * + * This event describes the serial number of the head. + * + * Together with the make and model events the purpose is to allow + * clients to recognize heads from previous sessions and for + * example load head- specific configurations back. + * + * It is not guaranteed this event will be ever sent. A reason for + * that can be that the compositor does not have information about + * the serial number of the head or the definition of a serial + * number is not sensible in the current setup. Clients can still + * try to identify the head by available information from other + * events but should be aware that there is an increased risk of + * false positives. + * + * If sent, the serial number event is sent after a wlr_output_head + * object is created and only sent once per object. The serial + * number does not change over the lifetime of the wlr_output_head + * object. + * + * It is not recommended to display the serial_number string in UI + * to users. For that the string provided by the description event + * should be preferred. + * @since 2 + */ + void (*serial_number)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + const char* serial_number); + /** + * current adaptive sync state + * + * This event describes whether adaptive sync is currently + * enabled for the head or not. Adaptive sync is also known as + * Variable Refresh Rate or VRR. + * @since 4 + */ + void (*adaptive_sync)(void* data, + struct zwlr_output_head_v1* zwlr_output_head_v1, + uint32_t state); +}; + +/** + * @ingroup iface_zwlr_output_head_v1 + */ +static inline int +zwlr_output_head_v1_add_listener(struct zwlr_output_head_v1* zwlr_output_head_v1, + const struct zwlr_output_head_v1_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_head_v1, + (void (**)(void)) listener, + data); +} + +#define ZWLR_OUTPUT_HEAD_V1_RELEASE 0 + +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_NAME_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_DESCRIPTION_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_PHYSICAL_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_ENABLED_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_CURRENT_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_TRANSFORM_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_SCALE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_FINISHED_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION 2 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION 2 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION 2 +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_SINCE_VERSION 4 + +/** + * @ingroup iface_zwlr_output_head_v1 + */ +#define ZWLR_OUTPUT_HEAD_V1_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_zwlr_output_head_v1 */ +static inline void +zwlr_output_head_v1_set_user_data(struct zwlr_output_head_v1* zwlr_output_head_v1, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_head_v1, user_data); +} + +/** @ingroup iface_zwlr_output_head_v1 */ +static inline void* +zwlr_output_head_v1_get_user_data(struct zwlr_output_head_v1* zwlr_output_head_v1) { + return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_head_v1); +} + +static inline uint32_t +zwlr_output_head_v1_get_version(struct zwlr_output_head_v1* zwlr_output_head_v1) { + return wl_proxy_get_version((struct wl_proxy*) zwlr_output_head_v1); +} + +/** @ingroup iface_zwlr_output_head_v1 */ +static inline void +zwlr_output_head_v1_destroy(struct zwlr_output_head_v1* zwlr_output_head_v1) { + wl_proxy_destroy((struct wl_proxy*) zwlr_output_head_v1); +} + +// /** +// * @ingroup iface_zwlr_output_head_v1 +// * +// * This request indicates that the client will no longer use this head +// * object. +// */ +// static inline void +// zwlr_output_head_v1_release(struct zwlr_output_head_v1 *zwlr_output_head_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_head_v1, +// ZWLR_OUTPUT_HEAD_V1_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_head_v1), WL_MARSHAL_FLAG_DESTROY); +// } + +/** + * @ingroup iface_zwlr_output_mode_v1 + * @struct zwlr_output_mode_v1_listener + */ +struct zwlr_output_mode_v1_listener { + /** + * mode size + * + * This event describes the mode size. The size is given in + * physical hardware units of the output device. This is not + * necessarily the same as the output size in the global compositor + * space. For instance, the output may be scaled or transformed. + * @param width width of the mode in hardware units + * @param height height of the mode in hardware units + */ + void (*size)(void* data, + struct zwlr_output_mode_v1* zwlr_output_mode_v1, + int32_t width, + int32_t height); + /** + * mode refresh rate + * + * This event describes the mode's fixed vertical refresh rate. + * It is only sent if the mode has a fixed refresh rate. + * @param refresh vertical refresh rate in mHz + */ + void (*refresh)(void* data, + struct zwlr_output_mode_v1* zwlr_output_mode_v1, + int32_t refresh); + /** + * mode is preferred + * + * This event advertises this mode as preferred. + */ + void (*preferred)(void* data, + struct zwlr_output_mode_v1* zwlr_output_mode_v1); + /** + * the mode has disappeared + * + * This event indicates that the mode is no longer available. The + * mode object becomes inert. Clients should send a destroy request + * and release any resources associated with it. + */ + void (*finished)(void* data, + struct zwlr_output_mode_v1* zwlr_output_mode_v1); +}; + +/** + * @ingroup iface_zwlr_output_mode_v1 + */ +static inline int +zwlr_output_mode_v1_add_listener(struct zwlr_output_mode_v1* zwlr_output_mode_v1, + const struct zwlr_output_mode_v1_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_mode_v1, + (void (**)(void)) listener, + data); +} + +#define ZWLR_OUTPUT_MODE_V1_RELEASE 0 + +/** + * @ingroup iface_zwlr_output_mode_v1 + */ +#define ZWLR_OUTPUT_MODE_V1_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_mode_v1 + */ +#define ZWLR_OUTPUT_MODE_V1_REFRESH_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_mode_v1 + */ +#define ZWLR_OUTPUT_MODE_V1_PREFERRED_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_mode_v1 + */ +#define ZWLR_OUTPUT_MODE_V1_FINISHED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_output_mode_v1 + */ +#define ZWLR_OUTPUT_MODE_V1_RELEASE_SINCE_VERSION 3 + +/** @ingroup iface_zwlr_output_mode_v1 */ +static inline void +zwlr_output_mode_v1_set_user_data(struct zwlr_output_mode_v1* zwlr_output_mode_v1, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_mode_v1, user_data); +} + +/** @ingroup iface_zwlr_output_mode_v1 */ +static inline void* +zwlr_output_mode_v1_get_user_data(struct zwlr_output_mode_v1* zwlr_output_mode_v1) { + return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_mode_v1); +} + +static inline uint32_t +zwlr_output_mode_v1_get_version(struct zwlr_output_mode_v1* zwlr_output_mode_v1) { + return wl_proxy_get_version((struct wl_proxy*) zwlr_output_mode_v1); +} + +/** @ingroup iface_zwlr_output_mode_v1 */ +static inline void +zwlr_output_mode_v1_destroy(struct zwlr_output_mode_v1* zwlr_output_mode_v1) { + wl_proxy_destroy((struct wl_proxy*) zwlr_output_mode_v1); +} + +// /** +// * @ingroup iface_zwlr_output_mode_v1 +// * +// * This request indicates that the client will no longer use this mode +// * object. +// */ +// static inline void +// zwlr_output_mode_v1_release(struct zwlr_output_mode_v1 *zwlr_output_mode_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_mode_v1, +// ZWLR_OUTPUT_MODE_V1_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_mode_v1), WL_MARSHAL_FLAG_DESTROY); +// } + +#ifndef ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ENUM + #define ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ENUM +enum zwlr_output_configuration_v1_error { + /** + * head has been configured twice + */ + ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_CONFIGURED_HEAD = 1, + /** + * head has not been configured + */ + ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_UNCONFIGURED_HEAD = 2, + /** + * request sent after configuration has been applied or tested + */ + ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_USED = 3, +}; +#endif /* ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ENUM */ + +/** + * @ingroup iface_zwlr_output_configuration_v1 + * @struct zwlr_output_configuration_v1_listener + */ +struct zwlr_output_configuration_v1_listener { + /** + * configuration changes succeeded + * + * Sent after the compositor has successfully applied the changes + * or tested them. + * + * Upon receiving this event, the client should destroy this + * object. + * + * If the current configuration has changed, events to describe the + * changes will be sent followed by a wlr_output_manager.done + * event. + */ + void (*succeeded)(void* data, + struct zwlr_output_configuration_v1* zwlr_output_configuration_v1); + /** + * configuration changes failed + * + * Sent if the compositor rejects the changes or failed to apply + * them. The compositor should revert any changes made by the apply + * request that triggered this event. + * + * Upon receiving this event, the client should destroy this + * object. + */ + void (*failed)(void* data, + struct zwlr_output_configuration_v1* zwlr_output_configuration_v1); + /** + * configuration has been cancelled + * + * Sent if the compositor cancels the configuration because the + * state of an output changed and the client has outdated + * information (e.g. after an output has been hotplugged). + * + * The client can create a new configuration with a newer serial + * and try again. + * + * Upon receiving this event, the client should destroy this + * object. + */ + void (*cancelled)(void* data, + struct zwlr_output_configuration_v1* zwlr_output_configuration_v1); +}; + +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +static inline int +zwlr_output_configuration_v1_add_listener(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1, + const struct zwlr_output_configuration_v1_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) zwlr_output_configuration_v1, + (void (**)(void)) listener, + data); +} + +#define ZWLR_OUTPUT_CONFIGURATION_V1_ENABLE_HEAD 0 +#define ZWLR_OUTPUT_CONFIGURATION_V1_DISABLE_HEAD 1 +#define ZWLR_OUTPUT_CONFIGURATION_V1_APPLY 2 +#define ZWLR_OUTPUT_CONFIGURATION_V1_TEST 3 +#define ZWLR_OUTPUT_CONFIGURATION_V1_DESTROY 4 + +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_SUCCEEDED_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_FAILED_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_CANCELLED_SINCE_VERSION 1 + +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_ENABLE_HEAD_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_DISABLE_HEAD_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_APPLY_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_TEST_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_V1_DESTROY_SINCE_VERSION 1 + +/** @ingroup iface_zwlr_output_configuration_v1 */ +static inline void +zwlr_output_configuration_v1_set_user_data(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_configuration_v1, user_data); +} + +/** @ingroup iface_zwlr_output_configuration_v1 */ +static inline void* +zwlr_output_configuration_v1_get_user_data(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1) { + return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_configuration_v1); +} + +static inline uint32_t +zwlr_output_configuration_v1_get_version(struct zwlr_output_configuration_v1* zwlr_output_configuration_v1) { + return wl_proxy_get_version((struct wl_proxy*) zwlr_output_configuration_v1); +} + +// /** +// * @ingroup iface_zwlr_output_configuration_v1 +// * +// * Enable a head. This request creates a head configuration object that can +// * be used to change the head's properties. +// */ +// static inline struct zwlr_output_configuration_head_v1 * +// zwlr_output_configuration_v1_enable_head(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1, struct zwlr_output_head_v1 *head) +// { +// struct wl_proxy *id; + +// id = wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, +// ZWLR_OUTPUT_CONFIGURATION_V1_ENABLE_HEAD, &zwlr_output_configuration_head_v1_interface, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0, NULL, head); + +// return (struct zwlr_output_configuration_head_v1 *) id; +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_v1 +// * +// * Disable a head. +// */ +// static inline void +// zwlr_output_configuration_v1_disable_head(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1, struct zwlr_output_head_v1 *head) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, +// ZWLR_OUTPUT_CONFIGURATION_V1_DISABLE_HEAD, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0, head); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_v1 +// * +// * Apply the new output configuration. +// * +// * In case the configuration is successfully applied, there is no guarantee +// * that the new output state matches completely the requested +// * configuration. For instance, a compositor might round the scale if it +// * doesn't support fractional scaling. +// * +// * After this request has been sent, the compositor must respond with an +// * succeeded, failed or cancelled event. Sending a request that isn't the +// * destructor is a protocol error. +// */ +// static inline void +// zwlr_output_configuration_v1_apply(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, +// ZWLR_OUTPUT_CONFIGURATION_V1_APPLY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_v1 +// * +// * Test the new output configuration. The configuration won't be applied, +// * but will only be validated. +// * +// * Even if the compositor succeeds to test a configuration, applying it may +// * fail. +// * +// * After this request has been sent, the compositor must respond with an +// * succeeded, failed or cancelled event. Sending a request that isn't the +// * destructor is a protocol error. +// */ +// static inline void +// zwlr_output_configuration_v1_test(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, +// ZWLR_OUTPUT_CONFIGURATION_V1_TEST, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), 0); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_v1 +// * +// * Using this request a client can tell the compositor that it is not going +// * to use the configuration object anymore. Any changes to the outputs +// * that have not been applied will be discarded. +// * +// * This request also destroys wlr_output_configuration_head objects created +// * via this object. +// */ +// static inline void +// zwlr_output_configuration_v1_destroy(struct zwlr_output_configuration_v1 *zwlr_output_configuration_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_v1, +// ZWLR_OUTPUT_CONFIGURATION_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_v1), WL_MARSHAL_FLAG_DESTROY); +// } + +#ifndef ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ENUM + #define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ENUM +enum zwlr_output_configuration_head_v1_error { + /** + * property has already been set + */ + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ALREADY_SET = 1, + /** + * mode doesn't belong to head + */ + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_MODE = 2, + /** + * mode is invalid + */ + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_CUSTOM_MODE = 3, + /** + * transform value outside enum + */ + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_TRANSFORM = 4, + /** + * scale negative or zero + */ + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_SCALE = 5, + /** + * invalid enum value used in the set_adaptive_sync request + * @since 4 + */ + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_ADAPTIVE_SYNC_STATE = 6, +}; + /** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ + #define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_ADAPTIVE_SYNC_STATE_SINCE_VERSION 4 +#endif /* ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_ENUM */ + +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_MODE 0 +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_CUSTOM_MODE 1 +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_POSITION 2 +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_TRANSFORM 3 +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_SCALE 4 +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_ADAPTIVE_SYNC 5 + +/** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_CUSTOM_MODE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_TRANSFORM_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_SCALE_SINCE_VERSION 1 +/** + * @ingroup iface_zwlr_output_configuration_head_v1 + */ +#define ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_ADAPTIVE_SYNC_SINCE_VERSION 4 + +/** @ingroup iface_zwlr_output_configuration_head_v1 */ +static inline void +zwlr_output_configuration_head_v1_set_user_data(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1, void* user_data) { + wl_proxy_set_user_data((struct wl_proxy*) zwlr_output_configuration_head_v1, user_data); +} + +/** @ingroup iface_zwlr_output_configuration_head_v1 */ +static inline void* +zwlr_output_configuration_head_v1_get_user_data(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1) { + return wl_proxy_get_user_data((struct wl_proxy*) zwlr_output_configuration_head_v1); +} + +static inline uint32_t +zwlr_output_configuration_head_v1_get_version(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1) { + return wl_proxy_get_version((struct wl_proxy*) zwlr_output_configuration_head_v1); +} + +/** @ingroup iface_zwlr_output_configuration_head_v1 */ +static inline void +zwlr_output_configuration_head_v1_destroy(struct zwlr_output_configuration_head_v1* zwlr_output_configuration_head_v1) { + wl_proxy_destroy((struct wl_proxy*) zwlr_output_configuration_head_v1); +} + +// /** +// * @ingroup iface_zwlr_output_configuration_head_v1 +// * +// * This request sets the head's mode. +// */ +// static inline void +// zwlr_output_configuration_head_v1_set_mode(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, struct zwlr_output_mode_v1 *mode) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, +// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, mode); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_head_v1 +// * +// * This request assigns a custom mode to the head. The size is given in +// * physical hardware units of the output device. If set to zero, the +// * refresh rate is unspecified. +// * +// * It is a protocol error to set both a mode and a custom mode. +// */ +// static inline void +// zwlr_output_configuration_head_v1_set_custom_mode(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, int32_t width, int32_t height, int32_t refresh) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, +// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_CUSTOM_MODE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, width, height, refresh); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_head_v1 +// * +// * This request sets the head's position in the global compositor space. +// */ +// static inline void +// zwlr_output_configuration_head_v1_set_position(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, int32_t x, int32_t y) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, +// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, x, y); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_head_v1 +// * +// * This request sets the head's transform. +// */ +// static inline void +// zwlr_output_configuration_head_v1_set_transform(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, int32_t transform) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, +// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, transform); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_head_v1 +// * +// * This request sets the head's scale. +// */ +// static inline void +// zwlr_output_configuration_head_v1_set_scale(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, wl_fixed_t scale) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, +// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, scale); +// } + +// /** +// * @ingroup iface_zwlr_output_configuration_head_v1 +// * +// * This request enables/disables adaptive sync. Adaptive sync is also +// * known as Variable Refresh Rate or VRR. +// */ +// static inline void +// zwlr_output_configuration_head_v1_set_adaptive_sync(struct zwlr_output_configuration_head_v1 *zwlr_output_configuration_head_v1, uint32_t state) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zwlr_output_configuration_head_v1, +// ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_SET_ADAPTIVE_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) zwlr_output_configuration_head_v1), 0, state); +// } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c new file mode 100644 index 0000000..a231fd4 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c @@ -0,0 +1,176 @@ +#ifdef FF_HAVE_WAYLAND + +/* Generated by wayland-scanner 1.24.0 */ + +/* + * Copyright © 2019 Purism SPC + * + * Permission to use, copy, modify, distribute, and sell this + * software and its documentation for any purpose is hereby granted + * without fee, provided that the above copyright notice appear in + * all copies and that both that copyright notice and this permission + * notice appear in supporting documentation, and that the name of + * the copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + * THIS SOFTWARE. + */ + + #include + #include + #include + #include + + #ifndef __has_attribute + #define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */ + #endif + + #if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4) + #define WL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define WL_PRIVATE + #endif + +extern const struct wl_interface zwlr_output_configuration_head_v1_interface; +extern const struct wl_interface zwlr_output_configuration_v1_interface; +extern const struct wl_interface zwlr_output_head_v1_interface; +extern const struct wl_interface zwlr_output_mode_v1_interface; + +static const struct wl_interface* wlr_output_management_unstable_v1_types[] = { + NULL, + NULL, + NULL, + &zwlr_output_configuration_v1_interface, + NULL, + &zwlr_output_head_v1_interface, + &zwlr_output_mode_v1_interface, + &zwlr_output_mode_v1_interface, + &zwlr_output_configuration_head_v1_interface, + &zwlr_output_head_v1_interface, + &zwlr_output_head_v1_interface, + &zwlr_output_mode_v1_interface, +}; + +static const struct wl_message zwlr_output_manager_v1_requests[] = { + { "create_configuration", "nu", wlr_output_management_unstable_v1_types + 3 }, + { "stop", "", wlr_output_management_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwlr_output_manager_v1_events[] = { + { "head", "n", wlr_output_management_unstable_v1_types + 5 }, + { "done", "u", wlr_output_management_unstable_v1_types + 0 }, + { "finished", "", wlr_output_management_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_output_manager_v1_interface = { + "zwlr_output_manager_v1", + 4, + 2, + zwlr_output_manager_v1_requests, + 3, + zwlr_output_manager_v1_events, +}; + +static const struct wl_message zwlr_output_head_v1_requests[] = { + { "release", "3", wlr_output_management_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwlr_output_head_v1_events[] = { + { "name", "s", wlr_output_management_unstable_v1_types + 0 }, + { "description", "s", wlr_output_management_unstable_v1_types + 0 }, + { "physical_size", "ii", wlr_output_management_unstable_v1_types + 0 }, + { "mode", "n", wlr_output_management_unstable_v1_types + 6 }, + { "enabled", "i", wlr_output_management_unstable_v1_types + 0 }, + { "current_mode", "o", wlr_output_management_unstable_v1_types + 7 }, + { "position", "ii", wlr_output_management_unstable_v1_types + 0 }, + { "transform", "i", wlr_output_management_unstable_v1_types + 0 }, + { "scale", "f", wlr_output_management_unstable_v1_types + 0 }, + { "finished", "", wlr_output_management_unstable_v1_types + 0 }, + { "make", "2s", wlr_output_management_unstable_v1_types + 0 }, + { "model", "2s", wlr_output_management_unstable_v1_types + 0 }, + { "serial_number", "2s", wlr_output_management_unstable_v1_types + 0 }, + { "adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_output_head_v1_interface = { + "zwlr_output_head_v1", + 4, + 1, + zwlr_output_head_v1_requests, + 14, + zwlr_output_head_v1_events, +}; + +static const struct wl_message zwlr_output_mode_v1_requests[] = { + { "release", "3", wlr_output_management_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwlr_output_mode_v1_events[] = { + { "size", "ii", wlr_output_management_unstable_v1_types + 0 }, + { "refresh", "i", wlr_output_management_unstable_v1_types + 0 }, + { "preferred", "", wlr_output_management_unstable_v1_types + 0 }, + { "finished", "", wlr_output_management_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_output_mode_v1_interface = { + "zwlr_output_mode_v1", + 3, + 1, + zwlr_output_mode_v1_requests, + 4, + zwlr_output_mode_v1_events, +}; + +static const struct wl_message zwlr_output_configuration_v1_requests[] = { + { "enable_head", "no", wlr_output_management_unstable_v1_types + 8 }, + { "disable_head", "o", wlr_output_management_unstable_v1_types + 10 }, + { "apply", "", wlr_output_management_unstable_v1_types + 0 }, + { "test", "", wlr_output_management_unstable_v1_types + 0 }, + { "destroy", "", wlr_output_management_unstable_v1_types + 0 }, +}; + +static const struct wl_message zwlr_output_configuration_v1_events[] = { + { "succeeded", "", wlr_output_management_unstable_v1_types + 0 }, + { "failed", "", wlr_output_management_unstable_v1_types + 0 }, + { "cancelled", "", wlr_output_management_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_output_configuration_v1_interface = { + "zwlr_output_configuration_v1", + 4, + 5, + zwlr_output_configuration_v1_requests, + 3, + zwlr_output_configuration_v1_events, +}; + +static const struct wl_message zwlr_output_configuration_head_v1_requests[] = { + { "set_mode", "o", wlr_output_management_unstable_v1_types + 11 }, + { "set_custom_mode", "iii", wlr_output_management_unstable_v1_types + 0 }, + { "set_position", "ii", wlr_output_management_unstable_v1_types + 0 }, + { "set_transform", "i", wlr_output_management_unstable_v1_types + 0 }, + { "set_scale", "f", wlr_output_management_unstable_v1_types + 0 }, + { "set_adaptive_sync", "4u", wlr_output_management_unstable_v1_types + 0 }, +}; + +WL_PRIVATE const struct wl_interface zwlr_output_configuration_head_v1_interface = { + "zwlr_output_configuration_head_v1", + 4, + 6, + zwlr_output_configuration_head_v1_requests, + 0, + NULL, +}; + +#endif diff --git a/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-client-protocol.h b/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-client-protocol.h new file mode 100644 index 0000000..51784c6 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-client-protocol.h @@ -0,0 +1,414 @@ +/* Generated by wayland-scanner 1.22.0 */ + +#ifndef XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H +#define XDG_OUTPUT_UNSTABLE_V1_CLIENT_PROTOCOL_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @page page_xdg_output_unstable_v1 The xdg_output_unstable_v1 protocol + * Protocol to describe output regions + * + * @section page_desc_xdg_output_unstable_v1 Description + * + * This protocol aims at describing outputs in a way which is more in line + * with the concept of an output on desktop oriented systems. + * + * Some information are more specific to the concept of an output for + * a desktop oriented system and may not make sense in other applications, + * such as IVI systems for example. + * + * Typically, the global compositor space on a desktop system is made of + * a contiguous or overlapping set of rectangular regions. + * + * The logical_position and logical_size events defined in this protocol + * might provide information identical to their counterparts already + * available from wl_output, in which case the information provided by this + * protocol should be preferred to their equivalent in wl_output. The goal is + * to move the desktop specific concepts (such as output location within the + * global compositor space, etc.) out of the core wl_output protocol. + * + * Warning! The protocol described in this file is experimental and + * backward incompatible changes may be made. Backward compatible + * changes may be added together with the corresponding interface + * version bump. + * Backward incompatible changes are done by bumping the version + * number in the protocol and interface names and resetting the + * interface version. Once the protocol is to be declared stable, + * the 'z' prefix and the version number in the protocol and + * interface names are removed and the interface version number is + * reset. + * + * @section page_ifaces_xdg_output_unstable_v1 Interfaces + * - @subpage page_iface_zxdg_output_manager_v1 - manage xdg_output objects + * - @subpage page_iface_zxdg_output_v1 - compositor logical output region + * @section page_copyright_xdg_output_unstable_v1 Copyright + *
+ *
+ * Copyright © 2017 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ * 
+ */ +struct wl_output; +struct zxdg_output_manager_v1; +struct zxdg_output_v1; + +#ifndef ZXDG_OUTPUT_MANAGER_V1_INTERFACE + #define ZXDG_OUTPUT_MANAGER_V1_INTERFACE +/** + * @page page_iface_zxdg_output_manager_v1 zxdg_output_manager_v1 + * @section page_iface_zxdg_output_manager_v1_desc Description + * + * A global factory interface for xdg_output objects. + * @section page_iface_zxdg_output_manager_v1_api API + * See @ref iface_zxdg_output_manager_v1. + */ +/** + * @defgroup iface_zxdg_output_manager_v1 The zxdg_output_manager_v1 interface + * + * A global factory interface for xdg_output objects. + */ +extern const struct wl_interface zxdg_output_manager_v1_interface; +#endif +#ifndef ZXDG_OUTPUT_V1_INTERFACE + #define ZXDG_OUTPUT_V1_INTERFACE +/** + * @page page_iface_zxdg_output_v1 zxdg_output_v1 + * @section page_iface_zxdg_output_v1_desc Description + * + * An xdg_output describes part of the compositor geometry. + * + * This typically corresponds to a monitor that displays part of the + * compositor space. + * + * For objects version 3 onwards, after all xdg_output properties have been + * sent (when the object is created and when properties are updated), a + * wl_output.done event is sent. This allows changes to the output + * properties to be seen as atomic, even if they happen via multiple events. + * @section page_iface_zxdg_output_v1_api API + * See @ref iface_zxdg_output_v1. + */ +/** + * @defgroup iface_zxdg_output_v1 The zxdg_output_v1 interface + * + * An xdg_output describes part of the compositor geometry. + * + * This typically corresponds to a monitor that displays part of the + * compositor space. + * + * For objects version 3 onwards, after all xdg_output properties have been + * sent (when the object is created and when properties are updated), a + * wl_output.done event is sent. This allows changes to the output + * properties to be seen as atomic, even if they happen via multiple events. + */ +extern const struct wl_interface zxdg_output_v1_interface; +#endif + +#define ZXDG_OUTPUT_MANAGER_V1_DESTROY 0 +#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT 1 + +/** + * @ingroup iface_zxdg_output_manager_v1 + */ +#define ZXDG_OUTPUT_MANAGER_V1_DESTROY_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_output_manager_v1 + */ +#define ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION 1 + +// /** @ingroup iface_zxdg_output_manager_v1 */ +// static inline void +// zxdg_output_manager_v1_set_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, void *user_data) +// { +// wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_manager_v1, user_data); +// } + +// /** @ingroup iface_zxdg_output_manager_v1 */ +// static inline void * +// zxdg_output_manager_v1_get_user_data(struct zxdg_output_manager_v1 *zxdg_output_manager_v1) +// { +// return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_manager_v1); +// } + +// static inline uint32_t +// zxdg_output_manager_v1_get_version(struct zxdg_output_manager_v1 *zxdg_output_manager_v1) +// { +// return wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1); +// } + +// /** +// * @ingroup iface_zxdg_output_manager_v1 +// * +// * Using this request a client can tell the server that it is not +// * going to use the xdg_output_manager object anymore. +// * +// * Any objects already created through this instance are not affected. +// */ +// static inline void +// zxdg_output_manager_v1_destroy(struct zxdg_output_manager_v1 *zxdg_output_manager_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1, +// ZXDG_OUTPUT_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), WL_MARSHAL_FLAG_DESTROY); +// } + +// /** +// * @ingroup iface_zxdg_output_manager_v1 +// * +// * This creates a new xdg_output object for the given wl_output. +// */ +// static inline struct zxdg_output_v1 * +// zxdg_output_manager_v1_get_xdg_output(struct zxdg_output_manager_v1 *zxdg_output_manager_v1, struct wl_output *output) +// { +// struct wl_proxy *id; + +// id = wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_manager_v1, +// ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, wl_proxy_get_version((struct wl_proxy *) zxdg_output_manager_v1), 0, NULL, output); + +// return (struct zxdg_output_v1 *) id; +// } + +/** + * @ingroup iface_zxdg_output_v1 + * @struct zxdg_output_v1_listener + */ +struct zxdg_output_v1_listener { + /** + * position of the output within the global compositor space + * + * The position event describes the location of the wl_output + * within the global compositor space. + * + * The logical_position event is sent after creating an xdg_output + * (see xdg_output_manager.get_xdg_output) and whenever the + * location of the output changes within the global compositor + * space. + * @param x x position within the global compositor space + * @param y y position within the global compositor space + */ + void (*logical_position)(void* data, + struct zxdg_output_v1* zxdg_output_v1, + int32_t x, + int32_t y); + /** + * size of the output in the global compositor space + * + * The logical_size event describes the size of the output in the + * global compositor space. + * + * Most regular Wayland clients should not pay attention to the + * logical size and would rather rely on xdg_shell interfaces. + * + * Some clients such as Xwayland, however, need this to configure + * their surfaces in the global compositor space as the compositor + * may apply a different scale from what is advertised by the + * output scaling property (to achieve fractional scaling, for + * example). + * + * For example, for a wl_output mode 3840×2160 and a scale factor + * 2: + * + * - A compositor not scaling the monitor viewport in its + * compositing space will advertise a logical size of 3840×2160, + * + * - A compositor scaling the monitor viewport with scale factor 2 + * will advertise a logical size of 1920×1080, + * + * - A compositor scaling the monitor viewport using a fractional + * scale of 1.5 will advertise a logical size of 2560×1440. + * + * For example, for a wl_output mode 1920×1080 and a 90 degree + * rotation, the compositor will advertise a logical size of + * 1080x1920. + * + * The logical_size event is sent after creating an xdg_output (see + * xdg_output_manager.get_xdg_output) and whenever the logical size + * of the output changes, either as a result of a change in the + * applied scale or because of a change in the corresponding output + * mode(see wl_output.mode) or transform (see wl_output.transform). + * @param width width in global compositor space + * @param height height in global compositor space + */ + void (*logical_size)(void* data, + struct zxdg_output_v1* zxdg_output_v1, + int32_t width, + int32_t height); + /** + * all information about the output have been sent + * + * This event is sent after all other properties of an xdg_output + * have been sent. + * + * This allows changes to the xdg_output properties to be seen as + * atomic, even if they happen via multiple events. + * + * For objects version 3 onwards, this event is deprecated. + * Compositors are not required to send it anymore and must send + * wl_output.done instead. + */ + void (*done)(void* data, + struct zxdg_output_v1* zxdg_output_v1); + /** + * name of this output + * + * Many compositors will assign names to their outputs, show them + * to the user, allow them to be configured by name, etc. The + * client may wish to know this name as well to offer the user + * similar behaviors. + * + * The naming convention is compositor defined, but limited to + * alphanumeric characters and dashes (-). Each name is unique + * among all wl_output globals, but if a wl_output global is + * destroyed the same name may be reused later. The names will also + * remain consistent across sessions with the same hardware and + * software configuration. + * + * Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. + * However, do not assume that the name is a reflection of an + * underlying DRM connector, X11 connection, etc. + * + * The name event is sent after creating an xdg_output (see + * xdg_output_manager.get_xdg_output). This event is only sent once + * per xdg_output, and the name does not change over the lifetime + * of the wl_output global. + * + * This event is deprecated, instead clients should use + * wl_output.name. Compositors must still support this event. + * @param name output name + * @since 2 + */ + void (*name)(void* data, + struct zxdg_output_v1* zxdg_output_v1, + const char* name); + /** + * human-readable description of this output + * + * Many compositors can produce human-readable descriptions of + * their outputs. The client may wish to know this description as + * well, to communicate the user for various purposes. + * + * The description is a UTF-8 string with no convention defined for + * its contents. Examples might include 'Foocorp 11" Display' or + * 'Virtual X11 output via :1'. + * + * The description event is sent after creating an xdg_output (see + * xdg_output_manager.get_xdg_output) and whenever the description + * changes. The description is optional, and may not be sent at + * all. + * + * For objects of version 2 and lower, this event is only sent once + * per xdg_output, and the description does not change over the + * lifetime of the wl_output global. + * + * This event is deprecated, instead clients should use + * wl_output.description. Compositors must still support this + * event. + * @param description output description + * @since 2 + */ + void (*description)(void* data, + struct zxdg_output_v1* zxdg_output_v1, + const char* description); +}; + +/** + * @ingroup iface_zxdg_output_v1 + */ +static inline int +zxdg_output_v1_add_listener(struct zxdg_output_v1* zxdg_output_v1, + const struct zxdg_output_v1_listener* listener, + void* data) { + return wl_proxy_add_listener((struct wl_proxy*) zxdg_output_v1, + (void (**)(void)) listener, + data); +} + +#define ZXDG_OUTPUT_V1_DESTROY 0 + +/** + * @ingroup iface_zxdg_output_v1 + */ +#define ZXDG_OUTPUT_V1_LOGICAL_POSITION_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_output_v1 + */ +#define ZXDG_OUTPUT_V1_LOGICAL_SIZE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_output_v1 + */ +#define ZXDG_OUTPUT_V1_DONE_SINCE_VERSION 1 +/** + * @ingroup iface_zxdg_output_v1 + */ +#define ZXDG_OUTPUT_V1_NAME_SINCE_VERSION 2 +/** + * @ingroup iface_zxdg_output_v1 + */ +#define ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION 2 + +/** + * @ingroup iface_zxdg_output_v1 + */ +#define ZXDG_OUTPUT_V1_DESTROY_SINCE_VERSION 1 + +// /** @ingroup iface_zxdg_output_v1 */ +// static inline void +// zxdg_output_v1_set_user_data(struct zxdg_output_v1 *zxdg_output_v1, void *user_data) +// { +// wl_proxy_set_user_data((struct wl_proxy *) zxdg_output_v1, user_data); +// } + +// /** @ingroup iface_zxdg_output_v1 */ +// static inline void * +// zxdg_output_v1_get_user_data(struct zxdg_output_v1 *zxdg_output_v1) +// { +// return wl_proxy_get_user_data((struct wl_proxy *) zxdg_output_v1); +// } + +// static inline uint32_t +// zxdg_output_v1_get_version(struct zxdg_output_v1 *zxdg_output_v1) +// { +// return wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1); +// } + +// /** +// * @ingroup iface_zxdg_output_v1 +// * +// * Using this request a client can tell the server that it is not +// * going to use the xdg_output object anymore. +// */ +// static inline void +// zxdg_output_v1_destroy(struct zxdg_output_v1 *zxdg_output_v1) +// { +// wl_proxy_marshal_flags((struct wl_proxy *) zxdg_output_v1, +// ZXDG_OUTPUT_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) zxdg_output_v1), WL_MARSHAL_FLAG_DESTROY); +// } + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c b/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c new file mode 100644 index 0000000..76f6257 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/xdg-output-unstable-v1-protocol.c @@ -0,0 +1,76 @@ +#ifdef FF_HAVE_WAYLAND +/* Generated by wayland-scanner 1.22.0 */ + +/* + * Copyright © 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + #include + #include + #include + +extern const struct wl_interface wl_output_interface; +extern const struct wl_interface zxdg_output_v1_interface; + +static const struct wl_interface* xdg_output_unstable_v1_types[] = { + NULL, + NULL, + &zxdg_output_v1_interface, + NULL, // &wl_output_interface, +}; + +static const struct wl_message zxdg_output_manager_v1_requests[] = { + { "destroy", "", xdg_output_unstable_v1_types + 0 }, + { "get_xdg_output", "no", xdg_output_unstable_v1_types + 2 }, +}; + +WL_EXPORT const struct wl_interface zxdg_output_manager_v1_interface = { + "zxdg_output_manager_v1", + 3, + 2, + zxdg_output_manager_v1_requests, + 0, + NULL, +}; + +static const struct wl_message zxdg_output_v1_requests[] = { + { "destroy", "", xdg_output_unstable_v1_types + 0 }, +}; + +static const struct wl_message zxdg_output_v1_events[] = { + { "logical_position", "ii", xdg_output_unstable_v1_types + 0 }, + { "logical_size", "ii", xdg_output_unstable_v1_types + 0 }, + { "done", "", xdg_output_unstable_v1_types + 0 }, + { "name", "2s", xdg_output_unstable_v1_types + 0 }, + { "description", "2s", xdg_output_unstable_v1_types + 0 }, +}; + +WL_EXPORT const struct wl_interface zxdg_output_v1_interface = { + "zxdg_output_v1", + 3, + 1, + zxdg_output_v1_requests, + 5, + zxdg_output_v1_events, +}; + +#endif diff --git a/src/detection/displayserver/linux/wayland/zwlr-output.c b/src/detection/displayserver/linux/wayland/zwlr-output.c new file mode 100644 index 0000000..632bd19 --- /dev/null +++ b/src/detection/displayserver/linux/wayland/zwlr-output.c @@ -0,0 +1,212 @@ +#ifdef FF_HAVE_WAYLAND + + #include "wayland.h" + #include "wlr-output-management-unstable-v1-client-protocol.h" + +static void waylandZwlrTransformListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, int32_t transform) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + wldata->transform = (enum wl_output_transform) transform; +} + +static void waylandZwlrScaleListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, wl_fixed_t scale) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + wldata->dpi = (uint32_t) scale * 3 / 8; // wl_fixed_to_double(scale) * 96; +} + +typedef struct WaylandZwlrMode { + int32_t width; + int32_t height; + int32_t refreshRate; + bool preferred; + struct zwlr_output_mode_v1* pMode; +} WaylandZwlrMode; + +static void waylandZwlrModeSizeListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1, int32_t width, int32_t height) { + WaylandZwlrMode* mode = (WaylandZwlrMode*) data; + mode->width = width; + mode->height = height; +} + +static void waylandZwlrModeRefreshListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1, int32_t rate) { + WaylandZwlrMode* mode = (WaylandZwlrMode*) data; + mode->refreshRate = rate; +} + +static void waylandZwlrModePreferredListener(void* data, FF_A_UNUSED struct zwlr_output_mode_v1* zwlr_output_mode_v1) { + WaylandZwlrMode* mode = (WaylandZwlrMode*) data; + mode->preferred = true; +} + +static const struct zwlr_output_mode_v1_listener modeListener = { + .size = waylandZwlrModeSizeListener, + .refresh = waylandZwlrModeRefreshListener, + .preferred = waylandZwlrModePreferredListener, + .finished = (void*) stubListener, +}; + +static void waylandZwlrModeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, struct zwlr_output_mode_v1* mode) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!wldata->internal) { + return; + } + + WaylandZwlrMode* newMode = FF_LIST_ADD(WaylandZwlrMode, *(FFlist*) wldata->internal); + *newMode = (WaylandZwlrMode) { .pMode = mode }; + + // Strangely, the listener is called only in this function, but not in `waylandZwlrCurrentModeListener` + wldata->parent->ffwl_proxy_add_listener((struct wl_proxy*) mode, (void (**)(void)) &modeListener, newMode); +} + +static void waylandZwlrCurrentModeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, struct zwlr_output_mode_v1* mode) { + // waylandZwlrModeListener is always run before this + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!wldata->internal) { + return; + } + + int set = 0; + FF_LIST_FOR_EACH (WaylandZwlrMode, m, *(FFlist*) wldata->internal) { + if (m->pMode == mode) { + wldata->width = m->width; + wldata->height = m->height; + wldata->refreshRate = m->refreshRate; + if (++set == 2) { + break; + } + } + if (m->preferred) { + wldata->preferredWidth = m->width; + wldata->preferredHeight = m->height; + wldata->preferredRefreshRate = m->refreshRate; + if (++set == 2) { + break; + } + } + } +} + +static void waylandZwlrPhysicalSizeListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, int32_t width, int32_t height) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + wldata->physicalWidth = width; + wldata->physicalHeight = height; +} + +static void waylandZwlrEnabledListener(void* data, FF_A_UNUSED struct zwlr_output_head_v1* zwlr_output_head_v1, bool enabled) { + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!enabled) { + wldata->internal = NULL; + } +} + +static const struct zwlr_output_head_v1_listener headListener = { + .name = (void*) ffWaylandOutputNameListener, + .description = (void*) ffWaylandOutputDescriptionListener, + .physical_size = waylandZwlrPhysicalSizeListener, + .mode = waylandZwlrModeListener, + .enabled = (void*) waylandZwlrEnabledListener, + .current_mode = waylandZwlrCurrentModeListener, + .position = (void*) stubListener, + .transform = waylandZwlrTransformListener, + .scale = waylandZwlrScaleListener, + .finished = (void*) stubListener, + .make = (void*) stubListener, + .model = (void*) stubListener, + .serial_number = (void*) stubListener, + .adaptive_sync = (void*) stubListener, +}; + +static void waylandHandleZwlrHead(void* data, FF_A_UNUSED struct zwlr_output_manager_v1* zwlr_output_manager_v1, struct zwlr_output_head_v1* head) { + WaylandData* wldata = data; + + FF_LIST_AUTO_DESTROY modes = ffListCreate(); + WaylandDisplay display = { + .parent = wldata, + .transform = WL_OUTPUT_TRANSFORM_NORMAL, + .type = FF_DISPLAY_TYPE_UNKNOWN, + .name = ffStrbufCreate(), + .description = ffStrbufCreate(), + .edidName = ffStrbufCreate(), + .internal = &modes, + }; + + wldata->ffwl_proxy_add_listener((struct wl_proxy*) head, (void (**)(void)) &headListener, &display); + wldata->ffwl_display_roundtrip(wldata->display); + + if (display.width <= 0 || display.height <= 0 || !display.internal) { + return; + } + + uint32_t rotation = ffWaylandHandleRotation(&display); + + FFDisplayResult* item = ffdsAppendDisplay(wldata->result, + (uint32_t) display.width, + (uint32_t) display.height, + display.refreshRate / 1000.0, + (uint32_t) display.dpi, + (uint32_t) display.preferredWidth, + (uint32_t) display.preferredHeight, + display.preferredRefreshRate / 1000.0, + rotation, + display.edidName.length + ? &display.edidName + : display.description.length && !ffStrbufContain(&display.description, &display.name) + ? &display.description + : &display.name, + display.type, + false, + display.id, + (uint32_t) display.physicalWidth, + (uint32_t) display.physicalHeight, + "wayland-zwlr"); + if (item) { + if (display.hdrSupported) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED; + } else if (display.hdrInfoAvailable) { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + } else { + item->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; + } + + item->manufactureYear = display.myear; + item->manufactureWeek = display.mweek; + item->serial = display.serial; + } + + ffStrbufDestroy(&display.description); + ffStrbufDestroy(&display.name); + ffStrbufDestroy(&display.edidName); + + // These must be released manually + FF_LIST_FOR_EACH (WaylandZwlrMode, m, modes) { + wldata->ffwl_proxy_destroy((void*) m->pMode); + } + wldata->ffwl_proxy_destroy((void*) head); +} + +static const struct zwlr_output_manager_v1_listener outputListener = { + .head = waylandHandleZwlrHead, + .done = (void*) stubListener, + .finished = (void*) stubListener, +}; + +const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) { + uint32_t bindVersion = min(version, ZWLR_OUTPUT_MANAGER_V1_HEAD_SINCE_VERSION); + struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, bindVersion, name, zwlr_output_manager_v1_interface.name, bindVersion, NULL); + if (output == NULL) { + return "Failed to bind zwlr_output_manager_v1"; + } + + if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &outputListener, wldata) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to add listener to zwlr_output_manager_v1"; + } + if (wldata->ffwl_display_roundtrip(wldata->display) < 0) { + wldata->ffwl_proxy_destroy(output); + return "Failed to roundtrip display"; + } + wldata->ffwl_proxy_destroy(output); + + return NULL; +} + +#endif -- cgit v1.2.3