From e953ed9d887c6653349b1231e707039e16984417 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 18 Nov 2024 15:47:48 +0800 Subject: [PATCH 01/48] Packaging: update debian stuff [ci skip] --- debian/changelog | 6 ++++++ debian/files | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 6ef906c917..bf1ef555e6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +fastfetch (2.30.1) jammy; urgency=medium + + * Update to 2.30.1 + + -- Carter Li Mon, 18 Nov 2024 15:40:48 +0800 + fastfetch (2.30.0) jammy; urgency=medium * Update to 2.30.0 diff --git a/debian/files b/debian/files index a935a0912b..6cd2ef9b59 100644 --- a/debian/files +++ b/debian/files @@ -1 +1 @@ -fastfetch_2.30.0_source.buildinfo universe/utils optional +fastfetch_2.30.1_source.buildinfo universe/utils optional From 465170428f1ab0736b84a1fc9276672db211ef5c Mon Sep 17 00:00:00 2001 From: R0CKSTAR Date: Tue, 19 Nov 2024 19:36:12 +0800 Subject: [PATCH 02/48] mtgpu: header file cleanup for forward compatibility (#1405) Signed-off-by: Xiaodong Ye --- src/detection/gpu/mtml.h | 46 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/detection/gpu/mtml.h b/src/detection/gpu/mtml.h index a97cfeb37c..008f83ae24 100644 --- a/src/detection/gpu/mtml.h +++ b/src/detection/gpu/mtml.h @@ -4,10 +4,8 @@ // THIS FILE IS CREATED FROM SCRATCH, BY READING THE OFFICIAL MTML API // DOCUMENTATION REFERENCED BELOW, IN ORDER TO MAKE FASTFETCH MIT COMPLIANT. -#define MTML_API __attribute__((visibility("default"))) #define MTML_DEVICE_PCI_SBDF_BUFFER_SIZE 32 #define MTML_DEVICE_NAME_BUFFER_SIZE 32 -#define MTML_DEVICE_UUID_BUFFER_SIZE 48 /** * Return values for MTML API calls. @@ -23,10 +21,6 @@ typedef enum typedef enum { MTML_BRAND_MTT = 0, //!< MTT series. - MTML_BRAND_UNKNOWN, //!< An unknown brand. - - // Keep this on the last line. - MTML_BRAND_COUNT //!< The number of brands. } MtmlBrandType; typedef struct MtmlLibrary MtmlLibrary; @@ -57,62 +51,62 @@ typedef struct } MtmlPciInfo; // Retrieves the number of cores of a device. -MtmlReturn MTML_API mtmlDeviceCountGpuCores(const MtmlDevice* device, unsigned int* numCores); +MtmlReturn mtmlDeviceCountGpuCores(const MtmlDevice* device, unsigned int* numCores); // Retrieves the brand of a device. -MtmlReturn MTML_API mtmlDeviceGetBrand(const MtmlDevice *dev, MtmlBrandType *type); +MtmlReturn mtmlDeviceGetBrand(const MtmlDevice *dev, MtmlBrandType *type); // Retrieves the index associated with the specified device. -MtmlReturn MTML_API mtmlDeviceGetIndex(const MtmlDevice *dev, unsigned int *index); +MtmlReturn mtmlDeviceGetIndex(const MtmlDevice *dev, unsigned int *index); // Retrieves the name of a device. -MtmlReturn MTML_API mtmlDeviceGetName(const MtmlDevice *dev, char *name, unsigned int length); +MtmlReturn mtmlDeviceGetName(const MtmlDevice *dev, char *name, unsigned int length); // Retrieves the PCI attributes of a device. -MtmlReturn MTML_API mtmlDeviceGetPciInfo(const MtmlDevice *dev, MtmlPciInfo *pci); +MtmlReturn mtmlDeviceGetPciInfo(const MtmlDevice *dev, MtmlPciInfo *pci); /** * Retrieves the UUID of a specified device. The UUID is a hexadecimal string in the * form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, where each 'x' is an ASCII character that represents a hexadecimal * digit. The UUID is globally unique for every single device thus can be used to identify different devices * physically. */ -MtmlReturn MTML_API mtmlDeviceGetUUID(const MtmlDevice *dev, char *uuid, unsigned int length); +MtmlReturn mtmlDeviceGetUUID(const MtmlDevice *dev, char *uuid, unsigned int length); // Initializes a GPU opaque object to represent a specific graphic core on the target device that is designated by its index. -MtmlReturn MTML_API mtmlDeviceInitGpu(const MtmlDevice *dev, MtmlGpu **gpu); +MtmlReturn mtmlDeviceInitGpu(const MtmlDevice *dev, MtmlGpu **gpu); // Initializes a memory opaque object to represent the memory on the target device. -MtmlReturn MTML_API mtmlDeviceInitMemory(const MtmlDevice *dev, MtmlMemory **mem); +MtmlReturn mtmlDeviceInitMemory(const MtmlDevice *dev, MtmlMemory **mem); // Retrieves the maximum supported clock speed for the device's graphic core. -MtmlReturn MTML_API mtmlGpuGetMaxClock(const MtmlGpu *gpu, unsigned int *clockMhz); +MtmlReturn mtmlGpuGetMaxClock(const MtmlGpu *gpu, unsigned int *clockMhz); // Retrieves the current temperature readings for the device's graphic core, in degrees Celsius. -MtmlReturn MTML_API mtmlGpuGetTemperature(const MtmlGpu *gpu, unsigned int *temp); +MtmlReturn mtmlGpuGetTemperature(const MtmlGpu *gpu, unsigned int *temp); // Retrieves the current utilization rate for the device's graphic core. -MtmlReturn MTML_API mtmlGpuGetUtilization(const MtmlGpu *gpu, unsigned int *utilization); +MtmlReturn mtmlGpuGetUtilization(const MtmlGpu *gpu, unsigned int *utilization); // Retrieves the number of devices that can be accessed by the library opaque object. -MtmlReturn MTML_API mtmlLibraryCountDevice(const MtmlLibrary *lib, unsigned int *count); +MtmlReturn mtmlLibraryCountDevice(const MtmlLibrary *lib, unsigned int *count); /** * Initializes a device opaque object to represent a device that is designated by its index. * The index ranges from (0) to (deviceCount - 1), where deviceCount is retrieved from \ref mtmlLibraryCountDevice(). */ -MtmlReturn MTML_API mtmlLibraryInit(MtmlLibrary **lib); +MtmlReturn mtmlLibraryInit(MtmlLibrary **lib); /** * Initializes a device opaque object to represent a device that is designated by its index. * The index ranges from (0) to (deviceCount - 1), where deviceCount is retrieved from \ref mtmlLibraryCountDevice(). */ -MtmlReturn MTML_API mtmlLibraryInitDeviceByIndex(const MtmlLibrary *lib, unsigned int index, MtmlDevice **dev); +MtmlReturn mtmlLibraryInitDeviceByIndex(const MtmlLibrary *lib, unsigned int index, MtmlDevice **dev); /** * Initializes a device opaque object to represent a device that is designated by its PCI Sbdf. * The PCI Sbdf format like 00000000:3a:00.0 refer to \ref MtmlPciInfo::sbdf. */ -MtmlReturn MTML_API mtmlLibraryInitDeviceByPciSbdf(const MtmlLibrary *lib, const char *pciSbdf, MtmlDevice **dev); +MtmlReturn mtmlLibraryInitDeviceByPciSbdf(const MtmlLibrary *lib, const char *pciSbdf, MtmlDevice **dev); // Initializes a MtmlSystem opaque pointer that is bound to a library opaque object. -MtmlReturn MTML_API mtmlLibraryInitSystem(const MtmlLibrary *lib, MtmlSystem **sys); +MtmlReturn mtmlLibraryInitSystem(const MtmlLibrary *lib, MtmlSystem **sys); /** * Shuts down the library opaque object that is previously initialized by \ref mtmlLibraryInit() and releases its resources. * The \a lib pointer cannot be used anymore after this function returns. */ -MtmlReturn MTML_API mtmlLibraryShutDown(MtmlLibrary *lib); +MtmlReturn mtmlLibraryShutDown(MtmlLibrary *lib); // Retrieves the amount of total memory available on the device, in bytes. -MtmlReturn MTML_API mtmlMemoryGetTotal(const MtmlMemory *mem, unsigned long long *total); +MtmlReturn mtmlMemoryGetTotal(const MtmlMemory *mem, unsigned long long *total); // Retrieves the amount of used memory on the device, in bytes. -MtmlReturn MTML_API mtmlMemoryGetUsed(const MtmlMemory *mem, unsigned long long *used); +MtmlReturn mtmlMemoryGetUsed(const MtmlMemory *mem, unsigned long long *used); // Retrieves the current memory utilization rate for the device. -MtmlReturn MTML_API mtmlMemoryGetUtilization(const MtmlMemory *mem, unsigned int *utilization); +MtmlReturn mtmlMemoryGetUtilization(const MtmlMemory *mem, unsigned int *utilization); From 16b7a4a1be73179ef701152a22b071c0787d6492 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 19 Nov 2024 15:07:20 +0800 Subject: [PATCH 03/48] Media (Linux): improve performance of dbus communication --- src/common/dbus.h | 5 ++ src/detection/media/media_linux.c | 122 ++++++++++++++++++++---------- 2 files changed, 86 insertions(+), 41 deletions(-) diff --git a/src/common/dbus.h b/src/common/dbus.h index 282f008d92..3d2dc702ec 100644 --- a/src/common/dbus.h +++ b/src/common/dbus.h @@ -38,4 +38,9 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result); bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result); +static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface) +{ + return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface); +} + #endif // FF_HAVE_DBUS diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index 43e3f21157..a4953de500 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -17,36 +17,23 @@ continue; \ } -static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result) +static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator, FFMediaResult* result) { - DBusMessage* reply = ffDBusGetProperty(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata"); - if(reply == NULL) - return false; - - DBusMessageIter rootIterator; - if(!data->lib->ffdbus_message_iter_init(reply, &rootIterator)) - { - data->lib->ffdbus_message_unref(reply); - return false; - } + DBusMessageIter arrayIterator; - if(data->lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT) + if (data->lib->ffdbus_message_iter_get_arg_type(rootIterator) == DBUS_TYPE_VARIANT) { - data->lib->ffdbus_message_unref(reply); - return false; + DBusMessageIter variantIterator; + data->lib->ffdbus_message_iter_recurse(rootIterator, &variantIterator); + if(data->lib->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY) + return false; + data->lib->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator); } - - DBusMessageIter variantIterator; - data->lib->ffdbus_message_iter_recurse(&rootIterator, &variantIterator); - if(data->lib->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY) + else { - data->lib->ffdbus_message_unref(reply); - return false; + data->lib->ffdbus_message_iter_recurse(rootIterator, &arrayIterator); } - DBusMessageIter arrayIterator; - data->lib->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator); - while(true) { if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) @@ -66,13 +53,17 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul data->lib->ffdbus_message_iter_next(&dictIterator); - if(ffStrEquals(key, "xesam:title")) + if(!ffStrStartsWith(key, "xesam:")) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) + + key += strlen("xesam:"); + if(ffStrEquals(key, "title")) ffDBusGetString(data, &dictIterator, &result->song); - else if(ffStrEquals(key, "xesam:album")) + else if(ffStrEquals(key, "album")) ffDBusGetString(data, &dictIterator, &result->album); - else if(ffStrEquals(key, "xesam:artist")) + else if(ffStrEquals(key, "artist")) ffDBusGetString(data, &dictIterator, &result->artist); - else if(ffStrEquals(key, "xesam:url")) + else if(ffStrEquals(key, "url")) ffDBusGetString(data, &dictIterator, &result->url); if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0 && result->url.length > 0) @@ -81,7 +72,53 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul FF_DBUS_ITER_CONTINUE(data, &arrayIterator) } - data->lib->ffdbus_message_unref(reply); + return true; +} + +static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result) +{ + // Get all properties at once to reduce the number of IPCs + DBusMessage* reply = ffDBusGetAllProperties(data, busName, "/org/mpris/MediaPlayer2", ""); + if(reply == NULL) + return false; + + DBusMessageIter rootIterator; + if(!data->lib->ffdbus_message_iter_init(reply, &rootIterator) && + data->lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY) + { + data->lib->ffdbus_message_unref(reply); + return false; + } + + DBusMessageIter arrayIterator; + data->lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator); + + FF_STRBUF_AUTO_DESTROY desktopIdentity = ffStrbufCreate(); + + while(true) + { + if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) + + DBusMessageIter dictIterator; + data->lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator); + + const char* key; + data->lib->ffdbus_message_iter_get_basic(&dictIterator, &key); + + data->lib->ffdbus_message_iter_next(&dictIterator); + + if(ffStrEquals(key, "Metadata")) + parseMprisMetadata(data, &dictIterator, result); + else if(ffStrEquals(key, "PlaybackStatus")) + ffDBusGetString(data, &dictIterator, &result->status); + else if(ffStrEquals(key, "Identity")) + ffDBusGetString(data, &dictIterator, &result->player); + else if(ffStrEquals(key, "DesktopEntry")) + ffDBusGetString(data, &dictIterator, &desktopIdentity); + + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) + } if(result->song.length == 0) { @@ -91,17 +128,20 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul return false; } - ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "PlaybackStatus", &result->status); - - //Set short bus name - ffStrbufAppendS(&result->playerId, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); + if (result->player.length == 0) + { + if (desktopIdentity.length > 0) + { + ffStrbufDestroy(&result->player); + ffStrbufInitMove(&result->player, &desktopIdentity); + } + else + { + ffStrbufAppend(&result->player, &result->playerId); + } + } - //We found a song, get the player name - ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player); - if(result->player.length == 0) - ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player); - if(result->player.length == 0) - ffStrbufAppend(&result->player, &result->playerId); + data->lib->ffdbus_message_unref(reply); return true; } @@ -122,9 +162,9 @@ static void getCustomBus(FFDBusData* data, const FFstrbuf* playerName, FFMediaRe static void getBestBus(FFDBusData* data, FFMediaResult* result) { if( - getBusProperties(data, FF_DBUS_MPRIS_PREFIX"spotify", result) || - getBusProperties(data, FF_DBUS_MPRIS_PREFIX"vlc", result) || - getBusProperties(data, FF_DBUS_MPRIS_PREFIX"plasma-browser-integration", result) + getBusProperties(data, FF_DBUS_MPRIS_PREFIX "spotify", result) || + getBusProperties(data, FF_DBUS_MPRIS_PREFIX "vlc", result) || + getBusProperties(data, FF_DBUS_MPRIS_PREFIX "plasma-browser-integration", result) ) return; DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", NULL); From fdc9bee4b384dfaaa0a7064787768348e69283c0 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 19 Nov 2024 15:10:26 +0800 Subject: [PATCH 04/48] DBus: use `general.processingTimeout` as its timeout instead hard coding --- src/common/dbus.c | 4 ++-- src/common/dbus.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/common/dbus.c b/src/common/dbus.c index 636cce7a6d..ea438335cb 100644 --- a/src/common/dbus.c +++ b/src/common/dbus.c @@ -171,7 +171,7 @@ DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const c if (arg) dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); - DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, FF_DBUS_TIMEOUT_MILLISECONDS, NULL); + DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL); dbus->lib->ffdbus_message_unref(message); @@ -189,7 +189,7 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); - DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, FF_DBUS_TIMEOUT_MILLISECONDS, NULL); + DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL); dbus->lib->ffdbus_message_unref(message); diff --git a/src/common/dbus.h b/src/common/dbus.h index 3d2dc702ec..35a1672f8e 100644 --- a/src/common/dbus.h +++ b/src/common/dbus.h @@ -6,8 +6,6 @@ #include "util/FFstrbuf.h" #include "common/library.h" -#define FF_DBUS_TIMEOUT_MILLISECONDS 100 - typedef struct FFDBusLibrary { FF_LIBRARY_SYMBOL(dbus_bus_get) From 4cbcd0f1073bdcba025706d9b580ae2f38f1c5bf Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 20 Nov 2024 08:43:28 +0800 Subject: [PATCH 05/48] Wifi (Linux): improve performance --- src/detection/wifi/wifi_linux.c | 74 +++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 12 deletions(-) diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index cd99a271a7..b1fcd6e899 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -36,6 +36,13 @@ typedef enum { NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192 = 0x00002000, } NM80211ApSecurityFlags; +#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \ + { \ + if(!(dbus).lib->ffdbus_message_iter_next(iterator)) \ + break; \ + continue; \ + } + static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { FFDBusData dbus; @@ -72,24 +79,67 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) if (!item->conn.status.length) ffStrbufSetStatic(&item->conn.status, "connected"); - if (!item->conn.ssid.length) - ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Ssid", &item->conn.ssid); - - if (!item->conn.bssid.length) - ffDBusGetPropertyString(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "HwAddress", &item->conn.bssid); + DBusMessage* reply = ffDBusGetAllProperties(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint"); + if(reply == NULL) + return "Failed to get access point properties"; - if (item->conn.signalQuality != item->conn.signalQuality) + DBusMessageIter rootIterator; + if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator) && + dbus.lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY) { - uint32_t strengthPercent; - if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Strength", &strengthPercent)) - item->conn.signalQuality = strengthPercent; + dbus.lib->ffdbus_message_unref(reply); + return "Invalid type of access point properties"; } + DBusMessageIter arrayIterator; + dbus.lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator); + NM80211ApFlags flags; NM80211ApSecurityFlags wpaFlags, rsnFlags; - if (ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "Flags", &flags) && - ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars, "org.freedesktop.NetworkManager.AccessPoint", "WpaFlags", &wpaFlags) && - ffDBusGetPropertyUint(&dbus, "org.freedesktop.NetworkManager", apPath.chars , "org.freedesktop.NetworkManager.AccessPoint", "RsnFlags", &rsnFlags)) + int flagCount = 0; + + while(true) + { + if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) + FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator) + + DBusMessageIter dictIterator; + dbus.lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator); + + const char* key; + dbus.lib->ffdbus_message_iter_get_basic(&dictIterator, &key); + + dbus.lib->ffdbus_message_iter_next(&dictIterator); + + if (ffStrEquals(key, "Ssid")) + { + if (!item->conn.ssid.length) + ffDBusGetString(&dbus, &dictIterator, &item->conn.ssid); + } + else if (ffStrEquals(key, "HwAddress")) + { + if (!item->conn.bssid.length) + ffDBusGetString(&dbus, &dictIterator, &item->conn.bssid); + } + else if (ffStrEquals(key, "Strength")) + { + if (item->conn.signalQuality != item->conn.signalQuality) + { + uint32_t strengthPercent; + if (ffDBusGetUint(&dbus, &dictIterator, &strengthPercent)) + item->conn.signalQuality = strengthPercent; + } + } + else if ((ffStrEquals(key, "Flags") && ffDBusGetUint(&dbus, &dictIterator, &flags)) || + (ffStrEquals(key, "WpaFlags") && ffDBusGetUint(&dbus, &dictIterator, &wpaFlags)) || + (ffStrEquals(key, "RsnFlags") && ffDBusGetUint(&dbus, &dictIterator, &rsnFlags)) + ) + ++flagCount; + + FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator) + } + + if (flagCount == 3) { if ((flags & NM_802_11_AP_FLAGS_PRIVACY) && (wpaFlags == NM_802_11_AP_SEC_NONE) && (rsnFlags == NM_802_11_AP_SEC_NONE)) From 3d5133eaba160d5d7298bff31a891587c5b37cd1 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 20 Nov 2024 09:37:32 +0800 Subject: [PATCH 06/48] DisplayServer (Linux): remove support of xcb & xlib They don't support multi-monitors. Prefer libdrm. --- CMakeLists.txt | 10 --- src/common/init.c | 6 -- .../displayserver/linux/displayserver_linux.c | 7 -- .../displayserver/linux/displayserver_linux.h | 4 - src/detection/displayserver/linux/xcb.c | 76 ++----------------- src/detection/displayserver/linux/xlib.c | 66 ++-------------- 6 files changed, 12 insertions(+), 157 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a0cca18a6..1c6eed1c42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,9 +57,7 @@ include(CMakeDependentOption) cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS" OFF) cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD" OFF) cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) -cmake_dependent_option(ENABLE_XCB "Enable xcb" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) -cmake_dependent_option(ENABLE_X11 "Enable x11" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX" OFF) cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS" OFF) @@ -1277,18 +1275,10 @@ ff_lib_enable(XCB_RANDR "xcb-randr" "XcbRandr" ) -ff_lib_enable(XCB - "xcb" - "Xcb" -) ff_lib_enable(XRANDR "xrandr" "XRandr" ) -ff_lib_enable(X11 - "x11" - "X11" -) ff_lib_enable(DRM "libdrm" "Libdrm" diff --git a/src/common/init.c b/src/common/init.c index 8f8dfea246..2cdce8df45 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -179,15 +179,9 @@ void ffListFeatures(void) #if FF_HAVE_XCB_RANDR "xcb-randr\n" #endif - #if FF_HAVE_XCB - "xcb\n" - #endif #if FF_HAVE_XRANDR "xrandr\n" #endif - #if FF_HAVE_X11 - "x11\n" - #endif #if FF_HAVE_DRM "drm\n" #endif diff --git a/src/detection/displayserver/linux/displayserver_linux.c b/src/detection/displayserver/linux/displayserver_linux.c index cc4e07b21b..84ea36ad66 100644 --- a/src/detection/displayserver/linux/displayserver_linux.c +++ b/src/detection/displayserver/linux/displayserver_linux.c @@ -54,18 +54,11 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) //Try the x11 libs, from most feature rich to least. //We use the display list to detect if a connection is needed. //They respect wmProtocolName, and only detect display if it is set. - if(ds->displays.length == 0) ffdsConnectXcbRandr(ds); if(ds->displays.length == 0) ffdsConnectXrandr(ds); - - if(ds->displays.length == 0) - ffdsConnectXcb(ds); - - if(ds->displays.length == 0) - ffdsConnectXlib(ds); } //This display detection method is display server independent. diff --git a/src/detection/displayserver/linux/displayserver_linux.h b/src/detection/displayserver/linux/displayserver_linux.h index 5452711e7b..19ae4e71f3 100644 --- a/src/detection/displayserver/linux/displayserver_linux.h +++ b/src/detection/displayserver/linux/displayserver_linux.h @@ -5,11 +5,7 @@ const char* ffdsConnectWayland(FFDisplayServerResult* result); const char* ffdsConnectXcbRandr(FFDisplayServerResult* result); -const char* ffdsConnectXcb(FFDisplayServerResult* result); - const char* ffdsConnectXrandr(FFDisplayServerResult* result); -const char* ffdsConnectXlib(FFDisplayServerResult* result); - const char* ffdsConnectDrm(FFDisplayServerResult* result); void ffdsDetectWMDE(FFDisplayServerResult* result); diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index a9e4b8d795..47508a2428 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -1,11 +1,15 @@ #include "displayserver_linux.h" -#include "util/mallocHelper.h" -#include "common/time.h" -#ifdef FF_HAVE_XCB +#ifdef FF_HAVE_XCB_RANDR + #include "common/library.h" +#include "common/time.h" +#include "util/edidHelper.h" +#include "util/mallocHelper.h" + #include #include +#include #include typedef struct XcbPropertyData @@ -82,72 +86,6 @@ static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connect ffStrbufSetS(&result->wmProcessName, wmName); } -const char* ffdsConnectXcb(FFDisplayServerResult* result) -{ - FF_LIBRARY_LOAD(xcb, "dlopen lbxcb failed", "libxcb" FF_LIBRARY_EXTENSION, 2) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcb, xcb_connect) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcb, xcb_get_setup) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcb, xcb_setup_roots_iterator) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcb, xcb_screen_next) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcb, xcb_disconnect) - - XcbPropertyData propertyData; - bool propertyDataInitialized = xcbInitPropertyData(xcb, &propertyData); - - xcb_connection_t* connection = ffxcb_connect(NULL, NULL); - if(connection == NULL) - return "xcb_connect failed"; - - xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(connection)); - - if(iterator.rem > 0 && propertyDataInitialized) - xcbDetectWMfromEWMH(&propertyData, connection, iterator.data->root, result); - - while(iterator.rem > 0) - { - xcb_screen_t* screen = iterator.data; - ffdsAppendDisplay(result, - (uint32_t) screen->width_in_pixels, - (uint32_t) screen->height_in_pixels, - 0, - (uint32_t) screen->width_in_pixels, - (uint32_t) screen->height_in_pixels, - 0, - NULL, - FF_DISPLAY_TYPE_UNKNOWN, - false, - 0, - (uint32_t) screen->width_in_millimeters, - (uint32_t) screen->height_in_millimeters, - "xcb" - ); - ffxcb_screen_next(&iterator); - } - - ffxcb_disconnect(connection); - - //If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland. - if(result->wmProtocolName.length == 0) - ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); - - return NULL; -} - -#else - -const char* ffdsConnectXcb(FFDisplayServerResult* result) -{ - //Do nothing. There are other implementations coming - FF_UNUSED(result) - return "Fastfetch was compiled without XCB support"; -} - -#endif - -#ifdef FF_HAVE_XCB_RANDR -#include "util/edidHelper.h" -#include - typedef struct XcbRandrData { FF_LIBRARY_SYMBOL(xcb_randr_get_screen_resources_current) diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 00ef3ce7ce..ef190c84ab 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -1,9 +1,13 @@ #include "displayserver_linux.h" -#ifdef FF_HAVE_X11 +#ifdef FF_HAVE_XRANDR + #include "common/library.h" #include "common/parsing.h" +#include "util/edidHelper.h" #include "util/stringUtils.h" + +#include #include typedef struct X11PropertyData @@ -58,66 +62,6 @@ static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDispl data->ffXFree(wmWindow); } -const char* ffdsConnectXlib(FFDisplayServerResult* result) -{ - FF_LIBRARY_LOAD(x11, "dlopen libX11 failed", "libX11" FF_LIBRARY_EXTENSION, 7, "libX11-xcb" FF_LIBRARY_EXTENSION, 2) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(x11, XOpenDisplay) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(x11, XCloseDisplay) - - X11PropertyData propertyData; - bool propertyDataInitialized = x11InitPropertyData(x11, &propertyData); - - Display* display = ffXOpenDisplay(x11); - if(display == NULL) - return "XOpenDisplay failed"; - - if(propertyDataInitialized && ScreenCount(display) > 0) - x11DetectWMFromEWMH(&propertyData, display, result); - - for(int i = 0; i < ScreenCount(display); i++) - { - Screen* screen = ScreenOfDisplay(display, i); - ffdsAppendDisplay(result, - (uint32_t) WidthOfScreen(screen), - (uint32_t) HeightOfScreen(screen), - 0, - (uint32_t) WidthOfScreen(screen), - (uint32_t) HeightOfScreen(screen), - 0, - NULL, - FF_DISPLAY_TYPE_UNKNOWN, - false, - 0, - (uint32_t) WidthMMOfScreen(screen), - (uint32_t) HeightMMOfScreen(screen), - "xlib" - ); - } - - ffXCloseDisplay(display); - - //If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland. - if(result->wmProtocolName.length == 0) - ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); - - return NULL; -} - -#else - -const char* ffdsConnectXlib(FFDisplayServerResult* result) -{ - //Do nothing. WM / DE detection will use environment vars to detect as much as possible. - FF_UNUSED(result); - return "Fastfetch was compiled without libX11 support"; -} - -#endif //FF_HAVE_X11 - -#ifdef FF_HAVE_XRANDR -#include "util/edidHelper.h" -#include - typedef struct XrandrData { FF_LIBRARY_SYMBOL(XInternAtom) From fa9290088d4d34b55f9520bc296c8852aec6ebe7 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 20 Nov 2024 14:33:47 +0800 Subject: [PATCH 07/48] Display (Linux): detect preferred resolution and refresh rate --- src/detection/displayserver/displayserver.c | 6 ++ src/detection/displayserver/displayserver.h | 20 ++++--- src/detection/displayserver/linux/drm.c | 37 +++++++----- .../linux/wayland/global-output.c | 25 +++++--- .../displayserver/linux/wayland/kde-output.c | 43 +++++++++----- .../displayserver/linux/wayland/wayland.h | 5 +- .../displayserver/linux/wayland/zwlr-output.c | 57 +++++++++++++------ src/detection/displayserver/linux/xcb.c | 51 +++++++++-------- src/detection/displayserver/linux/xlib.c | 35 +++++++----- src/modules/display/display.c | 7 ++- 10 files changed, 186 insertions(+), 100 deletions(-) diff --git a/src/detection/displayserver/displayserver.c b/src/detection/displayserver/displayserver.c index c2ba3e593a..6ae9efbc48 100644 --- a/src/detection/displayserver/displayserver.c +++ b/src/detection/displayserver/displayserver.c @@ -7,6 +7,9 @@ FFDisplayResult* ffdsAppendDisplay( double refreshRate, uint32_t scaledWidth, uint32_t scaledHeight, + uint32_t preferredWidth, + uint32_t preferredHeight, + double preferredRefreshRate, uint32_t rotation, FFstrbuf* name, FFDisplayType type, @@ -25,6 +28,9 @@ FFDisplayResult* ffdsAppendDisplay( display->refreshRate = refreshRate; display->scaledWidth = scaledWidth; display->scaledHeight = scaledHeight; + display->preferredWidth = preferredWidth; + display->preferredHeight = preferredHeight; + display->preferredRefreshRate = preferredRefreshRate; display->rotation = rotation; ffStrbufInitMove(&display->name, name); display->type = type; diff --git a/src/detection/displayserver/displayserver.h b/src/detection/displayserver/displayserver.h index 4de3bdd4d4..dd4fd96513 100644 --- a/src/detection/displayserver/displayserver.h +++ b/src/detection/displayserver/displayserver.h @@ -58,17 +58,20 @@ typedef enum __attribute__((__packed__)) FFDisplayHdrStatus typedef struct FFDisplayResult { - uint32_t width; - uint32_t height; - double refreshRate; - uint32_t scaledWidth; - uint32_t scaledHeight; + uint32_t width; // in px + uint32_t height; // in px + double refreshRate; // in Hz + uint32_t scaledWidth; // in px + uint32_t scaledHeight; // in px + uint32_t preferredWidth; // in px + uint32_t preferredHeight; // in px + double preferredRefreshRate; // in Hz FFstrbuf name; FFDisplayType type; uint32_t rotation; uint64_t id; // platform dependent - uint32_t physicalWidth; - uint32_t physicalHeight; + uint32_t physicalWidth; // in mm + uint32_t physicalHeight; // in mm bool primary; const char* platformApi; uint8_t bitDepth; @@ -97,6 +100,9 @@ FFDisplayResult* ffdsAppendDisplay( double refreshRate, uint32_t scaledWidth, uint32_t scaledHeight, + uint32_t preferredWidth, + uint32_t preferredHeight, + double preferredRefreshRate, uint32_t rotation, FFstrbuf* name, FFDisplayType type, diff --git a/src/detection/displayserver/linux/drm.c b/src/detection/displayserver/linux/drm.c index fb837e4a89..959358a168 100644 --- a/src/detection/displayserver/linux/drm.c +++ b/src/detection/displayserver/linux/drm.c @@ -84,6 +84,8 @@ static const char* drmParseSysfs(FFDisplayServerResult* result) width, height, refreshRate, 0, 0, + 0, 0, + 0, 0, &name, ffdsGetDisplayType(plainName), @@ -298,24 +300,30 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) ffdrmModeFreeEncoder(encoder); } - if (width == 0 || height == 0) + uint32_t preferredWidth = 0, preferredHeight = 0, preferredRefreshRate = 0; + + for (int iMode = 0; iMode < conn->count_modes; ++iMode) { - // NVIDIA DRM driver seems incomplete and conn->encoder_id == 0 - // Assume preferred resolution is used as what we do in drmParseSys - for (int iMode = 0; iMode < conn->count_modes; ++iMode) - { - drmModeModeInfo* mode = &conn->modes[iMode]; + drmModeModeInfo* mode = &conn->modes[iMode]; - if (mode->type & DRM_MODE_TYPE_PREFERRED) - { - width = mode->hdisplay; - height = mode->vdisplay; - refreshRate = mode->vrefresh; - break; - } + if (mode->type & DRM_MODE_TYPE_PREFERRED) + { + preferredWidth = mode->hdisplay; + preferredHeight = mode->vdisplay; + preferredRefreshRate = mode->vrefresh; + break; } } + // NVIDIA DRM driver seems incomplete and conn->encoder_id == 0 + // Assume preferred resolution is used as what we do in drmParseSys + if (width == 0 || height == 0) + { + width = preferredWidth; + height = preferredHeight; + refreshRate = preferredRefreshRate; + } + ffStrbufClear(&name); uint16_t myear = 0, mweak = 0; @@ -382,6 +390,9 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) refreshRate, 0, 0, + preferredWidth, + preferredHeight, + preferredRefreshRate, 0, &name, conn->connector_type == DRM_MODE_CONNECTOR_eDP || conn->connector_type == DRM_MODE_CONNECTOR_LVDS diff --git a/src/detection/displayserver/linux/wayland/global-output.c b/src/detection/displayserver/linux/wayland/global-output.c index ab9fc5c2fd..8b3671d166 100644 --- a/src/detection/displayserver/linux/wayland/global-output.c +++ b/src/detection/displayserver/linux/wayland/global-output.c @@ -6,13 +6,20 @@ 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; + + if (flags & WL_OUTPUT_MODE_CURRENT) + { + display->width = width; + display->height = height; + display->refreshRate = refreshRate; + } + if (flags & WL_OUTPUT_MODE_PREFERRED) + { + display->preferredWidth = width; + display->preferredHeight = height; + display->preferredRefreshRate = refreshRate; + } } static void waylandOutputScaleListener(void* data, FF_MAYBE_UNUSED struct wl_output* output, int32_t scale) @@ -79,9 +86,6 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist WaylandDisplay display = { .parent = wldata, - .width = 0, - .height = 0, - .refreshRate = 0, .scale = 1, .transform = WL_OUTPUT_TRANSFORM_NORMAL, .type = FF_DISPLAY_TYPE_UNKNOWN, @@ -118,6 +122,9 @@ void ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* regist display.refreshRate / 1000.0, (uint32_t) (display.width / display.scale), (uint32_t) (display.height / display.scale), + (uint32_t) display.preferredWidth, + (uint32_t) display.preferredHeight, + display.preferredRefreshRate / 1000.0, rotation, display.edidName.length ? &display.edidName diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c index beac7b6355..2b903bc550 100644 --- a/src/detection/displayserver/linux/wayland/kde-output.c +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -11,26 +11,33 @@ typedef struct WaylandKdeMode int32_t width; int32_t height; int32_t refreshRate; + bool preferred; 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) +static void waylandKdeModeSizeListener(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) +static void waylandKdeModeRefreshListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_mode_v2 *_, int32_t rate) { WaylandKdeMode* mode = (WaylandKdeMode*) data; mode->refreshRate = rate; } +static void waylandKdeModePreferredListener(void* data, FF_MAYBE_UNUSED struct kde_output_device_mode_v2 *_) +{ + WaylandKdeMode* mode = (WaylandKdeMode*) data; + mode->preferred = true; +} + static const struct kde_output_device_mode_v2_listener modeListener = { - .size = waylandKdeSizeListener, - .refresh = waylandKdeRefreshListener, - .preferred = (void*) stubListener, + .size = waylandKdeModeSizeListener, + .refresh = waylandKdeModeRefreshListener, + .preferred = waylandKdeModePreferredListener, .removed = (void*) stubListener, }; @@ -40,7 +47,7 @@ static void waylandKdeModeListener(void* data, FF_MAYBE_UNUSED struct kde_output if (!wldata->internal) return; WaylandKdeMode* newMode = ffListAdd((FFlist*) wldata->internal); - newMode->pMode = mode; + *newMode = (WaylandKdeMode) { .pMode = mode }; // Strangely, the listener is called only in this function, but not in `waylandKdeCurrentModeListener` wldata->parent->ffwl_proxy_add_listener((struct wl_proxy *) mode, (void (**)(void)) &modeListener, newMode); @@ -52,18 +59,24 @@ static void waylandKdeCurrentModeListener(void* data, FF_MAYBE_UNUSED struct kde WaylandDisplay* wldata = (WaylandDisplay*) data; if (!wldata->internal) return; - WaylandKdeMode* current = NULL; + int set = 0; FF_LIST_FOR_EACH(WaylandKdeMode, m, *(FFlist*) wldata->internal) { if (m->pMode == mode) { - current = m; - break; + wldata->width = m->width; + wldata->height = m->height; + wldata->refreshRate = m->refreshRate; + if (++set == 2) break; + } + else if (m->preferred) + { + wldata->preferredWidth = m->width; + wldata->preferredHeight = m->height; + wldata->preferredRefreshRate = m->refreshRate; + if (++set == 2) 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) @@ -164,9 +177,6 @@ void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, 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, @@ -191,6 +201,9 @@ void ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, display.refreshRate / 1000.0, (uint32_t) (display.width / display.scale), (uint32_t) (display.height / display.scale), + (uint32_t) display.preferredWidth, + (uint32_t) display.preferredHeight, + display.preferredRefreshRate / 1000.0, rotation, display.edidName.length ? &display.edidName diff --git a/src/detection/displayserver/linux/wayland/wayland.h b/src/detection/displayserver/linux/wayland/wayland.h index c19d881991..ab11d05388 100644 --- a/src/detection/displayserver/linux/wayland/wayland.h +++ b/src/detection/displayserver/linux/wayland/wayland.h @@ -36,9 +36,12 @@ typedef struct WaylandDisplay WaylandData* parent; int32_t width; int32_t height; + int32_t refreshRate; + int32_t preferredWidth; + int32_t preferredHeight; + int32_t preferredRefreshRate; int32_t physicalWidth; int32_t physicalHeight; - int32_t refreshRate; double scale; enum wl_output_transform transform; FFDisplayType type; diff --git a/src/detection/displayserver/linux/wayland/zwlr-output.c b/src/detection/displayserver/linux/wayland/zwlr-output.c index c54818a64a..65825bb622 100644 --- a/src/detection/displayserver/linux/wayland/zwlr-output.c +++ b/src/detection/displayserver/linux/wayland/zwlr-output.c @@ -20,34 +20,43 @@ typedef struct WaylandZwlrMode int32_t width; int32_t height; int32_t refreshRate; + bool preferred; 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) +static void waylandZwlrModeSizeListener(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) +static void waylandZwlrModeRefreshListener(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 waylandZwlrModePreferredListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_mode_v1 *zwlr_output_mode_v1) +{ + WaylandZwlrMode* mode = (WaylandZwlrMode*) data; + mode->preferred = true; +} + static const struct zwlr_output_mode_v1_listener modeListener = { - .size = waylandZwlrSizeListener, - .refresh = waylandZwlrRefreshListener, - .preferred = (void*) stubListener, + .size = waylandZwlrModeSizeListener, + .refresh = waylandZwlrModeRefreshListener, + .preferred = waylandZwlrModePreferredListener, .finished = (void*) stubListener, }; 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; + if (!wldata->internal) return; + WaylandZwlrMode* newMode = ffListAdd((FFlist*) wldata->internal); - newMode->pMode = mode; + *newMode = (WaylandZwlrMode) { .pMode = mode }; // Strangely, the listener is called only in this function, but not in `waylandZwlrCurrentModeListener` wldata->parent->ffwl_proxy_add_listener((struct wl_proxy *) mode, (void (**)(void)) &modeListener, newMode); @@ -57,18 +66,26 @@ static void waylandZwlrCurrentModeListener(void* data, FF_MAYBE_UNUSED struct zw { // waylandZwlrModeListener is always run before this WaylandDisplay* wldata = (WaylandDisplay*) data; - WaylandZwlrMode* current = NULL; + if (!wldata->internal) return; + + int set = 0; FF_LIST_FOR_EACH(WaylandZwlrMode, m, *(FFlist*) wldata->internal) { if (m->pMode == mode) { - current = m; - break; + wldata->width = m->width; + wldata->height = m->height; + wldata->refreshRate = m->refreshRate; + if (++set == 2) break; + } + else if (m->preferred) + { + wldata->preferredWidth = m->width; + wldata->preferredHeight = m->height; + wldata->preferredRefreshRate = m->refreshRate; + if (++set == 2) break; } } - wldata->width = current->width; - wldata->height = current->height; - wldata->refreshRate = current->refreshRate; } static void waylandZwlrPhysicalSizeListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, int32_t width, int32_t height) @@ -78,12 +95,18 @@ static void waylandZwlrPhysicalSizeListener(void* data, FF_MAYBE_UNUSED struct z wldata->physicalHeight = height; } +static void waylandZwlrEnabledListener(void* data, FF_MAYBE_UNUSED struct zwlr_output_head_v1 *zwlr_output_head_v1, bool enabled) +{ + WaylandDisplay* wldata = (WaylandDisplay*) data; + if (!enabled) wldata->internal = NULL; +} + static const struct zwlr_output_head_v1_listener headListener = { .name = (void*) ffWaylandOutputNameListener, .description = (void*) ffWaylandOutputDescriptionListener, .physical_size = waylandZwlrPhysicalSizeListener, .mode = waylandZwlrModeListener, - .enabled = (void*) stubListener, + .enabled = (void*) waylandZwlrEnabledListener, .current_mode = waylandZwlrCurrentModeListener, .position = (void*) stubListener, .transform = waylandZwlrTransformListener, @@ -102,9 +125,6 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output 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, @@ -117,7 +137,7 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output 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) + if(display.width <= 0 || display.height <= 0 || !display.internal) return; uint32_t rotation = ffWaylandHandleRotation(&display); @@ -128,6 +148,9 @@ static void waylandHandleZwlrHead(void *data, FF_MAYBE_UNUSED struct zwlr_output display.refreshRate / 1000.0, (uint32_t) (display.width / display.scale + 0.5), (uint32_t) (display.height / display.scale + 0.5), + (uint32_t) display.preferredWidth, + (uint32_t) display.preferredHeight, + display.preferredRefreshRate / 1000.0, rotation, display.edidName.length ? &display.edidName diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 47508a2428..b3eab2dece 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -119,28 +119,6 @@ typedef struct XcbRandrData xcb_randr_get_screen_resources_current_reply_t* screenResources; } XcbRandrData; -static double xcbRandrHandleMode(XcbRandrData* data, xcb_randr_mode_t mode) -{ - //We do the check here, because we want the best fallback display if this call failed - if(data->screenResources == NULL) - return 0; - - xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(data->screenResources); - - while(modesIterator.rem > 0) - { - if(modesIterator.data->id == mode) - { - xcb_randr_mode_info_t* modeInfo = modesIterator.data; - return (double) modeInfo->dot_clock / (double) (modeInfo->htotal * modeInfo->vtotal); - } - - data->ffxcb_randr_mode_info_next(&modesIterator); - } - - return 0; -} - static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrbuf* name, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength) { xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME); @@ -165,13 +143,38 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb break; } + xcb_randr_mode_info_t* currentMode = NULL; + xcb_randr_mode_info_t* preferredMode = NULL; + + if(data->screenResources) + { + xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(data->screenResources); + + if (output->num_preferred > 0) + preferredMode = modesIterator.data; + + while (modesIterator.rem > 0) + { + if (modesIterator.data->id == crtcInfoReply->mode) + { + currentMode = modesIterator.data; + break; + } + + data->ffxcb_randr_mode_info_next(&modesIterator); + } + } + FFDisplayResult* item = ffdsAppendDisplay( data->result, (uint32_t) crtcInfoReply->width, (uint32_t) crtcInfoReply->height, - xcbRandrHandleMode(data, crtcInfoReply->mode), + currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0, (uint32_t) crtcInfoReply->width, (uint32_t) crtcInfoReply->height, + preferredMode ? (uint32_t) preferredMode->width : 0, + preferredMode ? (uint32_t) preferredMode->height : 0, + preferredMode ? (double) preferredMode->dot_clock / (double) ((uint32_t) preferredMode->htotal * preferredMode->vtotal) : 0, rotation, name, displayType, @@ -261,6 +264,7 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* 0, (uint32_t) monitor->width, (uint32_t) monitor->height, + 0, 0, 0, 0, &name, displayType, @@ -316,6 +320,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen) 0, (uint32_t) screen->width_in_pixels, (uint32_t) screen->height_in_pixels, + 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index ef190c84ab..d2a1d1f245 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -85,19 +85,6 @@ typedef struct XrandrData XRRScreenResources* screenResources; } XrandrData; -static double xrandrHandleMode(XrandrData* data, RRMode mode) -{ - for(int i = 0; i < data->screenResources->nmode; i++) - { - if(data->screenResources->modes[i].id == mode) - { - XRRModeInfo* modeInfo = &data->screenResources->modes[i]; - return (double) modeInfo->dotClock / (double) (modeInfo->hTotal * modeInfo->vTotal); - } - } - return 0; -} - static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength) { //We do the check here, because we want the best fallback display if this call failed @@ -125,13 +112,31 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* break; } + XRRModeInfo* currentMode = NULL; + if (data->screenResources) + { + for(int i = 0; i < data->screenResources->nmode; i++) + { + if(data->screenResources->modes[i].id == crtcInfo->mode) + { + currentMode = &data->screenResources->modes[i]; + break; + } + } + } + + XRRModeInfo* preferredMode = data->screenResources && output->npreferred > 0 ? &data->screenResources->modes[0] : NULL; + FFDisplayResult* item = ffdsAppendDisplay( data->result, (uint32_t) crtcInfo->width, (uint32_t) crtcInfo->height, - xrandrHandleMode(data, crtcInfo->mode), + currentMode ? (double) currentMode->dotClock / (double) ((uint32_t) currentMode->hTotal * currentMode->vTotal) : 0, (uint32_t) crtcInfo->width, (uint32_t) crtcInfo->height, + preferredMode ? (uint32_t) preferredMode->width : 0, + preferredMode ? (uint32_t) preferredMode->height : 0, + preferredMode ? (double) preferredMode->dotClock / (double) ((uint32_t) preferredMode->hTotal * preferredMode->vTotal) : 0, rotation, name, displayType, @@ -208,6 +213,7 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo) 0, (uint32_t) monitorInfo->width, (uint32_t) monitorInfo->height, + 0, 0, 0, 0, &name, displayType, @@ -259,6 +265,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen) 0, (uint32_t) WidthOfScreen(screen), (uint32_t) HeightOfScreen(screen), + 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, diff --git a/src/modules/display/display.c b/src/modules/display/display.c index 6c720f31bd..ea81030b6c 100644 --- a/src/modules/display/display.c +++ b/src/modules/display/display.c @@ -350,16 +350,21 @@ void ffGenerateDisplayJsonResult(FF_MAYBE_UNUSED FFDisplayOptions* options, yyjs yyjson_mut_val* output = yyjson_mut_obj_add_obj(doc, obj, "output"); yyjson_mut_obj_add_uint(doc, output, "width", item->width); yyjson_mut_obj_add_uint(doc, output, "height", item->height); + yyjson_mut_obj_add_real(doc, output, "refreshRate", item->refreshRate); yyjson_mut_val* scaled = yyjson_mut_obj_add_obj(doc, obj, "scaled"); yyjson_mut_obj_add_uint(doc, scaled, "width", item->scaledWidth); yyjson_mut_obj_add_uint(doc, scaled, "height", item->scaledHeight); + yyjson_mut_val* preferred = yyjson_mut_obj_add_obj(doc, obj, "preferred"); + yyjson_mut_obj_add_uint(doc, preferred, "width", item->preferredWidth); + yyjson_mut_obj_add_uint(doc, preferred, "height", item->preferredHeight); + yyjson_mut_obj_add_real(doc, preferred, "refreshRate", item->preferredRefreshRate); + yyjson_mut_val* physical = yyjson_mut_obj_add_obj(doc, obj, "physical"); yyjson_mut_obj_add_uint(doc, physical, "width", item->physicalWidth); yyjson_mut_obj_add_uint(doc, physical, "height", item->physicalHeight); - yyjson_mut_obj_add_real(doc, obj, "refreshRate", item->refreshRate); yyjson_mut_obj_add_uint(doc, obj, "rotation", item->rotation); yyjson_mut_obj_add_uint(doc, obj, "bitDepth", item->bitDepth); if (item->hdrStatus == FF_DISPLAY_HDR_STATUS_UNKNOWN) From 21a35769a7fea0407c87031d892b3fbbbb4ee1e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 15:53:12 +0800 Subject: [PATCH 08/48] Display (macOS): detect maximum resolution & refresh rate --- .../displayserver/displayserver_apple.c | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/detection/displayserver/displayserver_apple.c b/src/detection/displayserver/displayserver_apple.c index 520750110f..e40d251163 100644 --- a/src/detection/displayserver/displayserver_apple.c +++ b/src/detection/displayserver/displayserver_apple.c @@ -60,7 +60,11 @@ static void detectDisplays(FFDisplayServerResult* ds) displayInfo = IODisplayCreateInfoDictionary(servicePort, kIODisplayOnlyPreferredName); } #endif + uint32_t physicalWidth = 0, physicalHeight = 0; + uint32_t preferredWidth = 0, preferredHeight = 0; + double preferredRefreshRate = 0; + if(displayInfo) { CFDictionaryRef productNames; @@ -76,6 +80,32 @@ static void detectDisplays(FFDisplayServerResult* ds) if (edidLength >= 128) ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); } + + if (!physicalWidth || !physicalHeight) + { + if (ffCfDictGetInt(displayInfo, CFSTR(kDisplayHorizontalImageSize), (int*) &physicalWidth) == NULL) + ffCfDictGetInt(displayInfo, CFSTR(kDisplayVerticalImageSize), (int*) &physicalHeight); + } + + ffCfDictGetInt(displayInfo, CFSTR("kCGDisplayPixelWidth"), (int*) &preferredWidth); + ffCfDictGetInt(displayInfo, CFSTR("kCGDisplayPixelHeight"), (int*) &preferredHeight); + if (preferredWidth && preferredHeight) + { + FF_CFTYPE_AUTO_RELEASE CFArrayRef allModes = CGDisplayCopyAllDisplayModes(screen, NULL); + if (allModes) + { + for (CFIndex i = 0, count = CFArrayGetCount(allModes); i < count; i++) + { + CGDisplayModeRef modeInfo = (CGDisplayModeRef) CFArrayGetValueAtIndex(allModes, i); + if (CGDisplayModeGetPixelWidth(modeInfo) == preferredWidth && CGDisplayModeGetPixelHeight(modeInfo) == preferredHeight) + { + double rr = CGDisplayModeGetRefreshRate(modeInfo); + if (rr > preferredRefreshRate) preferredRefreshRate = rr; + break; + } + } + } + } } if (!physicalWidth || !physicalHeight) @@ -91,6 +121,9 @@ static void detectDisplays(FFDisplayServerResult* ds) refreshRate, (uint32_t)CGDisplayModeGetWidth(mode), (uint32_t)CGDisplayModeGetHeight(mode), + preferredWidth, + preferredHeight, + preferredRefreshRate, (uint32_t)CGDisplayRotation(screen), &buffer, CGDisplayIsBuiltin(screen) ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL, From 4cca63a2997b16ed6d489e7955fb75717a13a851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 16:10:23 +0800 Subject: [PATCH 09/48] Display (Windows): detect preferred resolution & refresh rate --- .../displayserver/displayserver_windows.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index d0825dbc68..a25764ca48 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -149,12 +149,30 @@ static void detectDisplays(FFDisplayServerResult* ds) default: rotation = 0; break; } + DISPLAYCONFIG_TARGET_PREFERRED_MODE preferredMode = { + .header = { + .type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE, + .size = sizeof(preferredMode), + .adapterId = path->targetInfo.adapterId, + .id = path->targetInfo.id, + } + }; + double preferredRefreshRate = 0; + if (DisplayConfigGetDeviceInfo(&preferredMode.header) == ERROR_SUCCESS) + { + DISPLAYCONFIG_RATIONAL freq = preferredMode.targetMode.targetVideoSignalInfo.vSyncFreq; + preferredRefreshRate = freq.Numerator / (double) freq.Denominator; + } + FFDisplayResult* display = ffdsAppendDisplay(ds, width, height, path->targetInfo.refreshRate.Numerator / (double) path->targetInfo.refreshRate.Denominator, (uint32_t) (monitorInfo->info.rcMonitor.right - monitorInfo->info.rcMonitor.left), (uint32_t) (monitorInfo->info.rcMonitor.bottom - monitorInfo->info.rcMonitor.top), + preferredMode.width, + preferredMode.height, + preferredRefreshRate, rotation, &name, path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER ? FF_DISPLAY_TYPE_UNKNOWN : From 7948e627b037d1f810da5c0b3fa20561a8ed0447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 16:13:38 +0800 Subject: [PATCH 10/48] Display (Android): fix build --- src/detection/displayserver/displayserver_android.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/detection/displayserver/displayserver_android.c b/src/detection/displayserver/displayserver_android.c index 88e5b23d33..d10f394e03 100644 --- a/src/detection/displayserver/displayserver_android.c +++ b/src/detection/displayserver/displayserver_android.c @@ -61,6 +61,9 @@ static void detectWithDumpsys(FFDisplayServerResult* ds) 0, 0, 0, + 0, + 0, + 0, &name, FF_DISPLAY_TYPE_UNKNOWN, false, @@ -97,6 +100,9 @@ static bool detectWithGetprop(FFDisplayServerResult* ds) (uint32_t) (height / scaleFactor + .5), 0, 0, + 0, + 0, + NULL, FF_DISPLAY_TYPE_BUILTIN, false, 0, From 925c3471c2f0b7ef21c71d17fdebb5b14e7bd3b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 16:18:23 +0800 Subject: [PATCH 11/48] Display: add scale factor in custom format --- src/modules/display/display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/modules/display/display.c b/src/modules/display/display.c index ea81030b6c..07542d2eed 100644 --- a/src/modules/display/display.c +++ b/src/modules/display/display.c @@ -6,7 +6,7 @@ #include -#define FF_DISPLAY_NUM_FORMAT_ARGS 20 +#define FF_DISPLAY_NUM_FORMAT_ARGS 21 static int sortByNameAsc(FFDisplayResult* a, FFDisplayResult* b) { @@ -173,6 +173,8 @@ void ffPrintDisplay(FFDisplayOptions* options) else buf[0] = '\0'; + double scaleFactor = (double) result->width / (double) result->scaledWidth; + FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_DISPLAY_NUM_FORMAT_ARGS, ((FFformatarg[]) { FF_FORMAT_ARG(result->width, "width"), FF_FORMAT_ARG(result->height, "height"), @@ -194,6 +196,7 @@ void ffPrintDisplay(FFDisplayOptions* options) FF_FORMAT_ARG(buf, "serial"), FF_FORMAT_ARG(result->platformApi, "platform-api"), FF_FORMAT_ARG(hdrCompatible, "hdr-compatible"), + FF_FORMAT_ARG(scaleFactor, "scale-factor"), })); } } @@ -441,6 +444,7 @@ void ffPrintDisplayHelpFormat(void) "Serial number - serial", "The platform API used when detecting the display - platform-api", "True if the display is HDR compatible - hdr-compatible", + "HiDPI scale factor - scale-factor", })); } From cee880cb83d5446c2277486fce73e3b84e4c4a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 16:29:36 +0800 Subject: [PATCH 12/48] Display: print preferred resolution & refresh rate in custom format Fix #1406 --- src/modules/display/display.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/modules/display/display.c b/src/modules/display/display.c index 07542d2eed..3b009ab239 100644 --- a/src/modules/display/display.c +++ b/src/modules/display/display.c @@ -6,7 +6,7 @@ #include -#define FF_DISPLAY_NUM_FORMAT_ARGS 21 +#define FF_DISPLAY_NUM_FORMAT_ARGS 24 static int sortByNameAsc(FFDisplayResult* a, FFDisplayResult* b) { @@ -164,6 +164,17 @@ void ffPrintDisplay(FFDisplayOptions* options) else refreshRate[0] = 0; + char preferredRefreshRate[16]; + if(result->preferredRefreshRate > 0) + { + if(options->preciseRefreshRate) + snprintf(preferredRefreshRate, ARRAY_SIZE(preferredRefreshRate), "%g", ((int) (result->preferredRefreshRate * 1000 + 0.5)) / 1000.0); + else + snprintf(preferredRefreshRate, ARRAY_SIZE(preferredRefreshRate), "%i", (uint32_t) (result->preferredRefreshRate + 0.5)); + } + else + preferredRefreshRate[0] = 0; + char buf[32]; if (result->serial) { @@ -197,6 +208,9 @@ void ffPrintDisplay(FFDisplayOptions* options) FF_FORMAT_ARG(result->platformApi, "platform-api"), FF_FORMAT_ARG(hdrCompatible, "hdr-compatible"), FF_FORMAT_ARG(scaleFactor, "scale-factor"), + FF_FORMAT_ARG(result->preferredWidth, "preferred-width"), + FF_FORMAT_ARG(result->preferredHeight, "preferred-height"), + FF_FORMAT_ARG(preferredRefreshRate, "preferred-refresh-rate"), })); } } @@ -424,9 +438,9 @@ void ffGenerateDisplayJsonResult(FF_MAYBE_UNUSED FFDisplayOptions* options, yyjs void ffPrintDisplayHelpFormat(void) { FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_DISPLAY_MODULE_NAME, "{1}x{2} @ {3}Hz (as {4}x{5}) [{7}]", FF_DISPLAY_NUM_FORMAT_ARGS, ((const char* []) { - "Screen width (in pixels) - width", - "Screen height (in pixels) - height", - "Screen refresh rate (in Hz) - refresh-rate", + "Screen configured width (in pixels) - width", + "Screen configured height (in pixels) - height", + "Screen configured refresh rate (in Hz) - refresh-rate", "Screen scaled width (in pixels) - scaled-width", "Screen scaled height (in pixels) - scaled-height", "Screen name - name", @@ -445,6 +459,9 @@ void ffPrintDisplayHelpFormat(void) "The platform API used when detecting the display - platform-api", "True if the display is HDR compatible - hdr-compatible", "HiDPI scale factor - scale-factor", + "Screen preferred width (in pixels) - preferred-width", + "Screen preferred height (in pixels) - preferred-height", + "Screen preferred refresh rate (in Hz) - preferred-refresh-rate", })); } From 8b62ad72f76b08f61aba80c600100ad1f64a782b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 16:32:29 +0800 Subject: [PATCH 13/48] Display (FreeBSD): fix build --- src/detection/displayserver/linux/displayserver_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/displayserver/linux/displayserver_linux.c b/src/detection/displayserver/linux/displayserver_linux.c index 84ea36ad66..63b2c83152 100644 --- a/src/detection/displayserver/linux/displayserver_linux.c +++ b/src/detection/displayserver/linux/displayserver_linux.c @@ -79,7 +79,7 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) if (ffSettingsGetFreeBSDKenv("screen.height", &buf)) { uint32_t height = (uint32_t) ffStrbufToUInt(&buf, 0); - ffdsAppendDisplay(ds, width, height, 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, false, 0, 0, 0, "kenv"); + ffdsAppendDisplay(ds, width, height, 0, 0, 0, 0, 0, 0, 0, NULL, FF_DISPLAY_TYPE_UNKNOWN, false, 0, 0, 0, "kenv"); } } } From a567268ca10f8075c88c6850c442c08fbd9d59b6 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Wed, 20 Nov 2024 21:34:17 +0800 Subject: [PATCH 14/48] Display (Linux): fix preferred resolution detection for wayland --- src/detection/displayserver/linux/wayland/kde-output.c | 2 +- src/detection/displayserver/linux/wayland/zwlr-output.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c index 2b903bc550..6644880e09 100644 --- a/src/detection/displayserver/linux/wayland/kde-output.c +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -69,7 +69,7 @@ static void waylandKdeCurrentModeListener(void* data, FF_MAYBE_UNUSED struct kde wldata->refreshRate = m->refreshRate; if (++set == 2) break; } - else if (m->preferred) + if (m->preferred) { wldata->preferredWidth = m->width; wldata->preferredHeight = m->height; diff --git a/src/detection/displayserver/linux/wayland/zwlr-output.c b/src/detection/displayserver/linux/wayland/zwlr-output.c index 65825bb622..a19ec9fb6d 100644 --- a/src/detection/displayserver/linux/wayland/zwlr-output.c +++ b/src/detection/displayserver/linux/wayland/zwlr-output.c @@ -78,7 +78,7 @@ static void waylandZwlrCurrentModeListener(void* data, FF_MAYBE_UNUSED struct zw wldata->refreshRate = m->refreshRate; if (++set == 2) break; } - else if (m->preferred) + if (m->preferred) { wldata->preferredWidth = m->width; wldata->preferredHeight = m->height; From 71b073e1bf987340dcf2cb13eb2537297ee9cb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 20 Nov 2024 22:13:10 +0800 Subject: [PATCH 15/48] CMake: fix possible linking errors in `BINARY_LINK_TYPE=dynamic` mode --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c6eed1c42..d6fa6c3aad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1220,6 +1220,9 @@ endif() if(NOT BINARY_LINK_TYPE STREQUAL "dlopen") message(STATUS "Enabling custom link type: ${BINARY_LINK_TYPE}") target_compile_definitions(libfastfetch PRIVATE FF_DISABLE_DLOPEN=1) + if(NOT WIN32) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--copy-dt-needed-entries") + endif() endif() function(ff_lib_enable VARNAME PKGCONFIG_NAMES CMAKE_NAME) From 9a1d18556d5c6e3640984a35f35b08aab7444f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 21 Nov 2024 15:29:14 +0800 Subject: [PATCH 16/48] Display: don't report screen size when display is mirrored Fix #1406 --- src/detection/displayserver/displayserver_apple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/displayserver/displayserver_apple.c b/src/detection/displayserver/displayserver_apple.c index e40d251163..8f5ea3e3c5 100644 --- a/src/detection/displayserver/displayserver_apple.c +++ b/src/detection/displayserver/displayserver_apple.c @@ -108,7 +108,7 @@ static void detectDisplays(FFDisplayServerResult* ds) } } - if (!physicalWidth || !physicalHeight) + if ((!physicalWidth || !physicalHeight) && CGDisplayPrimaryDisplay(screen) == screen) // #1406 { CGSize size = CGDisplayScreenSize(screen); physicalWidth = (uint32_t) (size.width + 0.5); From d48c76b597dcf0c93d2695a01e52c9e2ea439b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 21 Nov 2024 16:08:40 +0800 Subject: [PATCH 17/48] Wifi: detect channel and frequency --- src/detection/wifi/wifi.h | 2 ++ src/detection/wifi/wifi_android.c | 2 ++ src/detection/wifi/wifi_apple.m | 11 +++++++++ src/detection/wifi/wifi_bsd.c | 2 ++ src/detection/wifi/wifi_linux.c | 2 ++ src/detection/wifi/wifi_windows.c | 40 +++++++++++++++++++++++++++---- src/modules/wifi/wifi.c | 2 ++ 7 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/detection/wifi/wifi.h b/src/detection/wifi/wifi.h index 10b4ffdbc9..74d59cd6d0 100644 --- a/src/detection/wifi/wifi.h +++ b/src/detection/wifi/wifi.h @@ -18,6 +18,8 @@ struct FFWifiConnection double signalQuality; // Percentage double rxRate; double txRate; + uint16_t channel; + uint16_t frequency; // MHz }; typedef struct FFWifiResult diff --git a/src/detection/wifi/wifi_android.c b/src/detection/wifi/wifi_android.c index a149892422..142b9cc2ec 100644 --- a/src/detection/wifi/wifi_android.c +++ b/src/detection/wifi/wifi_android.c @@ -43,6 +43,8 @@ const char* ffDetectWifi(FFlist* result) item->conn.signalQuality = 0.0/0.0; item->conn.rxRate = 0.0/0.0; item->conn.txRate = 0.0/0.0; + item->conn.channel = 0; + item->conn.frequency = 0; ffStrbufAppendS(&item->inf.status, yyjson_get_str(yyjson_obj_get(root, "supplicant_state"))); if(!item->inf.status.length) diff --git a/src/detection/wifi/wifi_apple.m b/src/detection/wifi/wifi_apple.m index 17cebcdfb9..f8f66cb9ec 100644 --- a/src/detection/wifi/wifi_apple.m +++ b/src/detection/wifi/wifi_apple.m @@ -80,6 +80,8 @@ @interface CWInterface() item->conn.signalQuality = 0.0/0.0; item->conn.rxRate = 0.0/0.0; item->conn.txRate = 0.0/0.0; + item->conn.channel = 0; + item->conn.frequency = 0; ffStrbufAppendS(&item->inf.description, inf.interfaceName.UTF8String); ffStrbufSetStatic(&item->inf.status, inf.powerOn ? "Power On" : "Power Off"); @@ -289,6 +291,15 @@ @interface CWInterface() ffStrbufAppendF(&item->conn.security, "Unknown (%ld)", inf.security); break; } + + item->conn.channel = (uint16_t) inf.wlanChannel.channelNumber; + switch (inf.wlanChannel.channelBand) + { + case kCWChannelBand2GHz: item->conn.frequency = 2400; break; + case kCWChannelBand5GHz: item->conn.frequency = 5000; break; + case kCWChannelBand6GHz: item->conn.frequency = 6000; break; + default: item->conn.frequency = 0; break; + } } return NULL; } diff --git a/src/detection/wifi/wifi_bsd.c b/src/detection/wifi/wifi_bsd.c index 1f47cf9ef3..875bce1adc 100644 --- a/src/detection/wifi/wifi_bsd.c +++ b/src/detection/wifi/wifi_bsd.c @@ -34,6 +34,8 @@ const char* ffDetectWifi(FFlist* result) item->conn.signalQuality = 0.0/0.0; item->conn.rxRate = 0.0/0.0; item->conn.txRate = 0.0/0.0; + item->conn.channel = 0; + item->conn.frequency = 0; ffParsePropLines(ifconfig.chars, "ssid ", &item->conn.ssid); if (item->conn.ssid.length) diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index b1fcd6e899..7ab9edf0b4 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -339,6 +339,8 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED FFlist* result) item->conn.signalQuality = 0.0/0.0; item->conn.rxRate = 0.0/0.0; item->conn.txRate = 0.0/0.0; + item->conn.channel = 0; + item->conn.frequency = 0; ffStrbufSetF(&buffer, "/sys/class/net/%s/operstate", i->if_name); if (!ffAppendFileBuffer(buffer.chars, &item->inf.status)) diff --git a/src/detection/wifi/wifi_windows.c b/src/detection/wifi/wifi_windows.c index 18262f2810..ac434e8d96 100644 --- a/src/detection/wifi/wifi_windows.c +++ b/src/detection/wifi/wifi_windows.c @@ -49,6 +49,7 @@ const char* ffDetectWifi(FFlist* result) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wlanapi, WlanQueryInterface) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wlanapi, WlanFreeMemory) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wlanapi, WlanCloseHandle) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(wlanapi, WlanGetNetworkBssList) DWORD curVersion; HANDLE hClient = NULL; @@ -82,21 +83,23 @@ const char* ffDetectWifi(FFlist* result) item->conn.signalQuality = 0.0/0.0; item->conn.rxRate = 0.0/0.0; item->conn.txRate = 0.0/0.0; + item->conn.channel = 0; + item->conn.frequency = 0; convertIfStateToString(ifInfo->isState, &item->inf.status); if(ifInfo->isState != wlan_interface_state_connected) continue; - DWORD connectInfoSize = sizeof(WLAN_CONNECTION_ATTRIBUTES); - WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_invalid; WLAN_CONNECTION_ATTRIBUTES* connInfo = NULL; + DWORD bufSize = sizeof(*connInfo); + WLAN_OPCODE_VALUE_TYPE opCode = wlan_opcode_value_type_query_only; if(ffWlanQueryInterface(hClient, &ifInfo->InterfaceGuid, wlan_intf_opcode_current_connection, NULL, - &connectInfoSize, + &bufSize, (PVOID*)&connInfo, &opCode) != ERROR_SUCCESS ) continue; @@ -107,8 +110,8 @@ const char* ffDetectWifi(FFlist* result) (const char *)connInfo->wlanAssociationAttributes.dot11Ssid.ucSSID); for (size_t i = 0; i < sizeof(connInfo->wlanAssociationAttributes.dot11Bssid); i++) - ffStrbufAppendF(&item->conn.bssid, "%.2X-", connInfo->wlanAssociationAttributes.dot11Bssid[i]); - ffStrbufTrimRight(&item->conn.bssid, '-'); + ffStrbufAppendF(&item->conn.bssid, "%.2X:", connInfo->wlanAssociationAttributes.dot11Bssid[i]); + ffStrbufTrimRight(&item->conn.bssid, ':'); switch (connInfo->wlanAssociationAttributes.dot11PhyType) { @@ -201,7 +204,34 @@ const char* ffDetectWifi(FFlist* result) else ffStrbufAppendS(&item->conn.security, "Insecure"); + WLAN_BSS_LIST* bssList = NULL; + if (ffWlanGetNetworkBssList(hClient, + &ifInfo->InterfaceGuid, + &connInfo->wlanAssociationAttributes.dot11Ssid, + connInfo->wlanAssociationAttributes.dot11BssType, + connInfo->wlanSecurityAttributes.bSecurityEnabled, + NULL, + &bssList) == ERROR_SUCCESS && bssList->dwNumberOfItems > 0 + ) { + item->conn.frequency = (uint16_t) (bssList->wlanBssEntries[0].ulChCenterFrequency / 1000); + ffWlanFreeMemory(bssList); + } + ffWlanFreeMemory(connInfo); + + ULONG* channelNumber = 0; + bufSize = sizeof(*channelNumber); + if(ffWlanQueryInterface(hClient, + &ifInfo->InterfaceGuid, + wlan_intf_opcode_channel_number, + NULL, + &bufSize, + (PVOID*)&channelNumber, + &opCode) == ERROR_SUCCESS + ) { + item->conn.channel = (uint16_t) *channelNumber; + ffWlanFreeMemory(channelNumber); + } } exit: diff --git a/src/modules/wifi/wifi.c b/src/modules/wifi/wifi.c index b2d829d42f..21fb5ee1ac 100644 --- a/src/modules/wifi/wifi.c +++ b/src/modules/wifi/wifi.c @@ -181,6 +181,8 @@ void ffGenerateWifiJsonResult(FF_MAYBE_UNUSED FFWifiOptions* options, yyjson_mut yyjson_mut_obj_add_real(doc, conn, "signalQuality", wifi->conn.signalQuality); yyjson_mut_obj_add_real(doc, conn, "rxRate", wifi->conn.rxRate); yyjson_mut_obj_add_real(doc, conn, "txRate", wifi->conn.txRate); + yyjson_mut_obj_add_uint(doc, conn, "channel", wifi->conn.channel); + yyjson_mut_obj_add_uint(doc, conn, "frequency", wifi->conn.frequency); } FF_LIST_FOR_EACH(FFWifiResult, item, result) From 601b9706b5166708ba37eebbac0c8b2a6afcc9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 21 Nov 2024 21:44:05 +0800 Subject: [PATCH 18/48] Display: report ppi to 0 if screen size is not available --- src/modules/display/display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/display/display.c b/src/modules/display/display.c index 3b009ab239..07884d5011 100644 --- a/src/modules/display/display.c +++ b/src/modules/display/display.c @@ -148,7 +148,7 @@ void ffPrintDisplay(FFDisplayOptions* options) } else { - double ppi = sqrt(result->width * result->width + result->height * result->height) / inch; + double ppi = inch == 0 ? 0 : sqrt(result->width * result->width + result->height * result->height) / inch; bool hdrEnabled = result->hdrStatus == FF_DISPLAY_HDR_STATUS_ENABLED; bool hdrCompatible = result->hdrStatus == FF_DISPLAY_HDR_STATUS_SUPPORTED || result->hdrStatus == FF_DISPLAY_HDR_STATUS_ENABLED; uint32_t iInch = (uint32_t) (inch + 0.5), iPpi = (uint32_t) (ppi + 0.5); From 06055cc6c30dfe1cc88269a8d5d6a4ac748c3e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 21 Nov 2024 22:03:25 +0800 Subject: [PATCH 19/48] Wifi (macOS): fix build on old OS version --- src/detection/wifi/wifi_apple.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/wifi/wifi_apple.m b/src/detection/wifi/wifi_apple.m index f8f66cb9ec..fb25961cee 100644 --- a/src/detection/wifi/wifi_apple.m +++ b/src/detection/wifi/wifi_apple.m @@ -297,7 +297,7 @@ @interface CWInterface() { case kCWChannelBand2GHz: item->conn.frequency = 2400; break; case kCWChannelBand5GHz: item->conn.frequency = 5000; break; - case kCWChannelBand6GHz: item->conn.frequency = 6000; break; + case 3 /*kCWChannelBand6GHz*/: item->conn.frequency = 6000; break; default: item->conn.frequency = 0; break; } } From 7000317841ffb85a43a1ae75cdb83095a39cb9fd Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 22 Nov 2024 10:31:12 +0800 Subject: [PATCH 20/48] Wifi (Linux): detect frequency & channel number --- src/detection/wifi/wifi_linux.c | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index 7ab9edf0b4..f883da64c0 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -43,6 +43,18 @@ typedef enum { continue; \ } +static uint16_t freq2channel(uint16_t frequency) +{ + // https://github.com/opetryna/win32wifi/blob/master/win32wifi/Win32Wifi.py#L140 + // FIXME: Does it work for 6 GHz? + if (frequency == 2484) + return 14; + else if (frequency < 2484) + return (uint16_t) (frequency - 2407) / 5; + else + return (frequency / 5) - 1000; +} + static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { FFDBusData dbus; @@ -130,6 +142,19 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) item->conn.signalQuality = strengthPercent; } } + else if (ffStrEquals(key, "Frequency")) + { + if (item->conn.frequency == 0) + { + uint32_t frequency; + if (ffDBusGetUint(&dbus, &dictIterator, &frequency)) + { + item->conn.frequency = (uint16_t) frequency; + if (item->conn.channel == 0) + item->conn.channel = freq2channel(item->conn.frequency); + } + } + } else if ((ffStrEquals(key, "Flags") && ffDBusGetUint(&dbus, &dictIterator, &flags)) || (ffStrEquals(key, "WpaFlags") && ffDBusGetUint(&dbus, &dictIterator, &wpaFlags)) || (ffStrEquals(key, "RsnFlags") && ffDBusGetUint(&dbus, &dictIterator, &rsnFlags)) @@ -224,6 +249,13 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)"); } + ffStrbufClear(buffer); + if(ffParsePropLines(output.chars, "freq: ", buffer)) + { + item->conn.frequency = (uint16_t) ffStrbufToUInt(buffer, 0); + item->conn.channel = freq2channel(item->conn.frequency); + } + return NULL; } @@ -269,6 +301,30 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) if(ioctl(sock, SIOCGIWRATE, &iwr) >= 0) item->conn.txRate = iwr.u.bitrate.value / 1000000.; + if(ioctl(sock, SIOCGIWFREQ, &iwr) >= 0) + { + if (iwr.u.freq.e == 0 && iwr.u.freq.m <= 1000) + { + item->conn.channel = (uint16_t) iwr.u.freq.m; + } + else + { + // convert it to MHz + while (iwr.u.freq.e < 6) + { + iwr.u.freq.m /= 10; + iwr.u.freq.e++; + } + while (iwr.u.freq.e > 6) + { + iwr.u.freq.m *= 10; + iwr.u.freq.e--; + } + item->conn.frequency = (uint16_t) iwr.u.freq.m; + item->conn.channel = freq2channel(item->conn.frequency); + } + } + struct iw_statistics stats; iwr.u.data.pointer = &stats; iwr.u.data.length = sizeof(stats); From 94f8ff938b2f73acb0ff45c031b0a26fd6678029 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 22 Nov 2024 11:01:54 +0800 Subject: [PATCH 21/48] Wifi: print channel band --- src/detection/wifi/wifi_apple.m | 4 ++-- src/modules/wifi/wifi.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/detection/wifi/wifi_apple.m b/src/detection/wifi/wifi_apple.m index fb25961cee..aefe49c881 100644 --- a/src/detection/wifi/wifi_apple.m +++ b/src/detection/wifi/wifi_apple.m @@ -296,8 +296,8 @@ @interface CWInterface() switch (inf.wlanChannel.channelBand) { case kCWChannelBand2GHz: item->conn.frequency = 2400; break; - case kCWChannelBand5GHz: item->conn.frequency = 5000; break; - case 3 /*kCWChannelBand6GHz*/: item->conn.frequency = 6000; break; + case kCWChannelBand5GHz: item->conn.frequency = 5400; break; + case 3 /*kCWChannelBand6GHz*/: item->conn.frequency = 6400; break; default: item->conn.frequency = 0; break; } } diff --git a/src/modules/wifi/wifi.c b/src/modules/wifi/wifi.c index 21fb5ee1ac..f52382d0c3 100644 --- a/src/modules/wifi/wifi.c +++ b/src/modules/wifi/wifi.c @@ -4,7 +4,7 @@ #include "modules/wifi/wifi.h" #include "util/stringUtils.h" -#define FF_WIFI_NUM_FORMAT_ARGS 11 +#define FF_WIFI_NUM_FORMAT_ARGS 13 void ffPrintWifi(FFWifiOptions* options) { @@ -29,6 +29,27 @@ void ffPrintWifi(FFWifiOptions* options) FFWifiResult* item = FF_LIST_GET(FFWifiResult, result, index); uint8_t moduleIndex = result.length == 1 ? 0 : (uint8_t)(index + 1); + // https://en.wikipedia.org/wiki/List_of_WLAN_channels + char bandStr[8]; + if (item->conn.frequency > 58000) + strcpy(bandStr, "60"); + if (item->conn.frequency > 40000) + strcpy(bandStr, "45"); + else if (item->conn.frequency > 5900) + strcpy(bandStr, "6"); + else if (item->conn.frequency > 5100) + strcpy(bandStr, "5"); + else if (item->conn.frequency > 4900) + strcpy(bandStr, "4.9"); + else if (item->conn.frequency > 3600) + strcpy(bandStr, "3.65"); + else if (item->conn.frequency > 2000) + strcpy(bandStr, "2.4"); + else if (item->conn.frequency > 800) + strcpy(bandStr, "0.9"); + else + bandStr[0] = '\0'; + if(options->moduleArgs.outputFormat.length == 0) { ffPrintLogoAndKey(FF_WIFI_MODULE_NAME, moduleIndex, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT); @@ -54,6 +75,8 @@ void ffPrintWifi(FFWifiOptions* options) ffStrbufAppendS(&buffer, " - "); ffStrbufAppend(&buffer, &item->conn.protocol); } + if (bandStr[0]) + ffStrbufAppendF(&buffer, " - %s GHz", bandStr); if(item->conn.security.length) { ffStrbufAppendS(&buffer, " - "); @@ -97,6 +120,8 @@ void ffPrintWifi(FFWifiOptions* options) FF_FORMAT_ARG(item->conn.txRate, "tx-rate"), FF_FORMAT_ARG(item->conn.security, "security"), FF_FORMAT_ARG(percentBar, "signal-quality-bar"), + FF_FORMAT_ARG(item->conn.channel, "channel"), + FF_FORMAT_ARG(bandStr, "band"), })); } @@ -211,6 +236,8 @@ void ffPrintWifiHelpFormat(void) "Connection TX rate - tx-rate", "Connection Security algorithm - security", "Connection signal quality (percentage bar) - signal-quality-bar", + "Connection channel number - channel", + "Connection channel band in GHz - band", })); } From 2197cfb06d2b336976986cb17ebb3a55e87e8d5e Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 22 Nov 2024 13:53:04 +0800 Subject: [PATCH 22/48] Wifi (Android): report more props --- src/detection/wifi/wifi.h | 12 ++++++++++++ src/detection/wifi/wifi_android.c | 3 +++ src/detection/wifi/wifi_linux.c | 18 +++--------------- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/detection/wifi/wifi.h b/src/detection/wifi/wifi.h index 74d59cd6d0..ab2ee07196 100644 --- a/src/detection/wifi/wifi.h +++ b/src/detection/wifi/wifi.h @@ -29,3 +29,15 @@ typedef struct FFWifiResult } FFWifiResult; const char* ffDetectWifi(FFlist* result /*list of FFWifiItem*/); + +static inline uint16_t ffWifiFreqToChannel(uint16_t frequency) +{ + // https://github.com/opetryna/win32wifi/blob/master/win32wifi/Win32Wifi.py#L140 + // FIXME: Does it work for 6 GHz? + if (frequency == 2484) + return 14; + else if (frequency < 2484) + return (uint16_t) (frequency - 2407) / 5; + else + return (frequency / 5) - 1000; +} diff --git a/src/detection/wifi/wifi_android.c b/src/detection/wifi/wifi_android.c index 142b9cc2ec..a3abdcc39e 100644 --- a/src/detection/wifi/wifi_android.c +++ b/src/detection/wifi/wifi_android.c @@ -62,6 +62,9 @@ const char* ffDetectWifi(FFlist* result) ffStrbufAppendS(&item->inf.description, yyjson_get_str(yyjson_obj_get(root, "ip"))); ffStrbufAppendS(&item->conn.bssid, yyjson_get_str(yyjson_obj_get(root, "bssid"))); ffStrbufAppendS(&item->conn.ssid, yyjson_get_str(yyjson_obj_get(root, "ssid"))); + item->conn.frequency = yyjson_get_int(yyjson_obj_get(root, "frequency_mhz")); + item->conn.txRate = yyjson_get_num(yyjson_obj_get(root, "link_speed_mbps")); + item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); return NULL; } diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index f883da64c0..9e2158c09b 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -43,18 +43,6 @@ typedef enum { continue; \ } -static uint16_t freq2channel(uint16_t frequency) -{ - // https://github.com/opetryna/win32wifi/blob/master/win32wifi/Win32Wifi.py#L140 - // FIXME: Does it work for 6 GHz? - if (frequency == 2484) - return 14; - else if (frequency < 2484) - return (uint16_t) (frequency - 2407) / 5; - else - return (frequency / 5) - 1000; -} - static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { FFDBusData dbus; @@ -151,7 +139,7 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { item->conn.frequency = (uint16_t) frequency; if (item->conn.channel == 0) - item->conn.channel = freq2channel(item->conn.frequency); + item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); } } } @@ -253,7 +241,7 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) if(ffParsePropLines(output.chars, "freq: ", buffer)) { item->conn.frequency = (uint16_t) ffStrbufToUInt(buffer, 0); - item->conn.channel = freq2channel(item->conn.frequency); + item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); } return NULL; @@ -321,7 +309,7 @@ static const char* detectWifiWithIoctls(FFWifiResult* item) iwr.u.freq.e--; } item->conn.frequency = (uint16_t) iwr.u.freq.m; - item->conn.channel = freq2channel(item->conn.frequency); + item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); } } From 864fb918bc3d8fbdcf22a927b76d3f6db714105e Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 22 Nov 2024 14:20:50 +0800 Subject: [PATCH 23/48] Chore: silence some warnings --- src/detection/brightness/brightness_linux.c | 2 +- src/detection/terminalfont/terminalfont_linux.c | 2 +- src/detection/wifi/wifi.h | 4 ++-- src/util/edidHelper.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detection/brightness/brightness_linux.c b/src/detection/brightness/brightness_linux.c index 9682a75986..645fb58c67 100644 --- a/src/detection/brightness/brightness_linux.c +++ b/src/detection/brightness/brightness_linux.c @@ -99,7 +99,7 @@ double ddca_set_default_sleep_multiplier(double multiplier); // ddcutil 1.4 DDCA_Status ddca_init(const char *libopts, int syslog_level, int opts); #endif -static const char* detectWithDdcci(FFBrightnessOptions* options, FFlist* result) +static const char* detectWithDdcci(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFlist* result) { FF_LIBRARY_LOAD(libddcutil, "dlopen ddcutil failed", "libddcutil" FF_LIBRARY_EXTENSION, 5); FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libddcutil, ddca_get_display_info_list2) diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index baf383def6..5cdc6bb749 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -250,7 +250,7 @@ static void detectFootTerminal(FFTerminalFontResult* terminalFont) ffFontInitValues(&terminalFont->font, font.chars, "8"); return; } - uint32_t size = equal + strlen("size="); + uint32_t size = equal + (uint32_t) strlen("size="); uint32_t comma = ffStrbufNextIndexC(&font, size, ','); if (comma < font.length) font.chars[comma] = '\0'; diff --git a/src/detection/wifi/wifi.h b/src/detection/wifi/wifi.h index ab2ee07196..f941869a05 100644 --- a/src/detection/wifi/wifi.h +++ b/src/detection/wifi/wifi.h @@ -37,7 +37,7 @@ static inline uint16_t ffWifiFreqToChannel(uint16_t frequency) if (frequency == 2484) return 14; else if (frequency < 2484) - return (uint16_t) (frequency - 2407) / 5; + return (uint16_t) ((frequency - 2407) / 5); else - return (frequency / 5) - 1000; + return (uint16_t) ((frequency / 5) - 1000); } diff --git a/src/util/edidHelper.c b/src/util/edidHelper.c index adf621197d..8cb7124a4e 100644 --- a/src/util/edidHelper.c +++ b/src/util/edidHelper.c @@ -73,7 +73,7 @@ void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial { if (edid[17] > 0 && edid[17] < 0xFF) { - *year = (uint16_t) edid[17] + 1990; + *year = (uint16_t) (edid[17] + 1990); *week = (uint16_t) edid[16]; if (*week == 0xFF) *week = 0; } From c0be2637a802547542678053d9126f7852e68281 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Fri, 22 Nov 2024 15:37:01 +0800 Subject: [PATCH 24/48] Wifi (Android): silence compiler warnings --- src/detection/wifi/wifi_android.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/wifi/wifi_android.c b/src/detection/wifi/wifi_android.c index a3abdcc39e..2c0360cbae 100644 --- a/src/detection/wifi/wifi_android.c +++ b/src/detection/wifi/wifi_android.c @@ -62,7 +62,7 @@ const char* ffDetectWifi(FFlist* result) ffStrbufAppendS(&item->inf.description, yyjson_get_str(yyjson_obj_get(root, "ip"))); ffStrbufAppendS(&item->conn.bssid, yyjson_get_str(yyjson_obj_get(root, "bssid"))); ffStrbufAppendS(&item->conn.ssid, yyjson_get_str(yyjson_obj_get(root, "ssid"))); - item->conn.frequency = yyjson_get_int(yyjson_obj_get(root, "frequency_mhz")); + item->conn.frequency = (uint16_t) yyjson_get_int(yyjson_obj_get(root, "frequency_mhz")); item->conn.txRate = yyjson_get_num(yyjson_obj_get(root, "link_speed_mbps")); item->conn.channel = ffWifiFreqToChannel(item->conn.frequency); From 55352be0cc9f221bcf8c8aac96b1383b7435c76c Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sat, 23 Nov 2024 12:21:48 +0800 Subject: [PATCH 25/48] Wifi (FreeBSD): support channel & frequency detection --- src/detection/wifi/wifi_bsd.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/detection/wifi/wifi_bsd.c b/src/detection/wifi/wifi_bsd.c index 875bce1adc..fafc8f1c9f 100644 --- a/src/detection/wifi/wifi_bsd.c +++ b/src/detection/wifi/wifi_bsd.c @@ -40,14 +40,21 @@ const char* ffDetectWifi(FFlist* result) ffParsePropLines(ifconfig.chars, "ssid ", &item->conn.ssid); if (item->conn.ssid.length) { - uint32_t ibssid = ffStrbufFirstIndexS(&item->conn.ssid, " bssid "); - if (ibssid < item->conn.ssid.length) + uint32_t idx = ffStrbufFirstIndexS(&item->conn.ssid, " bssid "); + if (idx < item->conn.ssid.length) { - ibssid += (uint32_t) strlen(" bssid "); - ffStrbufSetS(&item->conn.bssid, item->conn.ssid.chars + ibssid); + ffStrbufSetS(&item->conn.bssid, item->conn.ssid.chars + idx + (uint32_t) strlen(" bssid ")); + ffStrbufSubstrBefore(&item->conn.ssid, idx); } - ffStrbufSubstrBeforeFirstC(&item->conn.ssid, ' '); + idx = ffStrbufFirstIndexS(&item->conn.ssid, " channel "); + if (idx < item->conn.ssid.length) + { + const char* pchannel = item->conn.ssid.chars + idx + strlen(" channel "); + sscanf(pchannel, "%hu (%hu MHz %*s)", &item->conn.channel, &item->conn.frequency); + } + + ffStrbufSubstrBefore(&item->conn.ssid, idx); } ffParsePropLines(ifconfig.chars, "media: ", &item->conn.protocol); From 1b835544b6d435c956ad24e6f83a50c339a3b6d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 23 Nov 2024 22:44:45 +0800 Subject: [PATCH 26/48] Users: fix invalid var name Fix #1408 --- src/modules/users/users.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/users/users.c b/src/modules/users/users.c index 7be21109bc..650db448db 100644 --- a/src/modules/users/users.c +++ b/src/modules/users/users.c @@ -191,7 +191,7 @@ void ffGenerateUsersJsonResult(FFUsersOptions* options, yyjson_mut_doc* doc, yyj void ffPrintUsersHelpFormat(void) { FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_USERS_MODULE_NAME, "{1}@{2} - login time {5}", FF_USERS_NUM_FORMAT_ARGS, ((const char* []) { - "User name - user-name", + "User name - name", "Host name - host-name", "Session name - session", "Client IP - client-ip", From 64287eed217044a75a1a1c0c93639fab9583ba8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sun, 24 Nov 2024 01:02:06 +0800 Subject: [PATCH 27/48] Display: change physical size detection to use basic display parameters Some monitor report invalid data in DTD. Ref: #1406 --- src/util/edidHelper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/util/edidHelper.c b/src/util/edidHelper.c index 8cb7124a4e..8c920bd30d 100644 --- a/src/util/edidHelper.c +++ b/src/util/edidHelper.c @@ -65,8 +65,8 @@ bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name) void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height) { - *width = (((uint32_t) edid[68] & 0xF0) << 4) + edid[66]; - *height = (((uint32_t) edid[68] & 0x0F) << 8) + edid[67]; + *width = edid[21] * 10; + *height = edid[22] * 10; } void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week) From 3463fc331f2895cad7f4a1fbdb9c8186dcac6e5f Mon Sep 17 00:00:00 2001 From: Carlos Henrique Lima Melara <34252251+charles2910@users.noreply.github.com> Date: Sat, 23 Nov 2024 23:22:57 -0300 Subject: [PATCH 28/48] Scripts: use datetime to get date and set timezone to UTC (#1410) This will ensure the package is reproducible even in different timezones. --- scripts/gen-man.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/gen-man.py b/scripts/gen-man.py index def48b072d..2bb589add1 100755 --- a/scripts/gen-man.py +++ b/scripts/gen-man.py @@ -9,7 +9,7 @@ """ from json import load -from datetime import date +from datetime import datetime, timezone from time import time from re import search from os import environ, path @@ -36,8 +36,10 @@ titlePage = "Fastfetch man page" # date (center footer) # format : "Month (abbreviation) Day Year" -todayDate = date.fromtimestamp( - int(environ.get("SOURCE_DATE_EPOCH", time()))).strftime("%b %d %Y") +todayDate = datetime.fromtimestamp( + int(environ.get("SOURCE_DATE_EPOCH", time())), + tz=timezone.utc, +).strftime("%b %d %Y") # file to fastfetch version (left footer) pathToVersionFile = path.join(pathToCurrentDir, "../CMakeLists.txt") From e77c3119cadcc2596ba84568bb770b1229aaf53a Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 25 Nov 2024 14:18:33 +0800 Subject: [PATCH 29/48] OS (Linux): check for lmde Fix #1415 --- src/detection/os/os_linux.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index cab2cef8ae..a00584796b 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -273,5 +273,13 @@ void ffDetectOSImpl(FFOSResult* os) if (!detectDebianDerived(os)) getDebianVersion(os); } + else if(ffStrbufEqualS(&os->id, "linuxmint")) + { + if (ffStrbufEqualS(&os->name, "LMDE")) + { + ffStrbufSetS(&os->id, "lmde"); + ffStrbufSetS(&os->idLike, "linuxmint"); + } + } #endif } From 04088b5b2c709b37f6218c30766c51707be2655b Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 25 Nov 2024 14:31:07 +0800 Subject: [PATCH 30/48] Logo (Builtin): update MidOS Fix #1409 --- src/logo/ascii/midos.txt | 40 ++++++++++++++++++------------------ src/logo/ascii/midos_old.txt | 20 ++++++++++++++++++ src/logo/builtin.c | 11 ++++++++++ 3 files changed, 51 insertions(+), 20 deletions(-) create mode 100644 src/logo/ascii/midos_old.txt diff --git a/src/logo/ascii/midos.txt b/src/logo/ascii/midos.txt index 4790708285..9c9b80ed0e 100644 --- a/src/logo/ascii/midos.txt +++ b/src/logo/ascii/midos.txt @@ -1,20 +1,20 @@ - .:=+*#%%@@@@@@%%#*+=:. - .=*%@@@@@@@@@@@@@@@@@@@@@@%*=: - .=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+. - :*@@@@@@@@@@@@@@@@@$2++$1%@@@@@@@@@@@@@@@@#- - .*@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@#. - -%@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@- - -@@@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@@= -:@@@@@@@@@@@@@@@@@%%@@@%$2..$1#@@@@#@@@@@@@@@@@@@@@@@: -*@@@@@@@@@@@@#$2*=:..$1*@@@%$2..$1#@@@#$2..:=+$1#@@@@@@@@@@@@* -%@@@@@@@#+$2=:...-+$1#@@@@@%$2..$1#@@@@@#$2+=:..:-$1+#@@@@@@@% -%@@@@@$2:..:=+-..-+$1#@@@@@%$2..$1#@@@@@%$2+-..-+=:..:$1@@@@@@ -*@@@@@$2*%$1@@@@@@%$2+-..$1#@@@%$2..$1#@@@%$2..-+$1#@@@@@@$2%*$1@@@@@* -:@@@@@@@@@@@@@@@@@$2#%$1@@@%$2..$1#@@@$2%#$1@@@@@@@@@@@@@@@@@: - =@@@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@@= - -@@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@= - .*@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@#: - :*@@@@@@@@@@@@@@@@@$2==$1%@@@@@@@@@@@@@@@@#-. - .+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+: - :=*%@@@@@@@@@@@@@@@@@@@@@@%*=:. - .-=+*#%%@@@@@@%%#*+=-. \ No newline at end of file + ▁▂▃▄▅▆▇▇████▇▇▆▅▄▃▂▁ + ▃▅▇████████████████████▇▅▃ + ▂▅████████████████████████████▅▁ + ▗▟██████████████▛▀▀▜██████████████▙▖ + ▗▟████████████████▌ ▐████████████████▙▖ + ▗██████████████████▌ ▐██████████████████▖ + ▗███████████████████▌ ▐███████████████████▖ +▕███████████████▀▘ ██▌ ▐██ ▝▀███████████████▏ +▐██████████▛▀▀ ▂██▌ ▐██▂ ▀▀▜██████████▌ +███████▀▀ ▁▄▆████▌ ▐████▆▄▁ ▀▀███████ +█████ ▂▄▂ ▔▀▜████▌ ▐████▛▀▔ ▂▄▂ █████ +▐████▄▄▆█████▄▂ ▔▀██▌ ▐██▀▔ ▂▄█████▆▄▄████▌ +▕██████████████▇▄▂ ██▌ ▐██ ▂▄▇██████████████▏ + ▝███████████████████▌ ▐███████████████████▘ + ▝██████████████████▌ ▐██████████████████▘ + ▝▜████████████████▌ ▐████████████████▛▘ + ▝▜██████████████▙▄▄▟██████████████▛▘ + ▔▀▜██████████████████████████▛▀▔ + ▔▀▜████████████████████▛▀▔ + ▔▔▀▀▀▜██████▛▀▀▀▔▔ \ No newline at end of file diff --git a/src/logo/ascii/midos_old.txt b/src/logo/ascii/midos_old.txt new file mode 100644 index 0000000000..4790708285 --- /dev/null +++ b/src/logo/ascii/midos_old.txt @@ -0,0 +1,20 @@ + .:=+*#%%@@@@@@%%#*+=:. + .=*%@@@@@@@@@@@@@@@@@@@@@@%*=: + .=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+. + :*@@@@@@@@@@@@@@@@@$2++$1%@@@@@@@@@@@@@@@@#- + .*@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@#. + -%@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@- + -@@@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@@= +:@@@@@@@@@@@@@@@@@%%@@@%$2..$1#@@@@#@@@@@@@@@@@@@@@@@: +*@@@@@@@@@@@@#$2*=:..$1*@@@%$2..$1#@@@#$2..:=+$1#@@@@@@@@@@@@* +%@@@@@@@#+$2=:...-+$1#@@@@@%$2..$1#@@@@@#$2+=:..:-$1+#@@@@@@@% +%@@@@@$2:..:=+-..-+$1#@@@@@%$2..$1#@@@@@%$2+-..-+=:..:$1@@@@@@ +*@@@@@$2*%$1@@@@@@%$2+-..$1#@@@%$2..$1#@@@%$2..-+$1#@@@@@@$2%*$1@@@@@* +:@@@@@@@@@@@@@@@@@$2#%$1@@@%$2..$1#@@@$2%#$1@@@@@@@@@@@@@@@@@: + =@@@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@@= + -@@@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@@@= + .*@@@@@@@@@@@@@@@@@@%$2..$1#@@@@@@@@@@@@@@@@@@#: + :*@@@@@@@@@@@@@@@@@$2==$1%@@@@@@@@@@@@@@@@#-. + .+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+: + :=*%@@@@@@@@@@@@@@@@@@@@@@%*=:. + .-=+*#%%@@@@@@%%#*+=-. \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 77d2e05c05..60f874dce5 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -2837,6 +2837,17 @@ static const FFlogo M[] = { { .names = {"MidOS"}, .lines = FASTFETCH_DATATEXT_LOGO_MIDOS, + .colors = { + FF_COLOR_FG_LIGHT_BLACK, + }, + .colorKeys = FF_COLOR_FG_LIGHT_BLACK, + .colorTitle = FF_COLOR_FG_WHITE, + }, + // MidOSOld + { + .names = {"MidOS_old"}, + .lines = FASTFETCH_DATATEXT_LOGO_MIDOS_OLD, + .type = FF_LOGO_LINE_TYPE_ALTER_BIT, .colors = { FF_COLOR_FG_LIGHT_BLACK, FF_COLOR_FG_WHITE, From 0cd7aeac19521187e48ede35e3f6c132b97435d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 25 Nov 2024 22:21:53 +0800 Subject: [PATCH 31/48] Display (macOS): don't crash with NULL pointer references Fix #1393 --- .../displayserver/displayserver_apple.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/detection/displayserver/displayserver_apple.c b/src/detection/displayserver/displayserver_apple.c index 8f5ea3e3c5..e8eeb9fbf0 100644 --- a/src/detection/displayserver/displayserver_apple.c +++ b/src/detection/displayserver/displayserver_apple.c @@ -150,7 +150,7 @@ static void detectDisplays(FFDisplayServerResult* ds) } #endif - if (display->type == FF_DISPLAY_TYPE_BUILTIN) + if (display->type == FF_DISPLAY_TYPE_BUILTIN && displayInfo) display->hdrStatus = CFDictionaryContainsKey(displayInfo, CFSTR("ReferencePeakHDRLuminance")) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; #ifdef MAC_OS_X_VERSION_10_15 @@ -168,11 +168,15 @@ static void detectDisplays(FFDisplayServerResult* ds) #endif display->serial = CGDisplaySerialNumber(screen); - int value; - if (ffCfDictGetInt(displayInfo, CFSTR(kDisplayYearOfManufacture), &value) == NULL) - display->manufactureYear = (uint16_t) value; - if (ffCfDictGetInt(displayInfo, CFSTR(kDisplayWeekOfManufacture), &value) == NULL) - display->manufactureWeek = (uint16_t) value; + + if (displayInfo) + { + int value; + if (ffCfDictGetInt(displayInfo, CFSTR(kDisplayYearOfManufacture), &value) == NULL) + display->manufactureYear = (uint16_t) value; + if (ffCfDictGetInt(displayInfo, CFSTR(kDisplayWeekOfManufacture), &value) == NULL) + display->manufactureWeek = (uint16_t) value; + } } CGDisplayModeRelease(mode); } From b76eb875106fcf03e431db8667d8083004a7ff6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 25 Nov 2024 22:46:57 +0800 Subject: [PATCH 32/48] CI: fix building on macOS --- .github/workflows/ci.yml | 2 +- presets/ci.jsonc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7140fbd5ba..f743443e6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -274,7 +274,7 @@ jobs: macos-universal: name: macOS-universal - runs-on: macos-12 + runs-on: macos-latest permissions: security-events: write contents: read diff --git a/presets/ci.jsonc b/presets/ci.jsonc index 4380541358..eb3a0c2195 100644 --- a/presets/ci.jsonc +++ b/presets/ci.jsonc @@ -87,8 +87,8 @@ "opengl", "opencl", "users", - "bluetooth", - "bluetoothradio", + // "bluetooth", // doesn't work on macOS because it requires bluetooth permissions + // "bluetoothradio", "sound", "camera", "gamepad", From 7535ce8a18fb042f466ee92798dbeae2994d3d24 Mon Sep 17 00:00:00 2001 From: AzimovParviz Date: Tue, 26 Nov 2024 02:53:01 +0200 Subject: [PATCH 33/48] Support for dual CPU systems (#1417) * [macOS] Added support for dual CPUs on Mac computers Signed-off-by: Koneko * Change how number of cores is displayed when the system is dual CPU * Support for dual CPU on Windows * Dual CPU detection on Linux basic implementation --------- Signed-off-by: Koneko --- src/detection/cpu/cpu.h | 1 + src/detection/cpu/cpu_apple.c | 1 + src/detection/cpu/cpu_linux.c | 8 +++++++- src/detection/cpu/cpu_windows.c | 4 ++++ src/modules/cpu/cpu.c | 10 +++++++++- 5 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h index eb5bd90f44..59343dd98c 100644 --- a/src/detection/cpu/cpu.h +++ b/src/detection/cpu/cpu.h @@ -15,6 +15,7 @@ typedef struct FFCPUResult FFstrbuf name; FFstrbuf vendor; + uint16_t cpuCount; uint16_t coresPhysical; uint16_t coresLogical; uint16_t coresOnline; diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index 1d94b005ed..f2b4c42565 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -109,6 +109,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) return "sysctlbyname(machdep.cpu.brand_string) failed"; ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor); + cpu->cpuCount = (uint16_t) ffSysctlGetInt("hw.packages", 1); if (cpu->vendor.length == 0 && ffStrbufStartsWithS(&cpu->name, "Apple ")) ffStrbufAppendS(&cpu->vendor, "Apple"); diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 91c8ba46f6..56493cf2ac 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -222,6 +222,7 @@ static void detectArmName(FILE* cpuinfo, FFCPUResult* cpu, uint32_t implId) static const char* parseCpuInfo( FF_MAYBE_UNUSED FILE* cpuinfo, FF_MAYBE_UNUSED FFCPUResult* cpu, + FF_MAYBE_UNUSED FFstrbuf* cpuPhysicalId, FF_MAYBE_UNUSED FFstrbuf* physicalCoresBuffer, FF_MAYBE_UNUSED FFstrbuf* cpuMHz, FF_MAYBE_UNUSED FFstrbuf* cpuIsa, @@ -247,6 +248,9 @@ static const char* parseCpuInfo( #if !(__arm__ || __aarch64__) (cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) || (cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) || + //Is it cheaper to just parse every physical id or to check if it's already set to the parsed value? + (cpuPhysicalId->length == 0 && ffParsePropLine(line, "physical id:", cpuPhysicalId)) || + (cpuPhysicalId->length > 0 && ffParsePropLine(line, "physical id:", cpuPhysicalId)) || (physicalCoresBuffer->length == 0 && ffParsePropLine(line, "cpu cores :", physicalCoresBuffer)) || (cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) || #endif @@ -473,18 +477,20 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) cpu->temperature = options->temp ? detectCPUTemp() : FF_CPU_TEMP_UNSET; + FF_STRBUF_AUTO_DESTROY cpuPhysicalId= ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY physicalCoresBuffer = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuMHz = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuIsa = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuUarch = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuImplementerStr = ffStrbufCreate(); - const char* error = parseCpuInfo(cpuinfo, cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr); + const char* error = parseCpuInfo(cpuinfo, cpu, &cpuPhysicalId, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr); if (error) return error; cpu->coresLogical = (uint16_t) get_nprocs_conf(); cpu->coresOnline = (uint16_t) get_nprocs(); cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical); + cpu->cpuCount = (uint16_t) ffStrbufToUInt(&cpuPhysicalId, 1) +1; //Assuming at least 1 CPU is present otherwise we wouldn't get this far // Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252 ffCPUDetectSpeedByCpuid(cpu); diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 7479ff6d1c..313e7487ec 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -110,6 +110,10 @@ static const char* detectNCores(FFCPUResult* cpu) cpu->coresLogical += ptr->Group.GroupInfo[index].MaximumProcessorCount; } } + + if (ptr->Relationship == RelationProcessorPackage) { + cpu->cpuCount++; + } } return NULL; diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 614b0bf26a..1ee351229b 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -55,6 +55,9 @@ void ffPrintCPU(FFCPUOptions* options) FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate(); + if(cpu.cpuCount > 1) + ffStrbufAppendF(&str, "%u x ", cpu.cpuCount); + if(cpu.name.length > 0) ffStrbufAppend(&str, &cpu.name); else if(cpu.vendor.length > 0) @@ -68,7 +71,12 @@ void ffPrintCPU(FFCPUOptions* options) if(coreTypes.length > 0) ffStrbufAppendF(&str, " (%s)", coreTypes.chars); else if(cpu.coresOnline > 1) - ffStrbufAppendF(&str, " (%u)", cpu.coresOnline); + { + if(cpu.cpuCount > 1) + ffStrbufAppendF(&str, " (%u)", cpu.coresOnline / 2); + else + ffStrbufAppendF(&str, " (%u)", cpu.coresOnline); + } uint32_t freq = cpu.frequencyMax; if(freq == 0) From 8b41cbd50833a557d9c6aee82bb6474baba96c35 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 26 Nov 2024 14:47:02 +0800 Subject: [PATCH 34/48] CPU (Linux): refactor; fix cpu count detection --- src/detection/cpu/cpu_linux.c | 50 ++++++++++------ src/util/FFstrbuf.c | 44 ++++++++++++++ src/util/FFstrbuf.h | 2 + tests/strbuf.c | 107 ++++++++++++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 19 deletions(-) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 56493cf2ac..5a306d473d 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -159,14 +159,13 @@ static void detectAndroid(FFCPUResult* cpu) #if __arm__ || __aarch64__ #include "cpu_arm.h" -static void detectArmName(FILE* cpuinfo, FFCPUResult* cpu, uint32_t implId) +static void detectArmName(FFstrbuf* cpuinfo, FFCPUResult* cpu, uint32_t implId) { - FF_AUTO_FREE char* line = NULL; - rewind(cpuinfo); + char* line = NULL; size_t len = 0; uint32_t lastPartId = UINT32_MAX; uint32_t num = 0; - while(getline(&line, &len, cpuinfo) != -1) + while(ffStrbufGetline(&line, &len, cpuinfo)) { if (!ffStrStartsWith(line, "CPU part\t: ")) continue; uint32_t partId = (uint32_t) strtoul(line + strlen("CPU part\t: "), NULL, 16); @@ -220,19 +219,18 @@ static void detectArmName(FILE* cpuinfo, FFCPUResult* cpu, uint32_t implId) #endif static const char* parseCpuInfo( - FF_MAYBE_UNUSED FILE* cpuinfo, - FF_MAYBE_UNUSED FFCPUResult* cpu, - FF_MAYBE_UNUSED FFstrbuf* cpuPhysicalId, + FFstrbuf* cpuinfo, + FFCPUResult* cpu, FF_MAYBE_UNUSED FFstrbuf* physicalCoresBuffer, FF_MAYBE_UNUSED FFstrbuf* cpuMHz, FF_MAYBE_UNUSED FFstrbuf* cpuIsa, FF_MAYBE_UNUSED FFstrbuf* cpuUarch, FF_MAYBE_UNUSED FFstrbuf* cpuImplementer) { - FF_AUTO_FREE char* line = NULL; + char* line = NULL; size_t len = 0; - while(getline(&line, &len, cpuinfo) != -1) + while(ffStrbufGetline(&line, &len, cpuinfo)) { //Stop after reasonable information is acquired if((*line == '\0' || *line == '\n') @@ -248,9 +246,6 @@ static const char* parseCpuInfo( #if !(__arm__ || __aarch64__) (cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) || (cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) || - //Is it cheaper to just parse every physical id or to check if it's already set to the parsed value? - (cpuPhysicalId->length == 0 && ffParsePropLine(line, "physical id:", cpuPhysicalId)) || - (cpuPhysicalId->length > 0 && ffParsePropLine(line, "physical id:", cpuPhysicalId)) || (physicalCoresBuffer->length == 0 && ffParsePropLine(line, "cpu cores :", physicalCoresBuffer)) || (cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) || #endif @@ -469,28 +464,45 @@ FF_MAYBE_UNUSED static void detectArmSoc(FFCPUResult* cpu) } } +FF_MAYBE_UNUSED static uint16_t getCPUCount(FFstrbuf* cpuinfo) +{ + const char* p = cpuinfo->chars; + uint64_t bits = 0; + + while ((p = memmem(p, cpuinfo->length - (uint32_t) (p - cpuinfo->chars), "\nphysical id\t:", strlen("\nphysical id\t:")))) + { + if (!p) break; + p += strlen("\nphysical id\t:"); + char* pend; + uint32_t id = (uint32_t) strtoul(p, &pend, 10); + p = pend; + bits |= 1 << id; + } + + return (uint16_t) __builtin_popcountll(bits); +} + const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) { - FF_AUTO_CLOSE_FILE FILE* cpuinfo = fopen("/proc/cpuinfo", "r"); - if(cpuinfo == NULL) - return "fopen(\"/proc/cpuinfo\", \"r\") failed"; + FF_STRBUF_AUTO_DESTROY cpuinfo = ffStrbufCreateA(PROC_FILE_BUFFSIZ); + if (!ffReadFileBuffer("/proc/cpuinfo", &cpuinfo) || cpuinfo.length == 0) + return "ffReadFileBuffer(\"/proc/cpuinfo\") failed"; cpu->temperature = options->temp ? detectCPUTemp() : FF_CPU_TEMP_UNSET; - FF_STRBUF_AUTO_DESTROY cpuPhysicalId= ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY physicalCoresBuffer = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuMHz = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuIsa = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuUarch = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY cpuImplementerStr = ffStrbufCreate(); - const char* error = parseCpuInfo(cpuinfo, cpu, &cpuPhysicalId, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr); + const char* error = parseCpuInfo(&cpuinfo, cpu, &physicalCoresBuffer, &cpuMHz, &cpuIsa, &cpuUarch, &cpuImplementerStr); if (error) return error; cpu->coresLogical = (uint16_t) get_nprocs_conf(); cpu->coresOnline = (uint16_t) get_nprocs(); cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical); - cpu->cpuCount = (uint16_t) ffStrbufToUInt(&cpuPhysicalId, 1) +1; //Assuming at least 1 CPU is present otherwise we wouldn't get this far + cpu->cpuCount = getCPUCount(&cpuinfo); // Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252 ffCPUDetectSpeedByCpuid(cpu); @@ -525,7 +537,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) #endif if (cpu->name.length == 0) - detectArmName(cpuinfo, cpu, cpuImplementer); + detectArmName(&cpuinfo, cpu, cpuImplementer); #endif return NULL; diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 68240f00ec..f40572cefb 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -531,3 +531,47 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c) memset(&strbuf->chars[index], c, num); strbuf->length += num; } + +/** + * @brief Read a line from a FFstrbuf. + * + * @details Behaves like getline(3) but reads from a FFstrbuf. + * + * @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line. + * Can be NULL for the first call. + * @param[in,out] n The pointer to the size of the buffer of lineptr. + * @param[in] buffer The buffer to read from. The buffer must not be a string literal. + * + * @return true if a line has been read, false if the end of the buffer has been reached. + */ +bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer) +{ + assert(lineptr && n && buffer); + assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0)); + assert(!*lineptr || (*lineptr >= buffer->chars && *lineptr <= buffer->chars + buffer->length)); + + const char* pBufferEnd = buffer->chars + buffer->length; + if (!*lineptr) + *lineptr = buffer->chars; + else + { + *lineptr += *n; + if (*lineptr >= pBufferEnd) // non-empty last line + return false; + **lineptr = '\n'; + ++*lineptr; + } + if (*lineptr >= pBufferEnd) // empty last line + return false; + + size_t remaining = (size_t) (pBufferEnd - *lineptr); + char* ending = memchr(*lineptr, '\n', remaining); + if (ending) + { + *n = (size_t) (ending - *lineptr); + *ending = '\0'; + } + else + *n = remaining; + return true; +} diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 2ac123352c..cda2987f36 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -90,6 +90,8 @@ FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultV void ffStrbufUpperCase(FFstrbuf* strbuf); void ffStrbufLowerCase(FFstrbuf* strbuf); +bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer); + FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) { FFstrbuf strbuf; diff --git a/tests/strbuf.c b/tests/strbuf.c index 92141d4b91..aad76da2f5 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -458,6 +458,113 @@ int main(void) VERIFY(strbuf2.allocated == 32); } + { + int i = 0; + char* lineptr = NULL; + size_t n = 0; + const char* text = "Processor\t: ARMv7\nprocessor\t: 0\nBogoMIPS\t: 38.00\n\nprocessor\t: 1\nBogoMIPS\t: 38.00"; + ffStrbufSetS(&strbuf, text); + + while (ffStrbufGetline(&lineptr, &n, &strbuf)) + { + ++i; + switch (i) + { + case 1: + VERIFY(strcmp(lineptr, "Processor\t: ARMv7") == 0); + VERIFY(n == strlen("Processor\t: ARMv7")); + break; + case 2: + VERIFY(strcmp(lineptr, "processor\t: 0") == 0); + VERIFY(n == strlen("processor\t: 0")); + break; + case 3: + VERIFY(strcmp(lineptr, "BogoMIPS\t: 38.00") == 0); + VERIFY(n == strlen("BogoMIPS\t: 38.00")); + break; + case 4: + VERIFY(strcmp(lineptr, "") == 0); + VERIFY(n == 0); + break; + case 5: + VERIFY(strcmp(lineptr, "processor\t: 1") == 0); + VERIFY(n == strlen("processor\t: 1")); + break; + case 6: + VERIFY(strcmp(lineptr, "BogoMIPS\t: 38.00") == 0); + VERIFY(n == strlen("BogoMIPS\t: 38.00")); + break; + default: + VERIFY(false); + break; + } + } + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 6); + + lineptr = NULL; + n = 0; + i = 0; + text = "\n"; + ffStrbufSetS(&strbuf, text); + while (ffStrbufGetline(&lineptr, &n, &strbuf)) + { + ++i; + switch (i) + { + case 1: + VERIFY(strcmp(lineptr, "") == 0); + VERIFY(n == 0); + break; + default: + VERIFY(false); + break; + } + } + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 1); + + lineptr = NULL; + n = 0; + i = 0; + text = "abcd"; + ffStrbufSetS(&strbuf, text); + while (ffStrbufGetline(&lineptr, &n, &strbuf)) + { + ++i; + switch (i) + { + case 1: + VERIFY(strcmp(lineptr, "abcd") == 0); + VERIFY(n == strlen("abcd")); + break; + default: + VERIFY(false); + break; + } + } + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 1); + + lineptr = NULL; + n = 0; + i = 0; + text = ""; + ffStrbufSetS(&strbuf, text); + while (ffStrbufGetline(&lineptr, &n, &strbuf)) + { + ++i; + VERIFY(false); + } + + VERIFY(ffStrbufEqualS(&strbuf, text)); + VERIFY(*lineptr == '\0'); + VERIFY(i == 0); + } + //Success puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); } From 9955e9da0219f2559c43362b7c588678f37a5a75 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 26 Nov 2024 16:35:33 +0800 Subject: [PATCH 35/48] CPU: remove duplicate whitespaces in CPU name Eg. `Intel(R) Xeon(R) CPU E5620 @ 2.40GHz` --- src/detection/cpu/cpu.c | 1 + src/util/FFstrbuf.c | 22 ++++++++++++++++++++++ src/util/FFstrbuf.h | 1 + tests/strbuf.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/src/detection/cpu/cpu.c b/src/detection/cpu/cpu.c index a3b47416c1..2b9d41dced 100644 --- a/src/detection/cpu/cpu.c +++ b/src/detection/cpu/cpu.c @@ -16,6 +16,7 @@ const char* ffDetectCPU(const FFCPUOptions* options, FFCPUResult* cpu) ffStrbufRemoveStrings(&cpu->name, ARRAY_SIZE(removeStrings), removeStrings); ffStrbufSubstrBeforeFirstC(&cpu->name, '@'); //Cut the speed output in the name as we append our own ffStrbufTrimRight(&cpu->name, ' '); //If we removed the @ in previous step there was most likely a space before it + ffStrbufRemoveDupWhitespaces(&cpu->name); return NULL; } diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index f40572cefb..31ec637d62 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -575,3 +575,25 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer) *n = remaining; return true; } + +bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf) +{ + if (strbuf->allocated == 0) return false; // Doesn't work with static strings + + bool changed = false; + for (uint32_t i = 0; i < strbuf->length; i++) + { + if (strbuf->chars[i] != ' ') continue; + + i++; + uint32_t j = i; + for (; j < strbuf->length && strbuf->chars[j] == ' '; j++); + + if (j == i) continue; + memmove(&strbuf->chars[i], &strbuf->chars[j], strbuf->length - j + 1); + strbuf->length -= j - i; + changed = true; + } + + return changed; +} diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index cda2987f36..1c754b10a6 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -91,6 +91,7 @@ void ffStrbufUpperCase(FFstrbuf* strbuf); void ffStrbufLowerCase(FFstrbuf* strbuf); bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer); +bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf); FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) { diff --git a/tests/strbuf.c b/tests/strbuf.c index aad76da2f5..005a12fa5b 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -565,6 +565,34 @@ int main(void) VERIFY(i == 0); } + ffStrbufSetS(&strbuf, "Hello World"); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == false); + VERIFY(strcmp(strbuf.chars, "Hello World") == 0); + + ffStrbufSetS(&strbuf, "Hello World"); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, "Hello World") == 0); + + ffStrbufSetS(&strbuf, " Hello World "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, " Hello World ") == 0); + + ffStrbufSetS(&strbuf, " Hello World "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, " Hello World ") == 0); + + ffStrbufSetS(&strbuf, " "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == true); + VERIFY(strcmp(strbuf.chars, " ") == 0); + + ffStrbufClear(&strbuf); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == false); + VERIFY(strcmp(strbuf.chars, "") == 0); + + ffStrbufSetStatic(&strbuf, " "); + VERIFY(ffStrbufRemoveDupWhitespaces(&strbuf) == false); + VERIFY(strcmp(strbuf.chars, " ") == 0); + //Success puts("\e[32mAll tests passed!" FASTFETCH_TEXT_MODIFIER_RESET); } From ee564de4615f27069f7438427d7b5ef530ad1f00 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 26 Nov 2024 21:37:00 +0800 Subject: [PATCH 36/48] CPU: change `cpuCount` to `packages`; support custom format Fix #1413 --- src/detection/cpu/cpu.h | 2 +- src/detection/cpu/cpu_apple.c | 2 +- src/detection/cpu/cpu_linux.c | 6 ++++-- src/detection/cpu/cpu_windows.c | 2 +- src/modules/cpu/cpu.c | 14 ++++++++++---- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/detection/cpu/cpu.h b/src/detection/cpu/cpu.h index 59343dd98c..5af7a8275b 100644 --- a/src/detection/cpu/cpu.h +++ b/src/detection/cpu/cpu.h @@ -15,7 +15,7 @@ typedef struct FFCPUResult FFstrbuf name; FFstrbuf vendor; - uint16_t cpuCount; + uint16_t packages; uint16_t coresPhysical; uint16_t coresLogical; uint16_t coresOnline; diff --git a/src/detection/cpu/cpu_apple.c b/src/detection/cpu/cpu_apple.c index f2b4c42565..8d5cbf0a4f 100644 --- a/src/detection/cpu/cpu_apple.c +++ b/src/detection/cpu/cpu_apple.c @@ -109,7 +109,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) return "sysctlbyname(machdep.cpu.brand_string) failed"; ffSysctlGetString("machdep.cpu.vendor", &cpu->vendor); - cpu->cpuCount = (uint16_t) ffSysctlGetInt("hw.packages", 1); + cpu->packages = (uint16_t) ffSysctlGetInt("hw.packages", 1); if (cpu->vendor.length == 0 && ffStrbufStartsWithS(&cpu->name, "Apple ")) ffStrbufAppendS(&cpu->vendor, "Apple"); diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 5a306d473d..e90663d521 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -464,7 +464,7 @@ FF_MAYBE_UNUSED static void detectArmSoc(FFCPUResult* cpu) } } -FF_MAYBE_UNUSED static uint16_t getCPUCount(FFstrbuf* cpuinfo) +FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo) { const char* p = cpuinfo->chars; uint64_t bits = 0; @@ -502,7 +502,9 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) cpu->coresLogical = (uint16_t) get_nprocs_conf(); cpu->coresOnline = (uint16_t) get_nprocs(); cpu->coresPhysical = (uint16_t) ffStrbufToUInt(&physicalCoresBuffer, cpu->coresLogical); - cpu->cpuCount = getCPUCount(&cpuinfo); + #if __x86_64__ || __i386__ + cpu->packages = getPackageCount(&cpuinfo); + #endif // Ref https://github.com/fastfetch-cli/fastfetch/issues/1194#issuecomment-2295058252 ffCPUDetectSpeedByCpuid(cpu); diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 313e7487ec..411571010e 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -112,7 +112,7 @@ static const char* detectNCores(FFCPUResult* cpu) } if (ptr->Relationship == RelationProcessorPackage) { - cpu->cpuCount++; + cpu->packages++; } } diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 1ee351229b..1a924ca5db 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -6,7 +6,7 @@ #include "modules/cpu/cpu.h" #include "util/stringUtils.h" -#define FF_CPU_NUM_FORMAT_ARGS 9 +#define FF_CPU_NUM_FORMAT_ARGS 10 static int sortCores(const FFCPUCore* a, const FFCPUCore* b) { @@ -55,8 +55,8 @@ void ffPrintCPU(FFCPUOptions* options) FF_STRBUF_AUTO_DESTROY str = ffStrbufCreate(); - if(cpu.cpuCount > 1) - ffStrbufAppendF(&str, "%u x ", cpu.cpuCount); + if(cpu.packages > 1) + ffStrbufAppendF(&str, "%u x ", cpu.packages); if(cpu.name.length > 0) ffStrbufAppend(&str, &cpu.name); @@ -72,7 +72,7 @@ void ffPrintCPU(FFCPUOptions* options) ffStrbufAppendF(&str, " (%s)", coreTypes.chars); else if(cpu.coresOnline > 1) { - if(cpu.cpuCount > 1) + if(cpu.packages > 1) ffStrbufAppendF(&str, " (%u)", cpu.coresOnline / 2); else ffStrbufAppendF(&str, " (%u)", cpu.coresOnline); @@ -114,6 +114,7 @@ void ffPrintCPU(FFCPUOptions* options) FF_FORMAT_ARG(freqMax, "freq-max"), FF_FORMAT_ARG(tempStr, "temperature"), FF_FORMAT_ARG(coreTypes, "core-types"), + FF_FORMAT_ARG(cpu.packages, "packages"), })); } } @@ -211,6 +212,10 @@ void ffGenerateCPUJsonResult(FFCPUOptions* options, yyjson_mut_doc* doc, yyjson_ yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result"); yyjson_mut_obj_add_strbuf(doc, obj, "cpu", &cpu.name); yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &cpu.vendor); + if (cpu.packages == 0) + yyjson_mut_obj_add_null(doc, obj, "packages"); + else + yyjson_mut_obj_add_uint(doc, obj, "packages", cpu.packages); yyjson_mut_val* cores = yyjson_mut_obj_add_obj(doc, obj, "cores"); yyjson_mut_obj_add_uint(doc, cores, "physical", cpu.coresPhysical); @@ -248,6 +253,7 @@ void ffPrintCPUHelpFormat(void) "Max frequency (formatted) - freq-max", "Temperature (formatted) - temperature", "Logical core count grouped by frequency - core-types", + "Processor package count - packages", })); } From 69a7e64e48e13736a8d56718eb3a6bed1e7aaa1e Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 26 Nov 2024 21:49:28 +0800 Subject: [PATCH 37/48] CPU (Linux): support up to 128-socket boards --- src/detection/cpu/cpu_linux.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index e90663d521..326d28e6f1 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -467,19 +467,22 @@ FF_MAYBE_UNUSED static void detectArmSoc(FFCPUResult* cpu) FF_MAYBE_UNUSED static uint16_t getPackageCount(FFstrbuf* cpuinfo) { const char* p = cpuinfo->chars; - uint64_t bits = 0; + uint64_t low = 0, high = 0; while ((p = memmem(p, cpuinfo->length - (uint32_t) (p - cpuinfo->chars), "\nphysical id\t:", strlen("\nphysical id\t:")))) { if (!p) break; p += strlen("\nphysical id\t:"); char* pend; - uint32_t id = (uint32_t) strtoul(p, &pend, 10); + unsigned long id = strtoul(p, &pend, 10); + if (__builtin_expect(id > 64, false)) // Do 129-socket boards exist? + high |= 1 << (id - 64); + else + low |= 1 << id; p = pend; - bits |= 1 << id; } - return (uint16_t) __builtin_popcountll(bits); + return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high)); } const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu) From 90bbefe11aa10f8527c61055948075f2c54b5df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Tue, 26 Nov 2024 22:02:57 +0800 Subject: [PATCH 38/48] CPU (Windows): code cleanup --- src/detection/cpu/cpu_windows.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 411571010e..09f422e128 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -100,9 +100,7 @@ static const char* detectNCores(FFCPUResult* cpu) ptr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)(((uint8_t*)ptr) + ptr->Size) ) { - if (ptr->Relationship == RelationProcessorCore) - ++cpu->coresPhysical; - else if (ptr->Relationship == RelationGroup) + if (ptr->Relationship == RelationGroup) { for (uint32_t index = 0; index < ptr->Group.ActiveGroupCount; ++index) { @@ -110,10 +108,10 @@ static const char* detectNCores(FFCPUResult* cpu) cpu->coresLogical += ptr->Group.GroupInfo[index].MaximumProcessorCount; } } - - if (ptr->Relationship == RelationProcessorPackage) { + else if (ptr->Relationship == RelationProcessorCore) + ++cpu->coresPhysical; + else if (ptr->Relationship == RelationProcessorPackage) cpu->packages++; - } } return NULL; From 77c06193d69f00b4f4528e93fa95cef8720efa3e Mon Sep 17 00:00:00 2001 From: Carter Li Date: Thu, 28 Nov 2024 21:28:35 +0800 Subject: [PATCH 39/48] GPU (Linux): detect GPU NV type --- src/detection/gpu/gpu_linux.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index bf9cc1add4..f67a9cf60e 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -536,27 +536,27 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf .name = &gpu->name, }, soName); } - - if (gpu->type == FF_GPU_TYPE_UNKNOWN) - { - if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) - { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || - ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) - gpu->type = FF_GPU_TYPE_DISCRETE; - } - else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) - { - if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) - gpu->type = FF_GPU_TYPE_DISCRETE; - } - } } if (gpu->name.length == 0) ffGPUFillVendorAndName(subclassId, (uint16_t) vendorId, (uint16_t) deviceId, gpu); + if (gpu->type == FF_GPU_TYPE_UNKNOWN) + { + if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA) + { + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "GeForce") || + ffStrbufStartsWithIgnCaseS(&gpu->name, "Quadro") || + ffStrbufStartsWithIgnCaseS(&gpu->name, "Tesla")) + gpu->type = FF_GPU_TYPE_DISCRETE; + } + else if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_MTHREADS) + { + if (ffStrbufStartsWithIgnCaseS(&gpu->name, "MTT ")) + gpu->type = FF_GPU_TYPE_DISCRETE; + } + } + return NULL; } From bbe239647b22e442cb7dd85d263c59578f79fab5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Thu, 28 Nov 2024 21:55:02 +0800 Subject: [PATCH 40/48] Logo (Builtin): add Windows Server 2025 Fix #1420 --- .../displayserver/displayserver_windows.c | 33 +++++++++++-------- src/logo/ascii/windows_2025.txt | 17 ++++++++++ src/logo/builtin.c | 13 ++++++++ 3 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 src/logo/ascii/windows_2025.txt diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index a25764ca48..95f435cc94 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -236,19 +236,24 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) //https://github.com/hykilpikonna/hyfetch/blob/master/neofetch#L2067 const FFOSResult* os = ffDetectOS(); - if( - ffStrbufEqualS(&os->version, "11") || - ffStrbufEqualS(&os->version, "10") || - ffStrbufEqualS(&os->version, "2022") || - ffStrbufEqualS(&os->version, "2019") || - ffStrbufEqualS(&os->version, "2016") - ) ffStrbufSetStatic(&ds->dePrettyName, "Fluent"); - else if( - ffStrbufEqualS(&os->version, "8") || - ffStrbufEqualS(&os->version, "8.1") || - ffStrbufEqualS(&os->version, "2012 R2") || - ffStrbufEqualS(&os->version, "2012") - ) ffStrbufSetStatic(&ds->dePrettyName, "Metro"); + uint32_t ver = (uint32_t) ffStrbufToUInt(&os->version, 0); + if (ver > 1000) + { + // Windows Server + if (ver >= 2016) + ffStrbufSetStatic(&ds->dePrettyName, "Fluent"); + else if (ver >= 2012) + ffStrbufSetStatic(&ds->dePrettyName, "Metro"); + else + ffStrbufSetStatic(&ds->dePrettyName, "Aero"); + } else - ffStrbufSetStatic(&ds->dePrettyName, "Aero"); + { + if (ver >= 10) + ffStrbufSetStatic(&ds->dePrettyName, "Fluent"); + else if (ver >= 8) + ffStrbufSetStatic(&ds->dePrettyName, "Metro"); + else + ffStrbufSetStatic(&ds->dePrettyName, "Aero"); + } } diff --git a/src/logo/ascii/windows_2025.txt b/src/logo/ascii/windows_2025.txt new file mode 100644 index 0000000000..1c02084e78 --- /dev/null +++ b/src/logo/ascii/windows_2025.txt @@ -0,0 +1,17 @@ +$1 ##%%%%%%%%% $2%%%%%%%%%## +$1 ###%%%%%%%%%% $2%%%%%%%%%%### +$1 ####%%%%%%%%%%% $2%%%%%%%%%%%#### +$1 ##%%%%%%%%%%%%%% $2%%%%%%%%%%%%%%## +$1#%%%%%%%%%%%%%%%% $2%%%%%%%%%%%%%%%%# +$1%%%%%%%%%%%%%%%%% $2%%%%%%%%%%%%%%%%% +$1%%%%%%%%%%%%%%%%% $2%%%%%%%%%%%%%%%%% +$1%%%%%%%%%%%%%%%%% $2#%%%%%%%%%%%%%%%% + +$3%%%%%%%%%%%%%%%%% $4#%%%%%%%%%%%%%%%% +$3%%%%%%%%%%%%%%%%% $4%%%%%%%%%%%%%%%%% +$3%%%%%%%%%%%%%%%%% $4%%%%%%%%%%%%%%%%% +$3%%%%%%%%%%%%%%%%% $4%%%%%%%%%%%%%%%%# +$3 ###%%%%%%%%%%%%% $4%%%%%%%%%%%%%%%## +$3 ####%%%%%%%%%%% $4%%%%%%%%%%%#%#### +$3 ##%#%%%%%%%%% $4%%%%%%%%%%%###### +$3 ##%%%%%%%%% $4%%%%%%%%%######## \ No newline at end of file diff --git a/src/logo/builtin.c b/src/logo/builtin.c index 60f874dce5..c0e8670095 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -4820,6 +4820,19 @@ static const FFlogo W[] = { FF_COLOR_FG_WHITE, }, }, + // Windows2025 + { + .names = {"Windows Server 2025"}, + .lines = FASTFETCH_DATATEXT_LOGO_WINDOWS_2025, + .colors = { + FF_COLOR_FG_BLUE, + FF_COLOR_FG_BLUE, + FF_COLOR_FG_BLUE, + FF_COLOR_FG_BLUE, + }, + .colorKeys = FF_COLOR_FG_YELLOW, + .colorTitle = FF_COLOR_FG_CYAN, + }, // Windows11 { .names = {"Windows 11", "Windows Server 2022"}, From ee8801b54d526cf79188b4aed40d97e5f783822b Mon Sep 17 00:00:00 2001 From: Ryan Date: Thu, 28 Nov 2024 19:34:40 -0500 Subject: [PATCH 41/48] WM (Linux): fix wl-restart parsing (#1422) Make the WM name in `wl-restart -n 5 Hyprland` parse as "Hyprland" instead of "-n". --- src/detection/displayserver/linux/wayland/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detection/displayserver/linux/wayland/wayland.c b/src/detection/displayserver/linux/wayland/wayland.c index e4b387a517..d09eb06f98 100644 --- a/src/detection/displayserver/linux/wayland/wayland.c +++ b/src/detection/displayserver/linux/wayland/wayland.c @@ -39,7 +39,7 @@ static bool waylandDetectWM(int fd, FFDisplayServerResult* result) filename = result->wmProcessName.chars; if (ffStrEquals(filename, "wl-restart")) - ffStrbufSubstrAfterFirstC(&result->wmProcessName, '\0'); + ffStrbufSubstrAfterLastC(&result->wmProcessName, '\0'); ffStrbufSubstrBeforeFirstC(&result->wmProcessName, '\0'); //Trim the arguments ffStrbufSubstrAfterLastC(&result->wmProcessName, '/'); //Trim the path From 3004ce8565859457803720481a1b65cbfa57e13a Mon Sep 17 00:00:00 2001 From: Raymond Kemboi <113639995+Kemboiray@users.noreply.github.com> Date: Fri, 29 Nov 2024 05:25:58 +0300 Subject: [PATCH 42/48] Completion (Zsh): fix syntax error in completion file (#1421) A syntax error in the file caused the following output when trying to trigger completions in `zsh` (pressing ): ```zsh $ fastfetch File "", line 15 command_prefix = f"--logo-color-{i}[{flag["desc"]} ({i})]" ^^^^ SyntaxError: f-string: unmatched '[' ``` This fix replaces single quotes with double quotes in the f-strings in lines 37 and 41. --- completions/fastfetch.zsh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/completions/fastfetch.zsh b/completions/fastfetch.zsh index 5688c17458..08b92c90f2 100644 --- a/completions/fastfetch.zsh +++ b/completions/fastfetch.zsh @@ -26,7 +26,7 @@ def main(): for flag in data[key]: if flag["long"] == "logo-color-[1-9]": for i in range(1, 10): - command_prefix = f"--logo-color-{i}[{flag["desc"]} ({i})]" + command_prefix = f"--logo-color-{i}[{flag['desc']} ({i})]" print_command(command_prefix, flag) continue @@ -34,11 +34,11 @@ def main(): continue if "short" in flag: - command_prefix = f"-{flag["short"]}[{flag["desc"]}]" + command_prefix = f"-{flag['short']}[{flag['desc']}]" print_command(command_prefix, flag) if "long" in flag: - command_prefix = f"--{flag["long"]}[{flag["desc"]}]" + command_prefix = f"--{flag['long']}[{flag['desc']}]" print_command(command_prefix, flag) From 692ad502df5ff7aca23c00d22005ea4794134ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Sat, 30 Nov 2024 23:50:06 +0800 Subject: [PATCH 43/48] Wifi (Windows): make unit of bitrates be consistant Also fix a copy & paste bug --- src/detection/wifi/wifi_windows.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/detection/wifi/wifi_windows.c b/src/detection/wifi/wifi_windows.c index ac434e8d96..f3128a9d10 100644 --- a/src/detection/wifi/wifi_windows.c +++ b/src/detection/wifi/wifi_windows.c @@ -154,8 +154,8 @@ const char* ffDetectWifi(FFlist* result) } item->conn.signalQuality = connInfo->wlanAssociationAttributes.wlanSignalQuality; - item->conn.rxRate = connInfo->wlanAssociationAttributes.ulRxRate; - item->conn.txRate = connInfo->wlanAssociationAttributes.ulTxRate; + item->conn.rxRate = connInfo->wlanAssociationAttributes.ulRxRate / 1000.; + item->conn.txRate = connInfo->wlanAssociationAttributes.ulTxRate / 1000.; if(connInfo->wlanSecurityAttributes.bSecurityEnabled) { @@ -192,7 +192,7 @@ const char* ffDetectWifi(FFlist* result) ffStrbufAppendS(&item->conn.security, "OWE"); break; case 11 /* DOT11_AUTH_ALGO_WPA3_ENT */: - ffStrbufAppendS(&item->conn.security, "OWE-ENT"); + ffStrbufAppendS(&item->conn.security, "WPA3-ENT"); break; default: ffStrbufAppendF(&item->conn.security, "Unknown (%u)", (unsigned)connInfo->wlanSecurityAttributes.dot11AuthAlgorithm); From f073f4882ccb64027b8cf40762583560529f5100 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Sun, 1 Dec 2024 18:16:05 +0800 Subject: [PATCH 44/48] Wifi (Linux): detect Wifi-7 --- src/detection/wifi/wifi_linux.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index 9e2158c09b..6267db134c 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -229,7 +229,9 @@ static const char* detectWifiWithIw(FFWifiResult* item, FFstrbuf* buffer) { item->conn.txRate = ffStrbufToDouble(buffer); - if(ffStrbufContainS(buffer, " HE-MCS ")) + if(ffStrbufContainS(buffer, " EHT-MCS ")) + ffStrbufSetStatic(&item->conn.protocol, "802.11be (Wi-Fi 7)"); + else if(ffStrbufContainS(buffer, " HE-MCS ")) ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)"); else if(ffStrbufContainS(buffer, " VHT-MCS ")) ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)"); From e9ab67b380734d5c9527376b0b5e38b90bf37b97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Mon, 2 Dec 2024 15:54:59 +0800 Subject: [PATCH 45/48] Processing (Linux): interrupt poll & read syscalls when the child process is exited Fix #1418 --- src/common/init.c | 11 +++++++---- src/common/processing_linux.c | 22 ++++++++++++++++++---- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/common/init.c b/src/common/init.c index 2cdce8df45..d6adc13428 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -76,19 +76,21 @@ static void resetConsole(void) } #ifdef _WIN32 -BOOL WINAPI consoleHandler(DWORD signal) +BOOL WINAPI consoleHandler(FF_MAYBE_UNUSED DWORD signal) { - FF_UNUSED(signal); resetConsole(); exit(0); } #else -static void exitSignalHandler(int signal) +static void exitSignalHandler(FF_MAYBE_UNUSED int signal) { - FF_UNUSED(signal); resetConsole(); exit(0); } +static void chldSignalHandler(FF_MAYBE_UNUSED int signal) +{ + // empty; used to interrupt the poll and read syscalls +} #endif void ffStart(void) @@ -118,6 +120,7 @@ void ffStart(void) sigaction(SIGINT, &action, NULL); sigaction(SIGTERM, &action, NULL); sigaction(SIGQUIT, &action, NULL); + sigaction(SIGCHLD, &(struct sigaction) { .sa_handler = chldSignalHandler }, NULL); #endif //reset everything to default before we start printing diff --git a/src/common/processing_linux.c b/src/common/processing_linux.c index 3b290bc3d4..63d3951147 100644 --- a/src/common/processing_linux.c +++ b/src/common/processing_linux.c @@ -1,7 +1,6 @@ #include "fastfetch.h" #include "common/processing.h" #include "common/io/io.h" -#include "common/time.h" #include "util/stringUtils.h" #include "util/mallocHelper.h" @@ -90,6 +89,16 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use waitpid(childPid, NULL, 0); return "poll(&pollfd, 1, timeout) timeout (try increasing --processing-timeout)"; } + else if (errno == EINTR) + { + // The child process has been terminated. See `chldSignalHandler` in `common/init.c` + if (waitpid(childPid, NULL, WNOHANG) == childPid) + { + // Read remaining data from the pipe + fcntl(childPipeFd, F_SETFL, O_CLOEXEC | O_NONBLOCK); + childPid = -1; + } + } else if (pollfd.revents & POLLERR) { kill(childPid, SIGTERM); @@ -104,7 +113,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use else if (nRead == 0) { int stat_loc = 0; - if (waitpid(childPid, &stat_loc, 0) == childPid) + if (childPid > 0 && waitpid(childPid, &stat_loc, 0) == childPid) { if (!WIFEXITED(stat_loc)) return "child process exited abnormally"; @@ -113,10 +122,15 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use // We only handle 127 as an error. See `getTerminalVersionUrxvt` in `terminalshell.c` return NULL; } - return "waitpid() failed"; + return NULL; } else if (nRead < 0) - break; + { + if (errno == EAGAIN) + return NULL; + else + break; + } }; return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed"; From dfe36daf79183d40f80039178b528f953fdd2f30 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 2 Dec 2024 16:34:43 +0800 Subject: [PATCH 46/48] Release: v2.31.0 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ CMakeLists.txt | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5391125bc1..73f3386e1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +# 2.31.0 + +Bugfixes: +* Improve performance of media detection; fix musikcube detection (Media, Linux) + * After the change, `general.processingTimeout` will also control the timeout of dbus remote calls +* Fix invalid variable names (#1408, Users) +* Change physical size detection to use basic display parameters (#1406) +* Fix possible sigfaults when detecting displays (#1393) +* Fix Nvidia card type detection +* Fix wl-restart parsing (#1422, WM, Linux) +* Fix syntax error in completion file (#1421) +* Fix hunging when using `ssh-agent` as command text (#1418, Command, macOS) + +Features: +* Remove support of xcb & xlib and xrandr extension is always required (Display) +* Support preferred resolution & refresh rate detection + * On macOS there is no preferred resolution reported and maximum available resolution is reported instead. + * `--display-format {preferred-width}x{preferred-height}@{preferred-refresh-rate}` +* Report scale factor in custom format (Display) + * `--display-format {scale-factor}` +* Detect current Wi-Fi channel and maximum frequency (Wifi) +* Report processor package count (#1413, CPU) +* Remove duplicate whitespaces in CPU name + +Logo: +* Fix LMDE +* Update MidOS +* Add Windows Server 2025 + # 2.30.1 Bugfixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index d6fa6c3aad..12041866ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.30.1 + VERSION 2.31.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" From ab200d7e4af185fabf9d9155f3ef23aed741ff71 Mon Sep 17 00:00:00 2001 From: Carter Li Date: Mon, 2 Dec 2024 19:09:27 +0800 Subject: [PATCH 47/48] Terminal: Support sakura version & font detection Fix #1424 --- CHANGELOG.md | 1 + src/detection/terminalfont/terminalfont_linux.c | 2 ++ src/detection/terminalshell/terminalshell.c | 16 ++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73f3386e1c..c27b86326c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Features: * Detect current Wi-Fi channel and maximum frequency (Wifi) * Report processor package count (#1413, CPU) * Remove duplicate whitespaces in CPU name +* Support sakura terminal version & font detection (Terminal / TerminalFont, Linux) Logo: * Fix LMDE diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index 5cdc6bb749..2c0ecd28b0 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -454,4 +454,6 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo detectWestonTerminal(terminalFont); else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "terminator")) detectTerminator(terminalFont); + else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "sakura")) + detectFromConfigFile("sakura/sakura.conf", "font=", terminalFont);; } diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index 7ce6854a5e..ebacb444f0 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -661,6 +661,19 @@ FF_MAYBE_UNUSED static bool getTerminalVersionTilix(FFstrbuf* exe, FFstrbuf* ver ffStrbufSubstrAfter(version, index); return true; } + +FF_MAYBE_UNUSED static bool getTerminalVersionSakura(FFstrbuf* exe, FFstrbuf* version) +{ + if(ffProcessAppendStdErr(version, (char* const[]) { + exe->chars, + "--version", + NULL + }) != NULL) // sakura version is 3.8.8 + return false; + + ffStrbufSubstrAfterLastC(version, ' '); + return true; +} #endif #ifdef _WIN32 @@ -763,6 +776,9 @@ bool fftsGetTerminalVersion(FFstrbuf* processName, FF_MAYBE_UNUSED FFstrbuf* exe if(ffStrbufIgnCaseEqualS(processName, "tilix")) return getTerminalVersionTilix(exe, version); + if(ffStrbufIgnCaseEqualS(processName, "sakura")) + return getTerminalVersionSakura(exe, version); + #endif #ifdef _WIN32 From 6edf763f2bc45a50b5f051211b73bde24e2a3d5e Mon Sep 17 00:00:00 2001 From: Carter Li Date: Tue, 3 Dec 2024 10:55:00 +0800 Subject: [PATCH 48/48] Display (Linux): detect bit depth when libdrm is used --- src/detection/displayserver/linux/drm.c | 32 +++++++++++++++++-------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/detection/displayserver/linux/drm.c b/src/detection/displayserver/linux/drm.c index 959358a168..1fe274b479 100644 --- a/src/detection/displayserver/linux/drm.c +++ b/src/detection/displayserver/linux/drm.c @@ -220,12 +220,14 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetConnectorCurrent) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetCrtc) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetEncoder) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetFB) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetProperty) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeGetPropertyBlob) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeResources) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeCrtc) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeEncoder) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeConnector) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeEncoder) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeFB) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreeProperty) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmModeFreePropertyBlob) FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libdrm, drmFreeDevices) @@ -254,28 +256,29 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) continue; #endif - FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY | O_CLOEXEC); - if (fd < 0) + FF_AUTO_CLOSE_FD int primaryFd = open(path, O_RDWR | O_CLOEXEC); + if (primaryFd < 0) continue; - drmModeRes* res = ffdrmModeGetResources(fd); + drmModeRes* res = ffdrmModeGetResources(primaryFd); if (!res) continue; for (int iConn = 0; iConn < res->count_connectors; ++iConn) { - drmModeConnector* conn = ffdrmModeGetConnectorCurrent(fd, res->connectors[iConn]); + drmModeConnector* conn = ffdrmModeGetConnectorCurrent(primaryFd, res->connectors[iConn]); if (!conn) continue; if (conn->connection != DRM_MODE_DISCONNECTED) { - drmModeEncoder* encoder = ffdrmModeGetEncoder(fd, conn->encoder_id); + drmModeEncoder* encoder = ffdrmModeGetEncoder(primaryFd, conn->encoder_id); uint32_t width = 0, height = 0, refreshRate = 0; + uint8_t bitDepth = 0; if (encoder) { - drmModeCrtc* crtc = ffdrmModeGetCrtc(fd, encoder->crtc_id); + drmModeCrtc* crtc = ffdrmModeGetCrtc(primaryFd, encoder->crtc_id); if (crtc) { width = crtc->mode.hdisplay; @@ -294,6 +297,14 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) } } } + + drmModeFBPtr fb = ffdrmModeGetFB(primaryFd, crtc->buffer_id); + if (fb) + { + bitDepth = (uint8_t) (fb->depth / 3); + ffdrmModeFreeFB(fb); + } + ffdrmModeFreeCrtc(crtc); } @@ -332,7 +343,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) for (int iProp = 0; iProp < conn->count_props; ++iProp) { - drmModePropertyRes *prop = ffdrmModeGetProperty(fd, conn->props[iProp]); + drmModePropertyRes *prop = ffdrmModeGetProperty(primaryFd, conn->props[iProp]); if (!prop) continue; @@ -342,9 +353,9 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) drmModePropertyBlobPtr blob = NULL; if (prop->count_blobs > 0 && prop->blob_ids != NULL) - blob = ffdrmModeGetPropertyBlob(fd, prop->blob_ids[0]); + blob = ffdrmModeGetPropertyBlob(primaryFd, prop->blob_ids[0]); else - blob = ffdrmModeGetPropertyBlob(fd, (uint32_t) conn->prop_values[iProp]); + blob = ffdrmModeGetPropertyBlob(primaryFd, (uint32_t) conn->prop_values[iProp]); if (blob) { @@ -412,6 +423,7 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) item->serial = serial; item->manufactureYear = myear; item->manufactureWeek = mweak; + item->bitDepth = bitDepth; } }