Display (Wayland): support fractional scale for KDE

This commit is contained in:
Carter Li
2024-07-05 16:14:56 +08:00
committed by 李通洲
parent 3415d8197c
commit 013320bcde
9 changed files with 1309 additions and 45 deletions
+7
View File
@@ -395,6 +395,7 @@ set(LIBFASTFETCH_SRC
src/options/general.c
src/options/library.c
src/util/edidHelper.c
src/util/base64.c
src/util/FFlist.c
src/util/FFstrbuf.c
src/util/platform/FFPlatform.c
@@ -429,7 +430,9 @@ if(LINUX)
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
@@ -562,7 +565,9 @@ elseif(BSD)
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
@@ -763,7 +768,9 @@ elseif(SunOS)
src/detection/displayserver/linux/wayland/wayland.c
src/detection/displayserver/linux/wayland/global-output.c
src/detection/displayserver/linux/wayland/zwlr-output.c
src/detection/displayserver/linux/wayland/kde-output.c
src/detection/displayserver/linux/wayland/wlr-output-management-unstable-v1-protocol.c
src/detection/displayserver/linux/wayland/kde-output-device-v2-protocol.c
src/detection/displayserver/linux/wmde.c
src/detection/displayserver/linux/xcb.c
src/detection/displayserver/linux/xlib.c
@@ -0,0 +1,845 @@
/* Generated by wayland-scanner 1.22.0 */
#ifndef KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H
#define KDE_OUTPUT_DEVICE_V2_CLIENT_PROTOCOL_H
#include <stdint.h>
#include <stddef.h>
#include <wayland-util.h>
#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_v2 - output configuration representation
* - @subpage page_iface_kde_output_device_mode_v2 - output mode
* @section page_copyright_kde_output_device_v2 Copyright
* <pre>
*
* 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 <sebas@kde.org>
* SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
*
* SPDX-License-Identifier: MIT-CMU
* </pre>
*/
struct kde_output_device_mode_v2;
struct kde_output_device_v2;
#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.
* @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.
*/
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_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,
};
/**
* @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
#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 */
/**
* @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 when auto rotate is used
*
*
* @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
*
*
* @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);
};
/**
* @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);
}
/**
* @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 */
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_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);
};
/**
* @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 */
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
@@ -0,0 +1,81 @@
#ifdef FF_HAVE_WAYLAND
/* Generated by wayland-scanner 1.22.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 <sebas@kde.org>
* SPDX-FileCopyrightText: 2021 Méven Car <meven.car@enioka.com>
*
* SPDX-License-Identifier: MIT-CMU
*/
#include <stdlib.h>
#include <stdint.h>
#include <wayland-util.h>
extern const struct wl_interface kde_output_device_mode_v2_interface;
static const struct wl_interface *kde_output_device_v2_types[] = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&kde_output_device_mode_v2_interface,
&kde_output_device_mode_v2_interface,
};
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 + 8 },
{ "mode", "n", kde_output_device_v2_types + 9 },
{ "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 },
};
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
"kde_output_device_v2", 8,
0, NULL,
25, 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 },
};
WL_EXPORT const struct wl_interface kde_output_device_mode_v2_interface = {
"kde_output_device_mode_v2", 1,
0, NULL,
4, kde_output_device_mode_v2_events,
};
#endif
@@ -0,0 +1,225 @@
#ifdef FF_HAVE_WAYLAND
#include "wayland.h"
#include "kde-output-device-v2-client-protocol.h"
#include "util/edidHelper.h"
#include "util/base64.h"
typedef struct WaylandKdeMode
{
int32_t width;
int32_t height;
int32_t refreshRate;
struct kde_output_device_mode_v2* pMode;
} WaylandKdeMode;
static void waylandKdeSizeListener(void* data, FF_MAYBE_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 waylandKdeRefreshListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_mode_v2 *_, int32_t rate)
{
WaylandKdeMode* mode = (WaylandKdeMode*) data;
mode->refreshRate = rate;
}
static const struct kde_output_device_mode_v2_listener modeListener = {
.size = waylandKdeSizeListener,
.refresh = waylandKdeRefreshListener,
.preferred = (void*) stubListener,
.removed = (void*) stubListener,
};
static void waylandKdeModeListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, struct kde_output_device_mode_v2 *mode)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
if (!wldata->internal) return;
WaylandKdeMode* newMode = ffListAdd((FFlist*) wldata->internal);
newMode->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_MAYBE_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;
WaylandKdeMode* current = NULL;
FF_LIST_FOR_EACH(WaylandKdeMode, m, *(FFlist*) wldata->internal)
{
if (m->pMode == mode)
{
current = m;
break;
}
}
wldata->width = current->width;
wldata->height = current->height;
wldata->refreshRate = current->refreshRate;
}
static void waylandKdeScaleListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, wl_fixed_t scale)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
wldata->scale = wl_fixed_to_double(scale);
}
static void waylandKdeEdidListener(void* data, FF_MAYBE_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);
}
static void waylandKdeEnabledListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* _, int32_t enabled)
{
WaylandDisplay* wldata = (WaylandDisplay*) data;
if (!enabled) wldata->internal = NULL;
}
static void waylandKdeGeometryListener(void *data,
FF_MAYBE_UNUSED struct kde_output_device_v2 *kde_output_device_v2,
FF_MAYBE_UNUSED int32_t x,
FF_MAYBE_UNUSED int32_t y,
FF_MAYBE_UNUSED int32_t physical_width,
FF_MAYBE_UNUSED int32_t physical_height,
FF_MAYBE_UNUSED int32_t subpixel,
FF_MAYBE_UNUSED const char *make,
FF_MAYBE_UNUSED const char *model,
int32_t transform)
{
WaylandDisplay* display = data;
display->transform = (enum wl_output_transform) transform;
}
void waylandOutputNameListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_v2* output, const char *name)
{
WaylandDisplay* display = data;
if(ffStrStartsWith(name, "eDP-"))
display->type = FF_DISPLAY_TYPE_BUILTIN;
else if(ffStrStartsWith(name, "HDMI-"))
display->type = FF_DISPLAY_TYPE_EXTERNAL;
strncpy((char*) &display->id, name, sizeof(display->id));
ffStrbufAppendS(&display->name, name);
}
void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
{
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, version, name, kde_output_device_v2_interface.name, version, NULL);
if(output == NULL)
return;
FF_LIST_AUTO_DESTROY modes = ffListCreate(sizeof(WaylandKdeMode));
WaylandDisplay display = {
.parent = wldata,
.width = 0,
.height = 0,
.refreshRate = 0,
.scale = 1,
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
.type = FF_DISPLAY_TYPE_UNKNOWN,
.name = ffStrbufCreate(),
.description = ffStrbufCreate(),
.edidName = ffStrbufCreate(),
.internal = &modes,
};
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 = waylandOutputNameListener,
.high_dynamic_range = (void*) stubListener,
.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,
};
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display);
wldata->ffwl_display_roundtrip(wldata->display);
wldata->ffwl_proxy_destroy(output);
if(display.width <= 0 || display.height <= 0 || !display.internal)
return;
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;
break;
}
default:
break;
}
ffdsAppendDisplay(wldata->result,
(uint32_t) display.width,
(uint32_t) display.height,
display.refreshRate / 1000.0,
(uint32_t) (display.width / display.scale),
(uint32_t) (display.height / display.scale),
rotation,
display.edidName.length
? &display.edidName
: &display.name,
display.type,
false,
0
);
ffStrbufDestroy(&display.description);
ffStrbufDestroy(&display.name);
ffStrbufDestroy(&display.edidName);
}
#endif
@@ -11,6 +11,7 @@
#include "wayland.h"
#include "wlr-output-management-unstable-v1-client-protocol.h"
#include "kde-output-device-v2-client-protocol.h"
#ifndef __FreeBSD__
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
@@ -47,6 +48,11 @@ static void waylandGlobalAddListener(void* data, struct wl_registry* registry, u
wldata->protocolType = FF_WAYLAND_PROTOCOL_TYPE_ZWLR;
ffWaylandHandleZwlrOutput(wldata, registry, name, version);
}
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;
ffWaylandHandleKdeOutput(wldata, registry, name, version);
}
}
bool detectWayland(FFDisplayServerResult* result)
@@ -107,7 +113,8 @@ void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const
display->type = FF_DISPLAY_TYPE_BUILTIN;
else if(ffStrStartsWith(name, "HDMI-"))
display->type = FF_DISPLAY_TYPE_EXTERNAL;
ffdsMatchDrmConnector(name, &display->edidName);
if (!display->edidName.length)
ffdsMatchDrmConnector(name, &display->edidName);
ffStrbufAppendS(&display->name, name);
}
@@ -14,6 +14,7 @@ typedef enum 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
@@ -53,5 +54,6 @@ void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output
void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
#endif
+3 -44
View File
@@ -2,6 +2,7 @@
#include "common/io/io.h"
#include "common/printing.h"
#include "util/stringUtils.h"
#include "util/base64.h"
#include <limits.h>
#include <math.h>
@@ -16,48 +17,6 @@
#include <sys/termios.h>
#endif
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
static void base64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
{
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *out = output;
const char *ends = str + (size - size % 3);
while (str != ends) {
uint32_t n = __builtin_bswap32(*(uint32_t*) str);
*out++ = chars[(n >> 26) & 63];
*out++ = chars[(n >> 20) & 63];
*out++ = chars[(n >> 14) & 63];
*out++ = chars[(n >> 8) & 63];
str += 3;
}
if (size % 3 == 1) {
uint64_t n = (uint64_t)*str << 16;
*out++ = chars[(n >> 18) & 63];
*out++ = chars[(n >> 12) & 63];
*out++ = '=';
*out++ = '=';
} else if (size % 3 == 2) {
uint64_t n = (uint64_t)*str++ << 16;
n |= (uint64_t)*str << 8;
*out++ = chars[(n >> 18) & 63];
*out++ = chars[(n >> 12) & 63];
*out++ = chars[(n >> 6) & 63];
*out++ = '=';
}
*out = '\0';
*out_size = (uint32_t) (out - output);
}
static FFstrbuf base64Encode(const FFstrbuf* in)
{
FFstrbuf out = ffStrbufCreateA(10 + in->length * 4 / 3);
base64EncodeRaw(in->length, in->chars, &out.length, out.chars);
assert(out.length < out.allocated);
return out;
}
static bool printImageIterm(bool printError)
{
const FFOptionsLogo* options = &instance.config.logo;
@@ -71,7 +30,7 @@ static bool printImageIterm(bool printError)
fflush(stdout);
FF_STRBUF_AUTO_DESTROY base64 = base64Encode(&buf);
FF_STRBUF_AUTO_DESTROY base64 = ffBase64EncodeStrbuf(&buf);
ffStrbufClear(&buf);
if (!options->width || !options->height)
@@ -166,7 +125,7 @@ static bool printImageKittyDirect(bool printError)
return false;
}
FF_STRBUF_AUTO_DESTROY base64 = base64Encode(&options->source);
FF_STRBUF_AUTO_DESTROY base64 = ffBase64EncodeStrbuf(&options->source);
if (!options->width || !options->height)
{
+115
View File
@@ -0,0 +1,115 @@
#include "base64.h"
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
{
static const char chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char *out = output;
const char *ends = str + (size - size % 3);
while (str != ends)
{
uint32_t n = __builtin_bswap32(*(uint32_t *)str);
*out++ = chars[(n >> 26) & 63];
*out++ = chars[(n >> 20) & 63];
*out++ = chars[(n >> 14) & 63];
*out++ = chars[(n >> 8) & 63];
str += 3;
}
if (size % 3 == 1)
{
uint64_t n = (uint64_t)*str << 16;
*out++ = chars[(n >> 18) & 63];
*out++ = chars[(n >> 12) & 63];
*out++ = '=';
*out++ = '=';
}
else if (size % 3 == 2)
{
uint64_t n = (uint64_t)*str++ << 16;
n |= (uint64_t)*str << 8;
*out++ = chars[(n >> 18) & 63];
*out++ = chars[(n >> 12) & 63];
*out++ = chars[(n >> 6) & 63];
*out++ = '=';
}
*out = '\0';
*out_size = (uint32_t)(out - output);
}
static char decode_table[256];
void init_decode_table()
{
uint8_t ch = 0;
do
{
int32_t code = -1;
if (ch >= 'A' && ch <= 'Z')
code = ch - 0x41;
if (ch >= 'a' && ch <= 'z')
code = ch - 0x47;
if (ch >= '0' && ch <= '9')
code = ch + 0x04;
if (ch == '+' || ch == '-')
code = 0x3E;
if (ch == '/' || ch == '_')
code = 0x3F;
decode_table[ch] = (char) code;
} while (ch++ < 0xFF);
}
#define next_char(x) \
char x = decode_table[(unsigned char)*str++]; \
if (x < 0) \
return false;
bool ffBase64DecodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
{
if (*(uint64_t*) decode_table == 0)
init_decode_table();
char *out = output;
while (size > 0 && (str[size - 1] == '\n' || str[size - 1] == '\r' || str[size - 1] == '='))
size--;
const char *ends = str + size - 4;
while (true)
{
if (str > ends)
break;
while (*str == '\n' || *str == '\r')
str++;
if (str > ends)
break;
next_char(a);
next_char(b);
next_char(c);
next_char(d);
*out++ = (char)(a << 2 | b >> 4);
*out++ = (char)(b << 4 | c >> 2);
*out++ = (char)(c << 6 | d >> 0);
}
uint8_t mod = (uint8_t) (ends - str + 4) % 4;
if (mod == 2)
{
next_char(a);
next_char(b);
*out++ = (char)(a << 2 | b >> 4);
}
else if (mod == 3)
{
next_char(a);
next_char(b);
next_char(c);
*out++ = (char)(a << 2 | b >> 4);
*out++ = (char)(b << 4 | c >> 2);
}
*out = '\0';
*out_size = (uint32_t) (out - output);
return true;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "fastfetch.h"
void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output);
static inline FFstrbuf ffBase64EncodeStrbuf(const FFstrbuf* in)
{
FFstrbuf out = ffStrbufCreateA(10 + in->length * 4 / 3);
ffBase64EncodeRaw(in->length, in->chars, &out.length, out.chars);
assert(out.length < out.allocated);
return out;
}
bool ffBase64DecodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output);
static inline FFstrbuf ffBase64DecodeStrbuf(const FFstrbuf* in)
{
FFstrbuf out = ffStrbufCreateA(10 + in->length * 3 / 4);
ffBase64DecodeRaw(in->length, in->chars, &out.length, out.chars);
assert(out.length < out.allocated);
return out;
}