From ce43f06863d436c9927b295f8d5fbe4afc6a3449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 26 Jul 2024 23:08:24 +0800 Subject: [PATCH] DisplayServer (Linux): don't try to connect wayland and X11 in tty mode Fix #1110 --- .../displayserver/linux/displayserver_linux.c | 48 ++++- .../displayserver/linux/displayserver_linux.h | 3 +- .../displayserver/linux/wayland/wayland.c | 191 ++++++++---------- src/detection/displayserver/linux/wmde.c | 41 ---- 4 files changed, 129 insertions(+), 154 deletions(-) diff --git a/src/detection/displayserver/linux/displayserver_linux.c b/src/detection/displayserver/linux/displayserver_linux.c index e864bdc07..d8336f3a9 100644 --- a/src/detection/displayserver/linux/displayserver_linux.c +++ b/src/detection/displayserver/linux/displayserver_linux.c @@ -7,9 +7,48 @@ #include "common/settings.h" #endif +static void getWMProtocolNameFromEnv(FFDisplayServerResult* result) +{ + const char* env = getenv("XDG_SESSION_TYPE"); + if(env) + { + if(ffStrEqualsIgnCase(env, "wayland")) + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND); + else if(ffStrEqualsIgnCase(env, "x11") || ffStrEqualsIgnCase(env, "xorg")) + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); + else if(ffStrEqualsIgnCase(env, "tty")) + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY); + else + ffStrbufSetS(&result->wmProtocolName, env); + + return; + } + + if(getenv("WAYLAND_DISPLAY") != NULL || getenv("WAYLAND_SOCKET") != NULL) + { + ffStrbufSetStatic(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND); + return; + } + + if(getenv("DISPLAY") != NULL) // XWayland also set this + { + ffStrbufSetStatic(&result->wmProtocolName, FF_WM_PROTOCOL_X11); + return; + } + + env = getenv("TERM"); + if(ffStrSet(env) && ffStrEqualsIgnCase(env, "linux")) + { + ffStrbufSetStatic(&result->wmProtocolName, FF_WM_PROTOCOL_TTY); + return; + } +} + void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) { - if (instance.config.general.dsForceDrm == FF_DS_FORCE_DRM_TYPE_FALSE) + getWMProtocolNameFromEnv(ds); + + if (!ffStrbufEqualS(&ds->wmProtocolName, FF_WM_PROTOCOL_TTY) &&instance.config.general.dsForceDrm == FF_DS_FORCE_DRM_TYPE_FALSE) { //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 @@ -57,8 +96,11 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) } #endif - //This fills in missing information about WM / DE by using env vars and iterating processes - ffdsDetectWMDE(ds); + if(!ffStrbufEqualS(&ds->wmProtocolName, FF_WM_PROTOCOL_TTY)) + { + //This fills in missing information about WM / DE by using env vars and iterating processes + ffdsDetectWMDE(ds); + } } bool ffdsMatchDrmConnector(const char* connName, FFstrbuf* edidName) diff --git a/src/detection/displayserver/linux/displayserver_linux.h b/src/detection/displayserver/linux/displayserver_linux.h index c4937ee22..2a97e7008 100644 --- a/src/detection/displayserver/linux/displayserver_linux.h +++ b/src/detection/displayserver/linux/displayserver_linux.h @@ -7,8 +7,7 @@ bool ffdsMatchDrmConnector(const char* connName, FFstrbuf* edidName); -const char* ffdsConnectWlroots(FFDisplayServerResult* result); -void ffdsConnectWayland(FFDisplayServerResult* result); +const char* ffdsConnectWayland(FFDisplayServerResult* result); void ffdsConnectXcbRandr(FFDisplayServerResult* result); void ffdsConnectXcb(FFDisplayServerResult* result); diff --git a/src/detection/displayserver/linux/wayland/wayland.c b/src/detection/displayserver/linux/wayland/wayland.c index 2bf03ebe7..603d373af 100644 --- a/src/detection/displayserver/linux/wayland/wayland.c +++ b/src/detection/displayserver/linux/wayland/wayland.c @@ -22,12 +22,14 @@ static bool waylandDetectWM(int fd, FFDisplayServerResult* result) { struct ucred ucred; socklen_t len = sizeof(struct ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1 || ucred.pid <= 0) return false; FF_STRBUF_AUTO_DESTROY procPath = ffStrbufCreate(); ffStrbufAppendF(&procPath, "/proc/%d/cmdline", ucred.pid); //We check the cmdline for the process name, because it is not trimmed. - ffReadFileBuffer(procPath.chars, &result->wmProcessName); + if (!ffReadFileBuffer(procPath.chars, &result->wmProcessName)) + return false; + ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path return true; @@ -69,27 +71,91 @@ static void waylandGlobalAddListener(void* data, struct wl_registry* registry, u } } -bool detectWayland(FFDisplayServerResult* result) +void ffWaylandOutputNameListener(void* data, FF_MAYBE_UNUSED void* output, const char *name) +{ + WaylandDisplay* display = data; + if (display->id) return; + + display->type = ffdsGetDisplayType(name); + if (!display->edidName.length) + ffdsMatchDrmConnector(name, &display->edidName); + display->id = ffWaylandGenerateIdFromName(name); + ffStrbufAppendS(&display->name, name); +} + +void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output, const char* description) +{ + WaylandDisplay* display = data; + if (display->description.length) return; + + while (*description == ' ') ++description; + if (!ffStrEquals(description, "Unknown Display") && !ffStrContains(description, "(null)")) + ffStrbufAppendS(&display->description, description); +} + +uint32_t ffWaylandHandleRotation(WaylandDisplay* display) +{ + uint32_t rotation; + switch(display->transform) + { + case WL_OUTPUT_TRANSFORM_FLIPPED_90: + case WL_OUTPUT_TRANSFORM_90: + rotation = 90; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_180: + case WL_OUTPUT_TRANSFORM_180: + rotation = 180; + break; + case WL_OUTPUT_TRANSFORM_FLIPPED_270: + case WL_OUTPUT_TRANSFORM_270: + rotation = 270; + break; + default: + rotation = 0; + break; + } + + switch(rotation) + { + case 90: + case 270: { + int32_t temp = display->width; + display->width = display->height; + display->height = temp; + + temp = display->physicalWidth; + display->physicalWidth = display->physicalHeight; + display->physicalHeight = temp; + break; + } + default: + break; + } + return rotation; +} +#endif + +const char* ffdsConnectWayland(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) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_connect) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_get_fd) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_proxy_marshal_constructor) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_display_disconnect) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wayland, wl_registry_interface) WaylandData data = {}; - FF_LIBRARY_LOAD_SYMBOL_VAR(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) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_marshal_constructor_versioned) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_add_listener) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_proxy_destroy) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_display_roundtrip) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(wayland, data, wl_output_interface) data.display = ffwl_display_connect(NULL); if(data.display == NULL) - return false; + return "wl_display_connect returned NULL"; waylandDetectWM(ffwl_display_get_fd(data.display), result); @@ -97,7 +163,7 @@ bool detectWayland(FFDisplayServerResult* result) if(registry == NULL) { ffwl_display_disconnect(data.display); - return false; + return "wl_display_get_registry returned NULL"; } data.result = result; @@ -192,97 +258,6 @@ bool detectWayland(FFDisplayServerResult* result) //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 (display->id) return; - - display->type = ffdsGetDisplayType(name); - if (!display->edidName.length) - ffdsMatchDrmConnector(name, &display->edidName); - display->id = ffWaylandGenerateIdFromName(name); - ffStrbufAppendS(&display->name, name); -} - -void ffWaylandOutputDescriptionListener(void* data, FF_MAYBE_UNUSED void* output, const char* description) -{ - WaylandDisplay* display = data; - if (display->description.length) return; - - while (*description == ' ') ++description; - if (!ffStrEquals(description, "Unknown Display") && !ffStrContains(description, "(null)")) - ffStrbufAppendS(&display->description, description); -} - -uint32_t ffWaylandHandleRotation(WaylandDisplay* display) -{ - uint32_t rotation; - switch(display->transform) - { - case WL_OUTPUT_TRANSFORM_FLIPPED_90: - case WL_OUTPUT_TRANSFORM_90: - rotation = 90; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_180: - case WL_OUTPUT_TRANSFORM_180: - rotation = 180; - break; - case WL_OUTPUT_TRANSFORM_FLIPPED_270: - case WL_OUTPUT_TRANSFORM_270: - rotation = 270; - break; - default: - rotation = 0; - break; - } - - switch(rotation) - { - case 90: - case 270: { - int32_t temp = display->width; - display->width = display->height; - display->height = temp; - - temp = display->physicalWidth; - display->physicalWidth = display->physicalHeight; - display->physicalHeight = temp; - break; - } - default: - break; - } - return rotation; -} -#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); + ffStrbufSetStatic(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND); + return NULL; } diff --git a/src/detection/displayserver/linux/wmde.c b/src/detection/displayserver/linux/wmde.c index 0319cdd45..8f50b69ab 100644 --- a/src/detection/displayserver/linux/wmde.c +++ b/src/detection/displayserver/linux/wmde.c @@ -240,38 +240,6 @@ static void applyPrettyNameIfDE(FFDisplayServerResult* result, const char* name) } } -static void getWMProtocolNameFromEnv(FFDisplayServerResult* result) -{ - //This is only called if all connection attempts to a display server failed - //We don't need to check for wayland here, as the wayland code will always set the protocol name to wayland - - const char* env = getenv("XDG_SESSION_TYPE"); - if(ffStrSet(env)) - { - if(ffStrEqualsIgnCase(env, "x11")) - ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); - else if(ffStrEqualsIgnCase(env, "tty")) - ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY); - else - ffStrbufSetS(&result->wmProtocolName, env); - - return; - } - - env = getenv("DISPLAY"); - if(ffStrSet(env)) - { - ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); - return; - } - - env = getenv("TERM"); - if(ffStrSet(env) && ffStrEqualsIgnCase(env, "linux")) - { - ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY); - return; - } -} static const char* getFromProcesses(FFDisplayServerResult* result) { @@ -396,15 +364,6 @@ static const char* getFromProcesses(FFDisplayServerResult* result) void ffdsDetectWMDE(FFDisplayServerResult* result) { - //If all connections failed, use the environment variables to detect protocol name - if(result->wmProtocolName.length == 0) - getWMProtocolNameFromEnv(result); - - //We don't want to detect anything in TTY - //This can't happen if a connection succeeded, so we don't need to clear wmProcessName - if(ffStrbufIgnCaseCompS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) - return; - const char* env = parseEnv(); if(result->wmProcessName.length > 0)