mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d0d9831d41 | |||
| b3945e277c | |||
| 9f77851176 | |||
| 963eaa5395 | |||
| 07dfe57386 | |||
| a3c0085e2b | |||
| c8f28e4c79 | |||
| 861eea5899 | |||
| 1227799a38 | |||
| 35d1497053 | |||
| ea3734f004 | |||
| 5d35dade60 | |||
| 0c844fc342 | |||
| c1ed0a4e91 | |||
| e1af6fc0fe | |||
| c1d41a36bb | |||
| 958bde228b | |||
| 6655c446ba | |||
| 43657e8fd6 | |||
| 38f216291e | |||
| 01de158bba | |||
| 5a34b8d01f | |||
| afa0a7dac8 | |||
| 974ee2ab0d | |||
| ab1e3db665 | |||
| 95b64622c4 | |||
| d3c7529c45 | |||
| 89db425a03 | |||
| 269ad36df5 | |||
| 22cdb1247f | |||
| 905ed76ddd | |||
| 6da57d64c3 | |||
| 37e0a7b03f | |||
| 0c65cdc1f5 | |||
| 653e689f18 | |||
| a8aaf605b1 | |||
| 5f638a67ed | |||
| 0645f559af | |||
| f5a57ab747 | |||
| 92e05f7e38 | |||
| 8ba031b761 | |||
| fdb68669f4 | |||
| 12155e029b | |||
| 7926b74917 | |||
| 61af59fc00 | |||
| bc52613410 | |||
| f84bb1ebe2 | |||
| a160bc8de5 | |||
| cb599c6f2a | |||
| 5693700c16 | |||
| e8c067ff3d | |||
| 80cc4e3f4a | |||
| 8e78fadbeb | |||
| 1215eb06ca | |||
| 2aa899d83c | |||
| cf096eb101 | |||
| 5b4a26393d | |||
| 2ba878cbab | |||
| 0af40ab6a3 | |||
| b9777bec77 | |||
| 8801921d02 | |||
| c0c32456e8 | |||
| 640fa146c1 | |||
| de91429e1a | |||
| 1621484c96 | |||
| d8297d296e | |||
| 48bb82c8fb | |||
| c1c7f7b93f | |||
| 1d35811253 | |||
| fe0b43d92d | |||
| 446fe907d2 | |||
| d578f1006c | |||
| 33f3199383 | |||
| 21f3875c4f | |||
| 6bcd75835e | |||
| 24cec76251 | |||
| f8ac56691f | |||
| 810112cb26 | |||
| 2340c2afd7 | |||
| b6c8649cbf | |||
| 92a6b01133 | |||
| 396112e8ea | |||
| 5eacd0bb8e | |||
| ea3ea196aa | |||
| 0e6be69eb8 | |||
| d69e19377e | |||
| f4f466d4ba | |||
| 10b2fe13bd | |||
| b5dc4f59f1 | |||
| 7c0b743c61 | |||
| 6bd909c89d | |||
| 1fef41241a | |||
| 5c75e271ef | |||
| b6b1993f62 | |||
| cd0109c382 | |||
| 6698283430 | |||
| 83ce3e4554 | |||
| ff0f91dc3c | |||
| ab028964bf | |||
| 21353b8256 | |||
| 0a1de91a29 |
@@ -1,3 +1,32 @@
|
||||
# 2.6.0
|
||||
|
||||
Changes:
|
||||
* Remove support of option `--battery-dir`. We detect a lot of things in `/sys/class/*` and only module `Battery` supports specifying a custom directory for some reason, which is weird.
|
||||
* Remove `--chassis-use-wmi` which is no longer used.
|
||||
|
||||
Features:
|
||||
* Add `ENABLE_PROPRIETARY_GPU_DRIVER_API` cmake option to disable using of proprietary GPU driver APIs (GPU)
|
||||
* Support wallpaper detection for macOS Sonoma (Wallpaper, macOS)
|
||||
* Support power adapter detection for Asahi Linux (PowerAdapter, Linux)
|
||||
* Support battery serial number and manufacturer date detection (Battery)
|
||||
* Support host serial number and UUID detection (Host)
|
||||
* Support battery level detection for gamepads where possible (Gamepad)
|
||||
* Support maximum CPU clock detection. Previously base clock was printed (CPU, Windows)
|
||||
* Support manufacture date and serial number detection for physical monitors (Monitor)
|
||||
* Support ash (default shell of BusyBox) version detection (Shell, Linux)
|
||||
* Sound module in FreeBSD now uses native `ioctl`s. Pulseaudio dependency is no longer used.
|
||||
* Locale module in Windows now prints the same format as in Linux and other posix systems.
|
||||
|
||||
Bugfixes:
|
||||
* Fix overall memory leaks (macOS)
|
||||
* Remove trailing `\0` in JSON results (FreeBSD)
|
||||
* Fix physical monitor detection with Nvidia drivers (Monitor, Linux)
|
||||
* Don't print llvmpipe in vulkan module (Vulkan)
|
||||
* Fix system yyjson usage in `fastfetch.c`. Previously embedded `3rdparty/yyjson/yyjson.h` was used in `fastfetch.c` even if `ENABLE_SYSTEM_YYJSON` was set (CMake)
|
||||
* Fix locale module printing unexpected results in specific environments (Locale)
|
||||
* Fix battery temperature detection in Windows. Note only smart batteries report temperatures but few laptops uses smart battery (Battery, Windows)
|
||||
* Print device name if no backlight name is available, so we don't print empty parentheses (Brightness, FreeBSD)
|
||||
|
||||
# 2.5.0
|
||||
|
||||
Changes:
|
||||
|
||||
+44
-20
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.5.0
|
||||
VERSION 2.6.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -66,7 +66,7 @@ cmake_dependent_option(ENABLE_OSMESA "Enable osmesa" ON "LINUX OR BSD" OFF)
|
||||
cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" OFF)
|
||||
cmake_dependent_option(ENABLE_LIBNM "Enable libnm" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR BSD" OFF)
|
||||
cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF)
|
||||
cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" OFF)
|
||||
@@ -74,6 +74,7 @@ cmake_dependent_option(ENABLE_PCI_MEMORY "Enable detecting GPU memory size with
|
||||
|
||||
option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF)
|
||||
option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF)
|
||||
option(ENABLE_PROPRIETARY_GPU_DRIVER_API "Enable proprietary GPU driver API (NVML, IGCL and AGS)" ON)
|
||||
option(BUILD_TESTS "Build tests" OFF) # Also create test executables
|
||||
option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds
|
||||
|
||||
@@ -109,12 +110,8 @@ endif()
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--tsaware -Wl,--build-id -Wl,--subsystem,console:6.1,--major-os-version,6,--minor-os-version,1")
|
||||
endif()
|
||||
|
||||
# Used for dlopen finding dylibs installed by homebrew
|
||||
# `/opt/homebrew/lib` is not on in dlopen search path by default
|
||||
if(APPLE AND DEFINED ENV{HOMEBREW_PREFIX})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,$ENV{HOMEBREW_PREFIX}/lib")
|
||||
elseif(APPLE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-arc")
|
||||
endif()
|
||||
|
||||
set(FASTFETCH_FLAGS_DEBUG "-fno-omit-frame-pointer")
|
||||
@@ -290,7 +287,6 @@ set(LIBFASTFETCH_SRC
|
||||
src/detection/displayserver/displayserver.c
|
||||
src/detection/font/font.c
|
||||
src/detection/gpu/gpu.c
|
||||
src/detection/locale/locale.c
|
||||
src/detection/media/media.c
|
||||
src/detection/netio/netio.c
|
||||
src/detection/opencl/opencl.c
|
||||
@@ -374,7 +370,6 @@ set(LIBFASTFETCH_SRC
|
||||
src/util/FFlist.c
|
||||
src/util/FFstrbuf.c
|
||||
src/util/platform/FFPlatform.c
|
||||
src/util/stringUtils.c
|
||||
src/util/smbiosHelper.c
|
||||
)
|
||||
|
||||
@@ -405,12 +400,12 @@ if(LINUX)
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_linux.c
|
||||
src/detection/gpu/gpu_nvidia.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_linux.c
|
||||
src/detection/icons/icons_linux.c
|
||||
src/detection/libc/libc_linux.c
|
||||
src/detection/lm/lm_linux.c
|
||||
src/detection/locale/locale_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
src/detection/gamepad/gamepad_linux.c
|
||||
src/detection/media/media_linux.c
|
||||
@@ -420,7 +415,7 @@ if(LINUX)
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_linux.c
|
||||
src/detection/packages/packages_linux.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/poweradapter/poweradapter_linux.c
|
||||
src/detection/processes/processes_linux.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
src/detection/sound/sound_linux.c
|
||||
@@ -464,6 +459,7 @@ elseif(ANDROID)
|
||||
src/detection/icons/icons_nosupport.c
|
||||
src/detection/libc/libc_android.c
|
||||
src/detection/lm/lm_nosupport.c
|
||||
src/detection/locale/locale_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
src/detection/gamepad/gamepad_nosupport.c
|
||||
src/detection/media/media_nosupport.c
|
||||
@@ -519,12 +515,12 @@ elseif(BSD)
|
||||
src/detection/displayserver/linux/xlib.c
|
||||
src/detection/font/font_linux.c
|
||||
src/detection/gpu/gpu_linux.c
|
||||
src/detection/gpu/gpu_nvidia.c
|
||||
src/detection/gtk_qt/gtk.c
|
||||
src/detection/host/host_bsd.c
|
||||
src/detection/lm/lm_linux.c
|
||||
src/detection/icons/icons_linux.c
|
||||
src/detection/libc/libc_bsd.c
|
||||
src/detection/locale/locale_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
src/detection/gamepad/gamepad_bsd.c
|
||||
src/detection/media/media_linux.c
|
||||
@@ -537,7 +533,7 @@ elseif(BSD)
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_bsd.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
src/detection/sound/sound_linux.c
|
||||
src/detection/sound/sound_bsd.c
|
||||
src/detection/swap/swap_bsd.c
|
||||
src/detection/temps/temps_bsd.c
|
||||
src/detection/terminalfont/terminalfont_linux.c
|
||||
@@ -580,6 +576,7 @@ elseif(APPLE)
|
||||
src/detection/lm/lm_nosupport.c
|
||||
src/detection/icons/icons_nosupport.c
|
||||
src/detection/libc/libc_apple.c
|
||||
src/detection/locale/locale_linux.c
|
||||
src/detection/localip/localip_linux.c
|
||||
src/detection/gamepad/gamepad_apple.c
|
||||
src/detection/media/media_apple.m
|
||||
@@ -600,7 +597,7 @@ elseif(APPLE)
|
||||
src/detection/theme/theme_nosupport.c
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_apple.c
|
||||
src/detection/wallpaper/wallpaper_apple.m
|
||||
src/detection/wifi/wifi_apple.m
|
||||
src/detection/wm/wm_apple.c
|
||||
src/detection/de/de_nosupport.c
|
||||
@@ -620,7 +617,7 @@ elseif(WIN32)
|
||||
src/detection/bluetooth/bluetooth_windows.c
|
||||
src/detection/board/board_windows.c
|
||||
src/detection/brightness/brightness_windows.cpp
|
||||
src/detection/chassis/chassis_windows.cpp
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/cpu/cpu_windows.c
|
||||
src/detection/cpuusage/cpuusage_windows.c
|
||||
src/detection/cursor/cursor_windows.c
|
||||
@@ -630,13 +627,11 @@ elseif(WIN32)
|
||||
src/detection/displayserver/displayserver_windows.c
|
||||
src/detection/font/font_windows.c
|
||||
src/detection/gpu/gpu_windows.c
|
||||
src/detection/gpu/gpu_nvidia.c
|
||||
src/detection/gpu/gpu_intel.c
|
||||
src/detection/gpu/gpu_amd.c
|
||||
src/detection/host/host_windows.c
|
||||
src/detection/icons/icons_windows.c
|
||||
src/detection/libc/libc_windows.cpp
|
||||
src/detection/lm/lm_nosupport.c
|
||||
src/detection/locale/locale_windows.c
|
||||
src/detection/localip/localip_windows.c
|
||||
src/detection/gamepad/gamepad_windows.c
|
||||
src/detection/media/media_nosupport.c
|
||||
@@ -676,6 +671,17 @@ if(ENABLE_DIRECTX_HEADERS)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_wsl.cpp)
|
||||
endif()
|
||||
|
||||
if(ENABLE_PROPRIETARY_GPU_DRIVER_API AND (LINUX OR BSD OR WIN32))
|
||||
message(STATUS "Enabling proprietary GPU driver API")
|
||||
if(LINUX OR BSD OR WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_nvidia.c)
|
||||
endif()
|
||||
if(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_intel.c)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_amd.c)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(wcwidth HAVE_WCWIDTH)
|
||||
if(NOT HAVE_WCWIDTH)
|
||||
@@ -699,9 +705,20 @@ add_library(libfastfetch OBJECT
|
||||
${LIBFASTFETCH_SRC}
|
||||
)
|
||||
|
||||
if(ENABLE_PROPRIETARY_GPU_DRIVER_API AND (LINUX OR BSD OR WIN32))
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_USE_PROPRIETARY_GPU_DRIVER_API)
|
||||
endif()
|
||||
|
||||
if(yyjson_FOUND)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_USE_SYSTEM_YYJSON)
|
||||
target_link_libraries(libfastfetch PRIVATE yyjson)
|
||||
target_link_libraries(libfastfetch PRIVATE yyjson::yyjson)
|
||||
# `target_link_libraries(yyjson::yyjson)` sets rpath implicitly
|
||||
else()
|
||||
# Used for dlopen finding dylibs installed by homebrew
|
||||
# `/opt/homebrew/lib` is not on in dlopen search path by default
|
||||
if(APPLE AND DEFINED ENV{HOMEBREW_PREFIX})
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,$ENV{HOMEBREW_PREFIX}/lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(LINUX AND EXISTS "/lib/ld-musl-${CMAKE_HOST_SYSTEM_PROCESSOR}.so.1")
|
||||
@@ -993,6 +1010,13 @@ set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "")
|
||||
set_target_properties(fastfetch PROPERTIES LINKER_LANGUAGE C)
|
||||
set_target_properties(flashfetch PROPERTIES LINKER_LANGUAGE C)
|
||||
|
||||
if(yyjson_FOUND)
|
||||
target_compile_definitions(fastfetch PRIVATE FF_USE_SYSTEM_YYJSON)
|
||||
target_link_libraries(fastfetch PRIVATE yyjson::yyjson)
|
||||
target_compile_definitions(flashfetch PRIVATE FF_USE_SYSTEM_YYJSON)
|
||||
target_link_libraries(flashfetch PRIVATE yyjson::yyjson)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
set(TARGET_NAME fastfetch)
|
||||
target_sources(fastfetch
|
||||
|
||||
@@ -384,7 +384,6 @@ __fastfetch_completion()
|
||||
"--lib-pulse"
|
||||
"--lib-ddcutil"
|
||||
"--lib-nm"
|
||||
"--battery-dir"
|
||||
)
|
||||
|
||||
local FF_OPTIONS_LOGO=(
|
||||
|
||||
@@ -804,10 +804,6 @@
|
||||
"const": "battery",
|
||||
"description": "Print battery capacity, status, etc"
|
||||
},
|
||||
"dir": {
|
||||
"description": "The directory where the battery folders are. Standard: `/sys/class/power_supply/`. Linux only",
|
||||
"type": "string"
|
||||
},
|
||||
"useSetupApi": {
|
||||
"description": "Set if `SetupAPI` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only",
|
||||
"type": "boolean",
|
||||
@@ -883,11 +879,6 @@
|
||||
"const": "chassis",
|
||||
"description": "Print chassis type (desktop, laptop, etc)"
|
||||
},
|
||||
"useWmi": {
|
||||
"description": "Set if WMI query should be used on Windows, which detects more information but slower",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
|
||||
@@ -244,6 +244,15 @@ void ffListFeatures(void)
|
||||
#ifdef FF_HAVE_DIRECTX_HEADERS
|
||||
"Directx Headers\n"
|
||||
#endif
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
"Proprietary GPU driver API\n"
|
||||
#endif
|
||||
#ifdef FF_USE_SYSTEM_YYJSON
|
||||
"System yyjson\n"
|
||||
#endif
|
||||
#ifdef FF_USE_PCI_MEMORY
|
||||
"PCI memory\n"
|
||||
#endif
|
||||
""
|
||||
, stdout);
|
||||
}
|
||||
|
||||
+1
-1
@@ -105,7 +105,7 @@ static inline bool ffPathExists(const char* path, FFPathType pathType)
|
||||
|
||||
unsigned int mode = fileStat.st_mode & S_IFMT;
|
||||
|
||||
if(pathType & FF_PATHTYPE_FILE && mode == S_IFREG)
|
||||
if(pathType & FF_PATHTYPE_FILE && mode != S_IFDIR)
|
||||
return true;
|
||||
|
||||
if(pathType & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR)
|
||||
|
||||
@@ -83,8 +83,7 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
|
||||
char str[FF_PIPE_BUFSIZ];
|
||||
DWORD nRead = 0;
|
||||
FF_AUTO_CLOSE_FD HANDLE hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
OVERLAPPED overlapped = { .hEvent = hEvent };
|
||||
OVERLAPPED overlapped = { };
|
||||
// ReadFile always completes synchronously if the pipe is not created with FILE_FLAG_OVERLAPPED
|
||||
do
|
||||
{
|
||||
@@ -93,11 +92,11 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use
|
||||
switch (GetLastError())
|
||||
{
|
||||
case ERROR_IO_PENDING:
|
||||
if (!timeout || WaitForSingleObject(hEvent, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
if (!timeout || WaitForSingleObject(hChildPipeRead, (DWORD) timeout) != WAIT_OBJECT_0)
|
||||
{
|
||||
CancelIo(hChildPipeRead);
|
||||
TerminateProcess(hProcess, 1);
|
||||
return "WaitForSingleObject(hEvent) failed or timeout";
|
||||
return "WaitForSingleObject(hChildPipeRead) failed or timeout";
|
||||
}
|
||||
|
||||
if (!GetOverlappedResult(hChildPipeRead, &overlapped, &nRead, FALSE))
|
||||
|
||||
@@ -411,9 +411,8 @@ bool ffSettingsGetFreeBSDKenv(const char* propName, FFstrbuf* result)
|
||||
//https://wiki.ghostbsd.org/index.php/Kenv
|
||||
ffStrbufEnsureFree(result, KENV_MVALLEN);
|
||||
int len = kenv(KENV_GET, propName, result->chars + result->length, KENV_MVALLEN);
|
||||
if (len <= 0) return false;
|
||||
result->length += (uint32_t) len;
|
||||
result->chars[result->length] = '\0';
|
||||
if (len <= 1) return false; // number of bytes copied, including NUL terminator
|
||||
result->length += (uint32_t) len - 1;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -842,16 +842,6 @@
|
||||
"default": "default"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "chassis-use-wmi",
|
||||
"desc": "Set if WMI query should be used on Windows",
|
||||
"remark": "WMI query detects more information but is slower. Windows only",
|
||||
"arg": {
|
||||
"type": "bool",
|
||||
"optional": true,
|
||||
"default": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "separator-string",
|
||||
"desc": "Set the string printed by the separator module",
|
||||
@@ -1026,15 +1016,6 @@
|
||||
"default": "main"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "battery-dir",
|
||||
"desc": "The directory where the battery folders are",
|
||||
"remark": "Linux only",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"default": "/sys/class/power_supply/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "battery-use-setup-api",
|
||||
"desc": "Set if \"SetupAPI\" should be used on Windows to detect battery info",
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
typedef struct FFBatteryResult
|
||||
{
|
||||
FFstrbuf manufacturer;
|
||||
FFstrbuf manufactureDate;
|
||||
FFstrbuf modelName;
|
||||
FFstrbuf technology;
|
||||
double capacity;
|
||||
FFstrbuf status;
|
||||
FFstrbuf serial;
|
||||
double capacity;
|
||||
double temperature;
|
||||
uint32_t cycleCount;
|
||||
} FFBatteryResult;
|
||||
|
||||
@@ -40,6 +40,7 @@ static const char* parseTermuxApi(FFBatteryOptions* options, FFlist* results)
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->status);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
|
||||
battery->capacity = yyjson_get_num(yyjson_obj_get(root, "percentage"));
|
||||
ffStrbufAppendS(&battery->status, yyjson_get_str(yyjson_obj_get(root, "status")));
|
||||
|
||||
@@ -4,49 +4,46 @@
|
||||
#include "detection/temps/temps_apple.h"
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/pwr_mgt/IOPM.h>
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
io_iterator_t iterator;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess)
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryBattery = registryEntry;
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
{
|
||||
IOObjectRelease(registryEntry);
|
||||
if (IORegistryEntryCreateCFProperties(entryBattery, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
continue;
|
||||
}
|
||||
|
||||
bool boolValue;
|
||||
const char* error;
|
||||
|
||||
FFBatteryResult* battery = ffListAdd(results);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->serial);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->status);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
battery->capacity = 0.0/0.0;
|
||||
|
||||
int currentCapacity, maxCapacity;
|
||||
|
||||
if ((error = ffCfDictGetInt(properties, CFSTR("MaxCapacity"), &maxCapacity)))
|
||||
return error;
|
||||
if (maxCapacity <= 0)
|
||||
return "Querying MaxCapacity failed";
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSMaxCapacityKey), &maxCapacity) != NULL || maxCapacity <= 0)
|
||||
continue;
|
||||
|
||||
if ((error = ffCfDictGetInt(properties, CFSTR("CurrentCapacity"), ¤tCapacity)))
|
||||
return error;
|
||||
if(currentCapacity <= 0)
|
||||
return "Querying CurrentCapacity failed";
|
||||
if (ffCfDictGetInt(properties, CFSTR(kIOPMPSCurrentCapacityKey), ¤tCapacity) != NULL || currentCapacity <= 0)
|
||||
continue;
|
||||
|
||||
battery->capacity = currentCapacity * 100.0 / maxCapacity;
|
||||
|
||||
ffCfDictGetString(properties, CFSTR("DeviceName"), &battery->modelName);
|
||||
ffCfDictGetString(properties, CFSTR(kIOPMDeviceNameKey), &battery->modelName);
|
||||
ffCfDictGetString(properties, CFSTR(kIOPMPSSerialKey), &battery->serial);
|
||||
|
||||
if (!ffCfDictGetBool(properties, CFSTR("built-in"), &boolValue) && boolValue)
|
||||
{
|
||||
@@ -57,33 +54,43 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
}
|
||||
|
||||
int32_t cycleCount = 0;
|
||||
ffCfDictGetInt(properties, CFSTR("CycleCount"), &cycleCount);
|
||||
ffCfDictGetInt(properties, CFSTR(kIOPMPSCycleCountKey), &cycleCount);
|
||||
battery->cycleCount = cycleCount < 0 ? 0 : (uint32_t) cycleCount;
|
||||
|
||||
if (!ffCfDictGetBool(properties, CFSTR("ExternalConnected"), &boolValue) && boolValue)
|
||||
if (!ffCfDictGetBool(properties, CFSTR(kIOPMPSExternalConnectedKey), &boolValue) && boolValue)
|
||||
ffStrbufAppendS(&battery->status, "AC connected, ");
|
||||
else
|
||||
ffStrbufAppendS(&battery->status, "Discharging, ");
|
||||
if (!ffCfDictGetBool(properties, CFSTR("IsCharging"), &boolValue) && boolValue)
|
||||
if (!ffCfDictGetBool(properties, CFSTR(kIOPMPSIsChargingKey), &boolValue) && boolValue)
|
||||
ffStrbufAppendS(&battery->status, "Charging, ");
|
||||
if (!ffCfDictGetBool(properties, CFSTR("AtCriticalLevel"), &boolValue) && boolValue)
|
||||
if (!ffCfDictGetBool(properties, CFSTR(kIOPMPSAtCriticalLevelKey), &boolValue) && boolValue)
|
||||
ffStrbufAppendS(&battery->status, "Critical, ");
|
||||
ffStrbufTrimRight(&battery->status, ' ');
|
||||
ffStrbufTrimRight(&battery->status, ',');
|
||||
|
||||
CFDictionaryRef batteryData;
|
||||
if (ffCfDictGetDict(properties, CFSTR("BatteryData"), &batteryData) == NULL)
|
||||
{
|
||||
char manufactureDate[sizeof(uint64_t)];
|
||||
if (ffCfDictGetInt64(batteryData, CFSTR(kIOPMPSManufactureDateKey), (int64_t*) manufactureDate) == NULL)
|
||||
{
|
||||
// https://github.com/AsahiLinux/linux/blob/b5c05cbffb0488c7618106926d522cc3b43d93d5/drivers/power/supply/macsmc_power.c#L410-L419
|
||||
int year = (manufactureDate[0] - '0') * 10 + (manufactureDate[1] - '0') + 2000 - 8;
|
||||
int month = (manufactureDate[2] - '0') * 10 + (manufactureDate[3] - '0');
|
||||
int day = (manufactureDate[4] - '0') * 10 + (manufactureDate[3] - '5');
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
}
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
int64_t temp;
|
||||
if (!ffCfDictGetInt64(properties, CFSTR("Temperature"), &temp))
|
||||
if (!ffCfDictGetInt64(properties, CFSTR(kIOPMPSBatteryTemperatureKey), &temp))
|
||||
battery->temperature = (double) temp / 10 - 273.15;
|
||||
else
|
||||
ffDetectSmcTemps(FF_TEMP_BATTERY, &battery->temperature);
|
||||
}
|
||||
|
||||
IOObjectRelease(registryEntry);
|
||||
}
|
||||
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ const char* ffDetectBattery(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* r
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->status);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->serial);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
|
||||
battery->capacity = battio.battinfo.cap;
|
||||
if(battio.battinfo.state == ACPI_BATT_STAT_INVALID)
|
||||
|
||||
@@ -9,106 +9,133 @@ static void parseBattery(FFstrbuf* dir, const char* id, FFBatteryOptions* option
|
||||
{
|
||||
uint32_t dirLength = dir->length;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY testBatteryBuffer = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate();
|
||||
|
||||
//type must exist and be "Battery"
|
||||
ffStrbufAppendS(dir, "/type");
|
||||
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
ffStrbufTrimRightSpace(&testBatteryBuffer);
|
||||
if (ffReadFileBuffer(dir->chars, &tmpBuffer))
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Battery") != 0)
|
||||
if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Battery"))
|
||||
return;
|
||||
|
||||
//scope may not exist or must not be "Device"
|
||||
ffStrbufAppendS(dir, "/scope");
|
||||
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
ffStrbufTrimRightSpace(&testBatteryBuffer);
|
||||
if (ffReadFileBuffer(dir->chars, &tmpBuffer))
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if(ffStrbufIgnCaseCompS(&testBatteryBuffer, "Device") == 0)
|
||||
if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device"))
|
||||
return;
|
||||
|
||||
FFBatteryResult* result = ffListAdd(results);
|
||||
|
||||
//capacity must exist and be not empty
|
||||
ffStrbufAppendS(dir, "/capacity");
|
||||
bool available = ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
bool available = ffReadFileBuffer(dir->chars, &tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if(available)
|
||||
result->capacity = ffStrbufToDouble(&testBatteryBuffer);
|
||||
|
||||
if(!available)
|
||||
{
|
||||
result->capacity = 0.0/0.0;
|
||||
--results->length;
|
||||
if (!available)
|
||||
return;
|
||||
}
|
||||
|
||||
FFBatteryResult* result = ffListAdd(results);
|
||||
result->capacity = ffStrbufToDouble(&tmpBuffer);
|
||||
|
||||
//At this point, we have a battery. Try to get as much values as possible.
|
||||
|
||||
ffStrbufInit(&result->manufacturer);
|
||||
ffStrbufAppendS(dir, "/manufacturer");
|
||||
ffReadFileBuffer(dir->chars, &result->manufacturer);
|
||||
ffStrbufTrimRightSpace(&result->manufacturer);
|
||||
if (ffReadFileBuffer(dir->chars, &result->manufacturer))
|
||||
ffStrbufTrimRightSpace(&result->manufacturer);
|
||||
else if (ffStrEquals(id, "macsmc-battery")) // asahi
|
||||
ffStrbufSetStatic(&result->manufacturer, "Apple Inc.");
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->modelName);
|
||||
ffStrbufAppendS(dir, "/model_name");
|
||||
ffReadFileBuffer(dir->chars, &result->modelName);
|
||||
ffStrbufTrimRightSpace(&result->modelName);
|
||||
if (ffReadFileBuffer(dir->chars, &result->modelName))
|
||||
ffStrbufTrimRightSpace(&result->modelName);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->technology);
|
||||
ffStrbufAppendS(dir, "/technology");
|
||||
ffReadFileBuffer(dir->chars, &result->technology);
|
||||
ffStrbufTrimRightSpace(&result->technology);
|
||||
if (ffReadFileBuffer(dir->chars, &result->technology))
|
||||
ffStrbufTrimRightSpace(&result->technology);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->status);
|
||||
ffStrbufAppendS(dir, "/status");
|
||||
ffReadFileBuffer(dir->chars, &result->status);
|
||||
ffStrbufTrimRightSpace(&result->status);
|
||||
if (ffReadFileBuffer(dir->chars, &result->status))
|
||||
ffStrbufTrimRightSpace(&result->status);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->serial);
|
||||
ffStrbufAppendS(dir, "/serial_number");
|
||||
if (ffReadFileBuffer(dir->chars, &result->serial))
|
||||
ffStrbufTrimRightSpace(&result->serial);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufAppendS(dir, "/cycle_count");
|
||||
ffReadFileBuffer(dir->chars, &testBatteryBuffer);
|
||||
ffStrbufTrimRightSpace(&testBatteryBuffer);
|
||||
available = ffReadFileBuffer(dir->chars, &tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if (dir->length)
|
||||
if (available)
|
||||
{
|
||||
int64_t cycleCount = 0;
|
||||
cycleCount = (int64_t) strtoll(testBatteryBuffer.chars, NULL, 10);
|
||||
int64_t cycleCount = ffStrbufToSInt(&tmpBuffer, 0);
|
||||
result->cycleCount = cycleCount < 0 || cycleCount > UINT32_MAX ? 0 : (uint32_t) cycleCount;
|
||||
}
|
||||
|
||||
ffStrbufInit(&result->manufactureDate);
|
||||
ffStrbufAppendS(dir, "/manufacture_year");
|
||||
available = ffReadFileBuffer(dir->chars, &tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if (available)
|
||||
{
|
||||
int year = (int) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (year > 0)
|
||||
{
|
||||
ffStrbufAppendS(dir, "/manufacture_month");
|
||||
available = ffReadFileBuffer(dir->chars, &tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if (available)
|
||||
{
|
||||
int month = (int) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (month > 0)
|
||||
{
|
||||
ffStrbufAppendS(dir, "/manufacture_day");
|
||||
available = ffReadFileBuffer(dir->chars, &tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
if (available)
|
||||
{
|
||||
int day = (int) ffStrbufToSInt(&tmpBuffer, 0);
|
||||
if (day > 0)
|
||||
{
|
||||
ffStrbufSetF(&result->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
const FFlist* tempsResult = ffDetectTemps();
|
||||
|
||||
FF_LIST_FOR_EACH(FFTempValue, value, *tempsResult)
|
||||
{
|
||||
if (ffStrbufEqualS(&value->deviceName, id))
|
||||
{
|
||||
result->temperature = value->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ffStrbufAppendS(dir, "/temp");
|
||||
if (ffReadFileBuffer(dir->chars, &tmpBuffer))
|
||||
result->temperature = ffStrbufToDouble(&tmpBuffer) / 10;
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
|
||||
ffStrbufAppend(&baseDir, &options->dir);
|
||||
ffStrbufEnsureEndsWithC(&baseDir, '/');
|
||||
ffStrbufAppendS(&baseDir, "/sys/class/power_supply/");
|
||||
|
||||
uint32_t baseDirLength = baseDir.length;
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars);
|
||||
if(dirp == NULL)
|
||||
return "opendir(batteryDir) == NULL";
|
||||
return "opendir(\"/sys/class/power_supply/\") == NULL";
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
@@ -122,7 +149,7 @@ const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
}
|
||||
|
||||
if(results->length == 0)
|
||||
return "batteryDir doesn't contain any battery folder";
|
||||
return "\"/sys/class/power_supply/\" doesn't contain any battery folder";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "battery.h"
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
@@ -75,19 +76,19 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
|
||||
FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results);
|
||||
|
||||
if(memcmp(bi.Chemistry, "PbAc", 4) == 0)
|
||||
ffStrbufInitS(&battery->technology, "Lead Acid");
|
||||
ffStrbufInitStatic(&battery->technology, "Lead Acid");
|
||||
else if(memcmp(bi.Chemistry, "LION", 4) == 0 || memcmp(bi.Chemistry, "Li-I", 4) == 0)
|
||||
ffStrbufInitS(&battery->technology, "Lithium Ion");
|
||||
ffStrbufInitStatic(&battery->technology, "Lithium Ion");
|
||||
else if(memcmp(bi.Chemistry, "NiCd", 4) == 0)
|
||||
ffStrbufInitS(&battery->technology, "Nickel Cadmium");
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Cadmium");
|
||||
else if(memcmp(bi.Chemistry, "NiMH", 4) == 0)
|
||||
ffStrbufInitS(&battery->technology, "Nickel Metal Hydride");
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Metal Hydride");
|
||||
else if(memcmp(bi.Chemistry, "NiZn", 4) == 0)
|
||||
ffStrbufInitS(&battery->technology, "Nickel Zinc");
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Zinc");
|
||||
else if(memcmp(bi.Chemistry, "RAM\0", 4) == 0)
|
||||
ffStrbufInitS(&battery->technology, "Rechargeable Alkaline-Manganese");
|
||||
ffStrbufInitStatic(&battery->technology, "Rechargeable Alkaline-Manganese");
|
||||
else
|
||||
ffStrbufInitS(&battery->technology, "Unknown");
|
||||
ffStrbufInitStatic(&battery->technology, "Unknown");
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->modelName);
|
||||
@@ -105,6 +106,22 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
|
||||
ffStrbufSetWS(&battery->manufacturer, name);
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
bqi.InformationLevel = BatteryManufactureDate;
|
||||
BATTERY_MANUFACTURE_DATE date;
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &date, sizeof(date), &dwOut, NULL))
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", date.Year + 1900, date.Month, date.Day);
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->serial);
|
||||
bqi.InformationLevel = BatterySerialNumber;
|
||||
wchar_t name[64];
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL))
|
||||
ffStrbufSetWS(&battery->serial, name);
|
||||
}
|
||||
|
||||
battery->cycleCount = bi.CycleCount;
|
||||
|
||||
battery->temperature = 0.0/0.0;
|
||||
@@ -113,7 +130,7 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
|
||||
bqi.InformationLevel = BatteryTemperature;
|
||||
ULONG temp;
|
||||
if(DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &temp, sizeof(temp), &dwOut, NULL))
|
||||
battery->temperature = temp;
|
||||
battery->temperature = temp / 10.0 - 273.15;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -140,6 +157,83 @@ static const char* detectWithSetupApi(FFBatteryOptions* options, FFlist* results
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef struct FFSmbiosPortableBattery
|
||||
{
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
// 2.1+
|
||||
uint8_t Location; // string
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t ManufactureDate; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t DeviceName; // string
|
||||
uint8_t DeviceChemistry; // enum
|
||||
uint16_t DesignCapacity; // varies
|
||||
uint16_t DesignVoltage; // varies
|
||||
uint8_t SbdsVersionNumber; // string
|
||||
uint8_t MaximumErrorInBatteryData; // varies
|
||||
|
||||
// 2.2+
|
||||
uint16_t SbdsSerialNumber; // varies
|
||||
uint16_t SbdsManufactureDate; // varies
|
||||
uint8_t SbdsDeviceChemistry; // string
|
||||
uint8_t DesignCapacityMultiplier; // varies
|
||||
uint16_t OEMSpecific; // varies
|
||||
} FFSmbiosPortableBattery;
|
||||
|
||||
const char* detectBySmbios(FFBatteryResult* battery)
|
||||
{
|
||||
const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PORTABLE_BATTERY];
|
||||
if (!data)
|
||||
return "Portable battery section is not found in SMBIOS data";
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
ffStrbufSetStatic(&battery->modelName, ffSmbiosLocateString(strings, data->DeviceName));
|
||||
ffCleanUpSmbiosValue(&battery->modelName);
|
||||
ffStrbufSetStatic(&battery->manufacturer, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&battery->manufacturer);
|
||||
|
||||
if (data->ManufactureDate)
|
||||
{
|
||||
ffStrbufSetStatic(&battery->manufactureDate, ffSmbiosLocateString(strings, data->ManufactureDate));
|
||||
ffCleanUpSmbiosValue(&battery->manufactureDate);
|
||||
}
|
||||
else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsManufactureDate))
|
||||
{
|
||||
uint16_t day = data->SbdsManufactureDate & 0b11111;
|
||||
uint16_t month = (data->SbdsManufactureDate >> 5) & 0b1111;
|
||||
uint16_t year = (data->SbdsManufactureDate >> 9) + 1800;
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
}
|
||||
|
||||
switch (data->DeviceChemistry)
|
||||
{
|
||||
case 0x01: ffStrbufSetStatic(&battery->technology, "Other"); break;
|
||||
case 0x02: ffStrbufSetStatic(&battery->technology, "Unknown"); break;
|
||||
case 0x03: ffStrbufSetStatic(&battery->technology, "Lead Acid"); break;
|
||||
case 0x04: ffStrbufSetStatic(&battery->technology, "Nickel Cadmium"); break;
|
||||
case 0x05: ffStrbufSetStatic(&battery->technology, "Nickel metal hydride"); break;
|
||||
case 0x06: ffStrbufSetStatic(&battery->technology, "Lithium-ion"); break;
|
||||
case 0x07: ffStrbufSetStatic(&battery->technology, "Zinc air"); break;
|
||||
case 0x08: ffStrbufSetStatic(&battery->technology, "Lithium Polymer"); break;
|
||||
}
|
||||
|
||||
if (data->SerialNumber)
|
||||
{
|
||||
ffStrbufSetStatic(&battery->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&battery->serial);
|
||||
}
|
||||
else if (data->Header.Length > offsetof(FFSmbiosPortableBattery, SbdsSerialNumber))
|
||||
{
|
||||
ffStrbufSetF(&battery->serial, "%4X", data->SbdsSerialNumber);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
SYSTEM_BATTERY_STATE info;
|
||||
@@ -148,8 +242,10 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
FFBatteryResult* battery = (FFBatteryResult*)ffListAdd(results);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->status);
|
||||
ffStrbufInit(&battery->serial);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
|
||||
@@ -162,6 +258,9 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
}
|
||||
else if(info.Discharging)
|
||||
ffStrbufAppendS(&battery->status, "Discharging");
|
||||
|
||||
detectBySmbios(battery);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return "NtPowerInformation(SystemBatteryState) failed";
|
||||
@@ -169,7 +268,7 @@ static const char* detectWithNtApi(FF_MAYBE_UNUSED FFBatteryOptions* options, FF
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results)
|
||||
{
|
||||
return true
|
||||
return options->useSetupApi
|
||||
? detectWithSetupApi(options, results)
|
||||
: detectWithNtApi(options, results);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* result)
|
||||
@@ -15,5 +16,18 @@ const char* ffDetectBios(FFBiosResult* result)
|
||||
ffSettingsGetFreeBSDKenv("smbios.bios.version", &result->version);
|
||||
ffCleanUpSmbiosValue(&result->version);
|
||||
ffSysctlGetString("machdep.bootmethod", &result->type);
|
||||
|
||||
if (result->type.length == 0)
|
||||
{
|
||||
if (ffSettingsGetFreeBSDKenv("loader.efi", &result->type))
|
||||
ffStrbufSetStatic(&result->type, ffStrbufEqualS(&result->type, "1") ? "UEFI" : "BIOS");
|
||||
else
|
||||
{
|
||||
ffStrbufSetStatic(&result->type,
|
||||
ffPathExists("/dev/efi" /*efidev*/, FF_PATHTYPE_FILE) ||
|
||||
ffPathExists("/boot/efi/efi" /*efi partition*/, FF_PATHTYPE_DIRECTORY)
|
||||
? "UEFI" : "BIOS");
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "bios.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
#include <ntstatus.h>
|
||||
@@ -26,27 +25,46 @@ typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION
|
||||
};
|
||||
} SYSTEM_BOOT_ENVIRONMENT_INFORMATION;
|
||||
|
||||
|
||||
typedef struct FFSmbiosBios
|
||||
{
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Vendor; // string
|
||||
uint8_t BiosVersion; // string
|
||||
uint16_t BiosStartingAddressSegment; // varies
|
||||
uint8_t BiosReleaseDate; // string
|
||||
uint8_t BiosRomSize; // string
|
||||
uint32_t BiosCharacteristics; // bit field
|
||||
|
||||
// 2.4+
|
||||
uint8_t BiosCharacteristicsExtensionBytes[2]; // bit field
|
||||
uint8_t SystemBiosMajorRelease; // varies
|
||||
uint8_t SystemBiosMinorRelease; // varies
|
||||
uint8_t EmbeddedControllerFirmwareMajorRelease; // varies
|
||||
uint8_t EmbeddedControllerFirmwareMinorRelease; // varies
|
||||
|
||||
// 3.1+
|
||||
uint16_t ExtendedBiosRomSize; // bit field
|
||||
} FFSmbiosBios;
|
||||
|
||||
const char* ffDetectBios(FFBiosResult* bios)
|
||||
{
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL))
|
||||
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed";
|
||||
const FFSmbiosBios* data = (const FFSmbiosBios*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_BIOS];
|
||||
if (!data)
|
||||
return "BIOS section is not found in SMBIOS data";
|
||||
|
||||
if(!ffRegReadStrbuf(hKey, L"BIOSVersion", &bios->version, NULL))
|
||||
return "\"HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\BIOSVersion\" doesn't exist";
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
ffStrbufSetStatic(&bios->version, ffSmbiosLocateString(strings, data->BiosVersion));
|
||||
ffCleanUpSmbiosValue(&bios->version);
|
||||
ffRegReadStrbuf(hKey, L"BIOSVendor", &bios->vendor, NULL);
|
||||
ffStrbufSetStatic(&bios->vendor, ffSmbiosLocateString(strings, data->Vendor));
|
||||
ffCleanUpSmbiosValue(&bios->vendor);
|
||||
ffRegReadStrbuf(hKey, L"BIOSReleaseDate", &bios->date, NULL);
|
||||
ffStrbufSetStatic(&bios->date, ffSmbiosLocateString(strings, data->BiosReleaseDate));
|
||||
ffCleanUpSmbiosValue(&bios->date);
|
||||
|
||||
uint32_t major, minor;
|
||||
if(
|
||||
ffRegReadUint(hKey, L"BiosMajorRelease", &major, NULL) &&
|
||||
ffRegReadUint(hKey, L"BiosMinorRelease", &minor, NULL)
|
||||
)
|
||||
ffStrbufAppendF(&bios->release, "%u.%u", (unsigned)major, (unsigned)minor);
|
||||
if (data->Header.Length > offsetof(FFSmbiosBios, SystemBiosMajorRelease))
|
||||
ffStrbufSetF(&bios->release, "%u.%u", data->SystemBiosMajorRelease, data->SystemBiosMinorRelease);
|
||||
|
||||
// Same as GetFirmwareType, but support (?) Windows 7
|
||||
// https://ntdoc.m417z.com/system_information_class
|
||||
|
||||
@@ -7,6 +7,7 @@ typedef struct FFBoardResult
|
||||
FFstrbuf name;
|
||||
FFstrbuf vendor;
|
||||
FFstrbuf version;
|
||||
FFstrbuf serial;
|
||||
} FFBoardResult;
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board);
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
#include "board.h"
|
||||
|
||||
#include "common/sysctl.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* result)
|
||||
{
|
||||
const char* error = ffSysctlGetString("hw.model", &result->name);
|
||||
if (error)
|
||||
return error;
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t service = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!service)
|
||||
return "No IOPlatformExpertDevice found";
|
||||
|
||||
io_name_t name;
|
||||
if (IORegistryEntryGetName(service, name) == kIOReturnSuccess)
|
||||
ffStrbufSetS(&result->name, name);
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFTypeRef manufacturer = IORegistryEntryCreateCFProperty(service, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
|
||||
if (manufacturer)
|
||||
ffCfStrGetString(manufacturer, &result->vendor);
|
||||
|
||||
ffStrbufSetStatic(&result->vendor, "Apple");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ const char* ffDetectBoard(FFBoardResult* result)
|
||||
{
|
||||
ffSettingsGetFreeBSDKenv("smbios.planar.product", &result->name);
|
||||
ffCleanUpSmbiosValue(&result->name);
|
||||
ffSettingsGetFreeBSDKenv("smbios.planar.serial", &result->serial);
|
||||
ffCleanUpSmbiosValue(&result->serial);
|
||||
ffSettingsGetFreeBSDKenv("smbios.planar.maker", &result->vendor);
|
||||
ffCleanUpSmbiosValue(&result->vendor);
|
||||
ffSettingsGetFreeBSDKenv("smbios.planar.version", &result->version);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_name", "/sys/class/dmi/id/board_name", &board->name);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_serial", "/sys/class/dmi/id/board_serial", &board->serial);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_vendor", "/sys/class/dmi/id/board_vendor", &board->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/board_version", "/sys/class/dmi/id/board_version", &board->version);
|
||||
return NULL;
|
||||
|
||||
@@ -1,21 +1,38 @@
|
||||
#include "board.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
typedef struct FFSmbiosBaseboard
|
||||
{
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t Product; // string
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTag; // string
|
||||
uint8_t FeatureFlags; // bit field
|
||||
uint8_t LocationInChassis; // string
|
||||
uint16_t ChassisHandle; // varies
|
||||
uint8_t BoardType; // enum
|
||||
uint8_t NumberOfContainedObjectHandle; // varies
|
||||
uint16_t ContainedObjectHandle[]; // varies
|
||||
} FFSmbiosBaseboard;
|
||||
|
||||
const char* ffDetectBoard(FFBoardResult* board)
|
||||
{
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
const FFSmbiosBaseboard* data = (const FFSmbiosBaseboard*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_BASEBOARD_INFO];
|
||||
if (!data)
|
||||
return "Baseboard information section is not found in SMBIOS data";
|
||||
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL))
|
||||
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\") failed";
|
||||
|
||||
if(!ffRegReadStrbuf(hKey, L"BaseBoardProduct", &board->name, NULL))
|
||||
return "ffRegReadStrbuf(hKey, L\"BaseBoardProduct\") failed";
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
ffStrbufSetStatic(&board->name, ffSmbiosLocateString(strings, data->Product));
|
||||
ffCleanUpSmbiosValue(&board->name);
|
||||
ffRegReadStrbuf(hKey, L"BaseBoardManufacturer", &board->vendor, NULL);
|
||||
ffStrbufSetStatic(&board->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&board->serial);
|
||||
ffStrbufSetStatic(&board->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&board->vendor);
|
||||
ffRegReadStrbuf(hKey, L"BaseBoardVersion", &board->version, NULL);
|
||||
ffStrbufSetStatic(&board->version, ffSmbiosLocateString(strings, data->Version));
|
||||
ffCleanUpSmbiosValue(&board->version);
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -57,35 +57,35 @@ static const char* detectWithDdcci(FF_MAYBE_UNUSED const FFDisplayServerResult*
|
||||
if (!IOAVServiceCreate || !IOAVServiceReadI2C)
|
||||
return "IOAVService is not available";
|
||||
|
||||
io_iterator_t iterator;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess)
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("DCPAVServiceProxy"), &iterator) != kIOReturnSuccess)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY location = ffStrbufCreate();
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = NULL;
|
||||
{
|
||||
IOObjectRelease(registryEntry);
|
||||
continue;
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryAv = registryEntry;
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFBooleanRef IOAVServiceUserInterfaceSupported = IORegistryEntryCreateCFProperty(entryAv, CFSTR("IOAVServiceUserInterfaceSupported"), kCFAllocatorDefault, kNilOptions);
|
||||
if (IOAVServiceUserInterfaceSupported && !CFBooleanGetValue(IOAVServiceUserInterfaceSupported))
|
||||
{
|
||||
// IOAVServiceCreateWithService won't work
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef location = IORegistryEntryCreateCFProperty(entryAv, CFSTR("Location"), kCFAllocatorDefault, kNilOptions);
|
||||
if (location && CFStringCompare(location, CFSTR("Embedded"), 0) == 0)
|
||||
{
|
||||
// Builtin display should be handled by DisplayServices
|
||||
continue;
|
||||
}
|
||||
|
||||
service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry);
|
||||
if (!service) continue;
|
||||
}
|
||||
|
||||
ffStrbufClear(&location);
|
||||
if(ffCfDictGetString(properties, CFSTR("Location"), &location) || ffStrbufEqualS(&location, "Embedded"))
|
||||
{
|
||||
// Builtin display should be handled by DisplayServices
|
||||
IOObjectRelease(registryEntry);
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE IOAVServiceRef service = IOAVServiceCreateWithService(kCFAllocatorDefault, (io_service_t) registryEntry);
|
||||
IOObjectRelease(registryEntry);
|
||||
|
||||
if (!service) continue;
|
||||
|
||||
{
|
||||
uint8_t i2cIn[4] = { 0x82, 0x01, 0x10 /* luminance */ };
|
||||
i2cIn[3] = 0x6e ^ i2cIn[0] ^ i2cIn[1] ^ i2cIn[2];
|
||||
|
||||
@@ -36,6 +36,8 @@ const char* ffDetectBrightness(FF_MAYBE_UNUSED FFBrightnessOptions* options, FFl
|
||||
struct backlight_info info;
|
||||
if(ioctl(blfd, BACKLIGHTGETINFO, &info) < 0)
|
||||
ffStrbufAppendS(&brightness->name, info.name);
|
||||
else
|
||||
ffStrbufAppendS(&brightness->name, path + strlen("/dev/backlight/"));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
const char* ffChassisTypeToString(uint32_t type)
|
||||
{
|
||||
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.2.0.pdf
|
||||
// https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.7.0.pdf
|
||||
// 7.4.1 System Enclosure or Chassis Types
|
||||
switch (type)
|
||||
switch (type & 0b01111111)
|
||||
{
|
||||
case 0x01: return "Other";
|
||||
case 0x02: return "Unknown";
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
typedef struct FFChassisResult
|
||||
{
|
||||
FFstrbuf type;
|
||||
FFstrbuf serial;
|
||||
FFstrbuf vendor;
|
||||
FFstrbuf version;
|
||||
} FFChassisResult;
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options);
|
||||
const char* ffDetectChassis(FFChassisResult* result);
|
||||
const char* ffChassisTypeToString(uint32_t type);
|
||||
|
||||
@@ -2,13 +2,15 @@
|
||||
#include "common/settings.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options)
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
// Unlike other platforms, `smbios.chassis.type` return display string directly on my machine
|
||||
ffSettingsGetFreeBSDKenv("smbios.chassis.type", &result->type);
|
||||
ffCleanUpSmbiosValue(&result->type);
|
||||
ffSettingsGetFreeBSDKenv("smbios.chassis.maker", &result->vendor);
|
||||
ffCleanUpSmbiosValue(&result->vendor);
|
||||
ffSettingsGetFreeBSDKenv("smbios.chassis.serial", &result->serial);
|
||||
ffCleanUpSmbiosValue(&result->serial);
|
||||
ffSettingsGetFreeBSDKenv("smbios.chassis.version", &result->version);
|
||||
ffCleanUpSmbiosValue(&result->version);
|
||||
return NULL;
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options)
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_type", "/sys/class/dmi/id/chassis_type", &result->type);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_serial", "/sys/class/dmi/id/chassis_serial", &result->serial);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_vendor", "/sys/class/dmi/id/chassis_vendor", &result->vendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/chassis_version", "/sys/class/dmi/id/chassis_version", &result->version);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "chassis.h"
|
||||
|
||||
const char* ffDetectChassis(FF_MAYBE_UNUSED FFChassisResult* result, FF_MAYBE_UNUSED FFChassisOptions* options)
|
||||
const char* ffDetectChassis(FF_MAYBE_UNUSED FFChassisResult* result)
|
||||
{
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "chassis.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
// 7.4
|
||||
typedef struct FFSmbiosSystemEnclosure
|
||||
{
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t Type; // varies
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssetTagNumber; // string
|
||||
|
||||
// 2.1+
|
||||
uint8_t BootupState; // enum
|
||||
uint8_t PowerSupplyState; // enum
|
||||
uint8_t ThermalState; // enum
|
||||
uint8_t SecurityStatus; // enum
|
||||
|
||||
// 2.3+
|
||||
uint32_t OEMDefined; // varies
|
||||
uint8_t Height; // varies
|
||||
uint8_t NumberOfPowerCords; // varies
|
||||
uint8_t ContainedElementCount; // varies
|
||||
uint8_t ContainedRecordLength; // varies
|
||||
uint8_t ContainedElements[]; // varies
|
||||
} FFSmbiosSystemEnclosure;
|
||||
|
||||
const char* ffDetectChassis(FFChassisResult* result)
|
||||
{
|
||||
const FFSmbiosSystemEnclosure* data = (const FFSmbiosSystemEnclosure*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_SYSTEM_ENCLOSURE];
|
||||
if (!data)
|
||||
return "System enclosure is not found in SMBIOS data";
|
||||
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
ffStrbufSetStatic(&result->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&result->vendor);
|
||||
ffStrbufSetStatic(&result->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&result->serial);
|
||||
ffStrbufSetStatic(&result->version, ffSmbiosLocateString(strings, data->Version));
|
||||
ffCleanUpSmbiosValue(&result->version);
|
||||
ffStrbufSetStatic(&result->type, ffChassisTypeToString(data->Type));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
extern "C" {
|
||||
#include "chassis.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
}
|
||||
#include "util/windows/unicode.hpp"
|
||||
#include "util/windows/wmi.hpp"
|
||||
|
||||
static const char* detectWithRegistry(FFChassisResult* result)
|
||||
{
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL)) // SMBIOS
|
||||
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed";
|
||||
|
||||
uint32_t type = 0;
|
||||
if(!ffRegReadUint(hKey, L"EnclosureType", &type, NULL))
|
||||
return "\"HKEY_LOCAL_MACHINE\\HARDWARE\\DESCRIPTION\\System\\BIOS\\EnclosureType\" doesn't exist";
|
||||
|
||||
const char* typeStr = ffChassisTypeToString(type);
|
||||
if(!typeStr)
|
||||
return "Unknown chassis type";
|
||||
|
||||
ffStrbufAppendS(&result->type, typeStr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FF_MAYBE_UNUSED static const char* detectWithWmi(FFChassisResult* result)
|
||||
{
|
||||
FFWmiQuery query(L"SELECT Version, ChassisTypes, Manufacturer FROM Win32_SystemEnclosure");
|
||||
if (!query)
|
||||
return "Query WMI service failed";
|
||||
|
||||
if (FFWmiRecord record = query.next())
|
||||
{
|
||||
if (auto vtProp = record.get(L"ChassisTypes"))
|
||||
{
|
||||
auto [arr, len] = vtProp.get<std::pair<const int32_t*, uint32_t>>();
|
||||
if(len == 0)
|
||||
return "ChassisTypes contain no data";
|
||||
for (uint32_t i = 0; i < len; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
ffStrbufAppendS(&result->type, ", ");
|
||||
ffStrbufAppendS(&result->type, ffChassisTypeToString((uint32_t) arr[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
return "Get ChassisTypes failed";
|
||||
|
||||
if (auto vtProp = record.get(L"Version"))
|
||||
{
|
||||
ffStrbufSetWSV(&result->version, vtProp.get<std::wstring_view>());
|
||||
ffCleanUpSmbiosValue(&result->version);
|
||||
}
|
||||
|
||||
if (auto vtProp = record.get(L"Manufacturer"))
|
||||
{
|
||||
ffStrbufSetWSV(&result->vendor, vtProp.get<std::wstring_view>());
|
||||
ffCleanUpSmbiosValue(&result->vendor);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
return "No WMI result returned";
|
||||
}
|
||||
|
||||
extern "C"
|
||||
const char* ffDetectChassis(FFChassisResult* result, FFChassisOptions* options)
|
||||
{
|
||||
if (options->useWmi)
|
||||
return detectWithWmi(result);
|
||||
return detectWithRegistry(result);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "detection/temps/temps_apple.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
static double detectCpuTemp(const FFstrbuf* cpuName)
|
||||
{
|
||||
@@ -35,44 +36,33 @@ static const char* detectFrequency(FFCPUResult* cpu)
|
||||
{
|
||||
// https://github.com/giampaolo/psutil/pull/2222/files
|
||||
|
||||
io_iterator_t iterator;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleARMIODevice"), &iterator) != kIOReturnSuccess)
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryDevice = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("pmgr"));
|
||||
if (!entryDevice)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
if (!IOObjectConformsTo(entryDevice, "AppleARMIODevice"))
|
||||
return "\"pmgr\" should conform to \"AppleARMIODevice\"";
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL;
|
||||
if (IORegistryEntryCreateCFProperties(entryDevice, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
return "IORegistryEntryCreateCFProperties() failed";
|
||||
|
||||
uint32_t pMin, eMin, aMax, pCoreLength;
|
||||
if (ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), 0, 4, (uint8_t*) &pMin, &pCoreLength) != NULL) // pCore
|
||||
return "\"voltage-states5-sram\" in \"pmgr\" is not found";
|
||||
if (ffCfDictGetData(properties, CFSTR("voltage-states1-sram"), 0, 4, (uint8_t*) &eMin, NULL) != NULL) // eCore
|
||||
return "\"voltage-states1-sram\" in \"pmgr\" is not found";
|
||||
|
||||
cpu->frequencyMin = (pMin < eMin ? pMin : eMin) / (1000.0 * 1000 * 1000);
|
||||
|
||||
if (pCoreLength >= 8)
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
{
|
||||
IOObjectRelease(registryEntry);
|
||||
continue;
|
||||
}
|
||||
|
||||
io_name_t name;
|
||||
if (IORegistryEntryGetName(registryEntry, name) != KERN_SUCCESS)
|
||||
continue;
|
||||
if (strcmp(name, "pmgr") != 0)
|
||||
continue;
|
||||
|
||||
uint32_t pMin, eMin, aMax, pCoreLength;
|
||||
ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), 0, 4, (uint8_t*) &pMin, &pCoreLength); // pCore
|
||||
ffCfDictGetData(properties, CFSTR("voltage-states1-sram"), 0, 4, (uint8_t*) &eMin, NULL); // eCore
|
||||
cpu->frequencyMin = (pMin < eMin ? pMin : eMin) / (1000.0 * 1000 * 1000);
|
||||
|
||||
if (pCoreLength >= 8)
|
||||
{
|
||||
ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL);
|
||||
cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000);
|
||||
}
|
||||
else
|
||||
cpu->frequencyMax = 0.0;
|
||||
|
||||
CFRelease(properties);
|
||||
IOObjectRelease(registryEntry);
|
||||
ffCfDictGetData(properties, CFSTR("voltage-states5-sram"), pCoreLength - 8, 4, (uint8_t*) &aMax, NULL);
|
||||
cpu->frequencyMax = aMax / (1000.0 * 1000 * 1000);
|
||||
}
|
||||
else
|
||||
cpu->frequencyMax = 0.0;
|
||||
|
||||
IOObjectRelease(iterator);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -2,8 +2,81 @@
|
||||
#include "detection/temps/temps_windows.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
// 7.5
|
||||
typedef struct FFSmbiosProcessorInfo
|
||||
{
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t SocketDesignation; // string
|
||||
uint8_t ProcessorType; // enum
|
||||
uint8_t ProcessorFamily; // enum
|
||||
uint8_t ProcessorManufacturer; // string
|
||||
uint64_t ProcessorID; // varies
|
||||
uint8_t ProcessorVersion; // string
|
||||
uint8_t Voltage; // varies
|
||||
uint16_t ExternalClock; // varies
|
||||
uint16_t MaxSpeed; // varies
|
||||
uint16_t CurrentSpeed; // varies
|
||||
uint8_t Status; // varies
|
||||
uint8_t ProcessorUpgrade; // enum
|
||||
|
||||
// 2.1+
|
||||
uint16_t L1CacheHandle; // varies
|
||||
uint16_t L2CacheHandle; // varies
|
||||
uint16_t L3CacheHandle; // varies
|
||||
|
||||
// 2.3+
|
||||
uint8_t SerialNumber; // string
|
||||
uint8_t AssertTag; // string
|
||||
uint8_t PartNumber; // string
|
||||
|
||||
// 2.5+
|
||||
uint8_t CoreCount; // varies
|
||||
uint8_t CoreEnabled; // varies
|
||||
uint8_t ThreadCount; // varies
|
||||
uint16_t ProcessorCharacteristics; // bit field
|
||||
|
||||
// 2.6+
|
||||
uint16_t ProcessorFamily2; // enum
|
||||
|
||||
// 3.0+
|
||||
uint16_t CoreCount2; // varies
|
||||
uint16_t CoreEnabled2; // varies
|
||||
uint16_t ThreadCount2; // varies
|
||||
|
||||
// 3.6+
|
||||
uint16_t ThreadEnabled; // varies
|
||||
} FFSmbiosProcessorInfo;
|
||||
|
||||
static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu)
|
||||
{
|
||||
const FFSmbiosProcessorInfo* data = (const FFSmbiosProcessorInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_PROCESSOR_INFO];
|
||||
|
||||
if (!data)
|
||||
return "Processor information is not found in SMBIOS data";
|
||||
|
||||
while (data->ProcessorType != 0x03 /*Central Processor*/ || (data->Status & 0b00000111) != 1 /*Enabled*/)
|
||||
{
|
||||
data = (const FFSmbiosProcessorInfo*) ffSmbiosNextEntry(&data->Header);
|
||||
if (data->Header.Type != FF_SMBIOS_TYPE_PROCESSOR_INFO)
|
||||
return "No active CPU is found in SMBIOS data";
|
||||
}
|
||||
|
||||
double speed;
|
||||
if (data->MaxSpeed > 0 && data->MaxSpeed < 30000) // VMware reports weird values
|
||||
speed = data->MaxSpeed / 1000.0;
|
||||
else
|
||||
speed = data->CurrentSpeed / 1000.0;
|
||||
|
||||
if (cpu->frequencyMax < speed)
|
||||
cpu->frequencyMax = speed;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectByOS(FFCPUResult* cpu)
|
||||
{
|
||||
{
|
||||
DWORD length = 0;
|
||||
@@ -42,14 +115,24 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
uint32_t mhz;
|
||||
if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL))
|
||||
cpu->frequencyMax = mhz / 1000.0;
|
||||
cpu->frequencyMin = cpu->frequencyMax = mhz / 1000.0;
|
||||
}
|
||||
|
||||
ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL);
|
||||
ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
const char* error = detectByOS(cpu);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if(options->temp)
|
||||
ffDetectSmbiosTemp(&cpu->temperature, NULL);
|
||||
|
||||
detectMaxSpeedBySmbios(cpu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -8,22 +8,14 @@
|
||||
#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
|
||||
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
|
||||
|
||||
static inline void wrapIoObjectRelease(io_service_t* service)
|
||||
{
|
||||
assert(service);
|
||||
if (*service)
|
||||
IOObjectRelease(*service);
|
||||
}
|
||||
#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease)))
|
||||
|
||||
const char* ffDiskIOGetIoCounters(FFlist* result, FFDiskIOOptions* options)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS)
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry;
|
||||
|
||||
|
||||
@@ -129,8 +129,9 @@ static void detectDisplays(FFDisplayServerResult* ds)
|
||||
(uint32_t) (monitorInfo->info.rcMonitor.bottom - monitorInfo->info.rcMonitor.top),
|
||||
rotation,
|
||||
&name,
|
||||
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL ||
|
||||
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED ||
|
||||
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER ? FF_DISPLAY_TYPE_UNKNOWN :
|
||||
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL ||
|
||||
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED ||
|
||||
path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED
|
||||
? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL,
|
||||
!!(monitorInfo->info.dwFlags & MONITORINFOF_PRIMARY),
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "displayserver_linux.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include "common/settings.h"
|
||||
#endif
|
||||
|
||||
void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
{
|
||||
@@ -31,6 +34,26 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds)
|
||||
if(ds->displays.length == 0)
|
||||
ffdsConnectDrm(ds);
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
if(ds->displays.length == 0)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
|
||||
if (ffSettingsGetFreeBSDKenv("screen.width", &buf))
|
||||
{
|
||||
uint32_t width = (uint32_t) ffStrbufToUInt(&buf, 0);
|
||||
if (width)
|
||||
{
|
||||
ffStrbufClear(&buf);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//This fills in missing information about WM / DE by using env vars and iterating processes
|
||||
ffdsDetectWMDE(ds);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
typedef struct FFGamepadDevice
|
||||
{
|
||||
FFstrbuf identifier;
|
||||
FFstrbuf serial;
|
||||
FFstrbuf name;
|
||||
uint8_t battery; // 0-100%
|
||||
} FFGamepadDevice;
|
||||
|
||||
const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */);
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
#include "gamepad.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
|
||||
static void enumSet(const void* value, void *context)
|
||||
static void enumSet(IOHIDDeviceRef value, FFlist* results)
|
||||
{
|
||||
CFStringRef product = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDProductKey));
|
||||
CFStringRef serialNumber = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDSerialNumberKey));
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd((FFlist*) context);
|
||||
ffStrbufInit(&device->identifier);
|
||||
ffCfStrGetString(serialNumber, &device->identifier);
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(results);
|
||||
ffStrbufInit(&device->serial);
|
||||
ffStrbufInit(&device->name);
|
||||
ffCfStrGetString(product, &device->name);
|
||||
device->battery = 0;
|
||||
|
||||
CFStringRef manufacturer = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDManufacturerKey));
|
||||
ffCfStrGetString(manufacturer, &device->name);
|
||||
|
||||
CFStringRef product = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDProductKey));
|
||||
if (device->name.length)
|
||||
{
|
||||
ffCfStrGetString(product, &device->serial);
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
ffStrbufAppend(&device->name, &device->serial);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffCfStrGetString(product, &device->name);
|
||||
}
|
||||
|
||||
CFStringRef serialNumber = IOHIDDeviceGetProperty(value, CFSTR(kIOHIDSerialNumberKey));
|
||||
ffCfStrGetString(serialNumber, &device->serial);
|
||||
}
|
||||
|
||||
const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
@@ -21,21 +37,29 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
if (IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
|
||||
return "IOHIDManagerOpen() failed";
|
||||
|
||||
CFNumberRef FF_CFTYPE_AUTO_RELEASE genericDesktop = ffCfCreateInt(kHIDPage_GenericDesktop);
|
||||
CFNumberRef FF_CFTYPE_AUTO_RELEASE gamePad = ffCfCreateInt(kHIDUsage_GD_GamePad);
|
||||
CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){
|
||||
CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching1 = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){
|
||||
CFSTR(kIOHIDDeviceUsagePageKey),
|
||||
CFSTR(kIOHIDDeviceUsageKey)
|
||||
}, (const void **)(CFNumberRef[]){
|
||||
genericDesktop,
|
||||
gamePad
|
||||
ffCfCreateInt(kHIDPage_GenericDesktop),
|
||||
ffCfCreateInt(kHIDUsage_GD_Joystick)
|
||||
}, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
IOHIDManagerSetDeviceMatching(manager, matching);
|
||||
CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching2 = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){
|
||||
CFSTR(kIOHIDDeviceUsagePageKey),
|
||||
CFSTR(kIOHIDDeviceUsageKey)
|
||||
}, (const void **)(CFNumberRef[]){
|
||||
ffCfCreateInt(kHIDPage_GenericDesktop),
|
||||
ffCfCreateInt(kHIDUsage_GD_GamePad)
|
||||
}, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFArrayRef FF_CFTYPE_AUTO_RELEASE matchings = CFArrayCreate(kCFAllocatorDefault, (const void **)(CFTypeRef[]){
|
||||
matching1, matching2
|
||||
}, 2, &kCFTypeArrayCallBacks);
|
||||
IOHIDManagerSetDeviceMatchingMultiple(manager, matchings);
|
||||
|
||||
CFSetRef FF_CFTYPE_AUTO_RELEASE set = IOHIDManagerCopyDevices(manager);
|
||||
if (set)
|
||||
CFSetApplyFunction(set, &enumSet, devices);
|
||||
IOHIDManagerClose(manager, 0);
|
||||
CFSetApplyFunction(set, (CFSetApplierFunction) &enumSet, devices);
|
||||
IOHIDManagerClose(manager, kIOHIDOptionsTypeNone);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -42,8 +42,9 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
if (ioctl(fd, USB_GET_DEVICEINFO, &di) != -1)
|
||||
{
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
|
||||
ffStrbufInitS(&device->identifier, di.udi_serial);
|
||||
ffStrbufInitS(&device->serial, di.udi_serial);
|
||||
ffStrbufInitF(&device->name, "%s %s", di.udi_vendor, di.udi_product);
|
||||
device->battery = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,39 +5,88 @@
|
||||
#include <dirent.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static void detectGamepad(FFlist* devices, FFstrbuf* name, FFstrbuf* path)
|
||||
{
|
||||
uint32_t baseLen = path->length;
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
|
||||
ffStrbufInit(&device->serial);
|
||||
ffStrbufInitMove(&device->name, name);
|
||||
device->battery = 0;
|
||||
|
||||
ffStrbufAppendS(path, "uniq");
|
||||
if (ffAppendFileBuffer(path->chars, &device->serial))
|
||||
ffStrbufTrimRightSpace(&device->serial);
|
||||
|
||||
ffStrbufSubstrBefore(path, baseLen);
|
||||
ffStrbufAppendS(path, "device/power_supply/"); // /sys/class/input/jsX/device/device/power_supply
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(path->chars);
|
||||
if (dirp)
|
||||
{
|
||||
struct dirent* entry;
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if (entry->d_name[0] == '.' || (entry->d_type != DT_DIR && entry->d_type != DT_UNKNOWN))
|
||||
continue;
|
||||
ffStrbufAppendS(path, entry->d_name);
|
||||
ffStrbufAppendS(path, "/capacity"); // /sys/class/input/jsX/device/device/power_supply/XXX/capacity
|
||||
char capacity[32];
|
||||
ssize_t nRead = ffReadFileData(path->chars, sizeof(capacity) - 1, capacity);
|
||||
if (nRead > 0) // Tested with a PS4 controller
|
||||
{
|
||||
capacity[nRead] = '\0';
|
||||
device->battery = (uint8_t) strtoul(capacity, NULL, 10);
|
||||
break;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(path, "_level");
|
||||
nRead = ffReadFileData(path->chars, sizeof(capacity) - 1, capacity);
|
||||
if (nRead > 0) // Tested with a NS Pro controller
|
||||
{
|
||||
// https://github.com/torvalds/linux/blob/52b1853b080a082ec3749c3a9577f6c71b1d4a90/drivers/power/supply/power_supply_sysfs.c#L124
|
||||
switch (capacity[0])
|
||||
{
|
||||
case 'C': device->battery = 1; break; // Critical
|
||||
case 'L': device->battery = 25; break; // Low
|
||||
case 'N': device->battery = 50; break; // Normal
|
||||
case 'H': device->battery = 75; break; // High
|
||||
case 'F': device->battery = 100; break; // Full
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
{
|
||||
DIR* dirp = opendir("/sys/class/input/");
|
||||
if(dirp == NULL)
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir("/sys/class/input/");
|
||||
if (dirp == NULL)
|
||||
return "opendir(\"/sys/class/input/\") == NULL";
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/sys/class/input/");
|
||||
uint32_t baseLen = path.length;
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
while ((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(!ffStrStartsWith(entry->d_name, "js"))
|
||||
if (!ffStrStartsWith(entry->d_name, "js"))
|
||||
continue;
|
||||
if(!isdigit(entry->d_name[2]))
|
||||
if (!isdigit(entry->d_name[2]))
|
||||
continue;
|
||||
|
||||
ffStrbufAppendS(&path, entry->d_name);
|
||||
ffStrbufAppendS(&path, "/device/name");
|
||||
|
||||
if (ffPathExists(path.chars, FF_PATHTYPE_FILE))
|
||||
FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate();
|
||||
if (ffAppendFileBuffer(path.chars, &name))
|
||||
{
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
|
||||
ffStrbufInitS(&device->identifier, entry->d_name);
|
||||
ffStrbufInit(&device->name);
|
||||
if (ffAppendFileBuffer(path.chars, &device->name))
|
||||
ffStrbufTrimRightSpace(&device->name);
|
||||
ffStrbufTrimRightSpace(&name);
|
||||
ffStrbufSubstrBefore(&path, path.length - 4);
|
||||
detectGamepad(devices, &name, &path);
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(&path, baseLen);
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/windows/unicode.h"
|
||||
|
||||
#include <winternl.h>
|
||||
#include <windows.h>
|
||||
#include <hidsdi.h>
|
||||
|
||||
static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId)
|
||||
static const char* detectKnownDeviceName(uint32_t vendorId, uint32_t productId)
|
||||
{
|
||||
switch (vendorId)
|
||||
{
|
||||
@@ -30,38 +31,14 @@ static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId)
|
||||
{
|
||||
switch (productId)
|
||||
{
|
||||
case 0x0268: return "Sony Playstation 3 Controller";
|
||||
case 0x0268: return "Sony DualShock 3 / Six Axis";
|
||||
|
||||
case 0x05C4: return "Sony DualShock 4 Gen1";
|
||||
case 0x09CC: return "Sony DualShock 4 Gen2";
|
||||
case 0x0BA0: return "Sony PS4 Controller USB receiver";
|
||||
case 0x0BA0: return "Sony DualShock 4 USB receiver";
|
||||
|
||||
case 0x0CE6: return "Sony DualSense";
|
||||
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Microsoft
|
||||
case 0x045E:
|
||||
{
|
||||
switch (productId)
|
||||
{
|
||||
case 0x02E0: return "Microsoft X-Box One S pad (Wireless)";
|
||||
case 0x02FD: return "Microsoft X-Box One S pad (Wireless, 2016 FW)";
|
||||
case 0x0B05: return "Microsoft X-Box One Elite Series 2 pad (Wireless)";
|
||||
case 0x0B13: return "Microsoft X-Box Series X (Wireless)";
|
||||
|
||||
case 0x028E: return "Microsoft XBox 360";
|
||||
case 0x028F: return "Microsoft XBox 360 v2";
|
||||
case 0x02A1: return "Microsoft XBox 360";
|
||||
case 0x0291: return "Microsoft XBox 360 USB receiver";
|
||||
case 0x02A0: return "Microsoft XBox 360 Big Button IR";
|
||||
case 0x02DD: return "Microsoft XBox One";
|
||||
case 0xB326: return "Microsoft XBox One Firmware 2015";
|
||||
case 0x02E3: return "Microsoft XBox One Elite";
|
||||
case 0x02FF: return "Microsoft XBox One Elite";
|
||||
case 0x02EA: return "Microsoft XBox One S";
|
||||
case 0x0DF2: return "Sony DualSense Edge";
|
||||
|
||||
default: return NULL;
|
||||
}
|
||||
@@ -83,6 +60,7 @@ static const char* detectKnownGamepad(uint32_t vendorId, uint32_t productId)
|
||||
}
|
||||
}
|
||||
|
||||
case 0x045E: // Microsoft Xbox compatible controllers should be handled by Windows without problems
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +76,8 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
if ((nDevices = GetRawInputDeviceList(pRawInputDeviceList, &nDevices, sizeof(RAWINPUTDEVICELIST))) == (UINT) -1)
|
||||
return "GetRawInputDeviceList(pRawInputDeviceList) failed";
|
||||
|
||||
for (UINT i = 0; i < nDevices; ++i) {
|
||||
for (UINT i = 0; i < nDevices; ++i)
|
||||
{
|
||||
if (pRawInputDeviceList[i].dwType != 2) continue;
|
||||
|
||||
HANDLE hDevice = pRawInputDeviceList[i].hDevice;
|
||||
@@ -117,20 +96,94 @@ const char* ffDetectGamepad(FFlist* devices /* List of FFGamepadDevice */)
|
||||
continue;
|
||||
|
||||
FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices);
|
||||
ffStrbufInitWS(&device->identifier, devName);
|
||||
ffStrbufInit(&device->serial);
|
||||
ffStrbufInit(&device->name);
|
||||
device->battery = 0;
|
||||
|
||||
const char* knownGamepad = detectKnownGamepad(rdi.hid.dwVendorId, rdi.hid.dwProductId);
|
||||
const char* knownGamepad = detectKnownDeviceName(rdi.hid.dwVendorId, rdi.hid.dwProductId);
|
||||
if (knownGamepad)
|
||||
ffStrbufSetS(&device->name, knownGamepad);
|
||||
else
|
||||
HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
if (!hHidFile)
|
||||
{
|
||||
if (!knownGamepad)
|
||||
ffStrbufSetF(&device->name, "Unknown gamepad %04X-%04X", (unsigned) rdi.hid.dwVendorId, (unsigned) rdi.hid.dwProductId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!knownGamepad)
|
||||
{
|
||||
wchar_t displayName[126];
|
||||
HANDLE FF_AUTO_CLOSE_FD hHidFile = CreateFileW(devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hHidFile && HidD_GetProductString(hHidFile, displayName, sizeof(wchar_t) * 126))
|
||||
ffStrbufSetWS(&device->name, displayName);
|
||||
else
|
||||
ffStrbufSetF(&device->name, "Unknown gamepad %4X-%4X", (unsigned) rdi.hid.dwVendorId, (unsigned) rdi.hid.dwProductId);
|
||||
if (HidD_GetProductString(hHidFile, displayName, sizeof(displayName)))
|
||||
{
|
||||
wchar_t manufacturer[126];
|
||||
if (HidD_GetManufacturerString(hHidFile, manufacturer, sizeof(manufacturer)))
|
||||
{
|
||||
ffStrbufSetWS(&device->name, manufacturer);
|
||||
FF_STRBUF_AUTO_DESTROY displayNameStr = ffStrbufCreateWS(displayName);
|
||||
ffStrbufAppendC(&device->name, ' ');
|
||||
ffStrbufAppend(&device->name, &displayNameStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSetWS(&device->name, displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PHIDP_PREPARSED_DATA preparsedData = NULL;
|
||||
if (HidD_GetPreparsedData(hHidFile, &preparsedData))
|
||||
{
|
||||
HIDP_CAPS caps;
|
||||
NTSTATUS capsResult = HidP_GetCaps(preparsedData, &caps);
|
||||
HidD_FreePreparsedData(preparsedData);
|
||||
if (!NT_SUCCESS(capsResult))
|
||||
continue;
|
||||
|
||||
wchar_t serialNumber[127] = L"";
|
||||
if (HidD_GetSerialNumberString(hHidFile, serialNumber, sizeof(serialNumber)))
|
||||
ffStrbufSetWS(&device->serial, serialNumber);
|
||||
|
||||
if (
|
||||
(rdi.hid.dwVendorId == 0x054C && (
|
||||
rdi.hid.dwProductId == 0x05C4 || // PS4 Gen1
|
||||
rdi.hid.dwProductId == 0x09CC // PS4 Gen2
|
||||
)) ||
|
||||
(rdi.hid.dwVendorId == 0x057E && (
|
||||
rdi.hid.dwProductId == 0x2009 // NS Pro
|
||||
))
|
||||
)
|
||||
{
|
||||
// Controller must be connected by other programs
|
||||
FF_AUTO_FREE uint8_t* reportBuffer = malloc(caps.InputReportByteLength);
|
||||
OVERLAPPED overlapped = { };
|
||||
DWORD nBytes;
|
||||
if (ReadFile(hHidFile, reportBuffer, caps.InputReportByteLength, &nBytes, &overlapped) ||
|
||||
(WaitForSingleObject(hHidFile, FF_IO_TERM_RESP_WAIT_MS) == WAIT_OBJECT_0 && GetOverlappedResult(hHidFile, &overlapped, &nBytes, FALSE)))
|
||||
{
|
||||
if (rdi.hid.dwVendorId == 0x054C)
|
||||
{
|
||||
if (nBytes > 31)
|
||||
{
|
||||
uint8_t batteryInfo = reportBuffer[caps.InputReportByteLength == 64 /*USB?*/ ? 30 : 32];
|
||||
device->battery = (uint8_t) ((batteryInfo & 0x0f) * 100 / (batteryInfo & 0x10 /*charging?*/ ? 11 /*BATTERY_MAX_USB*/ : 8 /*BATTERY_MAX*/));
|
||||
if (device->battery > 100) device->battery = 100;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nBytes > 3 && reportBuffer[0] == 0x30)
|
||||
{
|
||||
uint8_t batteryInfo = reportBuffer[2];
|
||||
device->battery = (uint8_t) (((batteryInfo & 0xE0) >> 4) * 100 / 8);
|
||||
if (device->battery == 0) device->battery = 1;
|
||||
else if (device->battery > 100) device->battery = 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
CancelIo(hHidFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,15 +73,17 @@ const char* detectByOpenGL(FFlist* gpus)
|
||||
|
||||
if (!gpu->vendor.length)
|
||||
{
|
||||
if (ffStrbufContainS(&result.renderer, "Apple"))
|
||||
if (ffStrbufContainS(&gpu->name, "Apple"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
|
||||
else if (ffStrbufContainS(&result.renderer, "Intel"))
|
||||
else if (ffStrbufContainS(&gpu->name, "Intel"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL);
|
||||
else if (ffStrbufContainS(&result.renderer, "AMD") || ffStrbufContainS(&result.renderer, "ATI"))
|
||||
else if (ffStrbufContainS(&gpu->name, "AMD") || ffStrbufContainS(&gpu->name, "ATI"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD);
|
||||
else if (ffStrbufContainS(&result.renderer, "NVIDIA"))
|
||||
else if (ffStrbufContainS(&gpu->name, "NVIDIA"))
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA);
|
||||
}
|
||||
if (ffStrbufEqualS(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE))
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&result.version);
|
||||
|
||||
@@ -38,12 +38,12 @@ static double detectGpuTemp(const FFstrbuf* gpuName)
|
||||
|
||||
const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
io_iterator_t iterator;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOAcceleratorClassName), &iterator) != kIOReturnSuccess)
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = IO_OBJECT_NULL;
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOAcceleratorClassName), &iterator) != kIOReturnSuccess)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
@@ -106,8 +106,6 @@ const char* ffDetectGPUImpl(const FFGPUOptions* options, FFlist* gpus)
|
||||
IOObjectRelease(registryEntry);
|
||||
}
|
||||
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
ffGpuDetectMetal(gpus);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ const char* ffGpuDetectMetal(FFlist* gpus)
|
||||
FFGPUResult* gpu = NULL;
|
||||
FF_LIST_FOR_EACH(FFGPUResult, x, *gpus)
|
||||
{
|
||||
if (x->deviceId == device.registryID || ffStrbufEqualS(&x->name, device.name.UTF8String))
|
||||
if (x->deviceId == device.registryID)
|
||||
{
|
||||
gpu = x;
|
||||
break;
|
||||
@@ -32,9 +32,20 @@ const char* ffGpuDetectMetal(FFlist* gpus)
|
||||
else if ([device supportsFamily:MTLGPUFamilyCommon1])
|
||||
ffStrbufSetStatic(&gpu->platformApi, "Metal Common 1");
|
||||
|
||||
gpu->type = device.hasUnifiedMemory ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
if (gpu->type == device.hasUnifiedMemory)
|
||||
{
|
||||
gpu->type = FF_GPU_TYPE_INTEGRATED;
|
||||
gpu->shared.total = device.recommendedMaxWorkingSetSize;
|
||||
gpu->shared.used = device.currentAllocatedSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpu->type = FF_GPU_TYPE_DISCRETE;
|
||||
gpu->dedicated.total = device.recommendedMaxWorkingSetSize;
|
||||
gpu->dedicated.used = device.currentAllocatedSize;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return "Metal API is not supported by this macOS version";
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "detection/gpu/gpu.h"
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#include "detection/vulkan/vulkan.h"
|
||||
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#endif
|
||||
|
||||
#ifdef FF_HAVE_LIBPCI
|
||||
#include "common/io/io.h"
|
||||
#include "common/library.h"
|
||||
@@ -245,6 +248,7 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
gpu->temperature = FF_GPU_TEMP_UNSET;
|
||||
gpu->frequency = FF_GPU_FREQUENCY_UNSET;
|
||||
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
if (gpu->vendor.chars == FF_GPU_VENDOR_NAME_NVIDIA && (options->temp || options->driverSpecific))
|
||||
{
|
||||
ffDetectNvidiaGpuInfo(&(FFGpuDriverCondition) {
|
||||
@@ -266,6 +270,7 @@ static void pciHandleDevice(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
if (gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET)
|
||||
gpu->type = gpu->dedicated.total > (uint64_t)1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED;
|
||||
}
|
||||
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
|
||||
#ifdef __linux__
|
||||
if(options->temp && gpu->temperature != gpu->temperature)
|
||||
|
||||
@@ -12,6 +12,7 @@ struct FFNvmlData {
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetMemoryInfo_v2)
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetNumGpuCores)
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetClockInfo)
|
||||
FF_LIBRARY_SYMBOL(nvmlDeviceGetBrand)
|
||||
|
||||
bool inited;
|
||||
} nvmlData;
|
||||
@@ -32,6 +33,7 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetMemoryInfo_v2)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetNumGpuCores)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetClockInfo)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libnvml, nvmlData, nvmlDeviceGetBrand)
|
||||
|
||||
if (ffnvmlInit_v2() != NVML_SUCCESS)
|
||||
{
|
||||
@@ -79,6 +81,24 @@ const char* ffDetectNvidiaGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverR
|
||||
if (!device) return "Device not found";
|
||||
}
|
||||
|
||||
nvmlBrandType_t brand;
|
||||
if (nvmlData.ffnvmlDeviceGetBrand(device, &brand) == NVML_SUCCESS)
|
||||
{
|
||||
switch (brand)
|
||||
{
|
||||
case NVML_BRAND_NVIDIA_RTX:
|
||||
case NVML_BRAND_QUADRO_RTX:
|
||||
case NVML_BRAND_GEFORCE:
|
||||
case NVML_BRAND_TITAN:
|
||||
case NVML_BRAND_TESLA:
|
||||
case NVML_BRAND_QUADRO:
|
||||
*result.type = FF_GPU_TYPE_DISCRETE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.temp)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#include "gpu.h"
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/windows/registry.h"
|
||||
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
#include "detection/gpu/gpu_driver_specific.h"
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
static int isGpuNameEqual(const FFGPUResult* gpu, const FFstrbuf* name)
|
||||
@@ -10,6 +13,7 @@ static int isGpuNameEqual(const FFGPUResult* gpu, const FFstrbuf* name)
|
||||
return ffStrbufEqual(&gpu->name, name);
|
||||
}
|
||||
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
static inline bool getDriverSpecificDetectionFn(const char* vendor, __typeof__(&ffDetectNvidiaGpuInfo)* pDetectFn, const char** pDllName)
|
||||
{
|
||||
if (vendor == FF_GPU_VENDOR_NAME_NVIDIA)
|
||||
@@ -44,6 +48,7 @@ static inline bool getDriverSpecificDetectionFn(const char* vendor, __typeof__(&
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
|
||||
const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus)
|
||||
{
|
||||
@@ -139,6 +144,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
__typeof__(&ffDetectNvidiaGpuInfo) detectFn;
|
||||
const char* dllName;
|
||||
|
||||
@@ -168,6 +174,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist*
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif // FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -98,6 +98,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
|
||||
const char* vendorStr = ffGetGPUVendorString((unsigned) hardwareId.vendorID);
|
||||
ffStrbufSetStatic(&gpu->vendor, vendorStr);
|
||||
|
||||
#ifdef FF_USE_PROPRIETARY_GPU_DRIVER_API
|
||||
if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA && (options->driverSpecific || options->temp))
|
||||
{
|
||||
FFGpuDriverCondition cond = {
|
||||
@@ -117,6 +118,7 @@ const char* ffGPUDetectByDirectX(FF_MAYBE_UNUSED const FFGPUOptions* options, FF
|
||||
.frequency = &gpu->frequency,
|
||||
}, "/usr/lib/wsl/lib/libnvidia-ml.so");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
|
||||
typedef struct FFHostResult
|
||||
{
|
||||
FFstrbuf productFamily;
|
||||
FFstrbuf productName;
|
||||
FFstrbuf productVersion;
|
||||
FFstrbuf productSku;
|
||||
FFstrbuf sysVendor;
|
||||
FFstrbuf family;
|
||||
FFstrbuf name;
|
||||
FFstrbuf version;
|
||||
FFstrbuf sku;
|
||||
FFstrbuf serial;
|
||||
FFstrbuf uuid;
|
||||
FFstrbuf vendor;
|
||||
} FFHostResult;
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host);
|
||||
|
||||
@@ -5,32 +5,32 @@
|
||||
const char* ffDetectHost(FFHostResult* host)
|
||||
{
|
||||
// http://newandroidbook.com/ddb/
|
||||
ffSettingsGetAndroidProperty("ro.product.device", &host->productFamily);
|
||||
ffSettingsGetAndroidProperty("ro.product.device", &host->family);
|
||||
|
||||
ffSettingsGetAndroidProperty("ro.product.marketname", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.vendor.product.display", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->productName)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.brand", &host->productName);
|
||||
ffSettingsGetAndroidProperty("ro.product.marketname", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.vendor.product.display", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.brand", &host->name);
|
||||
|
||||
if (ffSettingsGetAndroidProperty("ro.product.model", &host->productVersion))
|
||||
if (ffSettingsGetAndroidProperty("ro.product.model", &host->version))
|
||||
{
|
||||
if (ffStrbufStartsWithIgnCase(&host->productVersion, &host->productName))
|
||||
if (ffStrbufStartsWithIgnCase(&host->version, &host->name))
|
||||
{
|
||||
ffStrbufSubstrAfter(&host->productVersion, host->productName.length);
|
||||
ffStrbufTrimLeft(&host->productVersion, ' ');
|
||||
ffStrbufSubstrAfter(&host->version, host->name.length);
|
||||
ffStrbufTrimLeft(&host->version, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
ffSettingsGetAndroidProperty("ro.product.manufacturer", &host->sysVendor);
|
||||
ffSettingsGetAndroidProperty("ro.product.manufacturer", &host->vendor);
|
||||
|
||||
if(host->sysVendor.length && !ffStrbufStartsWithIgnCase(&host->productName, &host->sysVendor))
|
||||
if(host->vendor.length && !ffStrbufStartsWithIgnCase(&host->name, &host->vendor))
|
||||
{
|
||||
ffStrbufPrependS(&host->productName, " ");
|
||||
ffStrbufPrepend(&host->productName, &host->sysVendor);
|
||||
ffStrbufPrependS(&host->name, " ");
|
||||
ffStrbufPrepend(&host->name, &host->vendor);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -169,40 +169,48 @@ static const char* getProductNameWithHwModel(const FFstrbuf* hwModel)
|
||||
|
||||
const char* getProductNameWithIokit(FFstrbuf* result)
|
||||
{
|
||||
io_iterator_t iterator;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceNameMatching("product"), &iterator) != kIOReturnSuccess)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceNameMatching("product"));
|
||||
if (!registryEntry)
|
||||
return "IOServiceGetMatchingService() failed";
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFMutableDictionaryRef properties = NULL;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
{
|
||||
IOObjectRelease(registryEntry);
|
||||
continue;
|
||||
}
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef productName = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("product-name"), kCFAllocatorDefault, kNilOptions);
|
||||
if (!productName)
|
||||
return "IORegistryEntryCreateCFProperty() failed";
|
||||
|
||||
if (ffCfDictGetString(properties, CFSTR("product-name"), result))
|
||||
break;
|
||||
}
|
||||
return ffCfStrGetString(productName, result);
|
||||
}
|
||||
|
||||
const char* getOthersByIokit(FFHostResult* host)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t registryEntry = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("IOPlatformExpertDevice"));
|
||||
if (!registryEntry)
|
||||
return "IOServiceGetMatchingService() failed";
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef serialNumber = IORegistryEntryCreateCFProperty(registryEntry, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, kNilOptions);
|
||||
if (serialNumber)
|
||||
ffCfStrGetString(serialNumber, &host->serial);
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef uuid = IORegistryEntryCreateCFProperty(registryEntry, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, kNilOptions);
|
||||
if (uuid)
|
||||
ffCfStrGetString(uuid, &host->uuid);
|
||||
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef manufacturer = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("manufacturer"), kCFAllocatorDefault, kNilOptions);
|
||||
if (manufacturer)
|
||||
ffCfStrGetString(manufacturer, &host->vendor);
|
||||
|
||||
IOObjectRelease(registryEntry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host)
|
||||
{
|
||||
ffStrbufSetStatic(&host->sysVendor, "Apple");
|
||||
|
||||
const char* error = ffSysctlGetString("hw.model", &host->productFamily);
|
||||
const char* error = ffSysctlGetString("hw.model", &host->family);
|
||||
if (error) return error;
|
||||
|
||||
ffStrbufSetStatic(&host->productName, getProductNameWithHwModel(&host->productFamily));
|
||||
if (host->productName.length == 0)
|
||||
getProductNameWithIokit(&host->productName);
|
||||
if (host->productName.length == 0)
|
||||
ffStrbufSet(&host->productName, &host->productFamily);
|
||||
|
||||
ffStrbufSetStatic(&host->name, getProductNameWithHwModel(&host->family));
|
||||
if (host->name.length == 0)
|
||||
getProductNameWithIokit(&host->name);
|
||||
if (host->name.length == 0)
|
||||
ffStrbufSet(&host->name, &host->family);
|
||||
getOthersByIokit(host);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -4,16 +4,20 @@
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host)
|
||||
{
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.product", &host->productName);
|
||||
ffCleanUpSmbiosValue(&host->productName);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.family", &host->productFamily);
|
||||
ffCleanUpSmbiosValue(&host->productFamily);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.version", &host->productVersion);
|
||||
ffCleanUpSmbiosValue(&host->productVersion);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.sku", &host->productSku);
|
||||
ffCleanUpSmbiosValue(&host->productSku);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.maker", &host->sysVendor);
|
||||
ffCleanUpSmbiosValue(&host->sysVendor);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.product", &host->name);
|
||||
ffCleanUpSmbiosValue(&host->name);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.family", &host->family);
|
||||
ffCleanUpSmbiosValue(&host->family);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.version", &host->version);
|
||||
ffCleanUpSmbiosValue(&host->version);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.sku", &host->sku);
|
||||
ffCleanUpSmbiosValue(&host->sku);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.serial", &host->serial);
|
||||
ffCleanUpSmbiosValue(&host->serial);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.uuid", &host->uuid);
|
||||
ffCleanUpSmbiosValue(&host->uuid);
|
||||
ffSettingsGetFreeBSDKenv("smbios.system.maker", &host->vendor);
|
||||
ffCleanUpSmbiosValue(&host->vendor);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -7,48 +7,76 @@
|
||||
|
||||
static void getHostProductName(FFstrbuf* name)
|
||||
{
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", name);
|
||||
if(name->length > 0)
|
||||
return;
|
||||
if (ffReadFileBuffer("/sys/firmware/devicetree/base/model", name))
|
||||
{
|
||||
ffStrbufTrimRightSpace(name);
|
||||
ffStrbufTrimRight(name, '\0');
|
||||
if(ffIsSmbiosValueSet(name))
|
||||
return;
|
||||
}
|
||||
|
||||
ffReadFileBuffer("/sys/firmware/devicetree/base/model", name);
|
||||
if(ffIsSmbiosValueSet(name))
|
||||
return;
|
||||
if (ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name))
|
||||
{
|
||||
ffStrbufTrimRightSpace(name);
|
||||
ffStrbufTrimRight(name, '\0');
|
||||
if(ffIsSmbiosValueSet(name))
|
||||
return;
|
||||
}
|
||||
|
||||
ffReadFileBuffer("/sys/firmware/devicetree/base/banner-name", name);
|
||||
if(ffIsSmbiosValueSet(name))
|
||||
return;
|
||||
|
||||
//does a clear before the read
|
||||
ffReadFileBuffer("/tmp/sysinfo/model", name);
|
||||
if(ffIsSmbiosValueSet(name))
|
||||
return;
|
||||
if (ffReadFileBuffer("/tmp/sysinfo/model", name))
|
||||
{
|
||||
ffStrbufTrimRightSpace(name);
|
||||
ffStrbufTrimRight(name, '\0');
|
||||
if(ffIsSmbiosValueSet(name))
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufClear(name);
|
||||
}
|
||||
|
||||
static void getHostSerialNumber(FFstrbuf* serial)
|
||||
{
|
||||
if (ffReadFileBuffer("/sys/firmware/devicetree/base/serial-number", serial))
|
||||
{
|
||||
ffStrbufTrimRightSpace(serial);
|
||||
ffStrbufTrimRight(serial, '\0');
|
||||
if(ffIsSmbiosValueSet(serial))
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufClear(serial);
|
||||
}
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host)
|
||||
{
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->productFamily);
|
||||
getHostProductName(&host->productName);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->productVersion);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->productSku);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->sysVendor);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family);
|
||||
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name))
|
||||
getHostProductName(&host->name);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_version", "/sys/class/dmi/id/product_version", &host->version);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_sku", "/sys/class/dmi/id/product_sku", &host->sku);
|
||||
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial))
|
||||
getHostSerialNumber(&host->serial);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_uuid", "/sys/class/dmi/id/product_uuid", &host->uuid);
|
||||
if (!ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor))
|
||||
{
|
||||
if (ffStrbufStartsWithS(&host->name, "Apple "))
|
||||
ffStrbufSetStatic(&host->vendor, "Apple Inc.");
|
||||
}
|
||||
|
||||
//KVM/Qemu virtual machine
|
||||
if(ffStrbufStartsWithS(&host->productName, "Standard PC"))
|
||||
ffStrbufPrependS(&host->productName, "KVM/QEMU ");
|
||||
if(ffStrbufStartsWithS(&host->name, "Standard PC"))
|
||||
ffStrbufPrependS(&host->name, "KVM/QEMU ");
|
||||
|
||||
if(host->productFamily.length == 0 && host->productName.length == 0)
|
||||
if(host->family.length == 0 && host->name.length == 0)
|
||||
{
|
||||
const char* wslDistroName = getenv("WSL_DISTRO_NAME");
|
||||
//On WSL, the real host can't be detected. Instead use WSL as host.
|
||||
if(wslDistroName != NULL || getenv("WSL_DISTRO") != NULL || getenv("WSL_INTEROP") != NULL)
|
||||
{
|
||||
ffStrbufAppendS(&host->productName, "Windows Subsystem for Linux");
|
||||
ffStrbufAppendS(&host->name, "Windows Subsystem for Linux");
|
||||
if (wslDistroName)
|
||||
ffStrbufAppendF(&host->productName, " - %s", wslDistroName);
|
||||
ffStrbufAppendS(&host->productFamily, "WSL");
|
||||
ffStrbufAppendF(&host->name, " - %s", wslDistroName);
|
||||
ffStrbufAppendS(&host->family, "WSL");
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY wslVer = ffStrbufCreate(); //Wide characters
|
||||
if(!ffProcessAppendStdOut(&wslVer, (char* const[]){
|
||||
@@ -61,7 +89,7 @@ const char* ffDetectHost(FFHostResult* host)
|
||||
ffStrbufSubstrAfterLastC(&wslVer, ' ');
|
||||
for(uint32_t i = 0; i < wslVer.length; ++i) {
|
||||
if(wslVer.chars[i]) //don't append \0
|
||||
ffStrbufAppendC(&host->productVersion, wslVer.chars[i]);
|
||||
ffStrbufAppendC(&host->version, wslVer.chars[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,69 @@
|
||||
#include "host.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/smbiosHelper.h"
|
||||
|
||||
typedef struct FFSmbiosSystemInfo
|
||||
{
|
||||
FFSmbiosHeader Header;
|
||||
|
||||
uint8_t Manufacturer; // string
|
||||
uint8_t ProductName; // string
|
||||
uint8_t Version; // string
|
||||
uint8_t SerialNumber; // string
|
||||
|
||||
// 2.1+
|
||||
struct {
|
||||
uint32_t TimeLow;
|
||||
uint16_t TimeMid;
|
||||
uint16_t TimeHighAndVersion;
|
||||
uint8_t ClockSeqHiAndReserved;
|
||||
uint8_t ClockSeqLow;
|
||||
uint8_t Node[6];
|
||||
} UUID; // varies
|
||||
uint8_t WakeUpType; // enum
|
||||
|
||||
// 2.4+
|
||||
uint8_t SKUNumber; // string
|
||||
uint8_t Family; // string
|
||||
} FFSmbiosSystemInfo;
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host)
|
||||
{
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
const FFSmbiosSystemInfo* data = (const FFSmbiosSystemInfo*) (*ffGetSmbiosHeaderTable())[FF_SMBIOS_TYPE_SYSTEM_INFO];
|
||||
if (!data)
|
||||
return "System information is not found in SMBIOS data";
|
||||
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\BIOS", &hKey, NULL))
|
||||
return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\BIOS\", &hKey, NULL) failed";
|
||||
const char* strings = (const char*) data + data->Header.Length;
|
||||
|
||||
ffRegReadStrbuf(hKey, L"SystemProductName", &host->productName, NULL);
|
||||
ffCleanUpSmbiosValue(&host->productName);
|
||||
ffRegReadStrbuf(hKey, L"SystemFamily", &host->productFamily, NULL);
|
||||
ffCleanUpSmbiosValue(&host->productFamily);
|
||||
ffRegReadStrbuf(hKey, L"SystemVersion", &host->productVersion, NULL);
|
||||
ffCleanUpSmbiosValue(&host->productVersion);
|
||||
ffRegReadStrbuf(hKey, L"SystemSKU", &host->productSku, NULL);
|
||||
ffCleanUpSmbiosValue(&host->productSku);
|
||||
ffRegReadStrbuf(hKey, L"SystemManufacturer", &host->sysVendor, NULL);
|
||||
ffCleanUpSmbiosValue(&host->sysVendor);
|
||||
ffStrbufSetStatic(&host->vendor, ffSmbiosLocateString(strings, data->Manufacturer));
|
||||
ffCleanUpSmbiosValue(&host->vendor);
|
||||
ffStrbufSetStatic(&host->name, ffSmbiosLocateString(strings, data->ProductName));
|
||||
ffCleanUpSmbiosValue(&host->name);
|
||||
ffStrbufSetStatic(&host->version, ffSmbiosLocateString(strings, data->Version));
|
||||
ffCleanUpSmbiosValue(&host->version);
|
||||
ffStrbufSetStatic(&host->serial, ffSmbiosLocateString(strings, data->SerialNumber));
|
||||
ffCleanUpSmbiosValue(&host->serial);
|
||||
|
||||
static_assert(offsetof(FFSmbiosSystemInfo, UUID) == 0x08, "FFSmbiosSystemInfo.UUID offset is wrong");
|
||||
if (data->Header.Length > offsetof(FFSmbiosSystemInfo, UUID))
|
||||
{
|
||||
ffStrbufSetF(&host->uuid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
data->UUID.TimeLow, data->UUID.TimeMid, data->UUID.TimeHighAndVersion,
|
||||
data->UUID.ClockSeqHiAndReserved, data->UUID.ClockSeqLow,
|
||||
data->UUID.Node[0], data->UUID.Node[1], data->UUID.Node[2], data->UUID.Node[3], data->UUID.Node[4], data->UUID.Node[5]);
|
||||
}
|
||||
|
||||
static_assert(offsetof(FFSmbiosSystemInfo, SKUNumber) == 0x19, "FFSmbiosSystemInfo.SKUNumber offset is wrong");
|
||||
if (data->Header.Length > offsetof(FFSmbiosSystemInfo, SKUNumber))
|
||||
{
|
||||
ffStrbufSetStatic(&host->sku, ffSmbiosLocateString(strings, data->SKUNumber));
|
||||
ffCleanUpSmbiosValue(&host->sku);
|
||||
}
|
||||
|
||||
if (data->Header.Length > offsetof(FFSmbiosSystemInfo, Family))
|
||||
{
|
||||
ffStrbufSetStatic(&host->family, ffSmbiosLocateString(strings, data->Family));
|
||||
ffCleanUpSmbiosValue(&host->family);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -21,14 +21,14 @@ static void getLocaleFromEnv(FFstrbuf* locale)
|
||||
|
||||
static void getLocaleFromStdFn(FFstrbuf* locale)
|
||||
{
|
||||
ffStrbufAppendS(locale, setlocale(LC_ALL, NULL));
|
||||
|
||||
#ifdef LC_MESSAGES
|
||||
ffStrbufAppendS(locale, setlocale(LC_MESSAGES, NULL));
|
||||
|
||||
if(locale->length > 0)
|
||||
return;
|
||||
|
||||
ffStrbufAppendS(locale, setlocale(LC_MESSAGES, NULL));
|
||||
#endif
|
||||
|
||||
ffStrbufAppendS(locale, setlocale(LC_ALL, NULL));
|
||||
}
|
||||
|
||||
void ffDetectLocale(FFstrbuf* result)
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "detection/locale/locale.h"
|
||||
#include "util/windows/unicode.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <locale.h>
|
||||
|
||||
void ffDetectLocale(FFstrbuf* result)
|
||||
{
|
||||
wchar_t name[LOCALE_NAME_MAX_LENGTH];
|
||||
int size = GetUserDefaultLocaleName(name, LOCALE_NAME_MAX_LENGTH);
|
||||
if (size > 1) // including '\0'
|
||||
{
|
||||
ffStrbufSetNWS(result, (uint32_t)size - 1, name);
|
||||
ffStrbufAppendS(result, ".UTF-8"); // set explicitly in `ffInitInstance`
|
||||
}
|
||||
else
|
||||
ffStrbufSetS(result, setlocale(LC_ALL, NULL));
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/media/media.h"
|
||||
#include "common/thread.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <string.h>
|
||||
@@ -11,7 +10,6 @@
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include "common/dbus.h"
|
||||
#include "common/library.h"
|
||||
#include "common/parsing.h"
|
||||
|
||||
static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result)
|
||||
{
|
||||
|
||||
@@ -8,6 +8,9 @@ typedef struct FFMonitorResult
|
||||
uint32_t physicalWidth; // in mm
|
||||
uint32_t physicalHeight; // in mm
|
||||
bool hdrCompatible;
|
||||
uint16_t manufactureYear;
|
||||
uint16_t manufactureWeek;
|
||||
uint32_t serial;
|
||||
} FFMonitorResult;
|
||||
|
||||
const char* ffDetectMonitor(FFlist* results);
|
||||
|
||||
@@ -40,9 +40,13 @@ const char* ffDetectMonitor(FFlist* results)
|
||||
CFDictionaryRef FF_CFTYPE_AUTO_RELEASE displayInfo = CoreDisplay_DisplayCreateInfoDictionary((CGDirectDisplayID) display->id);
|
||||
if(!displayInfo) continue;
|
||||
|
||||
bool isVirtual = false;
|
||||
if (ffCfDictGetBool(displayInfo, CFSTR("kCGDisplayIsVirtualDevice"), &isVirtual) == NULL && isVirtual)
|
||||
continue;
|
||||
|
||||
uint8_t edidData[128] = {};
|
||||
uint32_t edidLength = 0;
|
||||
if (false || !ffCfDictGetData(displayInfo, CFSTR("IODisplayEDID"), 0, sizeof(edidData), edidData, &edidLength))
|
||||
if (ffCfDictGetData(displayInfo, CFSTR("IODisplayEDID"), 0, sizeof(edidData), edidData, &edidLength) == NULL)
|
||||
{
|
||||
uint32_t width, height;
|
||||
ffEdidGetPhysicalResolution(edidData, &width, &height);
|
||||
@@ -75,6 +79,14 @@ const char* ffDetectMonitor(FFlist* results)
|
||||
monitor->physicalHeight = (uint32_t) (size.height + 0.5);
|
||||
monitor->hdrCompatible = CFDictionaryContainsKey(displayInfo, CFSTR("ReferencePeakHDRLuminance")) ||
|
||||
detectHdrSupportWithNSScreen(display);
|
||||
|
||||
int64_t serial, year, week;
|
||||
if (ffCfDictGetInt64(displayInfo, CFSTR("DisplaySerialNumber"), &serial) == NULL)
|
||||
monitor->serial = (uint32_t) (uint64_t) serial;
|
||||
if (ffCfDictGetInt64(displayInfo, CFSTR("DisplayYearManufacture"), &year) == NULL)
|
||||
monitor->manufactureYear = (uint16_t) year;
|
||||
if (ffCfDictGetInt64(displayInfo, CFSTR("DisplayWeekManufacture"), &week) == NULL)
|
||||
monitor->manufactureWeek = (uint16_t) week;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -29,10 +29,10 @@ const char* ffDetectMonitor(FFlist* results)
|
||||
ffStrbufAppendS(&drmDir, entry->d_name);
|
||||
uint32_t drmDirWithDnameLength = drmDir.length;
|
||||
|
||||
ffStrbufAppendS(&drmDir, "/enabled");
|
||||
char enabled = 'd'; // disabled
|
||||
ffReadFileData(drmDir.chars, sizeof(enabled), &enabled);
|
||||
if (enabled != 'e') // enabled
|
||||
ffStrbufAppendS(&drmDir, "/status");
|
||||
char status = 'd'; // disconnected
|
||||
ffReadFileData(drmDir.chars, sizeof(status), &status);
|
||||
if (status != 'c') // connected
|
||||
{
|
||||
ffStrbufSubstrBefore(&drmDir, drmDirLength);
|
||||
continue;
|
||||
@@ -59,6 +59,7 @@ const char* ffDetectMonitor(FFlist* results)
|
||||
ffStrbufInit(&display->name);
|
||||
ffEdidGetName(edidData, &display->name);
|
||||
ffEdidGetPhysicalSize(edidData, &display->physicalWidth, &display->physicalHeight);
|
||||
ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek);
|
||||
display->hdrCompatible = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,7 @@ const char* ffDetectMonitor(FFlist* results)
|
||||
FFMonitorResult* display = (FFMonitorResult*) ffListAdd(results);
|
||||
display->width = width;
|
||||
display->height = height;
|
||||
ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek);
|
||||
display->hdrCompatible = ffEdidGetHdrCompatible(edidData, edidLength); // Doesn't work. edidLength is always 128
|
||||
ffStrbufInit(&display->name);
|
||||
ffEdidGetName(edidData, &display->name);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "os.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -72,11 +74,11 @@ static bool detectOSCodeName(FFOSResult* os)
|
||||
|
||||
static void parseOSXSoftwareLicense(FFOSResult* os)
|
||||
{
|
||||
FILE* rtf = fopen("/System/Library/CoreServices/Setup Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf", "r");
|
||||
FF_AUTO_CLOSE_FILE FILE* rtf = fopen("/System/Library/CoreServices/Setup Assistant.app/Contents/Resources/en.lproj/OSXSoftwareLicense.rtf", "r");
|
||||
if(rtf == NULL)
|
||||
return;
|
||||
|
||||
char* line = NULL;
|
||||
FF_AUTO_FREE char* line = NULL;
|
||||
size_t len = 0;
|
||||
const char* searchStr = "\\f0\\b SOFTWARE LICENSE AGREEMENT FOR macOS ";
|
||||
while(getline(&line, &len, rtf) != EOF)
|
||||
@@ -89,11 +91,6 @@ static void parseOSXSoftwareLicense(FFOSResult* os)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(line != NULL)
|
||||
free(line);
|
||||
|
||||
fclose(rtf);
|
||||
}
|
||||
|
||||
void ffDetectOSImpl(FFOSResult* os)
|
||||
|
||||
@@ -9,14 +9,6 @@
|
||||
#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
|
||||
#include <IOKit/storage/nvme/NVMeSMARTLibExternal.h>
|
||||
|
||||
static inline void wrapIoObjectRelease(io_service_t* service)
|
||||
{
|
||||
assert(service);
|
||||
if (*service)
|
||||
IOObjectRelease(*service);
|
||||
}
|
||||
#define FF_IOOBJECT_AUTO_RELEASE __attribute__((__cleanup__(wrapIoObjectRelease)))
|
||||
|
||||
static inline void wrapIoDestroyPlugInInterface(IOCFPlugInInterface*** pluginInf)
|
||||
{
|
||||
assert(pluginInf);
|
||||
@@ -49,11 +41,11 @@ static const char* detectSsdTemp(io_service_t entryPhysical, double* temp)
|
||||
const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_iterator_t iterator = 0;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS)
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching(kIOMediaClass), &iterator) != KERN_SUCCESS)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
while ((registryEntry = IOIteratorNext(iterator)) != IO_OBJECT_NULL)
|
||||
{
|
||||
FF_IOOBJECT_AUTO_RELEASE io_registry_entry_t entryPartition = registryEntry;
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ typedef struct FFPowerAdapterResult
|
||||
FFstrbuf name;
|
||||
FFstrbuf modelName;
|
||||
FFstrbuf manufacturer;
|
||||
FFstrbuf serial;
|
||||
int watts;
|
||||
} FFPowerAdapterResult;
|
||||
|
||||
const char* ffDetectPowerAdapterImpl(FFlist* results);
|
||||
const char* ffDetectPowerAdapter(FFlist* results);
|
||||
|
||||
#define FF_POWERADAPTER_UNSET -2
|
||||
#define FF_POWERADAPTER_NOT_CONNECTED -1
|
||||
|
||||
@@ -2,51 +2,30 @@
|
||||
#include "poweradapter.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
|
||||
const char* ffDetectPowerAdapterImpl(FFlist* results)
|
||||
const char* ffDetectPowerAdapter(FFlist* results)
|
||||
{
|
||||
io_iterator_t iterator;
|
||||
if(IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSmartBattery"), &iterator) != kIOReturnSuccess)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef details = IOPSCopyExternalPowerAdapterDetails();
|
||||
FFPowerAdapterResult* adapter = ffListAdd(results);
|
||||
|
||||
io_registry_entry_t registryEntry;
|
||||
while((registryEntry = IOIteratorNext(iterator)) != 0)
|
||||
ffStrbufInit(&adapter->name);
|
||||
ffStrbufInit(&adapter->description);
|
||||
ffStrbufInit(&adapter->manufacturer);
|
||||
ffStrbufInit(&adapter->modelName);
|
||||
ffStrbufInit(&adapter->serial);
|
||||
adapter->watts = FF_POWERADAPTER_NOT_CONNECTED;
|
||||
|
||||
if (details)
|
||||
{
|
||||
CFMutableDictionaryRef properties;
|
||||
if(IORegistryEntryCreateCFProperties(registryEntry, &properties, kCFAllocatorDefault, kNilOptions) != kIOReturnSuccess)
|
||||
{
|
||||
IOObjectRelease(registryEntry);
|
||||
continue;
|
||||
}
|
||||
|
||||
FFPowerAdapterResult* adapter = ffListAdd(results);
|
||||
|
||||
ffStrbufInit(&adapter->name);
|
||||
ffStrbufInit(&adapter->description);
|
||||
ffStrbufInit(&adapter->manufacturer);
|
||||
ffStrbufInit(&adapter->modelName);
|
||||
adapter->watts = FF_POWERADAPTER_UNSET;
|
||||
|
||||
CFDictionaryRef adapterDict;
|
||||
if(!ffCfDictGetDict(properties, CFSTR("AdapterDetails"), &adapterDict))
|
||||
{
|
||||
if (ffCfDictGetInt(adapterDict, CFSTR("Watts"), &adapter->watts))
|
||||
{
|
||||
adapter->watts = FF_POWERADAPTER_NOT_CONNECTED;
|
||||
continue;
|
||||
}
|
||||
ffCfDictGetString(adapterDict, CFSTR("Name"), &adapter->name);
|
||||
ffCfDictGetString(adapterDict, CFSTR("Description"), &adapter->description);
|
||||
ffCfDictGetString(adapterDict, CFSTR("Manufacturer"), &adapter->manufacturer);
|
||||
ffCfDictGetString(adapterDict, CFSTR("Model"), &adapter->modelName);
|
||||
}
|
||||
|
||||
CFRelease(properties);
|
||||
IOObjectRelease(registryEntry);
|
||||
ffCfDictGetString(details, CFSTR(kIOPSNameKey), &adapter->name);
|
||||
ffCfDictGetString(details, CFSTR("Model"), &adapter->modelName);
|
||||
ffCfDictGetString(details, CFSTR("Manufacturer"), &adapter->manufacturer);
|
||||
ffCfDictGetString(details, CFSTR("Description"), &adapter->description);
|
||||
ffCfDictGetString(details, CFSTR("SerialString"), &adapter->serial);
|
||||
ffCfDictGetInt(details, CFSTR(kIOPSPowerAdapterWattsKey), &adapter->watts);
|
||||
}
|
||||
|
||||
IOObjectRelease(iterator);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "poweradapter.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
static void parsePowerAdapter(FFstrbuf* dir, FF_MAYBE_UNUSED const char* id, FFlist* results)
|
||||
{
|
||||
uint32_t dirLength = dir->length;
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY tmpBuffer = ffStrbufCreate();
|
||||
|
||||
//type must exist and be "Mains"
|
||||
ffStrbufAppendS(dir, "/type");
|
||||
if (ffReadFileBuffer(dir->chars, &tmpBuffer))
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if(!ffStrbufIgnCaseEqualS(&tmpBuffer, "Mains"))
|
||||
return;
|
||||
|
||||
//scope may not exist or must not be "Device" (?)
|
||||
ffStrbufAppendS(dir, "/scope");
|
||||
if (ffReadFileBuffer(dir->chars, &tmpBuffer))
|
||||
ffStrbufTrimRightSpace(&tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&tmpBuffer, "Device"))
|
||||
return;
|
||||
|
||||
//input_power_limit must exist and be not empty
|
||||
ffStrbufAppendS(dir, "/input_power_limit");
|
||||
bool available = ffReadFileBuffer(dir->chars, &tmpBuffer);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if (!available)
|
||||
return;
|
||||
|
||||
FFPowerAdapterResult* result = ffListAdd(results);
|
||||
ffStrbufInit(&result->name);
|
||||
ffStrbufInit(&result->description);
|
||||
|
||||
ffStrbufAppendS(dir, "/online");
|
||||
char online = '1';
|
||||
ffReadFileData(dir->chars, sizeof(online), &online);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
if (online == '0')
|
||||
result->watts = FF_POWERADAPTER_NOT_CONNECTED;
|
||||
else
|
||||
result->watts = (int) (ffStrbufToDouble(&tmpBuffer) / 1e6 + 0.5);
|
||||
|
||||
//At this point, we have a battery. Try to get as much values as possible.
|
||||
|
||||
ffStrbufInit(&result->manufacturer);
|
||||
ffStrbufAppendS(dir, "/manufacturer");
|
||||
if (ffReadFileBuffer(dir->chars, &result->manufacturer))
|
||||
ffStrbufTrimRightSpace(&result->manufacturer);
|
||||
else if (ffStrEquals(id, "macsmc-ac")) // asahi
|
||||
ffStrbufSetStatic(&result->manufacturer, "Apple Inc.");
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->modelName);
|
||||
ffStrbufAppendS(dir, "/model_name");
|
||||
if (ffReadFileBuffer(dir->chars, &result->modelName))
|
||||
ffStrbufTrimRightSpace(&result->modelName);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
|
||||
ffStrbufInit(&result->serial);
|
||||
ffStrbufAppendS(dir, "/serial_number");
|
||||
if (ffReadFileBuffer(dir->chars, &result->serial))
|
||||
ffStrbufTrimRightSpace(&result->serial);
|
||||
ffStrbufSubstrBefore(dir, dirLength);
|
||||
}
|
||||
|
||||
const char* ffDetectPowerAdapter(FFlist* results)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY baseDir = ffStrbufCreateA(64);
|
||||
ffStrbufAppendS(&baseDir, "/sys/class/power_supply/");
|
||||
|
||||
uint32_t baseDirLength = baseDir.length;
|
||||
|
||||
FF_AUTO_CLOSE_DIR DIR* dirp = opendir(baseDir.chars);
|
||||
if(dirp == NULL)
|
||||
return "opendir(\"/sys/class/power_supply/\") == NULL";
|
||||
|
||||
struct dirent* entry;
|
||||
while((entry = readdir(dirp)) != NULL)
|
||||
{
|
||||
if(ffStrEquals(entry->d_name, ".") || ffStrEquals(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
ffStrbufAppendS(&baseDir, entry->d_name);
|
||||
parsePowerAdapter(&baseDir, entry->d_name, results);
|
||||
ffStrbufSubstrBefore(&baseDir, baseDirLength);
|
||||
}
|
||||
|
||||
if(results->length == 0)
|
||||
return "\"/sys/class/power_supply/\" doesn't contain any power adapter folder";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "poweradapter.h"
|
||||
|
||||
const char* ffDetectPowerAdapterImpl(FFlist* results)
|
||||
const char* ffDetectPowerAdapter(FF_MAYBE_UNUSED FFlist* results)
|
||||
{
|
||||
FF_UNUSED(results);
|
||||
return "Not supported on this platform";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "sound.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/sysctl.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/soundcard.h>
|
||||
|
||||
const char* ffDetectSound(FFlist* devices)
|
||||
{
|
||||
char path[] = "/dev/mixer0";
|
||||
int defaultDev = ffSysctlGetInt("hw.snd.default_unit", -1);
|
||||
|
||||
for (int idev = 0; idev <= 9; ++idev)
|
||||
{
|
||||
path[strlen("/dev/mixer")] = (char) ('0' + idev);
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDWR);
|
||||
if (fd < 0) break;
|
||||
|
||||
uint32_t devmask = 0;
|
||||
if (ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0)
|
||||
continue;
|
||||
if (!(devmask & SOUND_MASK_VOLUME))
|
||||
continue;
|
||||
|
||||
uint32_t mutemask = 0;
|
||||
if (ioctl(fd, SOUND_MIXER_READ_MUTE, &mutemask) < 0)
|
||||
continue;
|
||||
|
||||
struct oss_card_info ci = { .card = idev };
|
||||
if (ioctl(fd, SNDCTL_CARDINFO, &ci) < 0)
|
||||
continue;
|
||||
|
||||
uint32_t volume;
|
||||
if (ioctl(fd, SOUND_MIXER_READ_VOLUME, &volume) < 0)
|
||||
continue;
|
||||
|
||||
FFSoundDevice* device = ffListAdd(devices);
|
||||
ffStrbufInitS(&device->identifier, path);
|
||||
ffStrbufInitF(&device->name, "%s %s", ci.longname, ci.hw_info);
|
||||
device->volume = mutemask & SOUND_MASK_VOLUME
|
||||
? 0
|
||||
: ((uint8_t) volume /*left*/ + (uint8_t) (volume >> 8) /*right*/) / 2;
|
||||
device->active = true;
|
||||
device->main = defaultDev == idev;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -85,12 +85,9 @@ static void smcUltostr(char *str, uint32_t val)
|
||||
|
||||
static const char *smcCall(io_connect_t conn, uint32_t selector, SmcKeyData_t *inputStructure, SmcKeyData_t *outputStructure)
|
||||
{
|
||||
size_t structureInputSize;
|
||||
size_t structureOutputSize;
|
||||
structureInputSize = sizeof(SmcKeyData_t);
|
||||
structureOutputSize = sizeof(SmcKeyData_t);
|
||||
size_t size = sizeof(SmcKeyData_t);
|
||||
|
||||
if (IOConnectCallStructMethod(conn, selector, inputStructure, structureInputSize, outputStructure, &structureOutputSize) != kIOReturnSuccess)
|
||||
if (IOConnectCallStructMethod(conn, selector, inputStructure, size, outputStructure, &size) != kIOReturnSuccess)
|
||||
return "IOConnectCallStructMethod(conn) failed";
|
||||
return NULL;
|
||||
}
|
||||
@@ -140,17 +137,13 @@ static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV
|
||||
|
||||
static const char *smcOpen(io_connect_t *conn)
|
||||
{
|
||||
io_iterator_t iterator;
|
||||
if (IOServiceGetMatchingServices(MACH_PORT_NULL, IOServiceMatching("AppleSMC"), &iterator) != kIOReturnSuccess)
|
||||
return "IOServiceGetMatchingServices() failed";
|
||||
|
||||
io_object_t device = IOIteratorNext(iterator);
|
||||
IOObjectRelease(iterator);
|
||||
if (device == 0)
|
||||
io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC"));
|
||||
if (!device)
|
||||
return "No SMC device found";
|
||||
|
||||
kern_return_t result = IOServiceOpen(device, mach_task_self(), 0, conn);
|
||||
IOObjectRelease(device);
|
||||
|
||||
if (result != kIOReturnSuccess)
|
||||
return "IOServiceOpen() failed";
|
||||
|
||||
@@ -290,10 +283,13 @@ static bool detectTemp(io_connect_t conn, const char *sensor, double* sum)
|
||||
const char *ffDetectSmcTemps(enum FFTempType type, double *result)
|
||||
{
|
||||
static io_connect_t conn;
|
||||
static dispatch_once_t once_control;
|
||||
dispatch_once_f(&once_control, &conn, (dispatch_function_t) smcOpen);
|
||||
if(!conn)
|
||||
return "smcOpen() failed";
|
||||
if (!conn)
|
||||
{
|
||||
if (smcOpen(&conn) != NULL)
|
||||
conn = (io_connect_t) -1;
|
||||
}
|
||||
else if (conn == (io_connect_t) -1)
|
||||
return "Could not open SMC connection";
|
||||
|
||||
uint32_t count = 0;
|
||||
*result = 0;
|
||||
|
||||
@@ -394,35 +394,35 @@ static bool detectContour(const FFstrbuf* exe, FFTerminalFontResult* result)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont);
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont);
|
||||
|
||||
static bool detectTerminalFontCommon(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
|
||||
static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
|
||||
{
|
||||
if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "alacritty"))
|
||||
if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "alacritty"))
|
||||
detectAlacritty(terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "terminator"))
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "terminator"))
|
||||
detectTerminator(terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "wezterm-gui"))
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "wezterm-gui"))
|
||||
detectWezterm(terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "tabby"))
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "tabby"))
|
||||
detectTabby(terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "contour"))
|
||||
detectContour(&terminalShell->terminalExe, terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "contour"))
|
||||
detectContour(&terminal->exe, terminalFont);
|
||||
|
||||
#ifndef _WIN32
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalExe, "/dev/pts/"))
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/pts/"))
|
||||
ffStrbufAppendS(&terminalFont->error, "Terminal font detection is not supported on PTS");
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "kitty"))
|
||||
detectKitty(&terminalShell->terminalExe, terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalExe, "/dev/tty"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "kitty"))
|
||||
detectKitty(&terminal->exe, terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->exe, "/dev/tty"))
|
||||
detectTTY(terminalFont);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__linux__)
|
||||
//Used by both Linux (WSL) and Windows
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "Windows Terminal") ||
|
||||
ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "WindowsTerminal.exe"))
|
||||
detectFromWindowsTeriminal(&terminalShell->terminalExe, terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "Windows Terminal") ||
|
||||
ffStrbufIgnCaseEqualS(&terminal->processName, "WindowsTerminal.exe"))
|
||||
detectFromWindowsTeriminal(&terminal->exe, terminalFont);
|
||||
#endif
|
||||
|
||||
else
|
||||
@@ -433,16 +433,16 @@ static bool detectTerminalFontCommon(const FFTerminalShellResult* terminalShell,
|
||||
|
||||
bool ffDetectTerminalFont(FFTerminalFontResult* result)
|
||||
{
|
||||
const FFTerminalShellResult* terminalShell = ffDetectTerminalShell();
|
||||
const FFTerminalResult* terminal = ffDetectTerminal();
|
||||
|
||||
if(terminalShell->terminalProcessName.length == 0)
|
||||
if(terminal->processName.length == 0)
|
||||
ffStrbufAppendS(&result->error, "Terminal font needs successful terminal detection");
|
||||
|
||||
else if(!detectTerminalFontCommon(terminalShell, result))
|
||||
ffDetectTerminalFontPlatform(terminalShell, result);
|
||||
else if(!detectTerminalFontCommon(terminal, result))
|
||||
ffDetectTerminalFontPlatform(terminal, result);
|
||||
|
||||
if(result->error.length == 0 && result->font.pretty.length == 0)
|
||||
ffStrbufAppendF(&result->error, "Unknown terminal: %s", terminalShell->terminalProcessName.chars);
|
||||
ffStrbufAppendF(&result->error, "Unknown terminal: %s", terminal->processName.chars);
|
||||
|
||||
return result->error.length == 0;
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ exit:
|
||||
#endif
|
||||
}
|
||||
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
|
||||
{
|
||||
if(ffStrbufCompS(&terminalShell->terminalProcessName, "com.termux") != 0)
|
||||
if(ffStrbufCompS(&terminal->processName, "com.termux") != 0)
|
||||
{
|
||||
ffStrbufSetS(&terminalFont->error, "Unsupported terminal");
|
||||
return;
|
||||
|
||||
@@ -91,13 +91,13 @@ static void detectWarpTerminal(FFTerminalFontResult* terminalFont)
|
||||
ffFontInitValues(&terminalFont->font, fontName.UTF8String, fontSize.UTF8String);
|
||||
}
|
||||
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
|
||||
{
|
||||
if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "iterm.app") == 0 ||
|
||||
ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "iTermServer-"))
|
||||
if(ffStrbufIgnCaseEqualS(&terminal->processName, "iterm.app") ||
|
||||
ffStrbufStartsWithIgnCaseS(&terminal->processName, "iTermServer-"))
|
||||
detectIterm2(terminalFont);
|
||||
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "Apple_Terminal") == 0)
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "Apple_Terminal"))
|
||||
detectAppleTerminal(terminalFont);
|
||||
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "WarpTerminal") == 0)
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal"))
|
||||
detectWarpTerminal(terminalFont);
|
||||
}
|
||||
|
||||
@@ -303,32 +303,32 @@ static void detectSt(FFTerminalFontResult* terminalFont, uint32_t pid)
|
||||
ffFontInitValues(&terminalFont->font, font.chars, size.chars);
|
||||
}
|
||||
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
|
||||
{
|
||||
if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "konsole"))
|
||||
if(ffStrbufIgnCaseEqualS(&terminal->processName, "konsole"))
|
||||
detectKonsole(terminalFont, "konsolerc");
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "yakuake"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "yakuake"))
|
||||
detectKonsole(terminalFont, "yakuakerc");
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "xfce4-terminal"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "xfce4-terminal"))
|
||||
detectXFCETerminal(terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "lxterminal"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "lxterminal"))
|
||||
detectFromConfigFile("lxterminal/lxterminal.conf", "fontname =", terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "tilix"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "tilix"))
|
||||
detectFromGSettings("/com/gexperts/Tilix/profiles/", "com.gexperts.Tilix.ProfilesList", "com.gexperts.Tilix.Profile", "default", terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "gnome-terminal-"))
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "gnome-terminal-"))
|
||||
detectFromGSettings("/org/gnome/terminal/legacy/profiles:/:", "org.gnome.Terminal.ProfilesList", "org.gnome.Terminal.Legacy.Profile", "default", terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "kgx"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "kgx"))
|
||||
detectKgx(terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "mate-terminal"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "mate-terminal"))
|
||||
detectFromGSettings("/org/mate/terminal/profiles/", "org.mate.terminal.global", "org.mate.terminal.profile", "default-profile", terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "deepin-terminal"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "deepin-terminal"))
|
||||
detectDeepinTerminal(terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "foot"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "foot"))
|
||||
detectFootTerminal(terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "qterminal"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "qterminal"))
|
||||
detectQTerminal(terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "xterm"))
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "xterm"))
|
||||
detectXterm(terminalFont);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminalShell->terminalProcessName, "st"))
|
||||
detectSt(terminalFont, terminalShell->terminalPid);
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "st"))
|
||||
detectSt(terminalFont, terminal->pid);
|
||||
}
|
||||
|
||||
@@ -85,12 +85,12 @@ static void detectConEmu(FFTerminalFontResult* terminalFont)
|
||||
ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars);
|
||||
}
|
||||
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalShellResult* terminalShell, FFTerminalFontResult* terminalFont)
|
||||
void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont)
|
||||
{
|
||||
if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "mintty") == 0)
|
||||
if(ffStrbufIgnCaseEqualS(&terminal->processName, "mintty"))
|
||||
detectMintty(terminalFont);
|
||||
else if(ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "conhost.exe") == 0)
|
||||
else if(ffStrbufIgnCaseEqualS(&terminal->processName, "conhost.exe"))
|
||||
detectConhost(terminalFont);
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "ConEmu"))
|
||||
else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "ConEmu"))
|
||||
detectConEmu(terminalFont);
|
||||
}
|
||||
|
||||
@@ -152,6 +152,22 @@ static bool getShellVersionNushell(FFstrbuf* exe, FFstrbuf* version)
|
||||
return getExeVersionRaw(exe, version); //0.73.0
|
||||
}
|
||||
|
||||
static bool getShellVersionAsh(FFstrbuf* exe, FFstrbuf* version)
|
||||
{
|
||||
if(ffProcessAppendStdErr(version, (char* const[]) {
|
||||
exe->chars,
|
||||
"--help",
|
||||
NULL
|
||||
}) != NULL)
|
||||
return false;
|
||||
|
||||
// BusyBox v1.36.1 (2023-11-07 18:53:09 UTC) multi-call binary...
|
||||
ffStrbufSubstrAfterFirstC(version, ' ');
|
||||
ffStrbufSubstrBeforeFirstC(version, ' ');
|
||||
ffStrbufTrimLeft(version, 'v');
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static bool getShellVersionWinPowerShell(FFstrbuf* exe, FFstrbuf* version)
|
||||
{
|
||||
@@ -210,6 +226,8 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version)
|
||||
return getShellVersionOils(exe, version);
|
||||
if(strcasecmp(exeName, "elvish") == 0)
|
||||
return getExeVersionRaw(exe, version);
|
||||
if(strcasecmp(exeName, "ash") == 0)
|
||||
return getShellVersionAsh(exe, version);
|
||||
if(strcasecmp(exeName, "python") == 0 && getenv("XONSH_VERSION"))
|
||||
{
|
||||
ffStrbufSetS(version, getenv("XONSH_VERSION"));
|
||||
|
||||
@@ -2,21 +2,27 @@
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
typedef struct FFTerminalShellResult
|
||||
typedef struct FFShellResult
|
||||
{
|
||||
FFstrbuf shellProcessName;
|
||||
FFstrbuf shellExe;
|
||||
const char* shellExeName; //pointer to a char in shellExe
|
||||
FFstrbuf shellPrettyName;
|
||||
FFstrbuf shellVersion;
|
||||
uint32_t shellPid;
|
||||
FFstrbuf processName;
|
||||
FFstrbuf exe;
|
||||
const char* exeName; //pointer to a char in exe
|
||||
FFstrbuf prettyName;
|
||||
FFstrbuf version;
|
||||
uint32_t pid;
|
||||
uint32_t ppid;
|
||||
} FFShellResult;
|
||||
|
||||
FFstrbuf terminalProcessName;
|
||||
FFstrbuf terminalExe;
|
||||
FFstrbuf terminalPrettyName;
|
||||
const char* terminalExeName; //pointer to a char in terminalExe
|
||||
FFstrbuf terminalVersion;
|
||||
uint32_t terminalPid;
|
||||
} FFTerminalShellResult;
|
||||
typedef struct FFTerminalResult
|
||||
{
|
||||
FFstrbuf processName;
|
||||
FFstrbuf exe;
|
||||
FFstrbuf prettyName;
|
||||
const char* exeName; //pointer to a char in exe
|
||||
FFstrbuf version;
|
||||
uint32_t pid;
|
||||
uint32_t ppid;
|
||||
} FFTerminalResult;
|
||||
|
||||
const FFTerminalShellResult* ffDetectTerminalShell();
|
||||
const FFShellResult* ffDetectShell();
|
||||
const FFTerminalResult* ffDetectTerminal();
|
||||
|
||||
@@ -75,7 +75,7 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid)
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData(statFilePath, sizeof(buf) - 1, buf);
|
||||
if(nRead < 0)
|
||||
return "ffReadFileData(statFilePath, sizeof(buf)-1, buf)";
|
||||
return "ffReadFileData(statFilePath, sizeof(buf)-1, buf) failed";
|
||||
buf[nRead] = '\0';
|
||||
|
||||
*ppid = 0;
|
||||
@@ -118,95 +118,114 @@ static const char* getProcessNameAndPpid(pid_t pid, char* name, pid_t* ppid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void getTerminalShell(FFTerminalShellResult* result, pid_t pid)
|
||||
static pid_t getShellInfo(FFShellResult* result, pid_t pid)
|
||||
{
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
|
||||
pid_t ppid = 0;
|
||||
|
||||
if(getProcessNameAndPpid(pid, name, &ppid))
|
||||
return;
|
||||
|
||||
//Common programs that are between terminal and own process, but are not the shell
|
||||
if(
|
||||
strcasecmp(name, "sh") == 0 || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell
|
||||
strcasecmp(name, "sudo") == 0 ||
|
||||
strcasecmp(name, "su") == 0 ||
|
||||
strcasecmp(name, "strace") == 0 ||
|
||||
strcasecmp(name, "sshd") == 0 ||
|
||||
strcasecmp(name, "gdb") == 0 ||
|
||||
strcasecmp(name, "lldb") == 0 ||
|
||||
strcasecmp(name, "login") == 0 ||
|
||||
strcasecmp(name, "ltrace") == 0 ||
|
||||
strcasecmp(name, "perf") == 0 ||
|
||||
strcasecmp(name, "guake-wrapped") == 0 ||
|
||||
strcasestr(name, "debug") != NULL ||
|
||||
strcasestr(name, "command-not-found") != NULL ||
|
||||
ffStrEndsWith(name, ".sh")
|
||||
) {
|
||||
getTerminalShell(result, ppid);
|
||||
return;
|
||||
}
|
||||
|
||||
//Known shells
|
||||
if (
|
||||
strcasecmp(name, "ash") == 0 ||
|
||||
strcasecmp(name, "bash") == 0 ||
|
||||
strcasecmp(name, "zsh") == 0 ||
|
||||
strcasecmp(name, "ksh") == 0 ||
|
||||
strcasecmp(name, "mksh") == 0 ||
|
||||
strcasecmp(name, "oksh") == 0 ||
|
||||
strcasecmp(name, "csh") == 0 ||
|
||||
strcasecmp(name, "tcsh") == 0 ||
|
||||
strcasecmp(name, "fish") == 0 ||
|
||||
strcasecmp(name, "dash") == 0 ||
|
||||
strcasecmp(name, "pwsh") == 0 ||
|
||||
strcasecmp(name, "nu") == 0 ||
|
||||
strcasecmp(name, "git-shell") == 0 ||
|
||||
strcasecmp(name, "elvish") == 0 ||
|
||||
strcasecmp(name, "oil.ovm") == 0 ||
|
||||
(strcasecmp(name, "python") == 0 && getenv("XONSH_VERSION"))
|
||||
) {
|
||||
if (result->shellProcessName.length == 0)
|
||||
while (getProcessNameAndPpid(pid, name, &ppid) == NULL)
|
||||
{
|
||||
//Common programs that are between terminal and own process, but are not the shell
|
||||
if(
|
||||
ffStrEquals(name, "sh") || //This prevents us from detecting things like pipes and redirects, i hope nobody uses plain `sh` as shell
|
||||
ffStrEquals(name, "sudo") ||
|
||||
ffStrEquals(name, "su") ||
|
||||
ffStrEquals(name, "strace") ||
|
||||
ffStrEquals(name, "sshd") ||
|
||||
ffStrEquals(name, "gdb") ||
|
||||
ffStrEquals(name, "lldb") ||
|
||||
ffStrEquals(name, "lldb-mi") ||
|
||||
ffStrEquals(name, "login") ||
|
||||
ffStrEquals(name, "ltrace") ||
|
||||
ffStrEquals(name, "perf") ||
|
||||
ffStrEquals(name, "guake-wrapped") ||
|
||||
ffStrContainsIgnCase(name, "debug") ||
|
||||
ffStrContainsIgnCase(name, "not-found") ||
|
||||
ffStrEndsWith(name, ".sh")
|
||||
)
|
||||
{
|
||||
result->shellPid = (uint32_t) pid;
|
||||
ffStrbufSetS(&result->shellProcessName, name);
|
||||
getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName);
|
||||
pid = ppid;
|
||||
continue;
|
||||
}
|
||||
|
||||
getTerminalShell(result, ppid);
|
||||
return;
|
||||
result->pid = (uint32_t) pid;
|
||||
result->ppid = (uint32_t) ppid;
|
||||
ffStrbufSetS(&result->processName, name);
|
||||
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName);
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
// https://github.com/fastfetch-cli/fastfetch/discussions/501
|
||||
if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)"))
|
||||
getProcessNameAndPpid(ppid, name, &ppid);
|
||||
#endif
|
||||
|
||||
result->terminalPid = (uint32_t) pid;
|
||||
ffStrbufSetS(&result->terminalProcessName, name);
|
||||
getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName);
|
||||
return ppid;
|
||||
}
|
||||
|
||||
static void getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
|
||||
{
|
||||
if(
|
||||
result->terminalProcessName.length > 0 &&
|
||||
!ffStrbufStartsWithIgnCaseS(&result->terminalProcessName, "login") &&
|
||||
!ffStrbufIgnCaseEqualS(&result->terminalProcessName, "(login)") &&
|
||||
char name[256];
|
||||
name[0] = '\0';
|
||||
|
||||
pid_t ppid = 0;
|
||||
|
||||
while (getProcessNameAndPpid(pid, name, &ppid) == NULL)
|
||||
{
|
||||
//Known shells
|
||||
if (
|
||||
ffStrEquals(name, "ash") ||
|
||||
ffStrEquals(name, "bash") ||
|
||||
ffStrEquals(name, "zsh") ||
|
||||
ffStrEquals(name, "ksh") ||
|
||||
ffStrEquals(name, "mksh") ||
|
||||
ffStrEquals(name, "oksh") ||
|
||||
ffStrEquals(name, "csh") ||
|
||||
ffStrEquals(name, "tcsh") ||
|
||||
ffStrEquals(name, "fish") ||
|
||||
ffStrEquals(name, "dash") ||
|
||||
ffStrEquals(name, "pwsh") ||
|
||||
ffStrEquals(name, "nu") ||
|
||||
ffStrEquals(name, "git-shell") ||
|
||||
ffStrEquals(name, "elvish") ||
|
||||
ffStrEquals(name, "oil.ovm") ||
|
||||
(ffStrEquals(name, "python") && getenv("XONSH_VERSION"))
|
||||
)
|
||||
{
|
||||
pid = ppid;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
!ffStrbufIgnCaseEqualS(&result->terminalProcessName, "launchd") &&
|
||||
!ffStrbufIgnCaseEqualS(&result->terminalProcessName, "stable") && //for WarpTerminal
|
||||
#else
|
||||
!ffStrbufIgnCaseEqualS(&result->terminalProcessName, "systemd") &&
|
||||
!ffStrbufIgnCaseEqualS(&result->terminalProcessName, "init") &&
|
||||
!ffStrbufIgnCaseEqualS(&result->terminalProcessName, "(init)") &&
|
||||
// https://github.com/fastfetch-cli/fastfetch/discussions/501
|
||||
if (ffStrEndsWith(name, " (figterm)") || ffStrEndsWith(name, " (cwterm)"))
|
||||
{
|
||||
if (__builtin_expect(getProcessNameAndPpid(ppid, name, &ppid) != NULL, false))
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
ffStrbufIgnCaseCompS(&result->terminalProcessName, "0") != 0
|
||||
result->pid = (uint32_t) pid;
|
||||
ffStrbufSetS(&result->processName, name);
|
||||
getProcessInformation(pid, &result->processName, &result->exe, &result->exeName);
|
||||
break;
|
||||
}
|
||||
return ppid;
|
||||
}
|
||||
|
||||
static void getTerminalFromEnv(FFTerminalResult* result)
|
||||
{
|
||||
if(
|
||||
result->processName.length > 0 &&
|
||||
!ffStrbufStartsWithS(&result->processName, "login") &&
|
||||
!ffStrbufEqualS(&result->processName, "(login)") &&
|
||||
|
||||
#ifdef __APPLE__
|
||||
!ffStrbufEqualS(&result->processName, "launchd") &&
|
||||
!ffStrbufEqualS(&result->processName, "stable") && //for WarpTerminal
|
||||
#else
|
||||
!ffStrbufEqualS(&result->processName, "systemd") &&
|
||||
!ffStrbufEqualS(&result->processName, "init") &&
|
||||
!ffStrbufEqualS(&result->processName, "(init)") &&
|
||||
#endif
|
||||
|
||||
!ffStrbufEqualS(&result->processName, "0")
|
||||
) return;
|
||||
|
||||
const char* term = NULL;
|
||||
@@ -262,25 +281,25 @@ static void getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
term = getenv("TERM");
|
||||
|
||||
//TTY
|
||||
if(!ffStrSet(term) || strcasecmp(term, "linux") == 0)
|
||||
if(!ffStrSet(term) || ffStrEquals(term, "linux"))
|
||||
term = ttyname(STDIN_FILENO);
|
||||
|
||||
if(ffStrSet(term))
|
||||
{
|
||||
ffStrbufSetS(&result->terminalProcessName, term);
|
||||
ffStrbufSetS(&result->terminalExe, term);
|
||||
setExeName(&result->terminalExe, &result->terminalExeName);
|
||||
ffStrbufSetS(&result->processName, term);
|
||||
ffStrbufSetS(&result->exe, term);
|
||||
setExeName(&result->exe, &result->exeName);
|
||||
}
|
||||
}
|
||||
|
||||
static void getUserShellFromEnv(FFTerminalShellResult* result)
|
||||
static void getUserShellFromEnv(FFShellResult* result)
|
||||
{
|
||||
//If shell detection via processes failed
|
||||
if(result->shellProcessName.length == 0 && instance.state.platform.userShell.length > 0)
|
||||
if(result->processName.length == 0 && instance.state.platform.userShell.length > 0)
|
||||
{
|
||||
ffStrbufSet(&result->shellExe, &instance.state.platform.userShell);
|
||||
setExeName(&result->shellExe, &result->shellExeName);
|
||||
ffStrbufAppendS(&result->shellProcessName, result->shellExeName);
|
||||
ffStrbufSet(&result->exe, &instance.state.platform.userShell);
|
||||
setExeName(&result->exe, &result->exeName);
|
||||
ffStrbufAppendS(&result->processName, result->exeName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,107 +307,133 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
|
||||
|
||||
bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version);
|
||||
|
||||
const FFTerminalShellResult* ffDetectTerminalShell()
|
||||
static void setShellInfoDetails(FFShellResult* result)
|
||||
{
|
||||
static FFTerminalShellResult result;
|
||||
ffStrbufClear(&result->version);
|
||||
fftsGetShellVersion(&result->exe, result->exeName, &result->version);
|
||||
|
||||
if(ffStrbufEqualS(&result->processName, "pwsh"))
|
||||
ffStrbufInitStatic(&result->prettyName, "PowerShell");
|
||||
else if(ffStrbufEqualS(&result->processName, "nu"))
|
||||
ffStrbufInitStatic(&result->prettyName, "nushell");
|
||||
else if(ffStrbufEqualS(&result->processName, "python") && getenv("XONSH_VERSION"))
|
||||
ffStrbufInitStatic(&result->prettyName, "xonsh");
|
||||
else if(ffStrbufEqualS(&result->processName, "oil.ovm"))
|
||||
ffStrbufInitStatic(&result->prettyName, "Oils");
|
||||
else
|
||||
{
|
||||
// https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734
|
||||
ffStrbufInitS(&result->prettyName, result->exeName);
|
||||
}
|
||||
}
|
||||
|
||||
static void setTerminalInfoDetails(FFTerminalResult* result)
|
||||
{
|
||||
if(result->exeName[0] == '.' && ffStrEndsWith(result->exeName, "-wrapped"))
|
||||
{
|
||||
// For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428
|
||||
// We use processName when detecting version and font, overriding it for simplification
|
||||
ffStrbufSetNS(
|
||||
&result->processName,
|
||||
(uint32_t) (strlen(result->exeName) - strlen(".-wrapped")),
|
||||
result->exeName + 1);
|
||||
}
|
||||
|
||||
if(ffStrbufEqualS(&result->processName, "wezterm-gui"))
|
||||
ffStrbufInitStatic(&result->prettyName, "WezTerm");
|
||||
else if(ffStrbufStartsWithS(&result->processName, "tmux:"))
|
||||
ffStrbufInitStatic(&result->prettyName, "tmux");
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
else if(ffStrbufEqualS(&result->processName, "com.termux"))
|
||||
ffStrbufInitStatic(&result->prettyName, "Termux");
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
|
||||
else if(ffStrbufStartsWithS(&result->processName, "gnome-terminal-"))
|
||||
ffStrbufInitStatic(&result->prettyName, "GNOME Terminal");
|
||||
else if(ffStrbufStartsWithS(&result->processName, "kgx"))
|
||||
ffStrbufInitStatic(&result->prettyName, "GNOME Console");
|
||||
else if(ffStrbufEqualS(&result->processName, "urxvt") ||
|
||||
ffStrbufEqualS(&result->processName, "urxvtd") ||
|
||||
ffStrbufEqualS(&result->processName, "rxvt")
|
||||
)
|
||||
ffStrbufInitStatic(&result->prettyName, "rxvt-unicode");
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
else if(ffStrbufEqualS(&result->processName, "iTerm.app") || ffStrbufStartsWithS(&result->processName, "iTermServer-"))
|
||||
ffStrbufInitStatic(&result->prettyName, "iTerm");
|
||||
else if(ffStrbufEqualS(&result->processName, "Apple_Terminal"))
|
||||
ffStrbufInitStatic(&result->prettyName, "Apple Terminal");
|
||||
else if(ffStrbufEqualS(&result->processName, "WarpTerminal"))
|
||||
ffStrbufInitStatic(&result->prettyName, "Warp");
|
||||
|
||||
#endif
|
||||
|
||||
else if(strncmp(result->exeName, result->processName.chars, result->processName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName
|
||||
ffStrbufInitS(&result->prettyName, result->exeName);
|
||||
else
|
||||
ffStrbufInitCopy(&result->prettyName, &result->processName);
|
||||
|
||||
ffStrbufInit(&result->version);
|
||||
fftsGetTerminalVersion(&result->processName, &result->exe, &result->version);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define FF_EXE_PATH_LEN PROC_PIDPATHINFO_MAXSIZE
|
||||
#elif defined(MAXPATH)
|
||||
#define FF_EXE_PATH_LEN MAXPATH
|
||||
#elif defined(PATH_MAX)
|
||||
#define FF_EXE_PATH_LEN PATH_MAX
|
||||
#else
|
||||
#define FF_EXE_PATH_LEN 260
|
||||
#endif
|
||||
|
||||
const FFShellResult* ffDetectShell()
|
||||
{
|
||||
static FFShellResult result;
|
||||
static bool init = false;
|
||||
if(init)
|
||||
return &result;
|
||||
init = true;
|
||||
|
||||
#ifdef __APPLE__
|
||||
const uint32_t exePathLen = PROC_PIDPATHINFO_MAXSIZE;
|
||||
#elif defined(MAXPATH)
|
||||
const uint32_t exePathLen = MAXPATH;
|
||||
#elif defined(PATH_MAX)
|
||||
const uint32_t exePathLen = PATH_MAX;
|
||||
#else
|
||||
const uint32_t exePathLen = 260;
|
||||
#endif
|
||||
ffStrbufInit(&result.processName);
|
||||
ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN);
|
||||
result.exeName = result.exe.chars;
|
||||
ffStrbufInit(&result.version);
|
||||
result.pid = 0;
|
||||
result.ppid = 0;
|
||||
|
||||
ffStrbufInit(&result.shellProcessName);
|
||||
ffStrbufInitA(&result.shellExe, exePathLen);
|
||||
result.shellExeName = result.shellExe.chars;
|
||||
ffStrbufInit(&result.shellVersion);
|
||||
result.shellPid = 0;
|
||||
|
||||
ffStrbufInit(&result.terminalProcessName);
|
||||
ffStrbufInitA(&result.terminalExe, exePathLen);
|
||||
result.terminalExeName = result.terminalExe.chars;
|
||||
result.terminalPid = 0;
|
||||
|
||||
getTerminalShell(&result, getppid());
|
||||
|
||||
getTerminalFromEnv(&result);
|
||||
pid_t ppid = getppid();
|
||||
ppid = getShellInfo(&result, ppid);
|
||||
getUserShellFromEnv(&result);
|
||||
|
||||
ffStrbufClear(&result.shellVersion);
|
||||
fftsGetShellVersion(&result.shellExe, result.shellExeName, &result.shellVersion);
|
||||
|
||||
if(ffStrbufEqualS(&result.shellProcessName, "pwsh"))
|
||||
ffStrbufInitStatic(&result.shellPrettyName, "PowerShell");
|
||||
else if(ffStrbufEqualS(&result.shellProcessName, "nu"))
|
||||
ffStrbufInitStatic(&result.shellPrettyName, "nushell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result.shellProcessName, "python") && getenv("XONSH_VERSION"))
|
||||
ffStrbufInitStatic(&result.shellPrettyName, "xonsh");
|
||||
else if(ffStrbufIgnCaseEqualS(&result.shellProcessName, "oil.ovm"))
|
||||
ffStrbufInitStatic(&result.shellPrettyName, "Oils");
|
||||
else
|
||||
{
|
||||
// https://github.com/fastfetch-cli/fastfetch/discussions/280#discussioncomment-3831734
|
||||
ffStrbufInitS(&result.shellPrettyName, result.shellExeName);
|
||||
}
|
||||
|
||||
if(result.terminalExeName[0] == '.' && ffStrEndsWith(result.terminalExeName, "-wrapped"))
|
||||
{
|
||||
// For NixOS. Ref: #510 and https://github.com/NixOS/nixpkgs/pull/249428
|
||||
// We use terminalProcessName when detecting version and font, overriding it for simplification
|
||||
ffStrbufSetNS(
|
||||
&result.terminalProcessName,
|
||||
(uint32_t) (strlen(result.terminalExeName) - strlen(".-wrapped")),
|
||||
result.terminalExeName + 1);
|
||||
}
|
||||
|
||||
if(ffStrbufEqualS(&result.terminalProcessName, "wezterm-gui"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "WezTerm");
|
||||
if(ffStrbufStartsWithS(&result.terminalProcessName, "tmux:"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "tmux");
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
||||
else if(ffStrbufEqualS(&result.terminalProcessName, "com.termux"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "Termux");
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD__)
|
||||
|
||||
else if(ffStrbufStartsWithS(&result.terminalProcessName, "gnome-terminal-"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "GNOME Terminal");
|
||||
else if(ffStrbufStartsWithS(&result.terminalProcessName, "kgx"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "GNOME Console");
|
||||
else if(ffStrbufEqualS(&result.terminalProcessName, "urxvt") ||
|
||||
ffStrbufEqualS(&result.terminalProcessName, "urxvtd") ||
|
||||
ffStrbufEqualS(&result.terminalProcessName, "rxvt")
|
||||
)
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "rxvt-unicode");
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
else if(ffStrbufEqualS(&result.terminalProcessName, "iTerm.app") || ffStrbufStartsWithS(&result.terminalProcessName, "iTermServer-"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "iTerm");
|
||||
else if(ffStrbufEqualS(&result.terminalProcessName, "Apple_Terminal"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "Apple Terminal");
|
||||
else if(ffStrbufEqualS(&result.terminalProcessName, "WarpTerminal"))
|
||||
ffStrbufInitStatic(&result.terminalPrettyName, "Warp");
|
||||
|
||||
#endif
|
||||
|
||||
else if(strncmp(result.terminalExeName, result.terminalProcessName.chars, result.terminalProcessName.length) == 0) // if exeName starts with processName, print it. Otherwise print processName
|
||||
ffStrbufInitS(&result.terminalPrettyName, result.terminalExeName);
|
||||
else
|
||||
ffStrbufInitCopy(&result.terminalPrettyName, &result.terminalProcessName);
|
||||
|
||||
ffStrbufInit(&result.terminalVersion);
|
||||
fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion);
|
||||
setShellInfoDetails(&result);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
const FFTerminalResult* ffDetectTerminal()
|
||||
{
|
||||
static FFTerminalResult result;
|
||||
static bool init = false;
|
||||
if(init)
|
||||
return &result;
|
||||
init = true;
|
||||
|
||||
ffStrbufInit(&result.processName);
|
||||
ffStrbufInitA(&result.exe, FF_EXE_PATH_LEN);
|
||||
result.exeName = result.exe.chars;
|
||||
result.pid = 0;
|
||||
result.ppid = 0;
|
||||
|
||||
pid_t ppid = (pid_t) ffDetectShell()->ppid;
|
||||
|
||||
if (ppid)
|
||||
ppid = getTerminalInfo(&result, ppid);
|
||||
getTerminalFromEnv(&result);
|
||||
setTerminalInfoDetails(&result);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -83,55 +83,71 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb
|
||||
|
||||
bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
|
||||
|
||||
static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid)
|
||||
static uint32_t getShellInfo(FFShellResult* result, uint32_t pid)
|
||||
{
|
||||
uint32_t ppid;
|
||||
|
||||
if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe, &result->shellExeName))
|
||||
return 0;
|
||||
|
||||
ffStrbufSet(&result->shellPrettyName, &result->shellProcessName);
|
||||
if(ffStrbufEndsWithIgnCaseS(&result->shellPrettyName, ".exe"))
|
||||
ffStrbufSubstrBefore(&result->shellPrettyName, result->shellPrettyName.length - 4);
|
||||
|
||||
//Common programs that are between terminal and own process, but are not the shell
|
||||
if(
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "sudo") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "su") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "doas") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "strace") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "sshd") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "gdb") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "lldb") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "guake-wrapped") ||
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe
|
||||
ffStrbufIgnCaseEqualS(&result->shellPrettyName, "flashfetch") ||
|
||||
ffStrbufContainIgnCaseS(&result->shellPrettyName, "debug") ||
|
||||
ffStrbufStartsWithIgnCaseS(&result->shellPrettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014
|
||||
) {
|
||||
ffStrbufClear(&result->shellProcessName);
|
||||
ffStrbufClear(&result->shellPrettyName);
|
||||
ffStrbufClear(&result->shellExe);
|
||||
result->shellExeName = NULL;
|
||||
return getShellInfo(result, ppid);
|
||||
}
|
||||
|
||||
ffStrbufClear(&result->shellVersion);
|
||||
fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion);
|
||||
|
||||
result->shellPid = pid;
|
||||
if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh"))
|
||||
ffStrbufSetS(&result->shellPrettyName, "PowerShell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell"))
|
||||
ffStrbufSetS(&result->shellPrettyName, "Windows PowerShell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell_ise"))
|
||||
ffStrbufSetS(&result->shellPrettyName, "Windows PowerShell ISE");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "cmd"))
|
||||
while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName))
|
||||
{
|
||||
ffStrbufClear(&result->shellPrettyName);
|
||||
ffStrbufSet(&result->prettyName, &result->processName);
|
||||
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
|
||||
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
|
||||
|
||||
//Common programs that are between terminal and own process, but are not the shell
|
||||
if(
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "sudo") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "su") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "doas") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "strace") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "sshd") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "guake-wrapped") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || //scoop warps the real binaries with a "shim" exe
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") ||
|
||||
ffStrbufContainIgnCaseS(&result->prettyName, "debug") ||
|
||||
ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014
|
||||
) {
|
||||
ffStrbufClear(&result->processName);
|
||||
ffStrbufClear(&result->prettyName);
|
||||
ffStrbufClear(&result->exe);
|
||||
result->exeName = NULL;
|
||||
pid = ppid;
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufClear(&result->version);
|
||||
fftsGetShellVersion(&result->exe, result->prettyName.chars, &result->version);
|
||||
|
||||
result->pid = pid;
|
||||
result->ppid = ppid;
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer"))
|
||||
{
|
||||
ffStrbufSetS(&result->prettyName, "Windows Explorer"); // Started without shell
|
||||
// In this case, terminal process will be created by fastfetch itself.
|
||||
ppid = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return ppid;
|
||||
}
|
||||
|
||||
static void setShellInfoDetails(FFShellResult* result)
|
||||
{
|
||||
if(ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh"))
|
||||
ffStrbufSetS(&result->prettyName, "PowerShell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "powershell"))
|
||||
ffStrbufSetS(&result->prettyName, "Windows PowerShell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise"))
|
||||
ffStrbufSetS(&result->prettyName, "Windows PowerShell ISE");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "cmd"))
|
||||
{
|
||||
ffStrbufClear(&result->prettyName);
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE snapshot = NULL;
|
||||
while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid)) && GetLastError() == ERROR_BAD_LENGTH) {}
|
||||
while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, result->pid)) && GetLastError() == ERROR_BAD_LENGTH) {}
|
||||
|
||||
if(snapshot)
|
||||
{
|
||||
@@ -141,33 +157,27 @@ static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid)
|
||||
{
|
||||
if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0)
|
||||
{
|
||||
ffStrbufAppendS(&result->shellPrettyName, "CMD (with Clink ");
|
||||
getProductVersion(module.szExePath, &result->shellPrettyName);
|
||||
ffStrbufAppendC(&result->shellPrettyName, ')');
|
||||
ffStrbufAppendS(&result->prettyName, "CMD (with Clink ");
|
||||
getProductVersion(module.szExePath, &result->prettyName);
|
||||
ffStrbufAppendC(&result->prettyName, ')');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(result->shellPrettyName.length == 0)
|
||||
ffStrbufAppendS(&result->shellPrettyName, "Command Prompt");
|
||||
if(result->prettyName.length == 0)
|
||||
ffStrbufAppendS(&result->prettyName, "Command Prompt");
|
||||
}
|
||||
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "nu"))
|
||||
ffStrbufSetS(&result->shellPrettyName, "nushell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer"))
|
||||
{
|
||||
ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell
|
||||
// In this case, terminal process will be created by fastfetch itself.
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ppid;
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "nu"))
|
||||
ffStrbufSetS(&result->prettyName, "nushell");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer"))
|
||||
ffStrbufSetS(&result->prettyName, "Windows Explorer");
|
||||
}
|
||||
|
||||
static bool getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
static bool getTerminalFromEnv(FFTerminalResult* result)
|
||||
{
|
||||
if(
|
||||
result->terminalProcessName.length > 0 &&
|
||||
ffStrbufIgnCaseCompS(&result->terminalProcessName, "explorer") != 0
|
||||
result->processName.length > 0 &&
|
||||
ffStrbufIgnCaseCompS(&result->processName, "explorer") != 0
|
||||
) return false;
|
||||
|
||||
const char* term = getenv("ConEmuPID");
|
||||
@@ -176,12 +186,12 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
{
|
||||
//ConEmu
|
||||
uint32_t pid = (uint32_t) strtoul(term, NULL, 10);
|
||||
result->terminalPid = pid;
|
||||
if(getProcessInfo(pid, NULL, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName))
|
||||
result->pid = pid;
|
||||
if(getProcessInfo(pid, NULL, &result->processName, &result->exe, &result->exeName))
|
||||
{
|
||||
ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName);
|
||||
if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe"))
|
||||
ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4);
|
||||
ffStrbufSet(&result->prettyName, &result->processName);
|
||||
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
|
||||
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -198,7 +208,7 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
if(!term && (
|
||||
getenv("WT_SESSION") != NULL ||
|
||||
getenv("WT_PROFILE_ID") != NULL
|
||||
)) term = "Windows Terminal";
|
||||
)) term = "WindowsTerminal";
|
||||
|
||||
//Alacritty
|
||||
if(!term && (
|
||||
@@ -216,17 +226,17 @@ static bool getTerminalFromEnv(FFTerminalShellResult* result)
|
||||
|
||||
if(term)
|
||||
{
|
||||
ffStrbufSetS(&result->terminalProcessName, term);
|
||||
ffStrbufSetS(&result->terminalPrettyName, term);
|
||||
ffStrbufSetS(&result->terminalExe, term);
|
||||
result->terminalExeName = "";
|
||||
ffStrbufSetS(&result->processName, term);
|
||||
ffStrbufSetS(&result->prettyName, term);
|
||||
ffStrbufSetS(&result->exe, term);
|
||||
result->exeName = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool detectDefaultTerminal(FFTerminalShellResult* result)
|
||||
static bool detectDefaultTerminal(FFTerminalResult* result)
|
||||
{
|
||||
wchar_t regPath[128] = L"SOFTWARE\\Classes\\PackagedCom\\ClassIndex\\";
|
||||
wchar_t* uuid = regPath + strlen("SOFTWARE\\Classes\\PackagedCom\\ClassIndex\\");
|
||||
@@ -251,18 +261,18 @@ static bool detectDefaultTerminal(FFTerminalShellResult* result)
|
||||
{
|
||||
if (ffStrbufStartsWithS(&path, "Microsoft.WindowsTerminal"))
|
||||
{
|
||||
ffStrbufSetS(&result->terminalProcessName, "WindowsTerminal.exe");
|
||||
ffStrbufSetS(&result->terminalPrettyName, "WindowsTerminal");
|
||||
ffStrbufSetF(&result->terminalExe, "%s\\WindowsApps\\%s\\WindowsTerminal.exe", getenv("ProgramFiles"), path.chars);
|
||||
if(ffPathExists(result->terminalExe.chars, FF_PATHTYPE_FILE))
|
||||
ffStrbufSetS(&result->processName, "WindowsTerminal.exe");
|
||||
ffStrbufSetS(&result->prettyName, "WindowsTerminal");
|
||||
ffStrbufSetF(&result->exe, "%s\\WindowsApps\\%s\\WindowsTerminal.exe", getenv("ProgramFiles"), path.chars);
|
||||
if(ffPathExists(result->exe.chars, FF_PATHTYPE_FILE))
|
||||
{
|
||||
result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1;
|
||||
result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufDestroy(&result->terminalExe);
|
||||
ffStrbufInitMove(&result->terminalExe, &path);
|
||||
result->terminalExeName = "";
|
||||
ffStrbufDestroy(&result->exe);
|
||||
ffStrbufInitMove(&result->exe, &path);
|
||||
result->exeName = "";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -271,122 +281,148 @@ static bool detectDefaultTerminal(FFTerminalShellResult* result)
|
||||
}
|
||||
|
||||
conhost:
|
||||
ffStrbufSetF(&result->terminalExe, "%s\\System32\\conhost.exe", getenv("SystemRoot"));
|
||||
if(ffPathExists(result->terminalExe.chars, FF_PATHTYPE_FILE))
|
||||
ffStrbufSetF(&result->exe, "%s\\System32\\conhost.exe", getenv("SystemRoot"));
|
||||
if(ffPathExists(result->exe.chars, FF_PATHTYPE_FILE))
|
||||
{
|
||||
ffStrbufSetS(&result->terminalProcessName, "conhost.exe");
|
||||
ffStrbufSetS(&result->terminalPrettyName, "conhost");
|
||||
result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1;
|
||||
ffStrbufSetS(&result->processName, "conhost.exe");
|
||||
ffStrbufSetS(&result->prettyName, "conhost");
|
||||
result->exeName = result->exe.chars + ffStrbufLastIndexC(&result->exe, '\\') + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
ffStrbufClear(&result->terminalExe);
|
||||
ffStrbufClear(&result->exe);
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid)
|
||||
static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid)
|
||||
{
|
||||
uint32_t ppid;
|
||||
|
||||
if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName))
|
||||
return 0;
|
||||
while (pid != 0 && getProcessInfo(pid, &ppid, &result->processName, &result->exe, &result->exeName))
|
||||
{
|
||||
ffStrbufSet(&result->prettyName, &result->processName);
|
||||
if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe"))
|
||||
ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4);
|
||||
|
||||
ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName);
|
||||
if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe"))
|
||||
ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4);
|
||||
|
||||
if(
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "pwsh") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "cmd") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "bash") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "zsh") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "fish") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "nu") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "powershell") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "powershell_ise") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "wsl") || // running inside wsl
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "servercoreshell") || // ServerCore Shell Launcher
|
||||
ffStrbufStartsWithIgnCaseS(&result->terminalPrettyName, "ConEmuC") // wrapper process of ConEmu
|
||||
) {
|
||||
//We are nested shell
|
||||
ffStrbufClear(&result->terminalProcessName);
|
||||
ffStrbufClear(&result->terminalPrettyName);
|
||||
ffStrbufClear(&result->terminalExe);
|
||||
result->terminalExeName = "";
|
||||
return getTerminalInfo(result, ppid);
|
||||
}
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "sihost") ||
|
||||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer")
|
||||
) {
|
||||
// A CUI program created by Windows Explorer will spawn a conhost as its child.
|
||||
// However the conhost process is just a placeholder;
|
||||
// The true terminal can be Windows Terminal or others.
|
||||
if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result))
|
||||
{
|
||||
ffStrbufClear(&result->terminalProcessName);
|
||||
ffStrbufClear(&result->terminalPrettyName);
|
||||
ffStrbufClear(&result->terminalExe);
|
||||
result->terminalExeName = "";
|
||||
return 0;
|
||||
if(
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "pwsh") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "cmd") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "bash") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "zsh") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "fish") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "nu") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "powershell") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "powershell_ise") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "wsl") || // running inside wsl
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "servercoreshell") || // ServerCore Shell Launcher
|
||||
ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // wrapper process of ConEmu
|
||||
) {
|
||||
//We are nested shell
|
||||
ffStrbufClear(&result->processName);
|
||||
ffStrbufClear(&result->prettyName);
|
||||
ffStrbufClear(&result->exe);
|
||||
result->exeName = "";
|
||||
pid = ppid;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
result->terminalPid = pid;
|
||||
|
||||
if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal"))
|
||||
ffStrbufSetStatic(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_")
|
||||
if(ffStrbufIgnCaseEqualS(&result->prettyName, "sihost") ||
|
||||
ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")
|
||||
) {
|
||||
// A CUI program created by Windows Explorer will spawn a conhost as its child.
|
||||
// However the conhost process is just a placeholder;
|
||||
// The true terminal can be Windows Terminal or others.
|
||||
if (!getTerminalFromEnv(result) && !detectDefaultTerminal(result))
|
||||
{
|
||||
ffStrbufClear(&result->processName);
|
||||
ffStrbufClear(&result->prettyName);
|
||||
ffStrbufClear(&result->exe);
|
||||
result->exeName = "";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result->pid = pid;
|
||||
result->ppid = ppid;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
return ppid;
|
||||
}
|
||||
|
||||
static void setTerminalInfoDetails(FFTerminalResult* result)
|
||||
{
|
||||
if(ffStrbufIgnCaseEqualS(&result->prettyName, "WindowsTerminal"))
|
||||
ffStrbufSetStatic(&result->prettyName, ffStrbufContainIgnCaseS(&result->exe, ".WindowsTerminalPreview_")
|
||||
? "Windows Terminal Preview"
|
||||
: "Windows Terminal"
|
||||
);
|
||||
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "conhost"))
|
||||
ffStrbufSetStatic(&result->terminalPrettyName, "Console Window Host");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "Code"))
|
||||
ffStrbufSetStatic(&result->terminalPrettyName, "Visual Studio Code");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer"))
|
||||
ffStrbufSetStatic(&result->terminalPrettyName, "Windows Explorer");
|
||||
else if(ffStrbufEqualS(&result->terminalPrettyName, "wezterm-gui"))
|
||||
ffStrbufSetStatic(&result->terminalPrettyName, "WezTerm");
|
||||
|
||||
return ppid;
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "conhost"))
|
||||
ffStrbufSetStatic(&result->prettyName, "Console Window Host");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "Code"))
|
||||
ffStrbufSetStatic(&result->prettyName, "Visual Studio Code");
|
||||
else if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer"))
|
||||
ffStrbufSetStatic(&result->prettyName, "Windows Explorer");
|
||||
else if(ffStrbufEqualS(&result->prettyName, "wezterm-gui"))
|
||||
ffStrbufSetStatic(&result->prettyName, "WezTerm");
|
||||
}
|
||||
|
||||
bool fftsGetTerminalVersion(FFstrbuf* processName, FFstrbuf* exe, FFstrbuf* version);
|
||||
|
||||
const FFTerminalShellResult* ffDetectTerminalShell(void)
|
||||
const FFShellResult* ffDetectShell(void)
|
||||
{
|
||||
static FFTerminalShellResult result;
|
||||
static FFShellResult result;
|
||||
static bool init = false;
|
||||
if(init)
|
||||
return &result;
|
||||
init = true;
|
||||
|
||||
ffStrbufInit(&result.shellProcessName);
|
||||
ffStrbufInitA(&result.shellExe, 128);
|
||||
result.shellExeName = "";
|
||||
ffStrbufInit(&result.shellPrettyName);
|
||||
ffStrbufInit(&result.shellVersion);
|
||||
result.shellPid = 0;
|
||||
|
||||
ffStrbufInit(&result.terminalProcessName);
|
||||
ffStrbufInitA(&result.terminalExe, 128);
|
||||
result.terminalExeName = "";
|
||||
ffStrbufInit(&result.terminalPrettyName);
|
||||
result.terminalPid = 0;
|
||||
ffStrbufInit(&result.processName);
|
||||
ffStrbufInitA(&result.exe, 128);
|
||||
result.exeName = "";
|
||||
ffStrbufInit(&result.prettyName);
|
||||
ffStrbufInit(&result.version);
|
||||
result.pid = 0;
|
||||
result.ppid = 0;
|
||||
|
||||
uint32_t ppid;
|
||||
if(!getProcessInfo(0, &ppid, NULL, NULL, NULL))
|
||||
return &result;
|
||||
|
||||
ppid = getShellInfo(&result, ppid);
|
||||
if(ppid)
|
||||
getTerminalInfo(&result, ppid);
|
||||
|
||||
if(result.terminalProcessName.length == 0)
|
||||
getTerminalFromEnv(&result);
|
||||
|
||||
ffStrbufInit(&result.terminalVersion);
|
||||
fftsGetTerminalVersion(&result.terminalProcessName, &result.terminalExe, &result.terminalVersion);
|
||||
setShellInfoDetails(&result);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
const FFTerminalResult* ffDetectTerminal(void)
|
||||
{
|
||||
static FFTerminalResult result;
|
||||
static bool init = false;
|
||||
if(init)
|
||||
return &result;
|
||||
init = true;
|
||||
|
||||
ffStrbufInit(&result.processName);
|
||||
ffStrbufInitA(&result.exe, 128);
|
||||
result.exeName = "";
|
||||
ffStrbufInit(&result.prettyName);
|
||||
ffStrbufInit(&result.version);
|
||||
result.pid = 0;
|
||||
result.ppid = 0;
|
||||
|
||||
uint32_t ppid = ffDetectShell()->ppid;
|
||||
if(ppid)
|
||||
getTerminalInfo(&result, ppid);
|
||||
|
||||
if(result.processName.length == 0)
|
||||
getTerminalFromEnv(&result);
|
||||
|
||||
setTerminalInfoDetails(&result);
|
||||
|
||||
fftsGetTerminalVersion(&result.processName, &result.exe, &result.version);
|
||||
|
||||
return &result;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/thread.h"
|
||||
#include "detection/gpu/gpu.h"
|
||||
#include "detection/vulkan/vulkan.h"
|
||||
|
||||
@@ -8,7 +7,7 @@
|
||||
#include "common/io/io.h"
|
||||
#include "common/parsing.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
@@ -211,14 +210,8 @@ static const char* detectVulkan(FFVulkanResult* result)
|
||||
continue;
|
||||
}
|
||||
|
||||
//If the highest device version is lower than the instance version, use it as our vulkan version
|
||||
//otherwise the instance version is the vulkan version
|
||||
if(ffVersionCompare(&instanceVersion, &maxDeviceApiVersion) > 0)
|
||||
ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion);
|
||||
else
|
||||
ffVersionToPretty(&instanceVersion, &result->apiVersion);
|
||||
|
||||
//Use the highest device conformace version as our conformance version
|
||||
ffVersionToPretty(&instanceVersion, &result->instanceVersion);
|
||||
ffVersionToPretty(&maxDeviceApiVersion, &result->apiVersion);
|
||||
ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion);
|
||||
|
||||
ffvkDestroyInstance(vkInstance, NULL);
|
||||
@@ -236,6 +229,7 @@ FFVulkanResult* ffDetectVulkan(void)
|
||||
ffStrbufInit(&result.driver);
|
||||
ffStrbufInit(&result.apiVersion);
|
||||
ffStrbufInit(&result.conformanceVersion);
|
||||
ffStrbufInit(&result.instanceVersion);
|
||||
ffListInit(&result.gpus, sizeof(FFGPUResult));
|
||||
|
||||
#ifdef FF_HAVE_VULKAN
|
||||
|
||||
@@ -7,6 +7,7 @@ typedef struct FFVulkanResult
|
||||
FFstrbuf driver;
|
||||
FFstrbuf apiVersion;
|
||||
FFstrbuf conformanceVersion;
|
||||
FFstrbuf instanceVersion;
|
||||
FFlist gpus; //List of FFGPUResult, see detection/gpu/gpu.h
|
||||
const char* error;
|
||||
} FFVulkanResult;
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#include "wallpaper.h"
|
||||
#include "common/settings.h"
|
||||
#include "util/apple/osascript.h"
|
||||
|
||||
const char* ffDetectWallpaper(FFstrbuf* result)
|
||||
{
|
||||
// https://stackoverflow.com/questions/301215/getting-desktop-background-on-mac
|
||||
|
||||
#ifdef FF_HAVE_SQLITE3
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&path, "Library/Application Support/Dock/desktoppicture.db");
|
||||
if (ffSettingsGetSQLite3String(path.chars,
|
||||
"SELECT value\n"
|
||||
"FROM preferences\n"
|
||||
"JOIN data ON preferences.data_id=data.ROWID\n"
|
||||
"JOIN pictures ON preferences.picture_id=pictures.ROWID\n"
|
||||
"JOIN displays ON pictures.display_id=displays.ROWID\n"
|
||||
"JOIN spaces ON pictures.space_id=spaces.ROWID\n"
|
||||
"WHERE display_id=1 AND space_id=1 AND key=1", result)
|
||||
)
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
|
||||
if (!ffOsascript("tell application \"Finder\" to get POSIX path of (get desktop picture as alias)", result))
|
||||
return "ffOsascript(get desktop picture) failed";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "wallpaper.h"
|
||||
#include "common/settings.h"
|
||||
#include "util/apple/osascript.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
const char* ffDetectWallpaper(FFstrbuf* result)
|
||||
{
|
||||
{
|
||||
// For Sonoma
|
||||
// https://github.com/JohnCoates/Aerial/issues/1332
|
||||
NSError* error;
|
||||
NSString* fileName = [NSString stringWithFormat:@"file://%s/Library/Application Support/com.apple.wallpaper/Store/Index.plist", instance.state.platform.homeDir.chars];
|
||||
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:fileName]
|
||||
error:&error];
|
||||
if (!error)
|
||||
{
|
||||
NSArray* choices = [dict valueForKeyPath:@"SystemDefault.Desktop.Content.Choices"];
|
||||
if (choices.count > 0)
|
||||
{
|
||||
NSDictionary* choice = [choices objectAtIndex:0];
|
||||
NSArray* files = [choice valueForKey:@"Files"];
|
||||
if (files.count > 0)
|
||||
{
|
||||
NSString* file = [[files objectAtIndex: 0] valueForKey: @"relative"];
|
||||
ffStrbufAppendS(result, [NSURL URLWithString:file].path.UTF8String);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSString* provider = [choice valueForKey:@"Provider"];
|
||||
NSString* builtinPrefix = @"com.apple.wallpaper.choice.";
|
||||
if ([provider hasPrefix:builtinPrefix])
|
||||
provider = [provider substringFromIndex:builtinPrefix.length];
|
||||
if ([provider isEqualToString:@"sonoma"])
|
||||
ffStrbufSetStatic(result, "macOS Sonoma");
|
||||
else if ([provider isEqualToString:@"aerials"]) // Most builtin aerial wallpapers are private
|
||||
ffStrbufSetStatic(result, "Built-in aerial photography");
|
||||
else
|
||||
ffStrbufAppendF(result, "Built-in %s wallpaper", provider.UTF8String);
|
||||
}
|
||||
}
|
||||
if (result->length > 0)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FF_HAVE_SQLITE3
|
||||
|
||||
{
|
||||
// For Ventura
|
||||
// https://stackoverflow.com/questions/301215/getting-desktop-background-on-mac
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateCopy(&instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&path, "Library/Application Support/Dock/desktoppicture.db");
|
||||
if (ffSettingsGetSQLite3String(path.chars,
|
||||
"SELECT value\n"
|
||||
"FROM preferences\n"
|
||||
"JOIN data ON preferences.data_id=data.ROWID\n"
|
||||
"JOIN pictures ON preferences.picture_id=pictures.ROWID\n"
|
||||
"JOIN displays ON pictures.display_id=displays.ROWID\n"
|
||||
"JOIN spaces ON pictures.space_id=spaces.ROWID\n"
|
||||
"WHERE display_id=1 AND space_id=1 AND key=1", result)
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (ffOsascript("tell application \"Finder\" to get POSIX path of (get desktop picture as alias)", result))
|
||||
return NULL;
|
||||
|
||||
return "All detection methods failed";
|
||||
}
|
||||
@@ -17,7 +17,7 @@ static NSDictionary* getWifiInfoByApple80211(NSString* ifName)
|
||||
|
||||
struct Apple80211* handle = NULL;
|
||||
if (Apple80211Open(&handle) < 0) return NULL;
|
||||
if (Apple80211BindToInterface(handle, (CFStringRef)ifName) < 0) return NULL;
|
||||
if (Apple80211BindToInterface(handle, (__bridge CFStringRef)ifName) < 0) return NULL;
|
||||
CFDictionaryRef result;
|
||||
if (Apple80211GetInfoCopy(handle, &result) < 0) return NULL;
|
||||
Apple80211Close(handle);
|
||||
|
||||
@@ -87,43 +87,43 @@ static const char* detectWifiWithLibnm(FFlist* result)
|
||||
switch(state)
|
||||
{
|
||||
case NM_DEVICE_STATE_UNKNOWN:
|
||||
ffStrbufAppendS(&item->inf.status, "Unknown");
|
||||
ffStrbufSetStatic(&item->inf.status, "Unknown");
|
||||
break;
|
||||
case NM_DEVICE_STATE_UNMANAGED:
|
||||
ffStrbufAppendS(&item->inf.status, "Unmanaged");
|
||||
ffStrbufSetStatic(&item->inf.status, "Unmanaged");
|
||||
break;
|
||||
case NM_DEVICE_STATE_UNAVAILABLE:
|
||||
ffStrbufAppendS(&item->inf.status, "Unavailable");
|
||||
ffStrbufSetStatic(&item->inf.status, "Unavailable");
|
||||
break;
|
||||
case NM_DEVICE_STATE_DISCONNECTED:
|
||||
ffStrbufAppendS(&item->inf.status, "Disconnected");
|
||||
ffStrbufSetStatic(&item->inf.status, "Disconnected");
|
||||
break;
|
||||
case NM_DEVICE_STATE_PREPARE:
|
||||
ffStrbufAppendS(&item->inf.status, "Prepare");
|
||||
ffStrbufSetStatic(&item->inf.status, "Prepare");
|
||||
break;
|
||||
case NM_DEVICE_STATE_CONFIG:
|
||||
ffStrbufAppendS(&item->inf.status, "Config");
|
||||
ffStrbufSetStatic(&item->inf.status, "Config");
|
||||
break;
|
||||
case NM_DEVICE_STATE_NEED_AUTH:
|
||||
ffStrbufAppendS(&item->inf.status, "Need auth");
|
||||
ffStrbufSetStatic(&item->inf.status, "Need auth");
|
||||
break;
|
||||
case NM_DEVICE_STATE_IP_CONFIG:
|
||||
ffStrbufAppendS(&item->inf.status, "IP config");
|
||||
ffStrbufSetStatic(&item->inf.status, "IP config");
|
||||
break;
|
||||
case NM_DEVICE_STATE_IP_CHECK:
|
||||
ffStrbufAppendS(&item->inf.status, "IP check");
|
||||
ffStrbufSetStatic(&item->inf.status, "IP check");
|
||||
break;
|
||||
case NM_DEVICE_STATE_SECONDARIES:
|
||||
ffStrbufAppendS(&item->inf.status, "Secondaries");
|
||||
ffStrbufSetStatic(&item->inf.status, "Secondaries");
|
||||
break;
|
||||
case NM_DEVICE_STATE_ACTIVATED:
|
||||
ffStrbufAppendS(&item->inf.status, "Activated");
|
||||
ffStrbufSetStatic(&item->inf.status, "Activated");
|
||||
break;
|
||||
case NM_DEVICE_STATE_DEACTIVATING:
|
||||
ffStrbufAppendS(&item->inf.status, "Deactivating");
|
||||
ffStrbufSetStatic(&item->inf.status, "Deactivating");
|
||||
break;
|
||||
case NM_DEVICE_STATE_FAILED:
|
||||
ffStrbufAppendS(&item->inf.status, "Failed");
|
||||
ffStrbufSetStatic(&item->inf.status, "Failed");
|
||||
break;
|
||||
}
|
||||
if(state != NM_DEVICE_STATE_ACTIVATED)
|
||||
@@ -133,6 +133,8 @@ static const char* detectWifiWithLibnm(FFlist* result)
|
||||
if (!ap)
|
||||
continue;
|
||||
|
||||
ffStrbufSetStatic(&item->conn.status, "Connected");
|
||||
|
||||
GBytes* activeSsid = ffnm_access_point_get_ssid(ap);
|
||||
if (activeSsid)
|
||||
{
|
||||
@@ -161,13 +163,13 @@ static const char* detectWifiWithLibnm(FFlist* result)
|
||||
if(ffParsePropLines(output.chars, "tx bitrate: ", &item->conn.protocol))
|
||||
{
|
||||
if(ffStrbufContainS(&item->conn.protocol, " HE-MCS "))
|
||||
ffStrbufSetS(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
|
||||
else if(ffStrbufContainS(&item->conn.protocol, " VHT-MCS "))
|
||||
ffStrbufSetS(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
else if(ffStrbufContainS(&item->conn.protocol, " MCS "))
|
||||
ffStrbufSetS(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
else
|
||||
ffStrbufSetS(&item->conn.protocol, "802.11a/b/g");
|
||||
ffStrbufClear(&item->conn.protocol);
|
||||
|
||||
sscanf(item->conn.protocol.chars, "%lf", &item->conn.txRate);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ private:
|
||||
extern "C"
|
||||
const char* ffDetectWMPlugin(FFstrbuf* pluginName)
|
||||
{
|
||||
DWORD pid = ffDetectTerminalShell()->terminalPid; // Whatever GUI program
|
||||
DWORD pid = ffDetectTerminal()->pid; // Whatever GUI program
|
||||
if (pid == 0) return "Unable to find a GUI program";
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE snapshot = NULL;
|
||||
|
||||
+5
-5
@@ -498,14 +498,14 @@ void ffLogoPrint(void)
|
||||
//Make sure the logo path is set correctly.
|
||||
updateLogoPath();
|
||||
|
||||
const FFTerminalShellResult* terminalShell = ffDetectTerminalShell();
|
||||
const FFTerminalResult* terminal = ffDetectTerminal();
|
||||
|
||||
//Terminal emulators that support kitty graphics protocol.
|
||||
bool supportsKitty =
|
||||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "kitty") == 0 ||
|
||||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "konsole") == 0 ||
|
||||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wezterm") == 0 ||
|
||||
ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0;
|
||||
ffStrbufIgnCaseEqualS(&terminal->processName, "kitty") ||
|
||||
ffStrbufIgnCaseEqualS(&terminal->processName, "konsole") ||
|
||||
ffStrbufIgnCaseEqualS(&terminal->processName, "wezterm") ||
|
||||
ffStrbufIgnCaseEqualS(&terminal->processName, "wayst");
|
||||
|
||||
//Try to load the logo as an image. If it succeeds, print it and return.
|
||||
if(logoPrintImageIfExists(supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false))
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "modules/battery/battery.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#define FF_BATTERY_NUM_FORMAT_ARGS 7
|
||||
#define FF_BATTERY_NUM_FORMAT_ARGS 8
|
||||
|
||||
static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uint8_t index)
|
||||
{
|
||||
@@ -71,6 +71,8 @@ static void printBattery(FFBatteryOptions* options, FFBatteryResult* result, uin
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->status},
|
||||
{FF_FORMAT_ARG_TYPE_DOUBLE, &result->temperature},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &result->cycleCount},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->serial},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->manufactureDate},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -96,6 +98,8 @@ void ffPrintBattery(FFBatteryOptions* options)
|
||||
ffStrbufDestroy(&result->modelName);
|
||||
ffStrbufDestroy(&result->technology);
|
||||
ffStrbufDestroy(&result->status);
|
||||
ffStrbufDestroy(&result->serial);
|
||||
ffStrbufDestroy(&result->manufactureDate);
|
||||
}
|
||||
if(results.length == 0)
|
||||
ffPrintError(FF_BATTERY_MODULE_NAME, 0, &options->moduleArgs, "No batteries found");
|
||||
@@ -115,14 +119,6 @@ bool ffParseBatteryCommandOptions(FFBatteryOptions* options, const char* key, co
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (ffStrEqualsIgnCase(subKey, "dir"))
|
||||
{
|
||||
ffOptionParseString(key, value, &options->dir);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ffStrEqualsIgnCase(subKey, "use-setup-api"))
|
||||
{
|
||||
@@ -147,14 +143,6 @@ void ffParseBatteryJsonObject(FFBatteryOptions* options, yyjson_val* module)
|
||||
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
|
||||
continue;
|
||||
|
||||
#ifdef __linux__
|
||||
if (ffStrEqualsIgnCase(key, "dir"))
|
||||
{
|
||||
ffStrbufSetS(&options->dir, yyjson_get_str(val));
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ffStrEqualsIgnCase(key, "useSetupApi"))
|
||||
{
|
||||
@@ -180,11 +168,6 @@ void ffGenerateBatteryJsonConfig(FFBatteryOptions* options, yyjson_mut_doc* doc,
|
||||
|
||||
ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs);
|
||||
|
||||
#ifdef __linux__
|
||||
if (!ffStrbufEqual(&defaultOptions.dir, &options->dir))
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "dir", &options->dir);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (defaultOptions.useSetupApi != options->useSetupApi)
|
||||
yyjson_mut_obj_add_bool(doc, module, "useSetupApi", options->useSetupApi);
|
||||
@@ -212,9 +195,11 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc,
|
||||
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
|
||||
yyjson_mut_obj_add_real(doc, obj, "capacity", battery->capacity);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &battery->manufacturer);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "manufactureDate", &battery->manufactureDate);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &battery->modelName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "status", &battery->status);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "technology", &battery->technology);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &battery->serial);
|
||||
yyjson_mut_obj_add_real(doc, obj, "temperature", battery->temperature);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "cycleCount", battery->cycleCount);
|
||||
}
|
||||
@@ -222,9 +207,11 @@ void ffGenerateBatteryJsonResult(FFBatteryOptions* options, yyjson_mut_doc* doc,
|
||||
FF_LIST_FOR_EACH(FFBatteryResult, battery, results)
|
||||
{
|
||||
ffStrbufDestroy(&battery->manufacturer);
|
||||
ffStrbufDestroy(&battery->manufactureDate);
|
||||
ffStrbufDestroy(&battery->modelName);
|
||||
ffStrbufDestroy(&battery->technology);
|
||||
ffStrbufDestroy(&battery->status);
|
||||
ffStrbufDestroy(&battery->serial);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +225,8 @@ void ffPrintBatteryHelpFormat(void)
|
||||
"Battery status",
|
||||
"Battery temperature",
|
||||
"Battery cycle count",
|
||||
"Battery serial number",
|
||||
"Battery manufactor date",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -257,9 +246,7 @@ void ffInitBatteryOptions(FFBatteryOptions* options)
|
||||
ffOptionInitModuleArg(&options->moduleArgs);
|
||||
options->temp = false;
|
||||
|
||||
#ifdef __linux__
|
||||
ffStrbufInitStatic(&options->dir, "/sys/class/power_supply/");
|
||||
#elif defined(_WIN32)
|
||||
#ifdef _WIN32
|
||||
options->useSetupApi = false;
|
||||
#endif
|
||||
}
|
||||
@@ -267,8 +254,4 @@ void ffInitBatteryOptions(FFBatteryOptions* options)
|
||||
void ffDestroyBatteryOptions(FFBatteryOptions* options)
|
||||
{
|
||||
ffOptionDestroyModuleArg(&options->moduleArgs);
|
||||
|
||||
#ifdef __linux__
|
||||
ffStrbufDestroy(&options->dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -11,9 +11,7 @@ typedef struct FFBatteryOptions
|
||||
|
||||
bool temp;
|
||||
|
||||
#ifdef __linux__
|
||||
FFstrbuf dir;
|
||||
#elif defined(_WIN32)
|
||||
#ifdef _WIN32
|
||||
bool useSetupApi;
|
||||
#endif
|
||||
} FFBatteryOptions;
|
||||
|
||||
@@ -12,8 +12,9 @@ void ffPrintBoard(FFBoardOptions* options)
|
||||
ffStrbufInit(&result.name);
|
||||
ffStrbufInit(&result.vendor);
|
||||
ffStrbufInit(&result.version);
|
||||
const char* error = ffDetectBoard(&result);
|
||||
ffStrbufInit(&result.serial);
|
||||
|
||||
const char* error = ffDetectBoard(&result);
|
||||
if(error)
|
||||
{
|
||||
ffPrintError(FF_BOARD_MODULE_NAME, 0, &options->moduleArgs, "%s", error);
|
||||
@@ -40,6 +41,7 @@ void ffPrintBoard(FFBoardOptions* options)
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.vendor},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.version},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.serial},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -47,6 +49,7 @@ exit:
|
||||
ffStrbufDestroy(&result.name);
|
||||
ffStrbufDestroy(&result.vendor);
|
||||
ffStrbufDestroy(&result.version);
|
||||
ffStrbufDestroy(&result.serial);
|
||||
}
|
||||
|
||||
bool ffParseBoardCommandOptions(FFBoardOptions* options, const char* key, const char* value)
|
||||
@@ -90,6 +93,7 @@ void ffGenerateBoardJsonResult(FF_MAYBE_UNUSED FFBoardOptions* options, yyjson_m
|
||||
ffStrbufInit(&board.name);
|
||||
ffStrbufInit(&board.vendor);
|
||||
ffStrbufInit(&board.version);
|
||||
ffStrbufInit(&board.serial);
|
||||
|
||||
const char* error = ffDetectBoard(&board);
|
||||
|
||||
@@ -109,11 +113,13 @@ void ffGenerateBoardJsonResult(FF_MAYBE_UNUSED FFBoardOptions* options, yyjson_m
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "name", &board.name);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &board.vendor);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &board.version);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &board.serial);
|
||||
|
||||
exit:
|
||||
ffStrbufDestroy(&board.name);
|
||||
ffStrbufDestroy(&board.vendor);
|
||||
ffStrbufDestroy(&board.version);
|
||||
ffStrbufDestroy(&board.serial);
|
||||
}
|
||||
|
||||
void ffPrintBoardHelpFormat(void)
|
||||
@@ -121,7 +127,8 @@ void ffPrintBoardHelpFormat(void)
|
||||
ffPrintModuleFormatHelp(FF_BOARD_MODULE_NAME, "{1} ({3})", FF_BOARD_NUM_FORMAT_ARGS, (const char* []) {
|
||||
"board name",
|
||||
"board vendor",
|
||||
"board version"
|
||||
"board version",
|
||||
"board serial number",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,9 @@ void ffPrintChassis(FFChassisOptions* options)
|
||||
ffStrbufInit(&result.type);
|
||||
ffStrbufInit(&result.vendor);
|
||||
ffStrbufInit(&result.version);
|
||||
ffStrbufInit(&result.serial);
|
||||
|
||||
const char* error = ffDetectChassis(&result, options);
|
||||
const char* error = ffDetectChassis(&result);
|
||||
|
||||
if(error)
|
||||
{
|
||||
@@ -41,6 +42,7 @@ void ffPrintChassis(FFChassisOptions* options)
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.type},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.vendor},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.version},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result.serial},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -48,6 +50,7 @@ exit:
|
||||
ffStrbufDestroy(&result.type);
|
||||
ffStrbufDestroy(&result.vendor);
|
||||
ffStrbufDestroy(&result.version);
|
||||
ffStrbufDestroy(&result.serial);
|
||||
}
|
||||
|
||||
bool ffParseChassisCommandOptions(FFChassisOptions* options, const char* key, const char* value)
|
||||
@@ -57,14 +60,6 @@ bool ffParseChassisCommandOptions(FFChassisOptions* options, const char* key, co
|
||||
if (ffOptionParseModuleArgs(key, subKey, value, &options->moduleArgs))
|
||||
return true;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ffStrEqualsIgnCase(subKey, "use-wmi"))
|
||||
{
|
||||
options->useWmi = ffOptionParseBoolean(value);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -81,14 +76,6 @@ void ffParseChassisJsonObject(FFChassisOptions* options, yyjson_val* module)
|
||||
if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs))
|
||||
continue;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ffStrEqualsIgnCase(key, "useWmi"))
|
||||
{
|
||||
options->useWmi = yyjson_get_bool(val);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
ffPrintError(FF_CHASSIS_MODULE_NAME, 0, &options->moduleArgs, "Unknown JSON key %s", key);
|
||||
}
|
||||
}
|
||||
@@ -99,11 +86,6 @@ void ffGenerateChassisJsonConfig(FFChassisOptions* options, yyjson_mut_doc* doc,
|
||||
ffInitChassisOptions(&defaultOptions);
|
||||
|
||||
ffJsonConfigGenerateModuleArgsConfig(doc, module, &defaultOptions.moduleArgs, &options->moduleArgs);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (options->useWmi != defaultOptions.useWmi)
|
||||
yyjson_mut_obj_add_bool(doc, module, "useWmi", options->useWmi);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
||||
@@ -112,8 +94,9 @@ void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjs
|
||||
ffStrbufInit(&result.type);
|
||||
ffStrbufInit(&result.vendor);
|
||||
ffStrbufInit(&result.version);
|
||||
ffStrbufInit(&result.serial);
|
||||
|
||||
const char* error = ffDetectChassis(&result, options);
|
||||
const char* error = ffDetectChassis(&result);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -131,11 +114,13 @@ void ffGenerateChassisJsonResult(FF_MAYBE_UNUSED FFChassisOptions* options, yyjs
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "type", &result.type);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &result.vendor);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &result.version);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &result.serial);
|
||||
|
||||
exit:
|
||||
ffStrbufDestroy(&result.type);
|
||||
ffStrbufDestroy(&result.vendor);
|
||||
ffStrbufDestroy(&result.version);
|
||||
ffStrbufDestroy(&result.serial);
|
||||
}
|
||||
|
||||
void ffPrintChassisHelpFormat(void)
|
||||
@@ -143,7 +128,8 @@ void ffPrintChassisHelpFormat(void)
|
||||
ffPrintModuleFormatHelp(FF_CHASSIS_MODULE_NAME, "{1}", FF_CHASSIS_NUM_FORMAT_ARGS, (const char* []) {
|
||||
"chassis type",
|
||||
"chassis vendor",
|
||||
"chassis version"
|
||||
"chassis version",
|
||||
"chassis serial number",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -161,10 +147,6 @@ void ffInitChassisOptions(FFChassisOptions* options)
|
||||
ffGenerateChassisJsonConfig
|
||||
);
|
||||
ffOptionInitModuleArg(&options->moduleArgs);
|
||||
|
||||
#ifdef _WIN32
|
||||
options->useWmi = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ffDestroyChassisOptions(FFChassisOptions* options)
|
||||
|
||||
@@ -8,8 +8,4 @@ typedef struct FFChassisOptions
|
||||
{
|
||||
FFModuleBaseInfo moduleInfo;
|
||||
FFModuleArgs moduleArgs;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool useWmi;
|
||||
#endif
|
||||
} FFChassisOptions;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "common/bar.h"
|
||||
#include "common/printing.h"
|
||||
#include "common/jsonconfig.h"
|
||||
#include "detection/gamepad/gamepad.h"
|
||||
@@ -10,14 +11,21 @@ static void printDevice(FFGamepadOptions* options, const FFGamepadDevice* device
|
||||
{
|
||||
if(options->moduleArgs.outputFormat.length == 0)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateCopy(&device->name);
|
||||
ffPrintLogoAndKey(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
ffStrbufPutTo(&device->name, stdout);
|
||||
if (device->battery > 0 && device->battery <= 100)
|
||||
{
|
||||
ffStrbufAppendC(&buffer, ' ');
|
||||
ffAppendPercentNum(&buffer, device->battery, 51, 21, true);
|
||||
}
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormat(FF_GAMEPAD_MODULE_NAME, index, &options->moduleArgs, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) {
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &device->name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &device->serial},
|
||||
{FF_FORMAT_ARG_TYPE_UINT8, &device->battery},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -44,7 +52,7 @@ void ffPrintGamepad(FFGamepadOptions* options)
|
||||
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
|
||||
{
|
||||
printDevice(options, device, result.length > 1 ? ++index : 0);
|
||||
ffStrbufDestroy(&device->identifier);
|
||||
ffStrbufDestroy(&device->serial);
|
||||
ffStrbufDestroy(&device->name);
|
||||
}
|
||||
}
|
||||
@@ -106,13 +114,13 @@ void ffGenerateGamepadJsonResult(FF_MAYBE_UNUSED FFGamepadOptions* options, yyjs
|
||||
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
|
||||
{
|
||||
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "identifier", &device->identifier);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &device->serial);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "name", &device->name);
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH(FFGamepadDevice, device, result)
|
||||
{
|
||||
ffStrbufDestroy(&device->identifier);
|
||||
ffStrbufDestroy(&device->serial);
|
||||
ffStrbufDestroy(&device->name);
|
||||
}
|
||||
}
|
||||
@@ -121,7 +129,8 @@ void ffPrintGamepadHelpFormat(void)
|
||||
{
|
||||
ffPrintModuleFormatHelp(FF_GAMEPAD_MODULE_NAME, "{1}", FF_GAMEPAD_NUM_FORMAT_ARGS, (const char* []) {
|
||||
"Name",
|
||||
"Identifier"
|
||||
"Serial number",
|
||||
"Battery",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+55
-41
@@ -4,25 +4,27 @@
|
||||
#include "modules/host/host.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#define FF_HOST_NUM_FORMAT_ARGS 5
|
||||
#define FF_HOST_NUM_FORMAT_ARGS 7
|
||||
|
||||
void ffPrintHost(FFHostOptions* options)
|
||||
{
|
||||
FFHostResult host;
|
||||
ffStrbufInit(&host.productFamily);
|
||||
ffStrbufInit(&host.productName);
|
||||
ffStrbufInit(&host.productVersion);
|
||||
ffStrbufInit(&host.productSku);
|
||||
ffStrbufInit(&host.sysVendor);
|
||||
const char* error = ffDetectHost(&host);
|
||||
ffStrbufInit(&host.family);
|
||||
ffStrbufInit(&host.name);
|
||||
ffStrbufInit(&host.version);
|
||||
ffStrbufInit(&host.sku);
|
||||
ffStrbufInit(&host.serial);
|
||||
ffStrbufInit(&host.uuid);
|
||||
ffStrbufInit(&host.vendor);
|
||||
|
||||
const char* error = ffDetectHost(&host);
|
||||
if(error)
|
||||
{
|
||||
ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "%s", error);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(host.productFamily.length == 0 && host.productName.length == 0)
|
||||
if(host.family.length == 0 && host.name.length == 0)
|
||||
{
|
||||
ffPrintError(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, "neither product_family nor product_name is set by O.E.M.");
|
||||
goto exit;
|
||||
@@ -34,33 +36,37 @@ void ffPrintHost(FFHostOptions* options)
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreate();
|
||||
|
||||
if(host.productName.length > 0)
|
||||
ffStrbufAppend(&output, &host.productName);
|
||||
if(host.name.length > 0)
|
||||
ffStrbufAppend(&output, &host.name);
|
||||
else
|
||||
ffStrbufAppend(&output, &host.productFamily);
|
||||
ffStrbufAppend(&output, &host.family);
|
||||
|
||||
if(host.productVersion.length > 0)
|
||||
ffStrbufAppendF(&output, " (%s)", host.productVersion.chars);
|
||||
if(host.version.length > 0)
|
||||
ffStrbufAppendF(&output, " (%s)", host.version.chars);
|
||||
|
||||
ffStrbufPutTo(&output, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormat(FF_HOST_MODULE_NAME, 0, &options->moduleArgs, FF_HOST_NUM_FORMAT_ARGS, (FFformatarg[]) {
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.productFamily},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.productName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.productVersion},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.productSku},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.sysVendor}
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.family},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.version},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.sku},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.vendor},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.serial},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &host.uuid},
|
||||
});
|
||||
}
|
||||
|
||||
exit:
|
||||
ffStrbufDestroy(&host.productFamily);
|
||||
ffStrbufDestroy(&host.productName);
|
||||
ffStrbufDestroy(&host.productVersion);
|
||||
ffStrbufDestroy(&host.productSku);
|
||||
ffStrbufDestroy(&host.sysVendor);
|
||||
ffStrbufDestroy(&host.family);
|
||||
ffStrbufDestroy(&host.name);
|
||||
ffStrbufDestroy(&host.version);
|
||||
ffStrbufDestroy(&host.sku);
|
||||
ffStrbufDestroy(&host.serial);
|
||||
ffStrbufDestroy(&host.uuid);
|
||||
ffStrbufDestroy(&host.vendor);
|
||||
}
|
||||
|
||||
bool ffParseHostCommandOptions(FFHostOptions* options, const char* key, const char* value)
|
||||
@@ -101,38 +107,44 @@ void ffGenerateHostJsonConfig(FFHostOptions* options, yyjson_mut_doc* doc, yyjso
|
||||
void ffGenerateHostJsonResult(FF_MAYBE_UNUSED FFHostOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
||||
{
|
||||
FFHostResult host;
|
||||
ffStrbufInit(&host.productFamily);
|
||||
ffStrbufInit(&host.productName);
|
||||
ffStrbufInit(&host.productVersion);
|
||||
ffStrbufInit(&host.productSku);
|
||||
ffStrbufInit(&host.sysVendor);
|
||||
const char* error = ffDetectHost(&host);
|
||||
ffStrbufInit(&host.family);
|
||||
ffStrbufInit(&host.name);
|
||||
ffStrbufInit(&host.version);
|
||||
ffStrbufInit(&host.sku);
|
||||
ffStrbufInit(&host.serial);
|
||||
ffStrbufInit(&host.uuid);
|
||||
ffStrbufInit(&host.vendor);
|
||||
|
||||
const char* error = ffDetectHost(&host);
|
||||
if (error)
|
||||
{
|
||||
yyjson_mut_obj_add_str(doc, module, "error", error);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (host.productFamily.length == 0 && host.productName.length == 0)
|
||||
if (host.family.length == 0 && host.name.length == 0)
|
||||
{
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "neither product_family nor product_name is set by O.E.M.");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result");
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "family", &host.productFamily);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.productName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.productVersion);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.productSku);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "sysVender", &host.sysVendor);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "family", &host.family);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "name", &host.name);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &host.version);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "sku", &host.sku);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &host.vendor);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &host.serial);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "uuid", &host.uuid);
|
||||
|
||||
exit:
|
||||
ffStrbufDestroy(&host.productFamily);
|
||||
ffStrbufDestroy(&host.productName);
|
||||
ffStrbufDestroy(&host.productVersion);
|
||||
ffStrbufDestroy(&host.productSku);
|
||||
ffStrbufDestroy(&host.sysVendor);
|
||||
ffStrbufDestroy(&host.family);
|
||||
ffStrbufDestroy(&host.name);
|
||||
ffStrbufDestroy(&host.version);
|
||||
ffStrbufDestroy(&host.sku);
|
||||
ffStrbufDestroy(&host.serial);
|
||||
ffStrbufDestroy(&host.uuid);
|
||||
ffStrbufDestroy(&host.vendor);
|
||||
}
|
||||
|
||||
void ffPrintHostHelpFormat(void)
|
||||
@@ -142,7 +154,9 @@ void ffPrintHostHelpFormat(void)
|
||||
"product name",
|
||||
"product version",
|
||||
"product sku",
|
||||
"sys vendor"
|
||||
"product vendor",
|
||||
"product serial number",
|
||||
"product uuid",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,15 @@ void ffPrintMonitor(FFMonitorOptions* options)
|
||||
}
|
||||
else
|
||||
{
|
||||
char buf[32];
|
||||
if (display->serial)
|
||||
{
|
||||
const uint8_t* nums = (uint8_t*) &display->serial;
|
||||
snprintf(buf, sizeof(buf), "%2X-%2X-%2X-%2X", nums[0], nums[1], nums[2], nums[3]);
|
||||
}
|
||||
else
|
||||
buf[0] = '\0';
|
||||
|
||||
ffPrintFormatString(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, FF_MONITOR_NUM_FORMAT_ARGS, (FFformatarg[]) {
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &display->name},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &display->width},
|
||||
@@ -67,6 +76,9 @@ void ffPrintMonitor(FFMonitorOptions* options)
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &display->physicalHeight},
|
||||
{FF_FORMAT_ARG_TYPE_DOUBLE, &inch},
|
||||
{FF_FORMAT_ARG_TYPE_DOUBLE, &ppi},
|
||||
{FF_FORMAT_ARG_TYPE_UINT16, &display->manufactureYear},
|
||||
{FF_FORMAT_ARG_TYPE_UINT16, &display->manufactureWeek},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, buf},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -131,11 +143,31 @@ void ffGenerateMonitorJsonResult(FF_MAYBE_UNUSED FFMonitorOptions* options, yyjs
|
||||
{
|
||||
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
|
||||
yyjson_mut_obj_add_bool(doc, obj, "hdrCompatible", item->hdrCompatible);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "width", item->width);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "height", item->height);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "physicalHeight", item->physicalHeight);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "physicalWidth", item->physicalWidth);
|
||||
|
||||
yyjson_mut_val* resolution = yyjson_mut_obj_add_obj(doc, obj, "resolution");
|
||||
yyjson_mut_obj_add_uint(doc, resolution, "width", item->width);
|
||||
yyjson_mut_obj_add_uint(doc, resolution, "height", item->height);
|
||||
|
||||
yyjson_mut_val* physical = yyjson_mut_obj_add_obj(doc, obj, "physical");
|
||||
yyjson_mut_obj_add_uint(doc, physical, "height", item->physicalHeight);
|
||||
yyjson_mut_obj_add_uint(doc, physical, "width", item->physicalWidth);
|
||||
|
||||
if (item->manufactureYear)
|
||||
{
|
||||
yyjson_mut_val* manufactureDate = yyjson_mut_obj_add_obj(doc, obj, "manufactureDate");
|
||||
yyjson_mut_obj_add_uint(doc, manufactureDate, "year", item->manufactureYear);
|
||||
yyjson_mut_obj_add_uint(doc, manufactureDate, "week", item->manufactureWeek);
|
||||
}
|
||||
else
|
||||
{
|
||||
yyjson_mut_obj_add_null(doc, obj, "manufactureDate");
|
||||
}
|
||||
|
||||
if (item->serial)
|
||||
yyjson_mut_obj_add_uint(doc, obj, "serial", item->serial);
|
||||
else
|
||||
yyjson_mut_obj_add_null(doc, obj, "serial");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +186,9 @@ void ffPrintMonitorHelpFormat(void)
|
||||
"Display physical width in millimeters",
|
||||
"Display physical height in millimeters",
|
||||
"Display physical diagonal length in inches",
|
||||
"Display physical pixels per inch (PPI)"
|
||||
"Year of manufacturing",
|
||||
"Nth week of manufacturing in the year",
|
||||
"Serial number",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#define FF_POWERADAPTER_DISPLAY_NAME "Power Adapter"
|
||||
#define FF_POWERADAPTER_NUM_FORMAT_ARGS 5
|
||||
#define FF_POWERADAPTER_NUM_FORMAT_ARGS 6
|
||||
|
||||
void ffPrintPowerAdapter(FFPowerAdapterOptions* options)
|
||||
{
|
||||
FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFPowerAdapterResult));
|
||||
|
||||
const char* error = ffDetectPowerAdapterImpl(&results);
|
||||
const char* error = ffDetectPowerAdapter(&results);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -27,35 +27,34 @@ void ffPrintPowerAdapter(FFPowerAdapterOptions* options)
|
||||
{
|
||||
FFPowerAdapterResult* result = ffListGet(&results, i);
|
||||
|
||||
if(result->watts != FF_POWERADAPTER_UNSET)
|
||||
if(options->moduleArgs.outputFormat.length == 0)
|
||||
{
|
||||
if(options->moduleArgs.outputFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
ffPrintLogoAndKey(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
|
||||
if(result->name.length > 0)
|
||||
puts(result->name.chars);
|
||||
else if(result->watts == FF_POWERADAPTER_NOT_CONNECTED)
|
||||
puts("not connected");
|
||||
else
|
||||
printf("%dW\n", result->watts);
|
||||
}
|
||||
if(result->name.length > 0)
|
||||
puts(result->name.chars);
|
||||
else if(result->watts == FF_POWERADAPTER_NOT_CONNECTED)
|
||||
puts("not connected");
|
||||
else
|
||||
{
|
||||
ffPrintFormat(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_POWERADAPTER_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_INT, &result->watts},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->description},
|
||||
});
|
||||
}
|
||||
printf("%dW\n", result->watts);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormat(FF_POWERADAPTER_DISPLAY_NAME, i, &options->moduleArgs, FF_POWERADAPTER_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_INT, &result->watts},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->name},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->manufacturer},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->modelName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->description},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->serial},
|
||||
});
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&result->manufacturer);
|
||||
ffStrbufDestroy(&result->description);
|
||||
ffStrbufDestroy(&result->modelName);
|
||||
ffStrbufDestroy(&result->name);
|
||||
ffStrbufDestroy(&result->serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +98,7 @@ void ffGeneratePowerAdapterJsonResult(FF_MAYBE_UNUSED FFPowerAdapterOptions* opt
|
||||
{
|
||||
FF_LIST_AUTO_DESTROY results = ffListCreate(sizeof(FFPowerAdapterResult));
|
||||
|
||||
const char* error = ffDetectPowerAdapterImpl(&results);
|
||||
const char* error = ffDetectPowerAdapter(&results);
|
||||
|
||||
if (error)
|
||||
{
|
||||
@@ -119,6 +118,7 @@ void ffGeneratePowerAdapterJsonResult(FF_MAYBE_UNUSED FFPowerAdapterOptions* opt
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "manufacturer", &item->manufacturer);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "modelName", &item->modelName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "serial", &item->serial);
|
||||
yyjson_mut_obj_add_int(doc, obj, "watts", item->watts);
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,7 @@ void ffPrintPowerAdapterHelpFormat(void)
|
||||
"PowerAdapter manufacturer",
|
||||
"PowerAdapter model",
|
||||
"PowerAdapter description"
|
||||
"PowerAdapter serial number"
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+19
-18
@@ -8,9 +8,9 @@
|
||||
|
||||
void ffPrintShell(FFShellOptions* options)
|
||||
{
|
||||
const FFTerminalShellResult* result = ffDetectTerminalShell();
|
||||
const FFShellResult* result = ffDetectShell();
|
||||
|
||||
if(result->shellProcessName.length == 0)
|
||||
if(result->processName.length == 0)
|
||||
{
|
||||
ffPrintError(FF_SHELL_MODULE_NAME, 0, &options->moduleArgs, "Couldn't detect shell");
|
||||
return;
|
||||
@@ -19,12 +19,12 @@ void ffPrintShell(FFShellOptions* options)
|
||||
if(options->moduleArgs.outputFormat.length == 0)
|
||||
{
|
||||
ffPrintLogoAndKey(FF_SHELL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
ffStrbufWriteTo(&result->shellPrettyName, stdout);
|
||||
ffStrbufWriteTo(&result->prettyName, stdout);
|
||||
|
||||
if(result->shellVersion.length > 0)
|
||||
if(result->version.length > 0)
|
||||
{
|
||||
putchar(' ');
|
||||
ffStrbufWriteTo(&result->shellVersion, stdout);
|
||||
ffStrbufWriteTo(&result->version, stdout);
|
||||
}
|
||||
|
||||
putchar('\n');
|
||||
@@ -32,12 +32,12 @@ void ffPrintShell(FFShellOptions* options)
|
||||
else
|
||||
{
|
||||
ffPrintFormat(FF_SHELL_MODULE_NAME, 0, &options->moduleArgs, FF_SHELL_NUM_FORMAT_ARGS, (FFformatarg[]) {
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->shellProcessName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->shellExe},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, result->shellExeName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->shellVersion},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &result->shellPid},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->shellPrettyName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->processName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->exe},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, result->exeName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->version},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &result->pid},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -79,20 +79,21 @@ void ffGenerateShellJsonConfig(FFShellOptions* options, yyjson_mut_doc* doc, yyj
|
||||
|
||||
void ffGenerateShellJsonResult(FF_MAYBE_UNUSED FFShellOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
||||
{
|
||||
const FFTerminalShellResult* result = ffDetectTerminalShell();
|
||||
const FFShellResult* result = ffDetectShell();
|
||||
|
||||
if(result->shellProcessName.length == 0)
|
||||
if(result->processName.length == 0)
|
||||
{
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Couldn't detect shell");
|
||||
return;
|
||||
}
|
||||
|
||||
yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result");
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->shellExe);
|
||||
yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->shellExeName);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "pid", result->shellPid);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->shellProcessName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->shellVersion);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->exe);
|
||||
yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->exeName);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->version);
|
||||
}
|
||||
|
||||
void ffPrintShellHelpFormat(void)
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
|
||||
void ffPrintTerminal(FFTerminalOptions* options)
|
||||
{
|
||||
const FFTerminalShellResult* result = ffDetectTerminalShell();
|
||||
const FFTerminalResult* result = ffDetectTerminal();
|
||||
|
||||
if(result->terminalProcessName.length == 0)
|
||||
if(result->processName.length == 0)
|
||||
{
|
||||
ffPrintError(FF_TERMINAL_MODULE_NAME, 0, &options->moduleArgs, "Couldn't detect terminal");
|
||||
return;
|
||||
@@ -22,20 +22,20 @@ void ffPrintTerminal(FFTerminalOptions* options)
|
||||
{
|
||||
ffPrintLogoAndKey(FF_TERMINAL_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
|
||||
if(result->terminalVersion.length)
|
||||
printf("%s %s\n", result->terminalPrettyName.chars, result->terminalVersion.chars);
|
||||
if(result->version.length)
|
||||
printf("%s %s\n", result->prettyName.chars, result->version.chars);
|
||||
else
|
||||
ffStrbufPutTo(&result->terminalPrettyName, stdout);
|
||||
ffStrbufPutTo(&result->prettyName, stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffPrintFormat(FF_TERMINAL_MODULE_NAME, 0, &options->moduleArgs, FF_TERMINAL_NUM_FORMAT_ARGS, (FFformatarg[]){
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalProcessName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalExe},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, result->terminalExeName},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &result->terminalPid},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalPrettyName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->terminalVersion},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->processName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->exe},
|
||||
{FF_FORMAT_ARG_TYPE_STRING, result->exeName},
|
||||
{FF_FORMAT_ARG_TYPE_UINT, &result->pid},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->prettyName},
|
||||
{FF_FORMAT_ARG_TYPE_STRBUF, &result->version},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -77,21 +77,22 @@ void ffGenerateTerminalJsonConfig(FFTerminalOptions* options, yyjson_mut_doc* do
|
||||
|
||||
void ffGenerateTerminalJsonResult(FF_MAYBE_UNUSED FFTerminalOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module)
|
||||
{
|
||||
const FFTerminalShellResult* result = ffDetectTerminalShell();
|
||||
const FFTerminalResult* result = ffDetectTerminal();
|
||||
|
||||
if(result->terminalProcessName.length == 0)
|
||||
if(result->processName.length == 0)
|
||||
{
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Couldn't detect terminal");
|
||||
return;
|
||||
}
|
||||
|
||||
yyjson_mut_val* obj = yyjson_mut_obj_add_obj(doc, module, "result");
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->terminalProcessName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->terminalExe);
|
||||
yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->terminalExeName);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "pid", result->terminalPid);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->terminalPrettyName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->terminalVersion);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "processName", &result->processName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "exe", &result->exe);
|
||||
yyjson_mut_obj_add_strcpy(doc, obj, "exeName", result->exeName);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "pid", result->pid);
|
||||
yyjson_mut_obj_add_uint(doc, obj, "ppid", result->ppid);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "prettyName", &result->prettyName);
|
||||
yyjson_mut_obj_add_strbuf(doc, obj, "version", &result->version);
|
||||
}
|
||||
|
||||
void ffPrintTerminalHelpFormat(void)
|
||||
|
||||
@@ -21,6 +21,13 @@ void ffPrintVulkan(FFVulkanOptions* options)
|
||||
{
|
||||
ffPrintLogoAndKey(FF_VULKAN_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
|
||||
|
||||
if (vulkan->apiVersion.length == 0 && vulkan->driver.length == 0)
|
||||
{
|
||||
ffStrbufWriteTo(&vulkan->instanceVersion, stdout);
|
||||
puts(" [Software only]");
|
||||
return;
|
||||
}
|
||||
|
||||
if(vulkan->apiVersion.length > 0)
|
||||
{
|
||||
ffStrbufWriteTo(&vulkan->apiVersion, stdout);
|
||||
@@ -101,6 +108,7 @@ void ffGenerateVulkanJsonResult(FF_MAYBE_UNUSED FFVulkanOptions* options, yyjson
|
||||
yyjson_mut_obj_add_strbuf(doc, gpuObj, "vendor", &vulkanGpu->vendor);
|
||||
yyjson_mut_obj_add_strbuf(doc, gpuObj, "name", &vulkanGpu->name);
|
||||
yyjson_mut_obj_add_strbuf(doc, gpuObj, "driver", &vulkanGpu->driver);
|
||||
yyjson_mut_obj_add_strbuf(doc, gpuObj, "platformApi", &vulkanGpu->platformApi);
|
||||
|
||||
yyjson_mut_val* memoryObj = yyjson_mut_obj_add_obj(doc, gpuObj, "memory");
|
||||
|
||||
@@ -139,7 +147,8 @@ void ffPrintVulkanHelpFormat(void)
|
||||
ffPrintModuleFormatHelp(FF_VULKAN_MODULE_NAME, "{2} - {1}", FF_VULKAN_NUM_FORMAT_ARGS, (const char* []) {
|
||||
"Driver name",
|
||||
"API version",
|
||||
"Conformance version"
|
||||
"Conformance version",
|
||||
"Instance version",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+23
-8
@@ -249,13 +249,17 @@ void ffStrbufTrimLeft(FFstrbuf* strbuf, char c)
|
||||
|
||||
void ffStrbufTrimRight(FFstrbuf* strbuf, char c)
|
||||
{
|
||||
if(strbuf->length == 0)
|
||||
if (strbuf->length == 0)
|
||||
return;
|
||||
|
||||
while(ffStrbufEndsWithC(strbuf, c))
|
||||
--strbuf->length;
|
||||
if (!ffStrbufEndsWithC(strbuf, c))
|
||||
return;
|
||||
|
||||
if(strbuf->allocated == 0)
|
||||
do
|
||||
--strbuf->length;
|
||||
while (ffStrbufEndsWithC(strbuf, c));
|
||||
|
||||
if (strbuf->allocated == 0)
|
||||
{
|
||||
//static string
|
||||
ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars);
|
||||
@@ -267,13 +271,17 @@ void ffStrbufTrimRight(FFstrbuf* strbuf, char c)
|
||||
|
||||
void ffStrbufTrimRightSpace(FFstrbuf* strbuf)
|
||||
{
|
||||
if(strbuf->length == 0)
|
||||
if (strbuf->length == 0)
|
||||
return;
|
||||
|
||||
while(ffStrbufEndsWithFn(strbuf, isspace))
|
||||
--strbuf->length;
|
||||
if (!ffStrbufEndsWithFn(strbuf, isspace))
|
||||
return;
|
||||
|
||||
if(strbuf->allocated == 0)
|
||||
do
|
||||
--strbuf->length;
|
||||
while (ffStrbufEndsWithFn(strbuf, isspace));
|
||||
|
||||
if (strbuf->allocated == 0)
|
||||
{
|
||||
//static string
|
||||
ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars);
|
||||
@@ -470,6 +478,13 @@ uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue)
|
||||
return str_end == strbuf->chars ? defaultValue : (uint64_t)result;
|
||||
}
|
||||
|
||||
int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue)
|
||||
{
|
||||
char* str_end;
|
||||
long long result = strtoll(strbuf->chars, &str_end, 10);
|
||||
return str_end == strbuf->chars ? defaultValue : (int64_t)result;
|
||||
}
|
||||
|
||||
void ffStrbufUpperCase(FFstrbuf* strbuf)
|
||||
{
|
||||
for (uint32_t i = 0; i < strbuf->length; ++i)
|
||||
|
||||
@@ -83,6 +83,7 @@ void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file);
|
||||
void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file);
|
||||
|
||||
FF_C_NODISCARD double ffStrbufToDouble(const FFstrbuf* strbuf);
|
||||
FF_C_NODISCARD int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue);
|
||||
FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue);
|
||||
|
||||
void ffStrbufUpperCase(FFstrbuf* strbuf);
|
||||
@@ -222,6 +223,8 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreate()
|
||||
static inline void ffStrbufInitStatic(FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
ffStrbufInit(strbuf);
|
||||
if (!str) return;
|
||||
|
||||
strbuf->allocated = 0;
|
||||
strbuf->length = (uint32_t) strlen(str);
|
||||
strbuf->chars = (char*) str;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user