mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
DisplayServer (Linux): refactor & support wlroots protocol
This commit is contained in:
@@ -11,20 +11,6 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
{
|
||||
if (instance.config.general.dsForceDrm == FF_DS_FORCE_DRM_TYPE_FALSE)
|
||||
{
|
||||
#ifdef __linux__
|
||||
{
|
||||
const char* desktopSession = getenv("DESKTOP_SESSION");
|
||||
if (desktopSession && ffStrEquals(desktopSession, "hyprland"))
|
||||
{
|
||||
ffStrbufSetStatic(&ds->wmProcessName, "xdg-desktop-portal-hyprland");
|
||||
ffStrbufSetStatic(&ds->wmPrettyName, FF_WM_PRETTY_HYPRLAND);
|
||||
ffStrbufSetStatic(&ds->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
|
||||
if (ffdsConnectWlroots(ds) == NULL)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//We try wayland as our preferred display server, as it supports the most features.
|
||||
//This method can't detect the name of our WM / DE
|
||||
ffdsConnectWayland(ds);
|
||||
|
||||
@@ -1,312 +0,0 @@
|
||||
#include "displayserver_linux.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
#include "common/library.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/thread.h"
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <sys/socket.h>
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
|
||||
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;
|
||||
} WaylandData;
|
||||
|
||||
typedef struct WaylandDisplay
|
||||
{
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t refreshRate;
|
||||
int32_t scale;
|
||||
enum wl_output_transform transform;
|
||||
FFDisplayType type;
|
||||
FFstrbuf name;
|
||||
FFstrbuf description;
|
||||
FFstrbuf vendorAndModelId;
|
||||
FFstrbuf edidName;
|
||||
} WaylandDisplay;
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
|
||||
{
|
||||
struct ucred ucred;
|
||||
socklen_t len = sizeof(struct ucred);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
|
||||
return;
|
||||
|
||||
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.
|
||||
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
|
||||
ffStrbufTrimRightSpace(&result->wmProcessName);
|
||||
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
|
||||
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
|
||||
}
|
||||
#else
|
||||
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
|
||||
{
|
||||
FF_UNUSED(fd, result);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void stubListener(void* data, ...)
|
||||
{
|
||||
(void) data;
|
||||
}
|
||||
|
||||
static void waylandOutputModeListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate)
|
||||
{
|
||||
if(!(flags & WL_OUTPUT_MODE_CURRENT))
|
||||
return;
|
||||
|
||||
WaylandDisplay* display = data;
|
||||
display->width = width;
|
||||
display->height = height;
|
||||
display->refreshRate = refreshRate;
|
||||
}
|
||||
|
||||
static void waylandOutputScaleListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, int32_t scale)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
display->scale = scale;
|
||||
}
|
||||
|
||||
static void waylandOutputGeometryListener(void *data,
|
||||
FF_MAYBE_UNUSED struct wl_output *output,
|
||||
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,
|
||||
const char *make,
|
||||
const char *model,
|
||||
int32_t transform)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
display->transform = (enum wl_output_transform) transform;
|
||||
if (make && !ffStrEqualsIgnCase(make, "unknown") && model && !ffStrEqualsIgnCase(model, "unknown"))
|
||||
{
|
||||
ffStrbufAppendS(&display->vendorAndModelId, make);
|
||||
ffStrbufAppendS(&display->vendorAndModelId, model);
|
||||
}
|
||||
}
|
||||
|
||||
static void waylandOutputNameListener(void *data, FF_MAYBE_UNUSED struct wl_output *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;
|
||||
ffdsMatchDrmConnector(name, &display->edidName);
|
||||
ffStrbufAppendS(&display->name, name);
|
||||
}
|
||||
|
||||
static void waylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED struct wl_output* wl_output, const char* description)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
while (*description == ' ') ++description;
|
||||
if (!ffStrEquals(description, "Unknown Display"))
|
||||
ffStrbufAppendS(&display->description, description);
|
||||
}
|
||||
|
||||
static void waylandOutputHandler(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, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
|
||||
if(output == NULL)
|
||||
return;
|
||||
|
||||
WaylandDisplay display = {
|
||||
.width = 0,
|
||||
.height = 0,
|
||||
.refreshRate = 0,
|
||||
.scale = 1,
|
||||
.transform = WL_OUTPUT_TRANSFORM_NORMAL,
|
||||
.type = FF_DISPLAY_TYPE_UNKNOWN,
|
||||
};
|
||||
ffStrbufInit(&display.name);
|
||||
ffStrbufInit(&display.description);
|
||||
ffStrbufInit(&display.vendorAndModelId);
|
||||
ffStrbufInit(&display.edidName);
|
||||
|
||||
// Dirty hack for #477
|
||||
// The order of these callbacks MUST follow `struct wl_output_listener`
|
||||
void* outputListener[] = {
|
||||
waylandOutputGeometryListener, // geometry
|
||||
waylandOutputModeListener, // mode
|
||||
stubListener, // done
|
||||
waylandOutputScaleListener, // scale
|
||||
waylandOutputNameListener, // name
|
||||
waylandOutputDescriptionListener, // description
|
||||
};
|
||||
static_assert(
|
||||
sizeof(outputListener) >= sizeof(struct wl_output_listener),
|
||||
"sizeof(outputListener) is too small. Please report it to fastfetch github issue"
|
||||
);
|
||||
|
||||
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)
|
||||
return;
|
||||
|
||||
switch(display.transform)
|
||||
{
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270: {
|
||||
int32_t temp = display.width;
|
||||
display.width = display.height;
|
||||
display.height = temp;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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.description.length
|
||||
? &display.description
|
||||
: display.vendorAndModelId.length
|
||||
? &display.vendorAndModelId : &display.name,
|
||||
display.type,
|
||||
false,
|
||||
0
|
||||
);
|
||||
|
||||
ffStrbufDestroy(&display.description);
|
||||
ffStrbufDestroy(&display.vendorAndModelId);
|
||||
ffStrbufDestroy(&display.name);
|
||||
ffStrbufDestroy(&display.edidName);
|
||||
}
|
||||
|
||||
static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version)
|
||||
{
|
||||
WaylandData* wldata = data;
|
||||
|
||||
if(ffStrEquals(interface, wldata->ffwl_output_interface->name))
|
||||
waylandOutputHandler(wldata, registry, name, version);
|
||||
}
|
||||
|
||||
bool detectWayland(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(wayland, &instance.config.library.libWayland, false, "libwayland-client" FF_LIBRARY_EXTENSION, 1)
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_get_fd, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_dispatch, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_proxy_marshal_constructor, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_disconnect, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_registry_interface, false)
|
||||
|
||||
WaylandData data;
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_marshal_constructor_versioned, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_add_listener, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_destroy, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_display_roundtrip, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_output_interface, false)
|
||||
|
||||
data.display = ffwl_display_connect(NULL);
|
||||
if(data.display == NULL)
|
||||
return false;
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
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);
|
||||
ffwl_display_dispatch(data.display);
|
||||
data.ffwl_display_roundtrip(data.display);
|
||||
|
||||
data.ffwl_proxy_destroy(registry);
|
||||
ffwl_display_disconnect(data.display);
|
||||
|
||||
//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.
|
||||
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void ffdsConnectWayland(FFDisplayServerResult* result)
|
||||
{
|
||||
//Wayland requires this to be set
|
||||
if(getenv("XDG_RUNTIME_DIR") == NULL)
|
||||
return;
|
||||
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
if(detectWayland(result))
|
||||
return;
|
||||
#endif
|
||||
|
||||
const char* xdgSessionType = getenv("XDG_SESSION_TYPE");
|
||||
|
||||
//If XDG_SESSION_TYPE is set, and doesn't contain "wayland", we are probably not running in a wayland session.
|
||||
if(xdgSessionType != NULL && strcasecmp(xdgSessionType, "wayland") != 0)
|
||||
return;
|
||||
|
||||
//If XDG_SESSION_TYPE is not set, check if WAYLAND_DISPLAY or WAYLAND_SOCKET is set.
|
||||
//If not, there is no indicator for a wayland session
|
||||
if(xdgSessionType == NULL && getenv("WAYLAND_DISPLAY") == NULL && getenv("WAYLAND_SOCKET") == NULL)
|
||||
return;
|
||||
|
||||
//We are probably running a wayland compositor at this point,
|
||||
//but fastfetch was compiled without the required library, or loading the library failed.
|
||||
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
|
||||
#include "wayland.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
static void waylandOutputModeListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate)
|
||||
{
|
||||
if(!(flags & WL_OUTPUT_MODE_CURRENT))
|
||||
return;
|
||||
|
||||
WaylandDisplay* display = data;
|
||||
display->width = width;
|
||||
display->height = height;
|
||||
display->refreshRate = refreshRate;
|
||||
}
|
||||
|
||||
static void waylandOutputScaleListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, int32_t scale)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
display->scale = scale;
|
||||
}
|
||||
|
||||
static void waylandOutputGeometryListener(void *data,
|
||||
FF_MAYBE_UNUSED struct wl_output *output,
|
||||
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 ffWaylandHandleGlobalOutput(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, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
|
||||
if(output == NULL)
|
||||
return;
|
||||
|
||||
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(),
|
||||
};
|
||||
|
||||
// Dirty hack for #477
|
||||
// The order of these callbacks MUST follow `struct wl_output_listener`
|
||||
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"
|
||||
);
|
||||
|
||||
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)
|
||||
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.description.length
|
||||
? &display.description
|
||||
: &display.name,
|
||||
display.type,
|
||||
false,
|
||||
0
|
||||
);
|
||||
|
||||
ffStrbufDestroy(&display.description);
|
||||
ffStrbufDestroy(&display.name);
|
||||
ffStrbufDestroy(&display.edidName);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,149 @@
|
||||
#include "../displayserver_linux.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "wayland.h"
|
||||
#include "wlr-output-management-unstable-v1-client-protocol.h"
|
||||
|
||||
#ifndef __FreeBSD__
|
||||
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
|
||||
{
|
||||
struct ucred ucred;
|
||||
socklen_t len = sizeof(struct ucred);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
|
||||
return;
|
||||
|
||||
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.
|
||||
ffReadFileBuffer(procPath.chars, &result->wmProcessName);
|
||||
ffStrbufTrimRightSpace(&result->wmProcessName);
|
||||
ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments
|
||||
ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path
|
||||
}
|
||||
#else
|
||||
static void waylandDetectWM(int fd, FFDisplayServerResult* result)
|
||||
{
|
||||
FF_UNUSED(fd, result);
|
||||
}
|
||||
#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;
|
||||
ffWaylandHandleGlobalOutput(wldata, registry, name, version);
|
||||
}
|
||||
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;
|
||||
ffWaylandHandleZwlrOutput(wldata, registry, name, version);
|
||||
}
|
||||
}
|
||||
|
||||
bool detectWayland(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(wayland, &instance.config.library.libWayland, false, "libwayland-client" FF_LIBRARY_EXTENSION, 1)
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_get_fd, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_proxy_marshal_constructor, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_disconnect, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL(wayland, wl_registry_interface, false)
|
||||
|
||||
WaylandData data = {};
|
||||
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_marshal_constructor_versioned, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_add_listener, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_destroy, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_display_roundtrip, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_output_interface, false)
|
||||
|
||||
data.display = ffwl_display_connect(NULL);
|
||||
if(data.display == NULL)
|
||||
return false;
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
data.ffwl_proxy_destroy(registry);
|
||||
ffwl_display_disconnect(data.display);
|
||||
|
||||
//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.
|
||||
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* 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;
|
||||
ffdsMatchDrmConnector(name, &display->edidName);
|
||||
ffStrbufAppendS(&display->name, name);
|
||||
}
|
||||
|
||||
void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output, const char* description)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
while (*description == ' ') ++description;
|
||||
if (!ffStrEquals(description, "Unknown Display") && !ffStrContains(description, "(null)"))
|
||||
ffStrbufAppendS(&display->description, description);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ffdsConnectWayland(FFDisplayServerResult* result)
|
||||
{
|
||||
//Wayland requires this to be set
|
||||
if(getenv("XDG_RUNTIME_DIR") == NULL)
|
||||
return;
|
||||
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
if(detectWayland(result))
|
||||
return;
|
||||
#endif
|
||||
|
||||
const char* xdgSessionType = getenv("XDG_SESSION_TYPE");
|
||||
|
||||
//If XDG_SESSION_TYPE is set, and doesn't contain "wayland", we are probably not running in a wayland session.
|
||||
if(xdgSessionType != NULL && ffStrEqualsIgnCase(xdgSessionType, "wayland"))
|
||||
return;
|
||||
|
||||
//If XDG_SESSION_TYPE is not set, check if WAYLAND_DISPLAY or WAYLAND_SOCKET is set.
|
||||
//If not, there is no indicator for a wayland session
|
||||
if(xdgSessionType == NULL && getenv("WAYLAND_DISPLAY") == NULL && getenv("WAYLAND_SOCKET") == NULL)
|
||||
return;
|
||||
|
||||
//We are probably running a wayland compositor at this point,
|
||||
//but fastfetch was compiled without the required library, or loading the library failed.
|
||||
ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
|
||||
#include "common/library.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
#include "../displayserver_linux.h"
|
||||
|
||||
typedef enum WaylandProtocolType
|
||||
{
|
||||
FF_WAYLAND_PROTOCOL_TYPE_NONE,
|
||||
FF_WAYLAND_PROTOCOL_TYPE_GLOBAL,
|
||||
FF_WAYLAND_PROTOCOL_TYPE_ZWLR,
|
||||
} 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;
|
||||
} WaylandData;
|
||||
|
||||
typedef struct WaylandDisplay
|
||||
{
|
||||
WaylandData* parent;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t refreshRate;
|
||||
double scale;
|
||||
enum wl_output_transform transform;
|
||||
FFDisplayType type;
|
||||
FFstrbuf name;
|
||||
FFstrbuf description;
|
||||
FFstrbuf edidName;
|
||||
void* internal;
|
||||
} WaylandDisplay;
|
||||
|
||||
inline static void stubListener(void* data, ...)
|
||||
{
|
||||
(void) data;
|
||||
}
|
||||
|
||||
void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const char *name);
|
||||
void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output, const char* description);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
+1298
File diff suppressed because it is too large
Load Diff
+160
@@ -0,0 +1,160 @@
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
|
||||
/* Generated by wayland-scanner 1.22.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 <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
#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
|
||||
@@ -0,0 +1,191 @@
|
||||
#ifdef FF_HAVE_WAYLAND
|
||||
|
||||
#include "wayland.h"
|
||||
#include "wlr-output-management-unstable-v1-client-protocol.h"
|
||||
|
||||
static void waylandZwlrTransformListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, int32_t transform)
|
||||
{
|
||||
WaylandDisplay* wldata = (WaylandDisplay*) data;
|
||||
wldata->transform = transform;
|
||||
}
|
||||
|
||||
static void waylandZwlrScaleListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, wl_fixed_t scale)
|
||||
{
|
||||
WaylandDisplay* wldata = (WaylandDisplay*) data;
|
||||
wldata->scale = wl_fixed_to_double(scale);
|
||||
}
|
||||
|
||||
typedef struct WaylandZwlrMode
|
||||
{
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t refreshRate;
|
||||
struct zwlr_output_mode_v1* pMode;
|
||||
} WaylandZwlrMode;
|
||||
|
||||
static void waylandZwlrSizeListener(void* data, FF_MAYBE_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 waylandZwlrRefreshListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_mode_v1 *zwlr_output_mode_v1, int32_t rate)
|
||||
{
|
||||
WaylandZwlrMode* mode = (WaylandZwlrMode*) data;
|
||||
mode->refreshRate = rate;
|
||||
}
|
||||
|
||||
static void waylandZwlrModeListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, struct zwlr_output_mode_v1 *mode)
|
||||
{
|
||||
WaylandDisplay* wldata = (WaylandDisplay*) data;
|
||||
WaylandZwlrMode* newMode = ffListAdd((FFlist*) wldata->internal);
|
||||
newMode->pMode = mode;
|
||||
const struct zwlr_output_mode_v1_listener listener = {
|
||||
.size = waylandZwlrSizeListener,
|
||||
.refresh = waylandZwlrRefreshListener,
|
||||
.preferred = (void*) stubListener,
|
||||
.finished = (void*) stubListener,
|
||||
};
|
||||
|
||||
// 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)) &listener, newMode);
|
||||
wldata->parent->ffwl_display_roundtrip(wldata->parent->display);
|
||||
}
|
||||
|
||||
static void waylandZwlrCurrentModeListener(void* data, FF_MAYBE_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;
|
||||
WaylandZwlrMode* current = NULL;
|
||||
FF_LIST_FOR_EACH(WaylandZwlrMode, 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 waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output_manager_v1 *zwlr_output_manager_v1, struct zwlr_output_head_v1 *head)
|
||||
{
|
||||
WaylandData* wldata = data;
|
||||
|
||||
const struct zwlr_output_head_v1_listener headListener = {
|
||||
.name = (void*) ffWaylandOutputNameListener,
|
||||
.description = (void*) ffWaylandOutputDescriptionListener,
|
||||
.physical_size = (void*) stubListener,
|
||||
.mode = waylandZwlrModeListener,
|
||||
.enabled = (void*) stubListener,
|
||||
.current_mode = waylandZwlrCurrentModeListener,
|
||||
.position = (void*) stubListener,
|
||||
.transform = waylandZwlrTransformListener,
|
||||
.scale = waylandZwlrScaleListener,
|
||||
.finished = (void*) stubListener,
|
||||
.serial_number = (void*) stubListener,
|
||||
.adaptive_sync = (void*) stubListener,
|
||||
};
|
||||
|
||||
FF_LIST_AUTO_DESTROY modes = ffListCreate(sizeof(WaylandZwlrMode));
|
||||
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,
|
||||
};
|
||||
|
||||
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)
|
||||
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.description.length
|
||||
? &display.description
|
||||
: &display.name,
|
||||
display.type,
|
||||
false,
|
||||
0
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void ffWaylandHandleZwlrOutput(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, &zwlr_output_manager_v1_interface, version, name, zwlr_output_manager_v1_interface.name, version, NULL);
|
||||
if(output == NULL)
|
||||
return;
|
||||
|
||||
const struct zwlr_output_manager_v1_listener outputListener = {
|
||||
.head = waylandHandleZwlrHead,
|
||||
.done = (void*) stubListener,
|
||||
.finished = (void*) stubListener,
|
||||
};
|
||||
|
||||
wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, wldata);
|
||||
wldata->ffwl_display_roundtrip(wldata->display);
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,111 +0,0 @@
|
||||
#include "displayserver_linux.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/processing.h"
|
||||
|
||||
static inline void wrapYyjsonFree(yyjson_doc** doc)
|
||||
{
|
||||
assert(doc);
|
||||
if (*doc)
|
||||
yyjson_doc_free(*doc);
|
||||
}
|
||||
|
||||
const char* ffdsConnectWlroots(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
if (ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
"wlr-randr",
|
||||
"--json",
|
||||
NULL
|
||||
}) != NULL || buffer.length == 0)
|
||||
return "Running wlr-randr failed";
|
||||
|
||||
yyjson_doc* __attribute__((__cleanup__(wrapYyjsonFree))) doc = yyjson_read_opts(buffer.chars, buffer.length, 0, NULL, NULL);
|
||||
if (!doc)
|
||||
return "Failed to parse wlr-randr info";
|
||||
|
||||
yyjson_val* root = yyjson_doc_get_root(doc);
|
||||
if (!yyjson_is_arr(root))
|
||||
return "Battery info result is not a JSON array";
|
||||
|
||||
yyjson_val* device;
|
||||
size_t idev, mdev;
|
||||
yyjson_arr_foreach(root, idev, mdev, device)
|
||||
{
|
||||
yyjson_val* modes = yyjson_obj_get(device, "modes");
|
||||
if (!yyjson_is_arr(modes))
|
||||
continue;
|
||||
|
||||
if (!yyjson_get_bool(yyjson_obj_get(device, "enabled")))
|
||||
continue;
|
||||
|
||||
yyjson_val* mode;
|
||||
size_t imode, mmode;
|
||||
yyjson_arr_foreach(modes, imode, mmode, mode)
|
||||
{
|
||||
if (!yyjson_is_obj(mode))
|
||||
continue;
|
||||
|
||||
if (!yyjson_get_bool(yyjson_obj_get(mode, "current")))
|
||||
continue;
|
||||
|
||||
uint32_t width = (uint32_t) yyjson_get_uint(yyjson_obj_get(mode, "width"));
|
||||
uint32_t height = (uint32_t) yyjson_get_uint(yyjson_obj_get(mode, "height"));
|
||||
|
||||
if (width == 0 || height == 0)
|
||||
continue;
|
||||
|
||||
double refreshRate = yyjson_get_real(yyjson_obj_get(mode, "refresh"));
|
||||
|
||||
double scale = (double) yyjson_get_real(yyjson_obj_get(device, "scale"));
|
||||
const char* connName = yyjson_get_str(yyjson_obj_get(device, "name"));
|
||||
FFDisplayType type = FF_DISPLAY_TYPE_UNKNOWN;
|
||||
if(ffStrStartsWith(connName, "eDP-"))
|
||||
type = FF_DISPLAY_TYPE_BUILTIN;
|
||||
else if(ffStrStartsWith(connName, "HDMI-"))
|
||||
type = FF_DISPLAY_TYPE_EXTERNAL;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY displayName = ffStrbufCreate();
|
||||
if (!ffdsMatchDrmConnector(connName, &displayName))
|
||||
{
|
||||
const char* desc = yyjson_get_str(yyjson_obj_get(device, "description"));
|
||||
if (ffStrContains(desc, "(null)"))
|
||||
ffStrbufSetS(&displayName, connName);
|
||||
else
|
||||
ffStrbufSetS(&displayName, desc);
|
||||
}
|
||||
uint32_t rotation = 0;
|
||||
const char* transform = yyjson_get_str(yyjson_obj_get(device, "transform"));
|
||||
if (!ffStrEquals(transform, "normal"))
|
||||
{
|
||||
// 90 | flipped-90
|
||||
if (ffStrEndsWith(transform, "90"))
|
||||
rotation = 90;
|
||||
else if (ffStrEndsWith(transform, "180"))
|
||||
rotation = 180;
|
||||
else if (ffStrEndsWith(transform, "270"))
|
||||
rotation = 270;
|
||||
}
|
||||
if (rotation % 180 != 0)
|
||||
{
|
||||
uint32_t temp = width;
|
||||
width = height;
|
||||
height = temp;
|
||||
}
|
||||
ffdsAppendDisplay(result,
|
||||
width,
|
||||
height,
|
||||
refreshRate,
|
||||
(uint32_t) (width / scale),
|
||||
(uint32_t) (height / scale),
|
||||
rotation,
|
||||
&displayName,
|
||||
type,
|
||||
false,
|
||||
0
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user