mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-13 02:42:09 +02:00
DisplayServer (Linux): wait for delayed Wayland output events
Ref: #2451
This commit is contained in:
@@ -25,6 +25,11 @@ static void waylandOutputScaleListener(void* data, [[maybe_unused]] struct wl_ou
|
||||
display->dpi = 96 * (uint32_t) scale;
|
||||
}
|
||||
|
||||
static void waylandOutputDoneListener(void* data, [[maybe_unused]] struct wl_output* output) {
|
||||
WaylandDisplay* display = data;
|
||||
display->done = true;
|
||||
}
|
||||
|
||||
static void waylandOutputGeometryListener(void* data,
|
||||
[[maybe_unused]] struct wl_output* output,
|
||||
[[maybe_unused]] int32_t x,
|
||||
@@ -54,7 +59,7 @@ static void handleXdgLogicalSize(void* data, [[maybe_unused]] struct zxdg_output
|
||||
static void* outputListener[] = {
|
||||
waylandOutputGeometryListener, // geometry
|
||||
waylandOutputModeListener, // mode
|
||||
stubListener, // done
|
||||
waylandOutputDoneListener, // done
|
||||
waylandOutputScaleListener, // scale
|
||||
ffWaylandOutputNameListener, // name
|
||||
ffWaylandOutputDescriptionListener, // description
|
||||
@@ -122,6 +127,13 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return "Failed to roundtrip wl_output";
|
||||
}
|
||||
if (bindVersion >= WL_OUTPUT_DONE_SINCE_VERSION && !display.done) {
|
||||
const char* error = ffWaylandWaitForDone(&display);
|
||||
if (error) {
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if (wldata->zxdgOutputManager) {
|
||||
uint32_t bindVersion = min(version, ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION);
|
||||
|
||||
@@ -147,11 +147,16 @@ static void waylandKdePriorityListener(void* data, [[maybe_unused]] struct kde_o
|
||||
display->primary = priority == 1;
|
||||
}
|
||||
|
||||
static void waylandKdeDoneListener(void* data, [[maybe_unused]] struct kde_output_device_v2* kde_output_device_v2) {
|
||||
WaylandDisplay* display = data;
|
||||
display->done = true;
|
||||
}
|
||||
|
||||
static struct kde_output_device_v2_listener outputListener = {
|
||||
.geometry = waylandKdeGeometryListener,
|
||||
.current_mode = waylandKdeCurrentModeListener,
|
||||
.mode = waylandKdeModeListener,
|
||||
.done = (void*) stubListener,
|
||||
.done = waylandKdeDoneListener,
|
||||
.scale = waylandKdeScaleListener,
|
||||
.edid = waylandKdeEdidListener,
|
||||
.enabled = waylandKdeEnabledListener,
|
||||
@@ -211,6 +216,13 @@ static const char* waylandKdeHandleOutput(WaylandData* wldata, struct wl_proxy*
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return "Failed to roundtrip kde_output_device_v2";
|
||||
}
|
||||
if (!display.done) {
|
||||
const char* error = ffWaylandWaitForDone(&display);
|
||||
if (error) {
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
|
||||
@@ -217,6 +217,39 @@ uint32_t ffWaylandHandleRotation(WaylandDisplay* display) {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
const char* ffWaylandWaitForDone(WaylandDisplay* display) {
|
||||
int32_t timeout = instance.config.general.processingTimeout;
|
||||
struct timespec ts;
|
||||
if (timeout == 0) {
|
||||
return "timeout is disabled";
|
||||
} else if (timeout > 0) {
|
||||
if (!display->parent->ffwl_display_dispatch_timeout) {
|
||||
return "timeout is enabled, but the libwayland-client version is too old to support it";
|
||||
}
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout % 1000) * 1000000;
|
||||
}
|
||||
|
||||
WaylandData* wldata = display->parent;
|
||||
|
||||
// Some compositors emit the final output state asynchronously after the roundtrip callback (#2074)
|
||||
while (!display->done) {
|
||||
if (timeout > 0) {
|
||||
if (wldata->ffwl_display_dispatch_timeout(wldata->display, &ts) < 0) {
|
||||
return "wl_display_dispatch_timeout() failed";
|
||||
}
|
||||
} else if (timeout < 0) {
|
||||
if (wldata->ffwl_display_dispatch(wldata->display) < 0) {
|
||||
return "wl_display_dispatch() failed";
|
||||
}
|
||||
} else {
|
||||
return "Timeout exceeded, but the compositor did not send a done event";
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* ffdsConnectWayland(FFDisplayServerResult* result) {
|
||||
if (getenv("XDG_RUNTIME_DIR") == nullptr) {
|
||||
return "Wayland requires $XDG_RUNTIME_DIR being set";
|
||||
@@ -236,6 +269,12 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result) {
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_destroy)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_display_roundtrip)
|
||||
|
||||
if (instance.config.general.processingTimeout < 0) {
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_LAZY(wayland, data, wl_display_dispatch)
|
||||
} else if (instance.config.general.processingTimeout > 0) {
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_LAZY(wayland, data, wl_display_dispatch_timeout)
|
||||
}
|
||||
|
||||
data.display = ffwl_display_connect(nullptr);
|
||||
if (data.display == nullptr) {
|
||||
return "wl_display_connect returned nullptr";
|
||||
|
||||
@@ -20,12 +20,19 @@ typedef enum WaylandProtocolType: uint8_t {
|
||||
FF_WAYLAND_PROTOCOL_TYPE_KDE_REGISTRY,
|
||||
} WaylandProtocolType;
|
||||
|
||||
// In case users have an ancient version of libwayland-client
|
||||
int wl_display_dispatch_timeout(struct wl_display *display, const struct timespec *timeout);
|
||||
|
||||
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)
|
||||
union {
|
||||
FF_LIBRARY_SYMBOL(wl_display_dispatch)
|
||||
FF_LIBRARY_SYMBOL(wl_display_dispatch_timeout)
|
||||
};
|
||||
struct wl_display* display;
|
||||
WaylandProtocolType protocolType;
|
||||
struct wl_proxy* zxdgOutputManager;
|
||||
@@ -58,6 +65,7 @@ typedef struct WaylandDisplay {
|
||||
FFstrbuf serial;
|
||||
uint8_t bitDepth;
|
||||
bool primary;
|
||||
bool done;
|
||||
} WaylandDisplay;
|
||||
|
||||
inline static void stubListener(void* data, ...) {
|
||||
@@ -79,6 +87,7 @@ void ffWaylandOutputNameListener(void* data, [[maybe_unused]] void* output, cons
|
||||
void ffWaylandOutputDescriptionListener(void* data, [[maybe_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* ffWaylandWaitForDone(WaylandDisplay* display);
|
||||
|
||||
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
|
||||
const char* ffWaylandHandleKdeOutputRegistry(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version);
|
||||
|
||||
Reference in New Issue
Block a user