mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 18:32:10 +02:00
Compare commits
124 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| acf610416c | |||
| 90d3b3d49f | |||
| bbc5b4de98 | |||
| 7f9b6187a6 | |||
| 8067e43631 | |||
| 61dba1ea05 | |||
| a94df76bfa | |||
| b2b748b07c | |||
| 77ce6b0e4c | |||
| d28d307b63 | |||
| 3492f9bfa1 | |||
| 79c67ec0d7 | |||
| 6527f03a9b | |||
| a8b629f58c | |||
| 5df00a3394 | |||
| 8a7c83cac6 | |||
| 27bffb3464 | |||
| 875afb7cde | |||
| 3e99a7035b | |||
| 63873763de | |||
| 27c83e88f2 | |||
| f48904805f | |||
| 531cd0909a | |||
| eafcdfec9e | |||
| d6bd855733 | |||
| af7e2d47d1 | |||
| f71c0b0866 | |||
| 1400291ae9 | |||
| 7799dbe481 | |||
| 8426833c36 | |||
| 235a2018fc | |||
| 470e3b4e57 | |||
| 1942dce980 | |||
| efca4f3597 | |||
| 43ddbdca85 | |||
| 5d29e26509 | |||
| 8daec2568c | |||
| 320e1bf4e0 | |||
| 38e98d3d51 | |||
| 50964fcddf | |||
| 6c7a8a8c41 | |||
| 92082eed54 | |||
| 26b3a84b8a | |||
| 0747fc0887 | |||
| 60fbe1fd0b | |||
| f8667d9faa | |||
| 1c89bbc34e | |||
| b37f020270 | |||
| fbc9569e13 | |||
| a923f61115 | |||
| bc0a515998 | |||
| 87d89130ad | |||
| f46aa316cb | |||
| fdb5f30cb8 | |||
| 91f1c4db10 | |||
| 44e2948b1d | |||
| b86acf6c36 | |||
| 9a15666248 | |||
| f5dfec6dcb | |||
| 8c55c06fa7 | |||
| 8159f473cc | |||
| dca3b154ef | |||
| 79b61f1391 | |||
| ba54763dde | |||
| 451bc394ee | |||
| 93f9ed1bf5 | |||
| d9e4389ed4 | |||
| b465052ad2 | |||
| 2e6b9cd503 | |||
| 0557f16c16 | |||
| 08e252a44c | |||
| 90e2d8f8d9 | |||
| 0dd8d80e02 | |||
| 3cddf31987 | |||
| fe1c5c8f6f | |||
| 994bd53d30 | |||
| 383a4190ca | |||
| 42f2e5a745 | |||
| 14b8bb2bb5 | |||
| b68ad3626c | |||
| cd25803e32 | |||
| 3d6bffe7fe | |||
| e694c8ac84 | |||
| dfff57dd85 | |||
| c5141855a2 | |||
| 6cb186f229 | |||
| e91f62aa70 | |||
| ab5cf94099 | |||
| d9eccd70ed | |||
| 025febc78d | |||
| 69cc19d6f5 | |||
| 2e4dd1d262 | |||
| 24ec0e6035 | |||
| 6e50aaf3ff | |||
| e7cd5f618d | |||
| 55e4896524 | |||
| 594c73461e | |||
| 94ceeb4482 | |||
| 4ee7dd72d0 | |||
| 414f7ce067 | |||
| e1dffe794b | |||
| 181b775f73 | |||
| c4c934d23e | |||
| 31c73543e8 | |||
| d79e1d7fbc | |||
| 3883047dce | |||
| 4eebc1b6ee | |||
| 08b79ff4ae | |||
| ffc38eb0f1 | |||
| 37ee193c40 | |||
| c10027f1d7 | |||
| 039fa1ba77 | |||
| 0db820a6c1 | |||
| 8b611899d1 | |||
| ba7e1eb18b | |||
| 6979b1efc5 | |||
| 4a61cdb1c9 | |||
| 75c28ec671 | |||
| 639252ece0 | |||
| a31d8ce87b | |||
| 41143c23f4 | |||
| 3c2e21b7b1 | |||
| 3eaebd3359 | |||
| 768bc154d4 |
+8
-2
@@ -1,7 +1,6 @@
|
||||
# find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" \) ! -path "src/3rdparty/*" -print0 | xargs -0 clang-format -i
|
||||
# find . -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" -o -name "*.hpp" -o -name "*.m" -o -name "*.mm" \) -print0 | xargs -0 clang-format -i
|
||||
|
||||
BasedOnStyle: LLVM
|
||||
Language: Cpp
|
||||
|
||||
UseTab: Never
|
||||
IndentWidth: 4
|
||||
@@ -81,3 +80,10 @@ AttributeMacros:
|
||||
|
||||
MaxEmptyLinesToKeep: 1
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
|
||||
---
|
||||
Language: ObjC
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
src/3rdparty/**
|
||||
build/**
|
||||
src/logo/builtin.c
|
||||
|
||||
@@ -21,6 +21,10 @@ Closes #
|
||||
|
||||
-
|
||||
|
||||
## Screenshots
|
||||
|
||||
<!-- Required if this PR introduces visual changes. -->
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have tested my changes locally.
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
||||
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libefl-all-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libefl-all-dev libunwind-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
uname -a
|
||||
apt-get update && apt-get install -y software-properties-common
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev libefl-all-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_THREADS=OFF
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_EET=OFF -DENABLE_THREADS=OFF
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update --accept
|
||||
pkg update --accept || true
|
||||
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja
|
||||
|
||||
run: |
|
||||
|
||||
@@ -1,3 +1,56 @@
|
||||
# 2.63.1
|
||||
|
||||
Bugfixes:
|
||||
* Fixes media length detection for Chrome on Linux (Media, Linux)
|
||||
* Fixes segmentation fault when specifying unsupported modules on command line
|
||||
* Disables usage of Netlink for Wi-Fi detection on s390x architectures (Wifi, Linux)
|
||||
|
||||
# 2.63.0
|
||||
|
||||
Changes:
|
||||
* Introduces a new **build-only** dependency, `libefl`, for querying the Enlightenment window manager configuration:
|
||||
* `libefl-all-dev` on Debian/Ubuntu
|
||||
* `libefl-devel` on Fedora
|
||||
* `efl` on Arch Linux
|
||||
* The Windows-specific options `battery.useSetupApi` and `global.wmiTimeout` have been removed. (Windows)
|
||||
|
||||
Features:
|
||||
* Adds wallpaper detection support on Haiku (#2314, Wallpaper, Haiku)
|
||||
* Adds Wi-Fi 6 GHz channel detection and improves protocol reporting (Wifi, Linux)
|
||||
* Improves Deepin version detection using `/etc/os-version` (#2300, OS, Linux)
|
||||
* Adds Ubuntu Kylin and Ubuntu Unity flavor detection (OS, Linux)
|
||||
* Adds NebiDE support (WMTheme, Linux)
|
||||
* Adds package counting for `cards` on NuTyX (#2287, Packages, Linux)
|
||||
* Adds `{am-pm}` to custom format for 12-hour time with am/pm (DateTime)
|
||||
* Adds support for the Enlightenment desktop environment (#2165, WM, Linux)
|
||||
* Adds support for playback progress detection (Media)
|
||||
* The module now prints the current playback position and total media duration when supported by the player. If you prefer the previous behavior, you can set `media.percent.type: ["hide-others"]` to hide the new fields.
|
||||
* Adds support for `global.playerName` for Windows (Media, Windows)
|
||||
* This allows detecting a specified media player while ignoring others.
|
||||
* Multi-battery detection is enabled on Windows by default (Battery, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Improves DisplayServer compatibility on Linux by handling newer `kde-output-device-v2` protocol updates (DisplayServer, Linux)
|
||||
* This fixes a long-standing issue where display detection fails with an `interface 'kde_output_device_mode_v2' has no event X` error.
|
||||
* Improves Wi-Fi reliability on Linux by switching to a netlink implementation (Wifi, Linux)
|
||||
* Improves network interface reliability and default route selection on macOS and Windows (Netif, macOS / Windows)
|
||||
* Validates temperature color thresholds as integers when parsing JSON configs (Temps)
|
||||
* Fixes TDE Konsole version detection (#2319, Terminal, Linux)
|
||||
* Various internal cleanups and optimizations
|
||||
|
||||
Logos:
|
||||
* Adds KibaOS, NebiOS, XJ380, openRuyi, Ximper
|
||||
* Fixes GNOME OS built-in logo detection (#2296)
|
||||
|
||||
# 2.62.1
|
||||
|
||||
Bugfixes:
|
||||
* Fixes the Host module not working on some devices (#2279, Host, Linux)
|
||||
* Regression from v2.61.0
|
||||
|
||||
Logos:
|
||||
* Adds EN-OS, LimeOS, Redrose and Uzbek
|
||||
|
||||
# 2.62.0
|
||||
|
||||
Changes:
|
||||
|
||||
+31
-36
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.62.0
|
||||
VERSION 2.63.1
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -77,6 +77,7 @@ cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBS
|
||||
cmake_dependent_option(ENABLE_DRM_AMDGPU "Enable libdrm_amdgpu" ON "LINUX OR FreeBSD OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_GIO "Enable gio-2.0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_EET "Enable eet" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR Haiku OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_SQLITE3 "Enable sqlite3" ON "LINUX OR FreeBSD OR APPLE OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF)
|
||||
cmake_dependent_option(ENABLE_RPM "Enable rpm" ON "LINUX OR GNU" OFF)
|
||||
@@ -160,7 +161,11 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS} -Werror=incompatible-pointe
|
||||
|
||||
if(WIN32 OR Haiku)
|
||||
enable_language(CXX)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
if(WIN32)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
else()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
||||
endif()
|
||||
|
||||
@@ -1029,20 +1034,18 @@ elseif(WIN32)
|
||||
src/common/impl/debug_windows.c
|
||||
src/common/impl/kmod_windows.c
|
||||
src/common/windows/getline.c
|
||||
src/common/windows/com.cpp
|
||||
src/common/windows/com.c
|
||||
src/common/windows/registry.c
|
||||
src/common/windows/unicode.c
|
||||
src/common/windows/wmi.cpp
|
||||
src/common/windows/variant.cpp
|
||||
src/common/windows/version.c
|
||||
src/detection/battery/battery_windows.c
|
||||
src/detection/bios/bios_windows.c
|
||||
src/detection/bluetooth/bluetooth_windows.c
|
||||
src/detection/bluetooth/bluetooth_windows.cpp
|
||||
src/detection/bluetoothradio/bluetoothradio_windows.c
|
||||
src/detection/board/board_windows.c
|
||||
src/detection/bootmgr/bootmgr_windows.c
|
||||
src/detection/brightness/brightness_windows.cpp
|
||||
src/detection/brightness/brightness_windows.c
|
||||
src/detection/btrfs/btrfs_nosupport.c
|
||||
src/detection/chassis/chassis_windows.c
|
||||
src/detection/cpu/cpu_windows.c
|
||||
@@ -1067,7 +1070,7 @@ elseif(WIN32)
|
||||
src/detection/locale/locale_windows.c
|
||||
src/detection/localip/localip_windows.c
|
||||
src/detection/gamepad/gamepad_windows.c
|
||||
src/detection/media/media_windows.c
|
||||
src/detection/media/media_windows.cpp
|
||||
src/detection/memory/memory_windows.c
|
||||
src/detection/mouse/mouse_windows.c
|
||||
src/detection/physicalmemory/physicalmemory_linux.c
|
||||
@@ -1238,7 +1241,7 @@ elseif(Haiku)
|
||||
src/detection/tpm/tpm_nosupport.c
|
||||
src/detection/uptime/uptime_haiku.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_nosupport.c
|
||||
src/detection/wallpaper/wallpaper_haiku.cpp
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/de/de_nosupport.c
|
||||
@@ -1334,6 +1337,14 @@ endif()
|
||||
if(WIN32)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_intel.c)
|
||||
list(APPEND LIBFASTFETCH_SRC src/detection/gpu/gpu_amd.c)
|
||||
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX("winrt/Windows.Foundation.h" HAVE_WINRT)
|
||||
if(HAVE_WINRT)
|
||||
message(STATUS "WinRT headers are available, media detection will be enabled")
|
||||
else()
|
||||
message(WARNING "WinRT headers are NOT available, media detection will be disabled")
|
||||
endif()
|
||||
endif()
|
||||
include(CheckFunctionExists)
|
||||
check_function_exists(wcwidth HAVE_WCWIDTH)
|
||||
@@ -1436,7 +1447,7 @@ if(LINUX)
|
||||
elseif(ANDROID)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE _FILE_OFFSET_BITS=64 "$<$<CONFIG:DEBUG>:__BIONIC_FORTIFY>" "$<$<CONFIG:DEBUG>:__BIONIC_FORTIFY_RUNTIME_CHECKS_ENABLED>")
|
||||
elseif(WIN32)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 NOMINMAX UNICODE) # "$<$<CONFIG:Release>:_FORTIFY_SOURCE=3>"
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN _WIN32_WINNT=0x0A00 NOMINMAX UNICODE) # "$<$<CONFIG:Release>:_FORTIFY_SOURCE=3>"
|
||||
elseif(APPLE)
|
||||
target_compile_definitions(libfastfetch PUBLIC _GNU_SOURCE _XOPEN_SOURCE __STDC_WANT_LIB_EXT1__ _FILE_OFFSET_BITS=64 _DARWIN_C_SOURCE)
|
||||
elseif(OpenBSD)
|
||||
@@ -1604,6 +1615,10 @@ ff_lib_enable(DCONF
|
||||
"dconf"
|
||||
"DConf"
|
||||
)
|
||||
ff_lib_enable(EET
|
||||
"eet"
|
||||
"Eet"
|
||||
)
|
||||
ff_lib_enable(DBUS
|
||||
"dbus-1"
|
||||
"DBus"
|
||||
@@ -1747,6 +1762,11 @@ elseif(WIN32)
|
||||
PRIVATE "mincore"
|
||||
)
|
||||
endif()
|
||||
if(HAVE_WINRT)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "runtimeobject"
|
||||
)
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
target_link_libraries(libfastfetch
|
||||
PRIVATE "m"
|
||||
@@ -1833,20 +1853,6 @@ target_link_libraries(libfastfetch
|
||||
target_compile_options(libfastfetch PRIVATE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions -fno-rtti>)
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
include(CheckIncludeFileCXX)
|
||||
CHECK_INCLUDE_FILE_CXX("winrt/Windows.Foundation.h" HAVE_WINRT)
|
||||
if(HAVE_WINRT)
|
||||
add_library(ffwinrt MODULE src/detection/media/media_windows.dll.cpp)
|
||||
target_link_libraries(ffwinrt PRIVATE "RuntimeObject")
|
||||
target_compile_definitions(ffwinrt PRIVATE WIN32_LEAN_AND_MEAN=1 WINRT_LEAN_AND_MEAN=1)
|
||||
target_link_options(ffwinrt
|
||||
PRIVATE "-static" # stdc++, winpthread, gcc_s, etc.
|
||||
)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
endif()
|
||||
if(FreeBSD)
|
||||
set(CMAKE_REQUIRED_INCLUDES "/usr/local/include" "/usr/include")
|
||||
endif()
|
||||
@@ -1856,12 +1862,6 @@ if(LINUX OR FreeBSD OR OpenBSD OR NetBSD)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LINUX_VIDEODEV2=1)
|
||||
endif()
|
||||
endif()
|
||||
if(LINUX)
|
||||
CHECK_INCLUDE_FILE("linux/wireless.h" HAVE_LINUX_WIRELESS)
|
||||
if(HAVE_LINUX_WIRELESS)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_LINUX_WIRELESS=1)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT WIN32)
|
||||
CHECK_INCLUDE_FILE("utmpx.h" HAVE_UTMPX)
|
||||
if(HAVE_UTMPX)
|
||||
@@ -1893,6 +1893,8 @@ if(NOT WIN32)
|
||||
message(WARNING "pthread_timedjoin_np was not found; networking timeout will not work")
|
||||
endif()
|
||||
endif()
|
||||
elseif(HAVE_WINRT)
|
||||
target_compile_definitions(libfastfetch PRIVATE FF_HAVE_WINRT=1)
|
||||
endif()
|
||||
|
||||
set(PACKAGES_DISABLE_LIST "")
|
||||
@@ -2039,13 +2041,6 @@ if (TARGET flashfetch)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (TARGET ffwinrt)
|
||||
install(
|
||||
TARGETS ffwinrt
|
||||
DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
install(
|
||||
FILES "${CMAKE_SOURCE_DIR}/completions/${CMAKE_PROJECT_NAME}.bash"
|
||||
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/bash-completion/completions"
|
||||
|
||||
Vendored
+18
@@ -1,3 +1,21 @@
|
||||
fastfetch (2.63.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.63.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 13 May 2026 16:02:28 +0800
|
||||
|
||||
fastfetch (2.62.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.62.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 24 Apr 2026 15:45:15 +0800
|
||||
|
||||
fastfetch (2.62.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.62.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 22 Apr 2026 09:49:55 +0800
|
||||
|
||||
fastfetch (2.61.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.61.0
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: fastfetch
|
||||
Section: universe/utils
|
||||
Priority: optional
|
||||
Maintainer: Carter Li <zhangsongcui@live.cn>
|
||||
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
|
||||
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, libefl-all-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
|
||||
Standards-Version: 4.0.0
|
||||
Homepage: https://github.com/fastfetch-cli/fastfetch
|
||||
|
||||
|
||||
+6
-13
@@ -334,7 +334,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"datetimeFormat": {
|
||||
"description": "Output format for the `DateTime` module. See Wiki for formatting syntax\n 1. {year}: Year\n 2. {year-short}: Last two digits of year\n 3. {month}: Month\n 4. {month-pretty}: Month with leading zero\n 5. {month-name}: Month name\n 6. {month-name-short}: Month name short\n 7. {week}: Week number on year\n 8. {weekday}: Weekday\n 9. {weekday-short}: Weekday short\n 10. {day-in-year}: Day in year\n 11. {day-in-month}: Day in month\n 12. {day-in-week}: Day in week\n 13. {hour}: Hour\n 14. {hour-pretty}: Hour with leading zero\n 15. {hour-12}: Hour 12h format\n 16. {hour-12-pretty}: Hour 12h format with leading zero\n 17. {minute}: Minute\n 18. {minute-pretty}: Minute with leading zero\n 19. {second}: Second\n 20. {second-pretty}: Second with leading zero\n 21. {offset-from-utc}: Offset from UTC in the ISO 8601 format\n 22. {timezone-name}: Locale-dependent timezone name or abbreviation\n 23. {day-pretty}: Day in month with leading zero",
|
||||
"description": "Output format for the `DateTime` module. See Wiki for formatting syntax\n 1. {year}: Year\n 2. {year-short}: Last two digits of year\n 3. {month}: Month\n 4. {month-pretty}: Month with leading zero\n 5. {month-name}: Month name\n 6. {month-name-short}: Month name short\n 7. {week}: Week number on year\n 8. {weekday}: Weekday\n 9. {weekday-short}: Weekday short\n 10. {day-in-year}: Day in year\n 11. {day-in-month}: Day in month\n 12. {day-in-week}: Day in week\n 13. {hour}: Hour\n 14. {hour-pretty}: Hour with leading zero\n 15. {hour-12}: Hour 12h format\n 16. {hour-12-pretty}: Hour 12h format with leading zero\n 17. {minute}: Minute\n 18. {minute-pretty}: Minute with leading zero\n 19. {second}: Second\n 20. {second-pretty}: Second with leading zero\n 21. {offset-from-utc}: Offset from UTC in the ISO 8601 format\n 22. {timezone-name}: Locale-dependent timezone name or abbreviation\n 23. {day-pretty}: Day in month with leading zero\n 24. {am-pm}: AM or PM",
|
||||
"type": "string"
|
||||
},
|
||||
"deFormat": {
|
||||
@@ -410,7 +410,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"mediaFormat": {
|
||||
"description": "Output format for the `Media` module. See Wiki for formatting syntax\n 1. {combined}: Pretty media name\n 2. {title}: Media name\n 3. {artist}: Artist name\n 4. {album}: Album name\n 5. {status}: Status",
|
||||
"description": "Output format for the `Media` module. See Wiki for formatting syntax\n 1. {combined}: Pretty media name\n 2. {title}: Media name\n 3. {artist}: Artist name\n 4. {album}: Album name\n 5. {status}: Status\n 6. {progress}: Progress in text\n 7. {progress-num}: Progress in percentage (number)\n 8. {progress-bar}: Progress in percentage (bar)\n 9. {player-name}: Player name\n 10. {player-id}: Player ID\n 11. {url}: URL",
|
||||
"type": "string"
|
||||
},
|
||||
"memoryFormat": {
|
||||
@@ -442,7 +442,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"packagesFormat": {
|
||||
"description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {kiss}: Number of kiss packages\n 44. {moss}: Number of moss packages\n 45. {nix-all}: Total number of all nix packages\n 46. {flatpak-all}: Total number of all flatpak app packages\n 47. {brew-all}: Total number of all brew packages\n 48. {guix-all}: Total number of all guix packages\n 49. {hpkg-all}: Total number of all hpkg packages",
|
||||
"description": "Output format for the `Packages` module. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {am-system}: Number of am-system packages\n 3. {am-user}: Number of am-user (aka appman) packages\n 4. {appimage}: Number of appimage packages\n 5. {apk}: Number of apk packages\n 6. {brew}: Number of brew packages\n 7. {brew-all}: Total number of all brew packages\n 8. {brew-cask}: Number of brew-cask packages\n 9. {cards}: Number of cards packages\n 10. {choco}: Number of choco packages\n 11. {dpkg}: Number of dpkg packages\n 12. {emerge}: Number of emerge packages\n 13. {eopkg}: Number of eopkg packages\n 14. {flatpak-all}: Total number of all flatpak app packages\n 15. {flatpak-system}: Number of flatpak-system app packages\n 16. {flatpak-user}: Number of flatpak-user app packages\n 17. {guix-all}: Total number of all guix packages\n 18. {guix-home}: Number of guix-home packages\n 19. {guix-system}: Number of guix-system packages\n 20. {guix-user}: Number of guix-user packages\n 21. {hpkg-all}: Total number of all hpkg packages\n 22. {hpkg-system}: Number of hpkg-system packages\n 23. {hpkg-user}: Number of hpkg-user packages\n 24. {kiss}: Number of kiss packages\n 25. {linglong}: Number of linglong packages\n 26. {lpkg}: Number of lpkg packages\n 27. {lpkgbuild}: Number of lpkgbuild packages\n 28. {macports}: Number of macports packages\n 29. {mport}: Number of mport packages\n 30. {moss}: Number of moss packages\n 31. {nix-all}: Total number of all nix packages\n 32. {nix-default}: Number of nix-default packages\n 33. {nix-system}: Number of nix-system packages\n 34. {nix-user}: Number of nix-user packages\n 35. {opkg}: Number of opkg packages\n 36. {pacman}: Number of pacman packages\n 37. {pacman-branch}: Pacman branch on manjaro\n 38. {pacstall}: Number of pacstall packages\n 39. {paludis}: Number of paludis packages\n 40. {pisi}: Number of pisi packages\n 41. {pkg}: Number of pkg packages\n 42. {pkgsrc}: Number of pkgsrc packages\n 43. {pkgtool}: Number of pkgtool packages\n 44. {rpm}: Number of rpm packages\n 45. {scoop-global}: Number of scoop-global packages\n 46. {scoop-user}: Number of scoop-user packages\n 47. {snap}: Number of snap packages\n 48. {soar}: Number of soar packages\n 49. {sorcery}: Number of sorcery packages\n 50. {winget}: Number of winget packages\n 51. {xbps}: Number of xbps packages",
|
||||
"type": "string"
|
||||
},
|
||||
"physicaldiskFormat": {
|
||||
@@ -898,11 +898,6 @@
|
||||
],
|
||||
"default": false
|
||||
},
|
||||
"wmiTimeout": {
|
||||
"type": "integer",
|
||||
"description": "Set the timeout (ms) for WMI queries, `-1` for no timeout. Windows only",
|
||||
"default": 5000
|
||||
},
|
||||
"processingTimeout": {
|
||||
"type": "integer",
|
||||
"description": "Set the timeout (ms) when waiting for child processes, `-1` for no timeout",
|
||||
@@ -1540,11 +1535,6 @@
|
||||
"const": "battery",
|
||||
"description": "Print battery information"
|
||||
},
|
||||
"useSetupApi": {
|
||||
"description": "Whether to use the `CM API` on Windows to detect battery information. Supports multiple batteries, but is slower (Windows only)",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"temp": {
|
||||
"$ref": "#/$defs/temperature"
|
||||
},
|
||||
@@ -3259,6 +3249,9 @@
|
||||
"const": "media",
|
||||
"description": "Print the name of the currently playing song"
|
||||
},
|
||||
"percent": {
|
||||
"$ref": "#/$defs/percent"
|
||||
},
|
||||
"key": {
|
||||
"$ref": "#/$defs/key"
|
||||
},
|
||||
|
||||
+141
-88
@@ -21,7 +21,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
/// \file adl_defines.h
|
||||
/// \brief Contains all definitions exposed by ADL for \ALL platforms.\n <b>Included in ADL SDK</b>
|
||||
/// \brief Contains all definitions exposed by ADL for \WIN platforms.\n <b>Included in ADL SDK</b>
|
||||
///
|
||||
/// This file contains all definitions used by ADL.
|
||||
/// The ADL definitions include the following:
|
||||
@@ -61,6 +61,8 @@
|
||||
#define ADL_ADAPTER_INDEX_ALL -1
|
||||
/// Defines APIs with iOption none
|
||||
#define ADL_MAIN_API_OPTION_NONE 0
|
||||
/// Defines the maximum of RPC endpoint
|
||||
#define ADL_MAX_RPC_ENDPOINT 32
|
||||
/// @}
|
||||
|
||||
/// \name Definitions for iOption parameter used by
|
||||
@@ -141,6 +143,12 @@
|
||||
#define ADL_ERR_FEATURESYNC_NOT_STARTED -24
|
||||
/// Adapter is in an invalid power state
|
||||
#define ADL_ERR_INVALID_POWER_STATE -25
|
||||
/// The RPC server is in busy state
|
||||
#define ADL_ERR_SERVER_BUSY -26
|
||||
/// The GPU is occupied by application which cannot be powered off
|
||||
#define ADL_ERR_GPU_IN_USE -27
|
||||
/// The general RPC connection error
|
||||
#define ADL_ERR_RPC -28
|
||||
|
||||
/// @}
|
||||
/// </A>
|
||||
@@ -380,6 +388,7 @@
|
||||
#define ADL_BUSTYPE_PCIE_GEN2 3 /* PCI Express 2nd generation bus */
|
||||
#define ADL_BUSTYPE_PCIE_GEN3 4 /* PCI Express 3rd generation bus */
|
||||
#define ADL_BUSTYPE_PCIE_GEN4 5 /* PCI Express 4th generation bus */
|
||||
#define ADL_BUSTYPE_PCIE_GEN5 6 /* PCI Express 5th generation bus */
|
||||
/// @}
|
||||
|
||||
/// \defgroup define_ws_caps Workstation Capabilities
|
||||
@@ -872,7 +881,7 @@
|
||||
typedef enum ADLThreadingModel
|
||||
{
|
||||
ADL_THREADING_UNLOCKED = 0, /*!< Default behavior. ADL will not enforce serialization of ADL API executions by multiple threads. Multiple threads will be allowed to enter to ADL at the same time. Note that ADL library is not guaranteed to be thread-safe. Client that calls ADL_Main_Control_Create have to provide its own mechanism for ADL calls serialization. */
|
||||
ADL_THREADING_LOCKED /*!< ADL will enforce serialization of ADL API when called by multiple threads. Only single thread will be allowed to enter ADL API at the time. This option makes ADL calls thread-safe. You shouldn't use this option if ADL calls will be executed on Linux on x-server rendering thread. It can cause the application to hung. */
|
||||
ADL_THREADING_LOCKED /*!< ADL will enforce serialization of ADL API when called by multiple threads. Only single thread will be allowed to enter ADL API at the time. This option makes ADL calls thread-safe. */
|
||||
}ADLThreadingModel;
|
||||
|
||||
/// @}
|
||||
@@ -1844,12 +1853,12 @@ enum ADLOD8FeatureControl
|
||||
ADL_OD8_TEMPERATURE_FAN = 1 << 6, //FanTargetTemperature
|
||||
ADL_OD8_TEMPERATURE_SYSTEM = 1 << 7, //MaxOpTemp
|
||||
ADL_OD8_MEMORY_TIMING_TUNE = 1 << 8,
|
||||
ADL_OD8_FAN_ZERO_RPM_CONTROL = 1 << 9 ,
|
||||
ADL_OD8_AUTO_UV_ENGINE = 1 << 10, //Auto under voltage
|
||||
ADL_OD8_AUTO_OC_ENGINE = 1 << 11, //Auto overclock engine
|
||||
ADL_OD8_AUTO_OC_MEMORY = 1 << 12, //Auto overclock memory
|
||||
ADL_OD8_FAN_CURVE = 1 << 13, //Fan curve
|
||||
ADL_OD8_WS_AUTO_FAN_ACOUSTIC_LIMIT = 1 << 14, //Workstation Manual Fan controller
|
||||
ADL_OD8_FAN_ZERO_RPM_CONTROL = 1 << 9,
|
||||
ADL_OD8_AUTO_UV_ENGINE = 1 << 10, //Auto under voltage
|
||||
ADL_OD8_AUTO_OC_ENGINE = 1 << 11, //Auto overclock engine
|
||||
ADL_OD8_AUTO_OC_MEMORY = 1 << 12, //Auto overclock memory
|
||||
ADL_OD8_FAN_CURVE = 1 << 13, //Fan curve
|
||||
ADL_OD8_WS_AUTO_FAN_ACOUSTIC_LIMIT = 1 << 14, //Workstation Manual Fan controller
|
||||
ADL_OD8_GFXCLK_QUADRATIC_CURVE = 1 << 15,
|
||||
ADL_OD8_OPTIMIZED_GPU_POWER_MODE = 1 << 16,
|
||||
ADL_OD8_ODVOLTAGE_LIMIT = 1 << 17,
|
||||
@@ -1860,43 +1869,45 @@ enum ADLOD8FeatureControl
|
||||
ADL_OD8_TDC_LIMIT = 1 << 22, //TDC slider
|
||||
ADL_OD8_FULL_CONTROL_MODE = 1 << 23, //Full control
|
||||
ADL_OD8_POWER_SAVING_FEATURE_CONTROL = 1 << 24, //Power saving feature control
|
||||
ADL_OD8_POWER_GAUGE = 1 << 25 //Power Gauge
|
||||
ADL_OD8_ACTIMING_PARAMETERS_TUNE = 1 << 25, // AC Timing Parameters Tuning
|
||||
ADL_OD8_OVERDRIVE_INTERFACE = 1 << 26, // Version info feature ID for RSX, do not expose in ADL.
|
||||
ADL_OD8_AUTO_UV_ENGINE_V2 = 1 << 27, // Auto UV 2.0 with actual stress testing.
|
||||
ADL_OD8_POWER_GAUGE = 1 << 28 //Power Gauge
|
||||
};
|
||||
|
||||
|
||||
typedef enum ADLOD8SettingId
|
||||
{
|
||||
OD8_GFXCLK_FMAX = 0,
|
||||
OD8_GFXCLK_FMIN,
|
||||
OD8_GFXCLK_FREQ1,
|
||||
OD8_GFXCLK_VOLTAGE1,
|
||||
OD8_GFXCLK_FREQ2,
|
||||
OD8_GFXCLK_VOLTAGE2,
|
||||
OD8_GFXCLK_FREQ3,
|
||||
OD8_GFXCLK_VOLTAGE3,
|
||||
OD8_UCLK_FMAX,
|
||||
OD8_POWER_PERCENTAGE,
|
||||
OD8_FAN_MIN_SPEED,
|
||||
OD8_FAN_ACOUSTIC_LIMIT,
|
||||
OD8_FAN_TARGET_TEMP,
|
||||
OD8_OPERATING_TEMP_MAX,
|
||||
OD8_AC_TIMING,
|
||||
OD8_FAN_ZERORPM_CONTROL,
|
||||
OD8_AUTO_UV_ENGINE_CONTROL,
|
||||
OD8_AUTO_OC_ENGINE_CONTROL,
|
||||
OD8_AUTO_OC_MEMORY_CONTROL,
|
||||
OD8_FAN_CURVE_TEMPERATURE_1,
|
||||
OD8_FAN_CURVE_SPEED_1,
|
||||
OD8_FAN_CURVE_TEMPERATURE_2,
|
||||
OD8_FAN_CURVE_SPEED_2,
|
||||
OD8_FAN_CURVE_TEMPERATURE_3,
|
||||
OD8_FAN_CURVE_SPEED_3,
|
||||
OD8_FAN_CURVE_TEMPERATURE_4,
|
||||
OD8_FAN_CURVE_SPEED_4,
|
||||
OD8_FAN_CURVE_TEMPERATURE_5,
|
||||
OD8_FAN_CURVE_SPEED_5,
|
||||
OD8_WS_FAN_AUTO_FAN_ACOUSTIC_LIMIT,
|
||||
OD8_GFXCLK_CURVE_COEFFICIENT_A, // As part of the agreement with UI team, the min/max voltage limits for the
|
||||
OD8_GFXCLK_FMAX = 0,
|
||||
OD8_GFXCLK_FMIN,
|
||||
OD8_GFXCLK_FREQ1,
|
||||
OD8_GFXCLK_VOLTAGE1,
|
||||
OD8_GFXCLK_FREQ2,
|
||||
OD8_GFXCLK_VOLTAGE2,
|
||||
OD8_GFXCLK_FREQ3,
|
||||
OD8_GFXCLK_VOLTAGE3,
|
||||
OD8_UCLK_FMAX,
|
||||
OD8_POWER_PERCENTAGE,
|
||||
OD8_FAN_MIN_SPEED, //10
|
||||
OD8_FAN_ACOUSTIC_LIMIT,
|
||||
OD8_FAN_TARGET_TEMP,
|
||||
OD8_OPERATING_TEMP_MAX,
|
||||
OD8_AC_TIMING,
|
||||
OD8_FAN_ZERORPM_CONTROL,
|
||||
OD8_AUTO_UV_ENGINE_CONTROL,
|
||||
OD8_AUTO_OC_ENGINE_CONTROL,
|
||||
OD8_AUTO_OC_MEMORY_CONTROL,
|
||||
OD8_FAN_CURVE_TEMPERATURE_1,
|
||||
OD8_FAN_CURVE_SPEED_1, //20
|
||||
OD8_FAN_CURVE_TEMPERATURE_2,
|
||||
OD8_FAN_CURVE_SPEED_2,
|
||||
OD8_FAN_CURVE_TEMPERATURE_3,
|
||||
OD8_FAN_CURVE_SPEED_3,
|
||||
OD8_FAN_CURVE_TEMPERATURE_4,
|
||||
OD8_FAN_CURVE_SPEED_4,
|
||||
OD8_FAN_CURVE_TEMPERATURE_5,
|
||||
OD8_FAN_CURVE_SPEED_5,
|
||||
OD8_WS_FAN_AUTO_FAN_ACOUSTIC_LIMIT,
|
||||
OD8_GFXCLK_CURVE_COEFFICIENT_A, // 30 As part of the agreement with UI team, the min/max voltage limits for the
|
||||
OD8_GFXCLK_CURVE_COEFFICIENT_B, // quadratic curve graph will be stored in the min and max limits of
|
||||
OD8_GFXCLK_CURVE_COEFFICIENT_C, // coefficient a, b and c. A, b and c themselves do not have limits.
|
||||
OD8_GFXCLK_CURVE_VFT_FMIN,
|
||||
@@ -1906,7 +1917,7 @@ typedef enum ADLOD8SettingId
|
||||
OD8_OD_VOLTAGE,// RSX - voltage offset feature
|
||||
OD8_ADV_OC_LIMITS_SETTING,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_1,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_2,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_2, //40
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_3,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_4,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_POINT_5,
|
||||
@@ -1915,8 +1926,33 @@ typedef enum ADLOD8SettingId
|
||||
OD8_GFX_VOLTAGE_LIMIT_SETTING,
|
||||
OD8_TDC_PERCENTAGE,
|
||||
OD8_FULL_CONTROL_MODE_SETTING,
|
||||
OD8_FULL_CONTROL_MODE_GFXCLK,
|
||||
OD8_FULL_CONTROL_MODE_UCLK, // 50,
|
||||
OD8_IDLE_POWER_SAVING_FEATURE_CONTROL,
|
||||
OD8_RUNTIME_POWER_SAVING_FEATURE_CONTROL,
|
||||
OD8_FULL_CONTROL_MODE_FEATURE_CONTROL,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_1,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_2,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_3,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_4,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_5,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_FREQ_ANCHOR_6,
|
||||
OD8_PER_ZONE_GFX_VOLTAGE_OFFSET_VOLTAGE_LIMIT, //60
|
||||
OD8_ACTIMING_PARAMETER_TRRDS,
|
||||
OD8_ACTIMING_PARAMETER_TCL,
|
||||
OD8_ACTIMING_PARAMETER_TCWL,
|
||||
OD8_ACTIMING_PARAMETER_TRCDRD,
|
||||
OD8_ACTIMING_PARAMETER_TRCDWR,
|
||||
OD8_ACTIMING_PARAMETER_TRAS,
|
||||
OD8_ACTIMING_PARAMETER_TRPAB,
|
||||
OD8_ACTIMING_PARAMETER_TRFC,
|
||||
OD8_ACTIMING_PARAMETER_TRFCPB,
|
||||
OD8_ACTIMING_PARAMETER_TRREFD, //70
|
||||
OD8_ACTIMING_PARAMETER_TREF,
|
||||
OD8_ACTIMING_PARAMETER_TWR,
|
||||
OD8_ACTIMING_PARAMETER_TWTRS,
|
||||
OD8_OVERDRIVE_INTERFACE_ID, //74
|
||||
OD8_AUTO_UV_ENGINE_V2_ID, //75
|
||||
OD8_POWER_GAUGE,
|
||||
OD8_COUNT
|
||||
} ADLOD8SettingId;
|
||||
@@ -1980,28 +2016,28 @@ typedef enum ADLSensorType
|
||||
PMLOG_SSDGPU_POWERLIMIT = 49, // DGPU Power limit
|
||||
PMLOG_TEMPERATURE_HOTSPOT_GCD = 50,
|
||||
PMLOG_TEMPERATURE_HOTSPOT_MCD = 51,
|
||||
PMLOG_THROTTLER_TEMP_EDGE_PERCENTAGE = 52,
|
||||
PMLOG_THROTTLER_TEMP_HOTSPOT_PERCENTAGE = 53,
|
||||
PMLOG_THROTTLER_TEMP_HOTSPOT_GCD_PERCENTAGE = 54,
|
||||
PMLOG_THROTTLER_TEMP_HOTSPOT_MCD_PERCENTAGE = 55,
|
||||
PMLOG_THROTTLER_TEMP_MEM_PERCENTAGE = 56,
|
||||
PMLOG_THROTTLER_TEMP_VR_GFX_PERCENTAGE = 57,
|
||||
PMLOG_THROTTLER_TEMP_VR_MEM0_PERCENTAGE = 58,
|
||||
PMLOG_THROTTLER_TEMP_VR_MEM1_PERCENTAGE = 59,
|
||||
PMLOG_THROTTLER_TEMP_VR_SOC_PERCENTAGE = 60,
|
||||
PMLOG_THROTTLER_TEMP_LIQUID0_PERCENTAGE = 61,
|
||||
PMLOG_THROTTLER_TEMP_LIQUID1_PERCENTAGE = 62,
|
||||
PMLOG_THROTTLER_TEMP_PLX_PERCENTAGE = 63,
|
||||
PMLOG_THROTTLER_TDC_GFX_PERCENTAGE = 64,
|
||||
PMLOG_THROTTLER_TDC_SOC_PERCENTAGE = 65,
|
||||
PMLOG_THROTTLER_TDC_USR_PERCENTAGE = 66,
|
||||
PMLOG_THROTTLER_PPT0_PERCENTAGE = 67,
|
||||
PMLOG_THROTTLER_PPT1_PERCENTAGE = 68,
|
||||
PMLOG_THROTTLER_PPT2_PERCENTAGE = 69,
|
||||
PMLOG_THROTTLER_PPT3_PERCENTAGE = 70,
|
||||
PMLOG_THROTTLER_FIT_PERCENTAGE = 71,
|
||||
PMLOG_THROTTLER_GFX_APCC_PLUS_PERCENTAGE = 72,
|
||||
PMLOG_BOARD_POWER = 73,
|
||||
PMLOG_THROTTLE_PERCENTAGE_TEMP_GFX = 52,
|
||||
PMLOG_THROTTLE_PERCENTAGE_TEMP_MEM = 53,
|
||||
PMLOG_THROTTLE_PERCENTAGE_TEMP_VR = 54,
|
||||
PMLOG_THROTTLE_PERCENTAGE_POWER = 55,
|
||||
PMLOG_THROTTLE_PERCENTAGE_TDC = 56,
|
||||
PMLOG_THROTTLE_PERCENTAGE_VMAX = 57,
|
||||
PMLOG_BUS_CURR_MAX_SPEED = 58,
|
||||
PMLOG_RESERVED_1 = 59, //Currently Unused
|
||||
PMLOG_RESERVED_2 = 60, //Currently Unused
|
||||
PMLOG_RESERVED_3 = 61, //Currently Unused
|
||||
PMLOG_RESERVED_4 = 62, //Currently Unused
|
||||
PMLOG_RESERVED_5 = 63, //Currently Unused
|
||||
PMLOG_RESERVED_6 = 64, //Currently Unused
|
||||
PMLOG_RESERVED_7 = 65, //Currently Unused
|
||||
PMLOG_RESERVED_8 = 66, //Currently Unused
|
||||
PMLOG_RESERVED_9 = 67, //Currently Unused
|
||||
PMLOG_RESERVED_10 = 68, //Currently Unused
|
||||
PMLOG_RESERVED_11 = 69, //Currently Unused
|
||||
PMLOG_RESERVED_12 = 70, //Currently Unused
|
||||
PMLOG_RESERVED_13 = 71, //Currently Unused
|
||||
PMLOG_RESERVED_14 = 72,
|
||||
PMLOG_BOARD_POWER = 73,
|
||||
PMLOG_MAX_SENSORS_REAL
|
||||
} ADLSensorType;
|
||||
|
||||
@@ -2068,28 +2104,29 @@ typedef enum ADL_PMLOG_SENSORS
|
||||
ADL_PMLOG_SSDGPU_POWERLIMIT = 49, // DGPU Power limit
|
||||
ADL_PMLOG_TEMPERATURE_HOTSPOT_GCD = 50,
|
||||
ADL_PMLOG_TEMPERATURE_HOTSPOT_MCD = 51,
|
||||
ADL_PMLOG_THROTTLER_TEMP_EDGE_PERCENTAGE = 52,
|
||||
ADL_PMLOG_THROTTLER_TEMP_HOTSPOT_PERCENTAGE = 53,
|
||||
ADL_PMLOG_THROTTLER_TEMP_HOTSPOT_GCD_PERCENTAGE = 54,
|
||||
ADL_PMLOG_THROTTLER_TEMP_HOTSPOT_MCD_PERCENTAGE = 55,
|
||||
ADL_PMLOG_THROTTLER_TEMP_MEM_PERCENTAGE = 56,
|
||||
ADL_PMLOG_THROTTLER_TEMP_VR_GFX_PERCENTAGE = 57,
|
||||
ADL_PMLOG_THROTTLER_TEMP_VR_MEM0_PERCENTAGE = 58,
|
||||
ADL_PMLOG_THROTTLER_TEMP_VR_MEM1_PERCENTAGE = 59,
|
||||
ADL_PMLOG_THROTTLER_TEMP_VR_SOC_PERCENTAGE = 60,
|
||||
ADL_PMLOG_THROTTLER_TEMP_LIQUID0_PERCENTAGE = 61,
|
||||
ADL_PMLOG_THROTTLER_TEMP_LIQUID1_PERCENTAGE = 62,
|
||||
ADL_PMLOG_THROTTLER_TEMP_PLX_PERCENTAGE = 63,
|
||||
ADL_PMLOG_THROTTLER_TDC_GFX_PERCENTAGE = 64,
|
||||
ADL_PMLOG_THROTTLER_TDC_SOC_PERCENTAGE = 65,
|
||||
ADL_PMLOG_THROTTLER_TDC_USR_PERCENTAGE = 66,
|
||||
ADL_PMLOG_THROTTLER_PPT0_PERCENTAGE = 67,
|
||||
ADL_PMLOG_THROTTLER_PPT1_PERCENTAGE = 68,
|
||||
ADL_PMLOG_THROTTLER_PPT2_PERCENTAGE = 69,
|
||||
ADL_PMLOG_THROTTLER_PPT3_PERCENTAGE = 70,
|
||||
ADL_PMLOG_THROTTLER_FIT_PERCENTAGE = 71,
|
||||
ADL_PMLOG_THROTTLER_GFX_APCC_PLUS_PERCENTAGE = 72,
|
||||
ADL_PMLOG_BOARD_POWER = 73,
|
||||
ADL_PMLOG_THROTTLE_PERCENTAGE_TEMP_GFX = 52,
|
||||
ADL_PMLOG_THROTTLE_PERCENTAGE_TEMP_MEM = 53,
|
||||
ADL_PMLOG_THROTTLE_PERCENTAGE_TEMP_VR = 54,
|
||||
ADL_PMLOG_THROTTLE_PERCENTAGE_POWER = 55,
|
||||
ADL_PMLOG_THROTTLE_PERCENTAGE_TDC = 56,
|
||||
ADL_PMLOG_THROTTLE_PERCENTAGE_VMAX = 57,
|
||||
ADL_PMLOG_BUS_CURR_MAX_SPEED = 58,
|
||||
ADL_PMLOG_RESERVED_1 = 59, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_2 = 60, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_3 = 61, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_4 = 62, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_5 = 63, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_6 = 64, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_7 = 65, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_8 = 66, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_9 = 67, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_10 = 68, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_11 = 69, //Currently Unused
|
||||
ADL_PMLOG_RESERVED_12 = 70, //Currently Unused
|
||||
ADL_PMLOG_CLK_NPUCLK = 71, //NPU frequency
|
||||
ADL_PMLOG_NPU_BUSY_AVG = 72, //NPU busy
|
||||
ADL_PMLOG_BOARD_POWER = 73,
|
||||
ADL_PMLOG_TEMPERATURE_INTAKE = 74,
|
||||
ADL_PMLOG_MAX_SENSORS_REAL
|
||||
} ADL_PMLOG_SENSORS;
|
||||
|
||||
@@ -2393,6 +2430,9 @@ typedef enum ADL_PMLOG_SENSORS
|
||||
/// Indicates there is crossGPU clone
|
||||
#define ADL_CROSSGPUDISPLAYCLONE 0x2
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \defgroup define_D3DKMT_HANDLE
|
||||
@@ -2493,7 +2533,11 @@ typedef enum ADL_UIFEATURES_GROUP
|
||||
ADL_UIFEATURES_GROUP_PROVSR = 12,
|
||||
ADL_UIFEATURES_GROUP_SMA = 13,
|
||||
ADL_UIFEATURES_GROUP_CAMERA = 14,
|
||||
ADL_UIFEATURES_GROUP_FRTCPRO = 15
|
||||
ADL_UIFEATURES_GROUP_FRTCPRO = 15,
|
||||
ADL_UIFEATURES_GROUP_DELAGNEXT = 16,
|
||||
ADL_UIFEATURES_GROUP_RTBOOST = 17,
|
||||
ADL_UIFEATURES_GROUP_UAI = 18
|
||||
|
||||
} ADL_UIFEATURES_GROUP;
|
||||
|
||||
|
||||
@@ -2587,9 +2631,18 @@ typedef enum ADL_USER_SETTINGS
|
||||
ADL_USER_SETTINGS_USU_PROFILE = 1 << 4, //notify USU settings change
|
||||
ADL_USER_SETTINGS_CVDC_PROFILE = 1 << 5, //notify Color Vision Deficiency Corretion settings change
|
||||
ADL_USER_SETTINGS_SCE_PROFILE = 1 << 6,
|
||||
ADL_USER_SETTINGS_PROVSR = 1 << 7
|
||||
ADL_USER_SETTINGS_PROVSR = 1 << 7,
|
||||
ADL_USER_SETTINGS_RTBOOST_PROFILE=1 << 8,
|
||||
ADL_USER_SETTINGS_USU2_PROFILE = 1 << 9, //notify USU2 settings change
|
||||
} ADL_USER_SETTINGS;
|
||||
|
||||
//FRAME_TIMESTAMPS_SHARED_MEMORY type
|
||||
typedef enum FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE
|
||||
{
|
||||
FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE_UNKNOWN = 0,
|
||||
FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE_LEGACY,
|
||||
FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE_INDEXED
|
||||
}FRAME_TIMESTAMPS_SHARED_MEMORY_TYPE;
|
||||
#define ADL_REG_DEVICE_FUNCTION_1 0x00000001
|
||||
#endif /* ADL_DEFINES_H_ */
|
||||
|
||||
|
||||
+2
-6
@@ -33,14 +33,10 @@
|
||||
|
||||
#include "adl_structures.h"
|
||||
|
||||
#if defined (LINUX)
|
||||
#define __stdcall
|
||||
#endif /* (LINUX) */
|
||||
|
||||
/// Memory Allocation Call back
|
||||
typedef void* ( __stdcall *ADL_MAIN_MALLOC_CALLBACK )( int );
|
||||
|
||||
#define ADL_SDK_MAJOR_VERSION 17
|
||||
#define ADL_SDK_MINOR_VERSION 1
|
||||
#define ADL_SDK_MAJOR_VERSION 18
|
||||
#define ADL_SDK_MINOR_VERSION 0
|
||||
|
||||
#endif /* ADL_SDK_H_ */
|
||||
|
||||
+29
-36
@@ -21,7 +21,7 @@
|
||||
// SOFTWARE.
|
||||
|
||||
/// \file adl_structures.h
|
||||
///\brief This file contains the structure declarations that are used by the public ADL interfaces for \ALL platforms.\n <b>Included in ADL SDK</b>
|
||||
///\brief This file contains the structure declarations that are used by the public ADL interfaces for \WIN platforms.\n <b>Included in ADL SDK</b>
|
||||
///
|
||||
/// All data structures used in AMD Display Library (ADL) public interfaces should be defined in this header file.
|
||||
///
|
||||
@@ -41,7 +41,7 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct AdapterInfo
|
||||
{
|
||||
/// \ALL_STRUCT_MEM
|
||||
/// \WIN_STRUCT_MEM
|
||||
|
||||
/// Size of the structure.
|
||||
int iSize;
|
||||
@@ -59,7 +59,7 @@ typedef struct AdapterInfo
|
||||
int iVendorID;
|
||||
/// Adapter name.
|
||||
char strAdapterName[ADL_MAX_PATH];
|
||||
/// Display name. For example, "\\\\Display0" for Windows or ":0:0" for Linux.
|
||||
/// Display name. For example, "\\\\Display0" for Windows.
|
||||
char strDisplayName[ADL_MAX_PATH];
|
||||
/// Present or not; 1 if present and 0 if not present.It the logical adapter is present, the display name such as \\\\.\\Display1 can be found from OS
|
||||
int iPresent;
|
||||
@@ -80,38 +80,8 @@ typedef struct AdapterInfo
|
||||
|
||||
#endif /* (_WIN32) || (_WIN64) */
|
||||
|
||||
#if defined (LINUX)
|
||||
/// \LNX_STRUCT_MEM
|
||||
|
||||
/// Internal X screen number from GPUMapInfo (DEPRICATED use XScreenInfo)
|
||||
int iXScreenNum;
|
||||
/// Internal driver index from GPUMapInfo
|
||||
int iDrvIndex;
|
||||
/// \deprecated Internal x config file screen identifier name. Use XScreenInfo instead.
|
||||
char strXScreenConfigName[ADL_MAX_PATH];
|
||||
|
||||
#endif /* (LINUX) */
|
||||
} AdapterInfo, *LPAdapterInfo;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///\brief Structure containing information about the Linux X screen information.
|
||||
///
|
||||
/// This structure is used to store the current screen number and xorg.conf ID name assoicated with an adapter index.
|
||||
/// This structure is updated during ADL_Main_Control_Refresh or ADL_ScreenInfo_Update.
|
||||
/// Note: This structure should be used in place of iXScreenNum and strXScreenConfigName in AdapterInfo as they will be
|
||||
/// deprecated.
|
||||
/// \nosubgrouping
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#if defined (LINUX)
|
||||
typedef struct XScreenInfo
|
||||
{
|
||||
/// Internal X screen number from GPUMapInfo.
|
||||
int iXScreenNum;
|
||||
/// Internal x config file screen identifier name.
|
||||
char strXScreenConfigName[ADL_MAX_PATH];
|
||||
} XScreenInfo, *LPXScreenInfo;
|
||||
#endif /* (LINUX) */
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///\brief Structure containing information about an controller mode
|
||||
///
|
||||
@@ -453,8 +423,12 @@ typedef struct ADLDDCInfo2
|
||||
int ulMaxBacklightMinLuminanceData;
|
||||
int ulMinBacklightMinLuminanceData;
|
||||
|
||||
// Display screen width/height
|
||||
int ulScreenWidth;
|
||||
int ulScreenHeight;
|
||||
|
||||
// Reserved for future use
|
||||
int iReserved[4];
|
||||
int iReserved[2];
|
||||
} ADLDDCInfo2, *LPADLDDCInfo2;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -3614,6 +3588,23 @@ typedef struct ADL_BOOST_SETTINGS
|
||||
int GlobalMinRes_Step; //Gloabl Min Resolution step value
|
||||
}ADL_BOOST_SETTINGS;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///\brief Structure containing information about BOOST Settings
|
||||
///
|
||||
/// Elements of BOOST settings.
|
||||
/// \nosubgrouping
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct ADL_BOOST_SETTINGSX2
|
||||
{
|
||||
int Hotkey; // Hotkey value
|
||||
int GlobalEnable; //Global enable value
|
||||
int GlobalMinRes; //Gloabl Min Resolution value
|
||||
int GlobalMinRes_MinLimit; //Gloabl Min Resolution slider min limit value
|
||||
int GlobalMinRes_MaxLimit; //Gloabl Min Resolution slider max limit value
|
||||
int GlobalMinRes_Step; //Gloabl Min Resolution step value
|
||||
int VsrSupported; //Allows for interop with Upscaling/RSR
|
||||
}ADL_BOOST_SETTINGSX2;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
///\brief Structure containing information about ProVSR Settings change reason
|
||||
@@ -3817,7 +3808,7 @@ typedef struct ADL_RADEON_LED_PATTERN_CONFIG
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
typedef struct AdapterInfoX2
|
||||
{
|
||||
/// \ALL_STRUCT_MEM
|
||||
/// \WIN_STRUCT_MEM
|
||||
|
||||
/// Size of the structure.
|
||||
int iSize;
|
||||
@@ -4164,6 +4155,7 @@ typedef struct ADLHDCPSettings
|
||||
///
|
||||
/// This structure is used to store the Mantle Driver information
|
||||
/// \nosubgrouping
|
||||
/// \deprecated This structure has been deprecated.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct ADLMantleAppInfo
|
||||
@@ -4286,4 +4278,5 @@ typedef struct ADLSmartShiftSettings
|
||||
int iCurrentValue;
|
||||
int iFlags; //refer to define_smartshift_bits
|
||||
}ADLSmartShiftSettings, *LPADLSmartShiftSettings;
|
||||
#endif /* ADL_STRUCTURES_H_ */
|
||||
|
||||
#endif /* ADL_STRUCTURES_H_ */
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/GPUOpen-LibrariesAndSDKs/display-library",
|
||||
"license": "MIT (embeded in source)",
|
||||
"version": "ADL SDK 17.1",
|
||||
"version": "ADL SDK 18.1",
|
||||
"author": "Advanced Micro Devices, Inc"
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,9 +18,9 @@ typedef struct FFlist {
|
||||
void* ffListAdd(FFlist* list, uint32_t elementSize);
|
||||
|
||||
// Removes the first element, and copy its value to `*result`
|
||||
bool ffListShift(FFlist* list, uint32_t elementSize, void* result);
|
||||
bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result);
|
||||
// Removes the last element, and copy its value to `*result`
|
||||
bool ffListPop(FFlist* list, uint32_t elementSize, void* result);
|
||||
bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result);
|
||||
|
||||
static inline void ffListInit(FFlist* list) {
|
||||
list->capacity = 0;
|
||||
|
||||
@@ -24,16 +24,39 @@ const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result) {
|
||||
}
|
||||
return NULL;
|
||||
} else if (CFGetTypeID(cf) == CFDataGetTypeID()) {
|
||||
if (CFDataGetLength((CFDataRef) cf) != sizeof(int)) {
|
||||
return "Data length is not sizeof(int)";
|
||||
if (CFDataGetLength((CFDataRef) cf) != sizeof(*result)) {
|
||||
return "Data length is not sizeof(int32_t)";
|
||||
}
|
||||
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(int)), (uint8_t*) result);
|
||||
CFDataGetBytes((CFDataRef) cf, CFRangeMake(0, sizeof(*result)), (uint8_t*) result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "TypeID is neither 'CFNumber' nor 'CFData'";
|
||||
}
|
||||
|
||||
const char* ffCfNumGetDouble(CFTypeRef cf, double* result) {
|
||||
if (CFGetTypeID(cf) == CFNumberGetTypeID()) {
|
||||
if (!CFNumberGetValue((CFNumberRef) cf, kCFNumberDoubleType, result) &&
|
||||
!CFNumberGetValue((CFNumberRef) cf, kCFNumberFloatType, result)) {
|
||||
return "Number type is not Double or Float";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "TypeID is neither 'CFNumber'";
|
||||
}
|
||||
|
||||
const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result) {
|
||||
if (CFGetTypeID(cf) != CFDateGetTypeID()) {
|
||||
return "TypeID is not 'CFDate'";
|
||||
}
|
||||
|
||||
CFAbsoluteTime absTime = CFDateGetAbsoluteTime((CFDateRef) cf);
|
||||
// Convert from seconds to milliseconds and add the difference between 1970 and 2001 in milliseconds
|
||||
*result = (uint64_t) ((absTime + 978307200 /*kCFAbsoluteTimeIntervalSince1970*/) * 1000);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result) {
|
||||
ffStrbufClear(result);
|
||||
if (!cf) {
|
||||
@@ -149,6 +172,15 @@ const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* res
|
||||
return ffCfNumGetInt64(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
return ffCfNumGetDouble(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
@@ -182,3 +214,12 @@ const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryR
|
||||
*result = cf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDictGetDateAsEpoch(CFDictionaryRef dict, CFStringRef key, uint64_t* result) {
|
||||
CFTypeRef cf = (CFTypeRef) CFDictionaryGetValue(dict, key);
|
||||
if (cf == NULL) {
|
||||
return "CFDictionaryGetValue() failed";
|
||||
}
|
||||
|
||||
return ffCfDateGetEpoch(cf, result);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,18 @@
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result);
|
||||
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result);
|
||||
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result);
|
||||
const char* ffCfNumGetDouble(CFTypeRef cf, double* result);
|
||||
const char* ffCfDateGetEpoch(CFTypeRef cf, uint64_t* result);
|
||||
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result);
|
||||
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
|
||||
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result);
|
||||
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result);
|
||||
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result);
|
||||
const char* ffCfDictGetDouble(CFDictionaryRef dict, CFStringRef key, double* result);
|
||||
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length);
|
||||
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
|
||||
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result);
|
||||
const char* ffCfDictGetDateAsEpoch(CFDictionaryRef dict, CFStringRef key, uint64_t* result);
|
||||
|
||||
static inline CFNumberRef ffCfCreateInt(int value) {
|
||||
return CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "osascript.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
bool ffOsascript(const char* input, FFstrbuf* result)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
static const char kSmcCmdReadBytes = 5;
|
||||
|
||||
+3
-3
@@ -29,12 +29,12 @@ typedef struct FFDBusData {
|
||||
const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); // Returns an error message or NULL on success
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result);
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2);
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
|
||||
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result);
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_t* result);
|
||||
void ffDBusDestroyData(FFDBusData* data);
|
||||
|
||||
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface) {
|
||||
|
||||
@@ -26,6 +26,7 @@ void ffPlatformInit(FFPlatform* platform) {
|
||||
ffStrbufInit(&info->release);
|
||||
ffStrbufInit(&info->version);
|
||||
ffStrbufInit(&info->architecture);
|
||||
info->pageSize = 0;
|
||||
|
||||
ffPlatformInitImpl(platform);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <kvm.h>
|
||||
#include "common/path.h"
|
||||
#elif defined(__HAIKU__)
|
||||
@@ -97,7 +98,7 @@ static void getExePath(FFPlatform* platform) {
|
||||
struct stat st;
|
||||
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode)) {
|
||||
int cntp;
|
||||
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
|
||||
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, (pid_t) platform->pid, sizeof(*kf), &cntp);
|
||||
if (kf) {
|
||||
int i;
|
||||
for (i = 0; i < cntp; i++) {
|
||||
|
||||
@@ -145,7 +145,7 @@ static void getUserName(FFPlatform* platform) {
|
||||
PLSA_UNICODE_STRING userName = NULL;
|
||||
if (NT_SUCCESS(LsaGetUserName(&userName, NULL))) {
|
||||
ffStrbufSetNWS(&platform->userName, userName->Length / sizeof(wchar_t), userName->Buffer);
|
||||
RtlFreeUnicodeString(userName);
|
||||
RtlFreeUnicodeString(userName); // Required. userName.Buffer is allocated separately
|
||||
LsaFreeMemory(userName);
|
||||
} else {
|
||||
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
|
||||
|
||||
@@ -12,7 +12,7 @@ void* ffListAdd(FFlist* list, uint32_t elementSize) {
|
||||
return ffListGet(list, elementSize, list->length - 1);
|
||||
}
|
||||
|
||||
bool ffListShift(FFlist* list, uint32_t elementSize, void* result) {
|
||||
bool ffListShift(FFlist* list, uint32_t elementSize, void* __restrict result) {
|
||||
if (list->length == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ bool ffListShift(FFlist* list, uint32_t elementSize, void* result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffListPop(FFlist* list, uint32_t elementSize, void* result) {
|
||||
bool ffListPop(FFlist* list, uint32_t elementSize, void* __restrict result) {
|
||||
if (list->length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -790,9 +790,10 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
|
||||
}
|
||||
|
||||
for (const char* p = comp; p < comp + compLength;) {
|
||||
const char* colon = memchr(p, separator, compLength);
|
||||
const char* colon = memchr(p, separator, (size_t) (comp + compLength - p));
|
||||
if (colon == NULL) {
|
||||
return strcmp(strbuf->chars, p) == 0;
|
||||
uint32_t remainingLen = (uint32_t) (comp + compLength - p);
|
||||
return strbuf->length == remainingLen && memcmp(strbuf->chars, p, remainingLen) == 0;
|
||||
}
|
||||
|
||||
uint32_t substrLength = (uint32_t) (colon - p);
|
||||
@@ -817,9 +818,10 @@ bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength
|
||||
}
|
||||
|
||||
for (const char* p = comp; p < comp + compLength;) {
|
||||
const char* colon = memchr(p, separator, compLength);
|
||||
const char* colon = memchr(p, separator, (size_t) (comp + compLength - p));
|
||||
if (colon == NULL) {
|
||||
return strcasecmp(strbuf->chars, p) == 0;
|
||||
uint32_t remainingLen = (uint32_t) (comp + compLength - p);
|
||||
return strbuf->length == remainingLen && strncasecmp(strbuf->chars, p, remainingLen) == 0;
|
||||
}
|
||||
|
||||
uint32_t substrLength = (uint32_t) (colon - p);
|
||||
|
||||
@@ -72,6 +72,7 @@ static bool handleMachSection(const FFMemoryMapping* mapping, const char* name,
|
||||
}
|
||||
uint32_t len = (uint32_t) strnlen(p, size - off);
|
||||
if (len < minLength) {
|
||||
off += len; // Skip short strings
|
||||
continue;
|
||||
}
|
||||
if (*p >= ' ' && *p <= '~') { // Ignore control characters
|
||||
@@ -177,8 +178,6 @@ static const char* dumpMachHeader(const FFMemoryMapping* mapping, off_t offset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -112,8 +112,9 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
if (*p == '\0') {
|
||||
continue;
|
||||
}
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
uint32_t len = (uint32_t) strnlen(p, data->d_size - off);
|
||||
if (len < minLength) {
|
||||
off += len;
|
||||
continue;
|
||||
}
|
||||
// Only process printable ASCII characters
|
||||
|
||||
@@ -49,8 +49,9 @@ const char* ffBinaryExtractStrings(const char* peFile, bool (*cb)(const char* st
|
||||
if (*p == '\0') {
|
||||
continue;
|
||||
}
|
||||
uint32_t len = (uint32_t) strlen(p);
|
||||
uint32_t len = (uint32_t) strnlen(p, section->SizeOfRawData - off);
|
||||
if (len < minLength) {
|
||||
off += len;
|
||||
continue;
|
||||
}
|
||||
// Only process printable ASCII characters
|
||||
|
||||
@@ -157,7 +157,7 @@ static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* option
|
||||
}
|
||||
}
|
||||
|
||||
static void parseStructureCommand(
|
||||
static bool parseStructureCommand(
|
||||
FFdata* data,
|
||||
const char* line,
|
||||
void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options)) {
|
||||
@@ -167,18 +167,26 @@ static void parseStructureCommand(
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name)) {
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (__builtin_expect(data->resultDoc != NULL, false)) {
|
||||
if (data->resultDoc != NULL) {
|
||||
fn(data, baseInfo, optionBuf);
|
||||
} else {
|
||||
baseInfo->printModule(optionBuf);
|
||||
}
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
|
||||
if (data->resultDoc) {
|
||||
yyjson_mut_doc* doc = data->resultDoc;
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", line);
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unknown module type");
|
||||
} else {
|
||||
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrintCommandOption(FFdata* data) {
|
||||
|
||||
+51
-6
@@ -76,7 +76,7 @@ bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
|
||||
uint8_t value;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
ffStrbufAppendC(result, (char) value);
|
||||
return false; // Don't append a comma
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) {
|
||||
@@ -92,6 +92,25 @@ bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
|
||||
|
||||
// At this point we have an array
|
||||
|
||||
int subArgType = dbus->lib->ffdbus_message_iter_get_arg_type(&subIter);
|
||||
if (subArgType == DBUS_TYPE_INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (subArgType == DBUS_TYPE_BYTE) {
|
||||
while (true) {
|
||||
uint8_t value;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(&subIter, &value);
|
||||
ffStrbufAppendC(result, (char) value);
|
||||
|
||||
if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool foundAValue = false;
|
||||
|
||||
while (true) {
|
||||
@@ -133,7 +152,7 @@ bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) {
|
||||
return ffDBusGetBool(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result) {
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if (argType == DBUS_TYPE_BYTE) {
|
||||
@@ -151,6 +170,13 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_UINT32) {
|
||||
uint32_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_UINT64) {
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
@@ -164,7 +190,7 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) {
|
||||
return ffDBusGetUint(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result) {
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if (argType == DBUS_TYPE_INT16) {
|
||||
@@ -175,6 +201,13 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_INT32) {
|
||||
int32_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_INT64) {
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
@@ -189,12 +222,24 @@ bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) {
|
||||
if (argType == DBUS_TYPE_UINT16) {
|
||||
uint16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = (int16_t) value;
|
||||
*result = (int32_t) value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_UINT32) {
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
uint32_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = (int32_t) value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (argType == DBUS_TYPE_UINT64) {
|
||||
uint64_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
if (value > INT64_MAX) {
|
||||
return false;
|
||||
}
|
||||
*result = (int64_t) value;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -267,7 +312,7 @@ bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char*
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result) {
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_t* result) {
|
||||
DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
|
||||
if (reply == NULL) {
|
||||
return false;
|
||||
|
||||
@@ -425,10 +425,11 @@ void ffFontInitXft(FFfont* font, const char* xft) {
|
||||
if (value.length > 0) {
|
||||
if (
|
||||
(keyLen == 4 && ffStrStartsWithIgnCase(keyStart, "size")) ||
|
||||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize"))) {
|
||||
(keyLen == 9 && (ffStrStartsWithIgnCase(keyStart, "pixelsize") || ffStrStartsWithIgnCase(keyStart, "pointsize")))) {
|
||||
if (sizeEmpty && ffCharIsDigit(value.chars[0])) {
|
||||
ffStrbufAppend(&font->size, &value);
|
||||
ffStrbufAppendS(&font->size, keyLen == 4 ? "pt" : "px");
|
||||
ffStrbufAppendS(&font->size,
|
||||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize")) ? "px" : "pt");
|
||||
}
|
||||
} else if (keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "style")) {
|
||||
// style may contain multiple words: "Bold Italic"
|
||||
@@ -457,6 +458,10 @@ void ffFontInitXft(FFfont* font, const char* xft) {
|
||||
ffStrbufInit(style);
|
||||
strbufAppendNSExcludingC(style, value.length, value.chars, '-');
|
||||
ffStrbufTrim(style, ' ');
|
||||
if (style->length == 0) {
|
||||
ffStrbufDestroy(style);
|
||||
--font->styles.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
|
||||
}
|
||||
|
||||
static inline bool formatArgSet(const FFformatarg* arg) {
|
||||
return arg->value != NULL && ((arg->type == FF_ARG_TYPE_DOUBLE && *(double*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_FLOAT && *(float*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_INT && *(int*) arg->value > 0) || (arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*) arg->value)->length > 0) || (arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*) arg->value)) || (arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT && *(uint32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_BOOL && *(bool*) arg->value) || (arg->type == FF_ARG_TYPE_LIST && ((FFlist*) arg->value)->length > 0));
|
||||
return arg->value != NULL && ((arg->type == FF_ARG_TYPE_DOUBLE && *(double*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_FLOAT && *(float*) arg->value > 0.0) || (arg->type == FF_ARG_TYPE_INT && *(int32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*) arg->value)->length > 0) || (arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*) arg->value)) || (arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT && *(uint32_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_UINT64 && *(uint64_t*) arg->value > 0) || (arg->type == FF_ARG_TYPE_BOOL && *(bool*) arg->value) || (arg->type == FF_ARG_TYPE_LIST && ((FFlist*) arg->value)->length > 0));
|
||||
}
|
||||
|
||||
void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t numArgs, const FFformatarg* arguments) {
|
||||
|
||||
+13
-7
@@ -57,9 +57,9 @@ void ffInitInstance(void) {
|
||||
initState(&instance.state);
|
||||
}
|
||||
|
||||
static volatile bool ffDisableLinewrap = true;
|
||||
static volatile bool ffHideCursor = true;
|
||||
#if _WIN32
|
||||
static volatile bool ffDisableLinewrap = false;
|
||||
static volatile bool ffHideCursor = false;
|
||||
#ifdef _WIN32
|
||||
static volatile UINT oldCp = CP_UTF8;
|
||||
#endif
|
||||
|
||||
@@ -122,7 +122,10 @@ void ffStart(void) {
|
||||
if (instance.config.display.noBuffer) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
}
|
||||
struct sigaction action = { .sa_handler = exitSignalHandler };
|
||||
struct sigaction action;
|
||||
sigemptyset(&action.sa_mask);
|
||||
action.sa_flags = 0;
|
||||
action.sa_handler = exitSignalHandler;
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
@@ -200,6 +203,9 @@ void ffListFeatures(void) {
|
||||
#if FF_HAVE_DCONF
|
||||
"dconf\n"
|
||||
#endif
|
||||
#if FF_HAVE_EET
|
||||
"eet\n"
|
||||
#endif
|
||||
#if FF_HAVE_DBUS
|
||||
"dbus\n"
|
||||
#endif
|
||||
@@ -251,12 +257,12 @@ void ffListFeatures(void) {
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
"linux/videodev2\n"
|
||||
#endif
|
||||
#if FF_HAVE_LINUX_WIRELESS
|
||||
"linux/wireless\n"
|
||||
#endif
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_HAVE_WINRT
|
||||
"WinRT headers\n"
|
||||
#endif
|
||||
#if FF_WIN81_COMPAT
|
||||
"Windows 8.1 Compatibility\n"
|
||||
#endif
|
||||
|
||||
@@ -252,14 +252,15 @@ bool ffSuppressIO(bool suppress) {
|
||||
}
|
||||
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty) {
|
||||
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
|
||||
int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC | O_DIRECTORY); // Ownership of dfd will be transformed to dir
|
||||
if (dfd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DIR* dir = fdopendir(dfd);
|
||||
FF_AUTO_CLOSE_DIR DIR* dir = fdopendir(dfd);
|
||||
if (dir == NULL) {
|
||||
return;
|
||||
close(dfd);
|
||||
return; // Should not happen
|
||||
}
|
||||
|
||||
uint32_t folderLength = folder->length;
|
||||
@@ -310,8 +311,6 @@ void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indenta
|
||||
|
||||
puts(entry->d_name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty) {
|
||||
|
||||
@@ -387,10 +387,12 @@ void ffListFilesRecursively(const char* path, bool pretty) {
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...) {
|
||||
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
FF_AUTO_CLOSE_FD HANDLE hConin = INVALID_HANDLE_VALUE;
|
||||
DWORD inputMode;
|
||||
if (!GetConsoleMode(hInput, &inputMode)) {
|
||||
DWORD inputMode = 0;
|
||||
bool hasInputMode = !!GetConsoleMode(hInput, &inputMode);
|
||||
if (!hasInputMode) {
|
||||
hConin = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
|
||||
hInput = hConin;
|
||||
hasInputMode = !!GetConsoleMode(hInput, &inputMode);
|
||||
}
|
||||
SetConsoleMode(hInput, 0);
|
||||
|
||||
@@ -439,12 +441,16 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
|
||||
while (true) {
|
||||
DWORD bytes = 0;
|
||||
if (!ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL) || bytes == 0) {
|
||||
if (!ReadFile(hInput, buffer + bytesRead, (DWORD) (sizeof(buffer) - 1 - bytesRead), &bytes, NULL) || bytes == 0) {
|
||||
va_end(args);
|
||||
return "ReadFile() failed";
|
||||
}
|
||||
|
||||
bytesRead += bytes;
|
||||
if (__builtin_expect(bytesRead >= sizeof(buffer) - 1, false)) {
|
||||
va_end(args);
|
||||
return "terminal response buffer overflow";
|
||||
}
|
||||
buffer[bytesRead] = '\0';
|
||||
|
||||
va_list cargs;
|
||||
@@ -461,7 +467,9 @@ const char* ffGetTerminalResponse(const char* request, int nParams, const char*
|
||||
}
|
||||
}
|
||||
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
if (hasInputMode) {
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
|
||||
|
||||
@@ -133,16 +133,11 @@ static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_
|
||||
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module) {
|
||||
switch (type[0]) {
|
||||
case 'b':
|
||||
case 'B': {
|
||||
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
|
||||
ffPrepareCPUUsage();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
case 'C': {
|
||||
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME)) {
|
||||
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME)) {
|
||||
ffPrepareCPUUsage();
|
||||
} else if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME)) {
|
||||
FF_A_CLEANUP(ffDestroyCommandOptions) FFCommandOptions options;
|
||||
ffInitCommandOptions(&options);
|
||||
if (module) {
|
||||
@@ -259,7 +254,7 @@ static const char* printJsonConfig(FFdata* data, bool prepare) {
|
||||
yyjson_val* conditions = yyjson_obj_get(module, "condition");
|
||||
if (conditions) {
|
||||
if (!yyjson_is_obj(conditions)) {
|
||||
return "Property 'conditions' must be an object";
|
||||
return "Property 'condition' must be an object";
|
||||
}
|
||||
|
||||
yyjson_val* system = yyjson_obj_get(conditions, "system");
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
static void* libraryLoad(const char* path, int maxVersion) {
|
||||
void* result = dlopen(path, FF_DLOPEN_FLAGS);
|
||||
|
||||
#ifdef _WIN32
|
||||
#if _WIN32
|
||||
|
||||
// libX.dll.1 never exists on Windows, while libX-1.dll may exist
|
||||
FF_UNUSED(maxVersion)
|
||||
@@ -114,7 +114,7 @@ void* dlopen(const char* path, FF_A_UNUSED int mode) {
|
||||
|
||||
PVOID module = NULL;
|
||||
status = LdrLoadDll(NULL, NULL, &(UNICODE_STRING) {
|
||||
.Length = (USHORT) pathWBytes - sizeof(wchar_t), // Exclude null terminator
|
||||
.Length = (USHORT) (pathWBytes - sizeof(wchar_t)), // Exclude null terminator
|
||||
.MaximumLength = (USHORT) pathWBytes,
|
||||
.Buffer = pathW,
|
||||
},
|
||||
@@ -139,7 +139,7 @@ int dlclose(void* handle) {
|
||||
|
||||
void* dlsym(void* handle, const char* symbol) {
|
||||
void* address;
|
||||
USHORT symbolBytes = (USHORT) strlen(symbol) + 1;
|
||||
USHORT symbolBytes = (USHORT) (strlen(symbol) + 1);
|
||||
NTSTATUS status = LdrGetProcedureAddress(handle, &(ANSI_STRING) {
|
||||
.Length = symbolBytes - sizeof(char),
|
||||
.MaximumLength = symbolBytes,
|
||||
@@ -158,7 +158,7 @@ void* ffLibraryGetModule(const wchar_t* libraryFileName) {
|
||||
assert(libraryFileName != NULL && "Use \"ffGetPeb()->ImageBaseAddress\" instead");
|
||||
|
||||
void* module = NULL;
|
||||
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t)) + sizeof(wchar_t);
|
||||
USHORT libraryFileNameBytes = (USHORT) (wcslen(libraryFileName) * sizeof(wchar_t) + sizeof(wchar_t));
|
||||
NTSTATUS status = LdrGetDllHandle(NULL, NULL, &(UNICODE_STRING) {
|
||||
.Length = libraryFileNameBytes - sizeof(wchar_t),
|
||||
.MaximumLength = libraryFileNameBytes,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "common/netif.h"
|
||||
#include "common/io.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
@@ -98,7 +97,16 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid));
|
||||
bool gotResponse = false;
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0) {
|
||||
if (rtmsg.hdr.rtm_seq == 1 && rtmsg.hdr.rtm_pid == (pid_t) pid) {
|
||||
gotResponse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gotResponse) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
@@ -109,8 +117,10 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
&& sdl->sdl_family == AF_LINK) {
|
||||
if (sdl->sdl_nlen > IF_NAMESIZE) {
|
||||
return false;
|
||||
}
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
@@ -171,7 +181,16 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0 && !(rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid));
|
||||
bool gotResponse = false;
|
||||
while (recv(pfRoute, &rtmsg, sizeof(rtmsg), 0) > 0) {
|
||||
if (rtmsg.hdr.rtm_seq == 2 && rtmsg.hdr.rtm_pid == (pid_t) pid) {
|
||||
gotResponse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gotResponse) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef __sun // On Solaris, the RTF_GATEWAY flag is not set for default routes for some reason
|
||||
if ((rtmsg.hdr.rtm_flags & (RTF_UP | RTF_GATEWAY)) == (RTF_UP | RTF_GATEWAY))
|
||||
@@ -182,8 +201,10 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
#ifndef __sun
|
||||
&& sdl->sdl_len
|
||||
#endif
|
||||
) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
&& sdl->sdl_family == AF_LINK) {
|
||||
if (sdl->sdl_nlen > IF_NAMESIZE) {
|
||||
return false;
|
||||
}
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
@@ -65,7 +65,9 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET)) {
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*) get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
if (sdl->sdl_nlen > IF_NAMESIZE) {
|
||||
continue;
|
||||
}
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
@@ -106,7 +108,9 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
if ((rtm->rtm_flags & RTF_GATEWAY) && !(rtm->rtm_flags & RTF_REJECT) && (sa->sa_family == AF_INET6)) {
|
||||
struct sockaddr_dl* sdl = (struct sockaddr_dl*) get_rt_address(rtm, RTA_IFP);
|
||||
if (sdl && sdl->sdl_family == AF_LINK) {
|
||||
assert(sdl->sdl_nlen <= IF_NAMESIZE);
|
||||
if (sdl->sdl_nlen > IF_NAMESIZE) {
|
||||
continue;
|
||||
}
|
||||
memcpy(result->ifName, sdl->sdl_data, sdl->sdl_nlen);
|
||||
result->ifName[sdl->sdl_nlen] = '\0';
|
||||
result->ifIndex = sdl->sdl_index;
|
||||
|
||||
@@ -25,7 +25,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
// TODO: Get the preferred source address
|
||||
return true;
|
||||
}
|
||||
result->ifName[0] = '0';
|
||||
result->ifName[0] = '\0';
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
}
|
||||
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET, SOCK_RAW, AF_INET6);
|
||||
FF_AUTO_CLOSE_FD int pfRoute = socket(AF_INET6, SOCK_RAW, AF_INET6);
|
||||
if (pfRoute < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "common/netif.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
#include <ws2tcpip.h> // AF_INET6, IN6_IS_ADDR_UNSPECIFIED
|
||||
#include <iphlpapi.h>
|
||||
@@ -7,7 +6,7 @@
|
||||
bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable))) {
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_INET, &pIpForwardTable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,7 +17,6 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_family == AF_INET &&
|
||||
row->DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr == 0) {
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
@@ -39,7 +37,6 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
smallestMetric = realMetric;
|
||||
result->ifIndex = row->InterfaceIndex;
|
||||
foundDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,7 +50,7 @@ bool ffNetifGetDefaultRouteImplV4(FFNetifDefaultRouteResult* result) {
|
||||
bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
PMIB_IPFORWARD_TABLE2 pIpForwardTable = NULL;
|
||||
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_UNSPEC, &pIpForwardTable))) {
|
||||
if (!NETIO_SUCCESS(GetIpForwardTable2(AF_INET6, &pIpForwardTable))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -64,7 +61,6 @@ bool ffNetifGetDefaultRouteImplV6(FFNetifDefaultRouteResult* result) {
|
||||
MIB_IPFORWARD_ROW2* row = &pIpForwardTable->Table[i];
|
||||
|
||||
if (row->DestinationPrefix.PrefixLength == 0 &&
|
||||
row->DestinationPrefix.Prefix.Ipv6.sin6_family == AF_INET6 &&
|
||||
IN6_IS_ADDR_UNSPECIFIED(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr)) {
|
||||
MIB_IF_ROW2 ifRow = {
|
||||
.InterfaceIndex = row->InterfaceIndex,
|
||||
|
||||
@@ -146,16 +146,24 @@ bool ffNetworkingDecompressGzip(FFstrbuf* buffer, char* headerEnd) {
|
||||
result = zlibData.ffinflate(&zs, Z_FINISH);
|
||||
}
|
||||
|
||||
// Check for decompression errors before using result
|
||||
if (result != Z_STREAM_END) {
|
||||
FF_DEBUG("Decompression failed with zlib error: %d", result);
|
||||
zlibData.ffinflateEnd(&zs);
|
||||
return false;
|
||||
}
|
||||
|
||||
zlibData.ffinflateEnd(&zs);
|
||||
|
||||
// Calculate decompressed size
|
||||
// Calculate decompressed size (from the last inflate call)
|
||||
uint32_t decompressedSize = (uint32_t) (availableOut - zs.avail_out);
|
||||
decompressedBuffer.length += decompressedSize;
|
||||
decompressedBuffer.chars[decompressedBuffer.length] = '\0';
|
||||
FF_DEBUG("Successfully decompressed %u bytes compressed data to %u bytes", compressedSize, decompressedBuffer.length);
|
||||
|
||||
// Modify Content-Length header and remove Content-Encoding header
|
||||
FF_STRBUF_AUTO_DESTROY newBuffer = ffStrbufCreateA(headerSize + decompressedSize + 64);
|
||||
// Use decompressedBuffer.length (total) not decompressedSize (last chunk only)
|
||||
FF_STRBUF_AUTO_DESTROY newBuffer = ffStrbufCreateA(headerSize + decompressedBuffer.length + 64);
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
@@ -448,7 +448,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
// Check for Content-Length header to pre-allocate enough memory
|
||||
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
|
||||
if (clHeader) {
|
||||
contentLength = (uint32_t) strtoul(clHeader + 16, NULL, 10);
|
||||
contentLength = (uint32_t) strtoul(clHeader + 15, NULL, 10);
|
||||
if (contentLength > 0) {
|
||||
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
|
||||
// Ensure buffer is large enough, adding header size and some margin
|
||||
@@ -473,18 +473,18 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
FF_DEBUG("No HTTP header end marker found");
|
||||
return "No HTTP header end found";
|
||||
}
|
||||
|
||||
if (!ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
FF_DEBUG("Received valid HTTP 200 response, content %u bytes, total %u bytes", contentLength, buffer->length);
|
||||
|
||||
if (contentLength > 0 && buffer->length != contentLength + headerEnd + 4) {
|
||||
FF_DEBUG("Received content length mismatches: %u != %u", buffer->length, contentLength + headerEnd + 4);
|
||||
return "Content length mismatch";
|
||||
}
|
||||
|
||||
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Received valid HTTP 200 response, content %u bytes, total %u bytes", contentLength, buffer->length);
|
||||
} else {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
|
||||
@@ -320,7 +320,7 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
// Check for Content-Length header to pre-allocate enough memory
|
||||
const char* clHeader = strcasestr(buffer->chars, "Content-Length:");
|
||||
if (clHeader) {
|
||||
contentLength = (uint32_t) strtoul(clHeader + 16, NULL, 10);
|
||||
contentLength = (uint32_t) strtoul(clHeader + 15, NULL, 10);
|
||||
if (contentLength > 0) {
|
||||
FF_DEBUG("Detected Content-Length: %u, pre-allocating buffer", contentLength);
|
||||
// Ensure buffer is large enough, adding header size and some margin
|
||||
@@ -345,20 +345,20 @@ const char* ffNetworkingRecvHttpResponse(FFNetworkingState* state, FFstrbuf* buf
|
||||
FF_DEBUG("No HTTP header end marker found");
|
||||
return "No HTTP header end found";
|
||||
}
|
||||
|
||||
if (!ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
FF_DEBUG("Received valid HTTP 200 response, content length: %u bytes, total length: %u bytes",
|
||||
contentLength,
|
||||
buffer->length);
|
||||
|
||||
if (contentLength > 0 && buffer->length != contentLength + headerEnd + 4) {
|
||||
FF_DEBUG("Received content length mismatches: %u != %u", buffer->length, contentLength + headerEnd + 4);
|
||||
return "Content length mismatch";
|
||||
}
|
||||
|
||||
if (ffStrbufStartsWithS(buffer, "HTTP/1.0 200 OK\r\n")) {
|
||||
FF_DEBUG("Received valid HTTP 200 response, content length: %u bytes, total length: %u bytes",
|
||||
contentLength,
|
||||
buffer->length);
|
||||
} else {
|
||||
FF_DEBUG("Invalid response: %.40s...", buffer->chars);
|
||||
return "Invalid response";
|
||||
}
|
||||
|
||||
// If compression was used, try to decompress
|
||||
#ifdef FF_HAVE_ZLIB
|
||||
if (state->compression) {
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
#include "common/color.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
// Return start position of the inner key if the argument key belongs to the module specified, NULL otherwise
|
||||
const char* ffOptionTestPrefix(const char* argumentKey, const char* moduleName) {
|
||||
assert(argumentKey && moduleName);
|
||||
|
||||
const char* subKey = argumentKey;
|
||||
if (!(subKey[0] == '-' && subKey[1] == '-')) {
|
||||
return NULL;
|
||||
@@ -47,13 +51,13 @@ uint32_t ffOptionParseUInt32(const char* argumentKey, const char* value) {
|
||||
}
|
||||
|
||||
char* end;
|
||||
uint32_t num = (uint32_t) strtoul(value, &end, 10);
|
||||
if (*end != '\0') {
|
||||
unsigned long num = strtoul(value, &end, 10);
|
||||
if (value[0] == '-' || *end != '\0' || num > UINT32_MAX) {
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
|
||||
exit(479);
|
||||
}
|
||||
|
||||
return num;
|
||||
return (uint32_t) num;
|
||||
}
|
||||
|
||||
int32_t ffOptionParseInt32(const char* argumentKey, const char* value) {
|
||||
@@ -63,13 +67,13 @@ int32_t ffOptionParseInt32(const char* argumentKey, const char* value) {
|
||||
}
|
||||
|
||||
char* end;
|
||||
int32_t num = (int32_t) strtol(value, &end, 10);
|
||||
if (*end != '\0') {
|
||||
long num = strtol(value, &end, 10);
|
||||
if (*end != '\0' || num < INT32_MIN || num > INT32_MAX) {
|
||||
fprintf(stderr, "Error: usage: %s <num>\n", argumentKey);
|
||||
exit(479);
|
||||
}
|
||||
|
||||
return num;
|
||||
return (int32_t) num;
|
||||
}
|
||||
|
||||
int ffOptionParseEnum(const char* argumentKey, const char* requestedKey, FFKeyValuePair pairs[]) {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/parsing.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat"
|
||||
@@ -101,6 +99,16 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
ffStrbufAppend(buffer, gtk3);
|
||||
ffStrbufAppendS(buffer, " [GTK3]");
|
||||
}
|
||||
} else if (gtk2->length > 0 && gtk4->length > 0) {
|
||||
if (ffStrbufIgnCaseEqual(gtk2, gtk4)) {
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK2/4]");
|
||||
} else {
|
||||
ffStrbufAppend(buffer, gtk2);
|
||||
ffStrbufAppendS(buffer, " [GTK2], ");
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
ffStrbufAppendS(buffer, " [GTK4]");
|
||||
}
|
||||
} else if (gtk3->length > 0 && gtk4->length > 0) {
|
||||
if (ffStrbufIgnCaseEqual(gtk3, gtk4)) {
|
||||
ffStrbufAppend(buffer, gtk4);
|
||||
|
||||
@@ -128,13 +128,6 @@ char* frealpath(HANDLE hFile, char* resolved_name) {
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (outBytes > MAX_PATH) {
|
||||
errno = E2BIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return resolved_name;
|
||||
} else {
|
||||
/* UTF-8 worst-case: up to 4 bytes per UTF-16 code unit */
|
||||
char tmp[(MAX_PATH + 4) * 4];
|
||||
@@ -152,7 +145,6 @@ char* frealpath(HANDLE hFile, char* resolved_name) {
|
||||
}
|
||||
|
||||
memcpy(resolved_name, tmp, outBytes);
|
||||
return resolved_name;
|
||||
}
|
||||
|
||||
return resolved_name;
|
||||
|
||||
@@ -59,9 +59,6 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
|
||||
const bool borderAsValue = options->barBorderLeftElapsed.length && options->barBorderRightElapsed.length;
|
||||
|
||||
uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
assert(blocksPercent <= options->barWidth);
|
||||
|
||||
if (!borderAsValue && options->barBorderLeft.length) {
|
||||
if (!options->pipe && options->barColorBorder.length > 0) {
|
||||
ffStrbufAppendF(buffer, "\e[%sm", options->barColorBorder.chars);
|
||||
@@ -86,6 +83,9 @@ void ffPercentAppendBar(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
|
||||
FFPercentageTypeFlags percentType = config.type == 0 ? options->percentType : config.type;
|
||||
|
||||
uint8_t blocksPercent = (uint8_t) (percent / 100.0 * options->barWidth + 0.5);
|
||||
assert(blocksPercent <= options->barWidth);
|
||||
|
||||
bool autoColorElapsed = ffStrbufIgnCaseEqualS(&options->barColorElapsed, "auto");
|
||||
|
||||
bool monochrome = (percentType & FF_PERCENTAGE_TYPE_BAR_MONOCHROME_BIT) || !autoColorElapsed;
|
||||
@@ -190,7 +190,11 @@ void ffPercentAppendNum(FFstrbuf* buffer, double percent, FFPercentageModuleConf
|
||||
}
|
||||
}
|
||||
}
|
||||
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent, options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
if (percent == -DBL_MAX) {
|
||||
ffStrbufAppendS(buffer, "-");
|
||||
} else {
|
||||
ffStrbufAppendF(buffer, "%*.*f%s%%", options->percentWidth, options->percentNdigits, percent, options->percentSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_ALWAYS ? " " : "");
|
||||
}
|
||||
|
||||
if (colored && !options->pipe) {
|
||||
ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET);
|
||||
|
||||
@@ -55,7 +55,7 @@ bool ffParsePropLinePointer(const char** line, const char* start, FFstrbuf* buff
|
||||
++(*line);
|
||||
}
|
||||
|
||||
// Allow faster parsing of quotet values
|
||||
// Allow faster parsing of quoted values
|
||||
if (**line == '"' || **line == '\'') {
|
||||
valueEnd = **line;
|
||||
++(*line);
|
||||
|
||||
+133
-4
@@ -220,11 +220,12 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName,
|
||||
}
|
||||
|
||||
if (type == FF_VARIANT_TYPE_INT) {
|
||||
int32_t value;
|
||||
int64_t value;
|
||||
if (ffDBusGetInt(&dbus, &rootIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .intValue = value };
|
||||
return (FFvariant) { .intValue = (int32_t) value };
|
||||
}
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
@@ -234,6 +235,7 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName,
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
|
||||
}
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
@@ -245,6 +247,7 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName,
|
||||
}
|
||||
}
|
||||
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
@@ -292,11 +295,12 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
dbus.lib->ffdbus_message_iter_next(&dictIterator);
|
||||
|
||||
if (type == FF_VARIANT_TYPE_INT) {
|
||||
int32_t value;
|
||||
int64_t value;
|
||||
if (ffDBusGetInt(&dbus, &dictIterator, &value)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .intValue = value };
|
||||
return (FFvariant) { .intValue = (int32_t) value };
|
||||
}
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
@@ -306,6 +310,7 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return (FFvariant) { .strValue = value.chars }; // Leaks value.chars
|
||||
}
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
@@ -317,9 +322,11 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
}
|
||||
}
|
||||
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return FF_VARIANT_NULL;
|
||||
}
|
||||
#else // FF_HAVE_DBUS
|
||||
@@ -478,3 +485,125 @@ bool ffSettingsGetFreeBSDKenv(const char* propName, FFstrbuf* result) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FF_HAVE_EET
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wfloat-conversion"
|
||||
#include <Eet.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
typedef struct E_Font_Default {
|
||||
char* text_class;
|
||||
char* font;
|
||||
int size;
|
||||
} E_Font_Default;
|
||||
|
||||
typedef struct E_Config {
|
||||
char* theme_default_border_style;
|
||||
char* icon_theme;
|
||||
int use_e_cursor;
|
||||
int cursor_size;
|
||||
char* desktop_default_background;
|
||||
Eina_List* font_defaults;
|
||||
} E_Config; // Must be the same name as the top level struct in e.cfg
|
||||
|
||||
#define FF_EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(clas, type) \
|
||||
(ffeet_eina_file_data_descriptor_class_set(clas, sizeof(*(clas)), #type, sizeof(type)))
|
||||
#define FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, struct_type, member, type) \
|
||||
do { \
|
||||
struct_type ___ett; \
|
||||
ffeet_data_descriptor_element_add(edd, #member, type, EET_G_UNKNOWN, (char*) (&(___ett.member)) - (char*) (&(___ett)), 0, /* 0, */ NULL, NULL); \
|
||||
} while (0)
|
||||
#define FF_EET_DATA_DESCRIPTOR_ADD_LIST(edd, struct_type, member, subtype) \
|
||||
do { \
|
||||
struct_type ___ett; \
|
||||
ffeet_data_descriptor_element_add(edd, #member, EET_T_UNKNOW, EET_G_LIST, (char*) (&(___ett.member)) - (char*) (&(___ett)), 0, /* 0, */ NULL, subtype); \
|
||||
} while (0)
|
||||
|
||||
bool ffSettingsGetEnlightenmentProperty(ffEnlightenmentSettings* result) {
|
||||
FF_LIBRARY_LOAD(libeet, false, "libeet" FF_LIBRARY_EXTENSION, 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_init, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_open, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_data_descriptor_file_new, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_data_read, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_close, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_shutdown, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_data_descriptor_free, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_eina_file_data_descriptor_class_set, false);
|
||||
FF_LIBRARY_LOAD_SYMBOL(libeet, eet_data_descriptor_element_add, false);
|
||||
|
||||
if (ffeet_init() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY fileName = ffStrbufCreateCopy(&instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(&fileName, ".e/e/config/standard/e.cfg");
|
||||
|
||||
Eet_File* ef = ffeet_open(fileName.chars, EET_FILE_MODE_READ);
|
||||
if (!ef) {
|
||||
ffeet_shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
Eet_Data_Descriptor_Class fontDdc;
|
||||
FF_EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&fontDdc, E_Font_Default);
|
||||
Eet_Data_Descriptor* fontDdd = ffeet_data_descriptor_file_new(&fontDdc);
|
||||
if (!fontDdd) {
|
||||
ffeet_close(ef);
|
||||
ffeet_shutdown();
|
||||
return false;
|
||||
}
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(fontDdd, E_Font_Default, text_class, EET_T_STRING);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(fontDdd, E_Font_Default, font, EET_T_STRING);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(fontDdd, E_Font_Default, size, EET_T_INT);
|
||||
|
||||
Eet_Data_Descriptor_Class eddc;
|
||||
FF_EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, E_Config);
|
||||
Eet_Data_Descriptor* edd = ffeet_data_descriptor_file_new(&eddc);
|
||||
if (!edd) {
|
||||
ffeet_data_descriptor_free(fontDdd);
|
||||
ffeet_close(ef);
|
||||
ffeet_shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, E_Config, theme_default_border_style, EET_T_STRING);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, E_Config, icon_theme, EET_T_STRING);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, E_Config, use_e_cursor, EET_T_INT);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, E_Config, cursor_size, EET_T_INT);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_BASIC(edd, E_Config, desktop_default_background, EET_T_STRING);
|
||||
FF_EET_DATA_DESCRIPTOR_ADD_LIST(edd, E_Config, font_defaults, fontDdd);
|
||||
|
||||
E_Config* parsed = ffeet_data_read(ef, edd, "config");
|
||||
|
||||
if (parsed) {
|
||||
// TODO: find a better method to get the main theme name
|
||||
result->theme = parsed->theme_default_border_style;
|
||||
result->icon_theme = parsed->icon_theme;
|
||||
result->use_e_cursor = !!parsed->use_e_cursor;
|
||||
result->cursor_size = parsed->cursor_size;
|
||||
result->desktop_default_background = parsed->desktop_default_background;
|
||||
|
||||
E_Font_Default* firstFont = eina_list_data_get(parsed->font_defaults);
|
||||
if (firstFont) {
|
||||
result->font = firstFont->font;
|
||||
}
|
||||
}
|
||||
|
||||
ffeet_close(ef);
|
||||
ffeet_data_descriptor_free(edd);
|
||||
ffeet_data_descriptor_free(fontDdd);
|
||||
if (!parsed) {
|
||||
// We don't shutdown eet so that `result->*` are not freed
|
||||
ffeet_shutdown();
|
||||
}
|
||||
|
||||
return !!parsed;
|
||||
}
|
||||
#else
|
||||
bool ffSettingsGetEnlightenmentProperty(FF_A_UNUSED ffEnlightenmentSettings* result) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,10 +47,12 @@ const char* ffSysctlGetString(const char* propName, FFstrbuf* result) {
|
||||
|
||||
ffStrbufEnsureFree(result, (uint32_t) neededLength - 1);
|
||||
|
||||
if (sysctlbyname(propName, result->chars + result->length, &neededLength, NULL, 0) == 0) {
|
||||
result->length += (uint32_t) neededLength - 1;
|
||||
if (sysctlbyname(propName, result->chars + result->length, &neededLength, NULL, 0) != 0) {
|
||||
return "sysctlbyname() failed to retrieve string data";
|
||||
}
|
||||
|
||||
result->length += (uint32_t) neededLength - 1;
|
||||
|
||||
result->chars[result->length] = '\0';
|
||||
|
||||
return NULL;
|
||||
@@ -81,9 +83,6 @@ void* ffSysctlGetData(int* request, u_int requestLength, size_t* resultLength) {
|
||||
}
|
||||
|
||||
void* data = malloc(*resultLength);
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sysctl(request, requestLength, data, resultLength, NULL, 0) != 0) {
|
||||
free(data);
|
||||
|
||||
+12
-2
@@ -123,7 +123,12 @@ bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, F
|
||||
|
||||
yyjson_val* greenVal = yyjson_obj_get(value, "green");
|
||||
if (greenVal) {
|
||||
int num = yyjson_get_int(greenVal);
|
||||
if (!yyjson_is_int(greenVal)) {
|
||||
fputs("Error: usage: temp.green must be an integer between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
}
|
||||
|
||||
int num = unsafe_yyjson_get_int(greenVal);
|
||||
if (num < 0 || num > 100) {
|
||||
fputs("Error: usage: temp.green must be between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
@@ -133,7 +138,12 @@ bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, F
|
||||
|
||||
yyjson_val* yellowVal = yyjson_obj_get(value, "yellow");
|
||||
if (yellowVal) {
|
||||
int num = yyjson_get_int(yellowVal);
|
||||
if (!yyjson_is_int(yellowVal)) {
|
||||
fputs("Error: usage: temp.yellow must be an integer between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
}
|
||||
|
||||
int num = unsafe_yyjson_get_int(yellowVal);
|
||||
if (num < 0 || num > 100) {
|
||||
fputs("Error: usage: temp.yellow must be between 0 and 100\n", stderr);
|
||||
exit(480);
|
||||
|
||||
@@ -30,6 +30,16 @@ FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* pro
|
||||
int ffSettingsGetSQLite3Int(const char* dbPath, const char* query);
|
||||
bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result);
|
||||
|
||||
typedef struct {
|
||||
char* theme;
|
||||
char* icon_theme;
|
||||
bool use_e_cursor;
|
||||
int cursor_size;
|
||||
char* desktop_default_background;
|
||||
char* font;
|
||||
} ffEnlightenmentSettings;
|
||||
bool ffSettingsGetEnlightenmentProperty(ffEnlightenmentSettings* result);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
bool ffSettingsGetAndroidProperty(const char* propName, FFstrbuf* result);
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "com.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if FF_HAVE_WINRT
|
||||
#include <roapi.h>
|
||||
|
||||
static void RoUninitializeWrap(void) {
|
||||
RoUninitialize();
|
||||
}
|
||||
|
||||
static const char* doInitCom() {
|
||||
HRESULT res = RoInitialize(RO_INIT_MULTITHREADED);
|
||||
if (FAILED(res)) {
|
||||
switch (res) {
|
||||
case E_INVALIDARG:
|
||||
return "RoInitialize() failed: invalid argument";
|
||||
case E_OUTOFMEMORY:
|
||||
return "RoInitialize() failed: out of memory";
|
||||
case E_UNEXPECTED:
|
||||
return "RoInitialize() failed: unexpected error";
|
||||
case RPC_E_CHANGED_MODE:
|
||||
// COM was already initialized with a different concurrency model
|
||||
return NULL;
|
||||
default:
|
||||
return "RoInitialize() failed: unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
atexit(RoUninitializeWrap);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#include <combaseapi.h>
|
||||
|
||||
static void CoUninitializeWrap(void) {
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
static const char* doInitCom() {
|
||||
HRESULT res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
if (FAILED(res)) {
|
||||
switch (res) {
|
||||
case E_INVALIDARG:
|
||||
return "CoInitializeEx() failed: invalid argument";
|
||||
case E_OUTOFMEMORY:
|
||||
return "CoInitializeEx() failed: out of memory";
|
||||
case RPC_E_CHANGED_MODE:
|
||||
// COM was already initialized with a different concurrency model
|
||||
return NULL;
|
||||
default:
|
||||
return "CoInitializeEx() failed: unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
atexit(CoUninitializeWrap);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* ffInitCom(void) {
|
||||
static const char* error = "";
|
||||
if (error && error[0] == '\0') {
|
||||
error = doInitCom();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#include "com.hpp"
|
||||
#include "fastfetch.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer
|
||||
// https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes
|
||||
static void CoUninitializeWrap(void) {
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
static const char* doInitCom() {
|
||||
// Initialize COM
|
||||
if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) {
|
||||
return "CoInitializeEx() failed";
|
||||
}
|
||||
|
||||
// Set general COM security levels
|
||||
|
||||
HRESULT hRes = CoInitializeSecurity(
|
||||
NULL,
|
||||
-1, // COM authentication
|
||||
NULL, // Authentication services
|
||||
NULL, // Reserved
|
||||
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
|
||||
NULL, // Authentication info
|
||||
EOAC_NONE, // Additional capabilities
|
||||
NULL // Reserved
|
||||
);
|
||||
|
||||
if (FAILED(hRes) && hRes != RPC_E_TOO_LATE /* Has been set by a random dll */) {
|
||||
CoUninitialize();
|
||||
return "CoInitializeSecurity() failed";
|
||||
}
|
||||
|
||||
atexit(CoUninitializeWrap);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffInitCom(void) {
|
||||
static const char* error = "";
|
||||
if (error && error[0] == '\0') {
|
||||
error = doInitCom();
|
||||
}
|
||||
return error;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/attributes.h"
|
||||
#include <assert.h>
|
||||
#include <unknwn.h>
|
||||
|
||||
// Initialize COM & WinRT
|
||||
const char* ffInitCom(void);
|
||||
|
||||
static inline void ffReleaseComObject(void* ppUnknown) {
|
||||
assert(ppUnknown);
|
||||
IUnknown* pUnknown = *(IUnknown**) ppUnknown;
|
||||
if (pUnknown) {
|
||||
#ifdef __cplusplus
|
||||
pUnknown->Release();
|
||||
#else
|
||||
pUnknown->lpVtbl->Release(pUnknown);
|
||||
#endif
|
||||
*(IUnknown**) ppUnknown = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define FF_AUTO_RELEASE_COM_OBJECT FF_A_CLEANUP(ffReleaseComObject)
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <unknwn.h>
|
||||
|
||||
const char* ffInitCom(void);
|
||||
|
||||
static inline void ffReleaseComObject(void* ppUnknown) {
|
||||
IUnknown* pUnknown = *(IUnknown**) ppUnknown;
|
||||
if (pUnknown) {
|
||||
pUnknown->Release();
|
||||
}
|
||||
}
|
||||
|
||||
#define FF_AUTO_RELEASE_COM_OBJECT FF_A_CLEANUP(ffReleaseComObject)
|
||||
|
||||
#else
|
||||
// Win32 COM headers requires C++ compiler
|
||||
#error Must be included in C++ source file
|
||||
#endif
|
||||
+11
-2
@@ -602,7 +602,15 @@ typedef struct _KUSER_SHARED_DATA {
|
||||
// ... more fields follow, but we don't need them
|
||||
} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA;
|
||||
|
||||
#define SharedUserData ((const KUSER_SHARED_DATA*) 0x7FFE0000UL)
|
||||
#ifdef __aarch64__
|
||||
#define SharedUserData ({ \
|
||||
__auto_type shared_user_data = (const volatile KUSER_SHARED_DATA*) (uintptr_t) 0x7FFE0000UL; \
|
||||
__asm__("" : "+r"(shared_user_data)); /* https://github.com/lhmouse/mcfgthread/issues/330 */ \
|
||||
shared_user_data; \
|
||||
})
|
||||
#else
|
||||
#define SharedUserData ((const volatile KUSER_SHARED_DATA*) (uintptr_t) 0x7FFE0000UL)
|
||||
#endif
|
||||
|
||||
static inline uint64_t ffKSystemTimeToUInt64(const volatile KSYSTEM_TIME* pTime) {
|
||||
#if _WIN64
|
||||
@@ -634,7 +642,8 @@ static inline bool ffIsWindows10OrGreater() {
|
||||
}
|
||||
|
||||
static inline bool ffIsWindows11OrGreater() {
|
||||
return ffIsWindows10OrGreater() && SharedUserData->NtBuildNumber >= 22000;
|
||||
return SharedUserData->NtMajorVersion > 10 ||
|
||||
(SharedUserData->NtMajorVersion == 10 && SharedUserData->NtBuildNumber >= 22000);
|
||||
}
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtOpenProcessToken(
|
||||
|
||||
@@ -11,10 +11,7 @@ bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrb
|
||||
DWORD handle;
|
||||
DWORD size = GetFileVersionInfoSizeW(filePath, &handle);
|
||||
if (size == 0) {
|
||||
DWORD err = GetLastError();
|
||||
FF_DEBUG("GetFileVersionInfoSizeW failed: err=%lu (%s)",
|
||||
(unsigned long) err,
|
||||
ffDebugWin32Error(err));
|
||||
FF_DEBUG("GetFileVersionInfoSizeW failed: %s", ffDebugWin32Error(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,10 +26,7 @@ bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrb
|
||||
}
|
||||
|
||||
if (!GetFileVersionInfoW(filePath, handle, size, versionData)) {
|
||||
DWORD err = GetLastError();
|
||||
FF_DEBUG("GetFileVersionInfoW failed: err=%lu (%s)",
|
||||
(unsigned long) err,
|
||||
ffDebugWin32Error(err));
|
||||
FF_DEBUG("GetFileVersionInfoW failed: %s", ffDebugWin32Error(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,284 +0,0 @@
|
||||
#include "wmi.hpp"
|
||||
#include "common/windows/com.hpp"
|
||||
#include "common/windows/unicode.hpp"
|
||||
|
||||
#include <synchapi.h>
|
||||
#include <wchar.h>
|
||||
#include <math.h>
|
||||
|
||||
static const char* doInitService(const wchar_t* networkResource, IWbemServices** result) {
|
||||
HRESULT hres;
|
||||
|
||||
// Obtain the initial locator to WMI
|
||||
IWbemLocator* pLoc = nullptr;
|
||||
hres = CoCreateInstance(
|
||||
CLSID_WbemLocator,
|
||||
nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IWbemLocator,
|
||||
(LPVOID*) &pLoc);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
return "Failed to create IWbemLocator object";
|
||||
}
|
||||
|
||||
// Connect to WMI through the IWbemLocator::ConnectServer method
|
||||
IWbemServices* pSvc = nullptr;
|
||||
|
||||
// Connect to the root\cimv2 namespace with
|
||||
// the current user and obtain pointer pSvc
|
||||
// to make IWbemServices calls.
|
||||
hres = pLoc->ConnectServer(
|
||||
bstr_t(networkResource), // Object path of WMI namespace
|
||||
nullptr, // User name. nullptr = current user
|
||||
nullptr, // User password. nullptr = current
|
||||
0, // Locale. nullptr indicates current
|
||||
0, // Security flags.
|
||||
0, // Authority (for example, Kerberos)
|
||||
0, // Context object
|
||||
&pSvc // pointer to IWbemServices proxy
|
||||
);
|
||||
pLoc->Release();
|
||||
pLoc = nullptr;
|
||||
|
||||
if (FAILED(hres)) {
|
||||
return "Could not connect WMI server";
|
||||
}
|
||||
|
||||
*result = pSvc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFWmiQuery::FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error, FFWmiNamespace wmiNs) {
|
||||
const char* errStr;
|
||||
if ((errStr = ffInitCom())) {
|
||||
if (error) {
|
||||
ffStrbufSetS(error, errStr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static IWbemServices* contexts[(int) FFWmiNamespace::LAST];
|
||||
|
||||
IWbemServices* context = contexts[(int) wmiNs];
|
||||
if (!context) {
|
||||
if ((errStr = doInitService(wmiNs == FFWmiNamespace::CIMV2 ? L"ROOT\\CIMV2" : L"ROOT\\WMI", &context))) {
|
||||
if (error) {
|
||||
ffStrbufSetS(error, errStr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
contexts[(int) wmiNs] = context;
|
||||
}
|
||||
|
||||
this->pService = context;
|
||||
|
||||
// Use the IWbemServices pointer to make requests of WMI
|
||||
HRESULT hres = context->ExecQuery(
|
||||
bstr_t(L"WQL"),
|
||||
bstr_t(queryStr),
|
||||
WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
|
||||
nullptr,
|
||||
&this->pEnumerator);
|
||||
|
||||
if (FAILED(hres)) {
|
||||
if (error) {
|
||||
ffStrbufAppendF(error, "Query for '%ls' failed. Error code = 0x%lX", queryStr, hres);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FFWmiRecord::getString(const wchar_t* key, FFstrbuf* strbuf) {
|
||||
bool result = true;
|
||||
|
||||
FFWmiVariant vtProp;
|
||||
|
||||
CIMTYPE type;
|
||||
if (FAILED(obj->Get(key, 0, &vtProp, &type, nullptr)) || vtProp.vt != VT_BSTR) {
|
||||
result = false;
|
||||
} else {
|
||||
switch (vtProp.vt) {
|
||||
case VT_BSTR:
|
||||
if (type == CIM_DATETIME) {
|
||||
FF_AUTO_RELEASE_COM_OBJECT ISWbemDateTime* pDateTime = nullptr;
|
||||
BSTR dateStr;
|
||||
if (FAILED(CoCreateInstance(__uuidof(SWbemDateTime), 0, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDateTime)))) {
|
||||
result = false;
|
||||
} else if (FAILED(pDateTime->put_Value(vtProp.bstrVal))) {
|
||||
result = false;
|
||||
} else if (FAILED(pDateTime->GetFileTime(VARIANT_TRUE, &dateStr))) {
|
||||
result = false;
|
||||
} else {
|
||||
ffStrbufSetNWS(strbuf, SysStringLen(dateStr), dateStr);
|
||||
}
|
||||
} else {
|
||||
ffStrbufSetNWS(strbuf, SysStringLen(vtProp.bstrVal), vtProp.bstrVal);
|
||||
}
|
||||
break;
|
||||
|
||||
case VT_LPSTR:
|
||||
ffStrbufAppendS(strbuf, vtProp.pcVal);
|
||||
break;
|
||||
|
||||
case VT_LPWSTR:
|
||||
default:
|
||||
ffStrbufSetWS(strbuf, vtProp.bstrVal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FFWmiRecord::getSigned(const wchar_t* key, int64_t* integer) {
|
||||
bool result = true;
|
||||
|
||||
FFWmiVariant vtProp;
|
||||
|
||||
CIMTYPE type;
|
||||
if (FAILED(obj->Get(key, 0, &vtProp, &type, nullptr))) {
|
||||
result = false;
|
||||
} else {
|
||||
switch (vtProp.vt) {
|
||||
case VT_BSTR:
|
||||
*integer = wcstoll(vtProp.bstrVal, nullptr, 10);
|
||||
break;
|
||||
case VT_I1:
|
||||
*integer = vtProp.cVal;
|
||||
break;
|
||||
case VT_I2:
|
||||
*integer = vtProp.iVal;
|
||||
break;
|
||||
case VT_INT:
|
||||
case VT_I4:
|
||||
*integer = vtProp.intVal;
|
||||
break;
|
||||
case VT_I8:
|
||||
*integer = vtProp.llVal;
|
||||
break;
|
||||
case VT_UI1:
|
||||
*integer = (int64_t) vtProp.bVal;
|
||||
break;
|
||||
case VT_UI2:
|
||||
*integer = (int64_t) vtProp.uiVal;
|
||||
break;
|
||||
case VT_UINT:
|
||||
case VT_UI4:
|
||||
*integer = (int64_t) vtProp.uintVal;
|
||||
break;
|
||||
case VT_UI8:
|
||||
*integer = (int64_t) vtProp.ullVal;
|
||||
break;
|
||||
case VT_BOOL:
|
||||
*integer = vtProp.boolVal != VARIANT_FALSE;
|
||||
break;
|
||||
default:
|
||||
*integer = 0;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FFWmiRecord::getUnsigned(const wchar_t* key, uint64_t* integer) {
|
||||
bool result = true;
|
||||
|
||||
FFWmiVariant vtProp;
|
||||
|
||||
if (FAILED(obj->Get(key, 0, &vtProp, nullptr, nullptr))) {
|
||||
result = false;
|
||||
} else {
|
||||
switch (vtProp.vt) {
|
||||
case VT_BSTR:
|
||||
*integer = wcstoull(vtProp.bstrVal, nullptr, 10);
|
||||
break;
|
||||
case VT_I1:
|
||||
*integer = (uint64_t) vtProp.cVal;
|
||||
break;
|
||||
case VT_I2:
|
||||
*integer = (uint64_t) vtProp.iVal;
|
||||
break;
|
||||
case VT_INT:
|
||||
case VT_I4:
|
||||
*integer = (uint64_t) vtProp.intVal;
|
||||
break;
|
||||
case VT_I8:
|
||||
*integer = (uint64_t) vtProp.llVal;
|
||||
break;
|
||||
case VT_UI1:
|
||||
*integer = vtProp.bVal;
|
||||
break;
|
||||
case VT_UI2:
|
||||
*integer = vtProp.uiVal;
|
||||
break;
|
||||
case VT_UINT:
|
||||
case VT_UI4:
|
||||
*integer = vtProp.uintVal;
|
||||
break;
|
||||
case VT_UI8:
|
||||
*integer = vtProp.ullVal;
|
||||
break;
|
||||
case VT_BOOL:
|
||||
*integer = vtProp.boolVal != VARIANT_FALSE;
|
||||
break;
|
||||
default:
|
||||
*integer = 0;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FFWmiRecord::getReal(const wchar_t* key, double* real) {
|
||||
bool result = true;
|
||||
|
||||
FFWmiVariant vtProp;
|
||||
|
||||
if (FAILED(obj->Get(key, 0, &vtProp, nullptr, nullptr))) {
|
||||
result = false;
|
||||
} else {
|
||||
switch (vtProp.vt) {
|
||||
case VT_BSTR:
|
||||
*real = wcstod(vtProp.bstrVal, nullptr);
|
||||
break;
|
||||
case VT_I1:
|
||||
*real = vtProp.cVal;
|
||||
break;
|
||||
case VT_I2:
|
||||
*real = vtProp.iVal;
|
||||
break;
|
||||
case VT_INT:
|
||||
case VT_I4:
|
||||
*real = vtProp.intVal;
|
||||
break;
|
||||
case VT_I8:
|
||||
*real = (double) vtProp.llVal;
|
||||
break;
|
||||
case VT_UI1:
|
||||
*real = vtProp.bVal;
|
||||
break;
|
||||
case VT_UI2:
|
||||
*real = vtProp.uiVal;
|
||||
break;
|
||||
case VT_UINT:
|
||||
case VT_UI4:
|
||||
*real = vtProp.uintVal;
|
||||
break;
|
||||
case VT_UI8:
|
||||
*real = (double) vtProp.ullVal;
|
||||
break;
|
||||
case VT_R4:
|
||||
*real = vtProp.fltVal;
|
||||
break;
|
||||
case VT_R8:
|
||||
*real = vtProp.dblVal;
|
||||
break;
|
||||
case VT_BOOL:
|
||||
*real = vtProp.boolVal != VARIANT_FALSE;
|
||||
break;
|
||||
default:
|
||||
*real = -DBL_MAX;
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <windef.h>
|
||||
#include <wmistr.h>
|
||||
#include <assert.h>
|
||||
|
||||
/**
|
||||
* The WmiOpenBlock function opens the WMI data block object for the specified WMI class.
|
||||
*
|
||||
* \param Guid Specifies the GUID for WMI class.
|
||||
* \param DesiredAccess Specifies the desired access rights to the data block object.
|
||||
* \param DataBlockHandle Pointer to a memory location where the routine returns a handle to the data block object.
|
||||
* \return ULONG Successful or errant status.
|
||||
*/
|
||||
NTSYSAPI ULONG NTAPI
|
||||
WmiOpenBlock(
|
||||
_In_ LPCGUID Guid,
|
||||
_In_ ACCESS_MASK DesiredAccess,
|
||||
_Out_ PHANDLE DataBlockHandle);
|
||||
|
||||
/**
|
||||
* The WmiQueryAllDataW function returns all WMI data blocks that implement a given WMI class (Unicode).
|
||||
*
|
||||
* \param DataBlockHandle Handle to a WMI data block object.
|
||||
* \param BufferLength Pointer to a memory location that specifies the size of the buffer.
|
||||
* \param Buffer Pointer to the buffer where the routine returns the WMI data.
|
||||
* \return ULONG Successful or errant status.
|
||||
*/
|
||||
NTSYSAPI ULONG NTAPI
|
||||
WmiQueryAllDataW(
|
||||
_In_ HANDLE DataBlockHandle,
|
||||
_Inout_ PULONG BufferLength,
|
||||
_Out_writes_bytes_opt_(*BufferLength) PVOID Buffer);
|
||||
|
||||
/**
|
||||
* The WmiCloseBlock function closes a WMI data block object.
|
||||
*
|
||||
* \param DataBlockHandle Handle to the data block object to be closed.
|
||||
* \return ULONG Successful or errant status.
|
||||
*/
|
||||
NTSYSAPI ULONG NTAPI
|
||||
WmiCloseBlock(
|
||||
_In_ HANDLE DataBlockHandle);
|
||||
|
||||
static inline void ffCloseWmiBlock(HANDLE* hBlock) {
|
||||
assert(hBlock);
|
||||
if (*hBlock) {
|
||||
WmiCloseBlock(*hBlock);
|
||||
}
|
||||
}
|
||||
|
||||
#define FF_AUTO_CLOSE_WMI_BLOCK __attribute__((cleanup(ffCloseWmiBlock)))
|
||||
|
||||
// MOF: https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/km/wmicore.mof
|
||||
@@ -1,97 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#include "fastfetch.h"
|
||||
}
|
||||
|
||||
#include <initguid.h>
|
||||
#include <wbemidl.h>
|
||||
|
||||
#include "variant.hpp"
|
||||
|
||||
enum class FFWmiNamespace {
|
||||
CIMV2,
|
||||
WMI,
|
||||
LAST,
|
||||
};
|
||||
|
||||
struct FFWmiRecord {
|
||||
IWbemClassObject* obj = nullptr;
|
||||
|
||||
explicit FFWmiRecord(IWbemClassObject* obj) : obj(obj) {};
|
||||
FFWmiRecord(const FFWmiRecord&) = delete;
|
||||
FFWmiRecord(FFWmiRecord&& other) {
|
||||
*this = (FFWmiRecord&&) other;
|
||||
}
|
||||
~FFWmiRecord() {
|
||||
if (obj) {
|
||||
obj->Release();
|
||||
}
|
||||
}
|
||||
explicit operator bool() {
|
||||
return !!obj;
|
||||
}
|
||||
FFWmiRecord& operator=(FFWmiRecord&& other) {
|
||||
if (obj) {
|
||||
obj->Release();
|
||||
}
|
||||
obj = other.obj;
|
||||
other.obj = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool getString(const wchar_t* key, FFstrbuf* strbuf);
|
||||
bool getSigned(const wchar_t* key, int64_t* integer);
|
||||
bool getUnsigned(const wchar_t* key, uint64_t* integer);
|
||||
bool getReal(const wchar_t* key, double* real);
|
||||
FFWmiVariant get(const wchar_t* key) {
|
||||
FFWmiVariant result;
|
||||
obj->Get(key, 0, &result, nullptr, nullptr);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct FFWmiQuery {
|
||||
IWbemServices* pService = nullptr;
|
||||
IEnumWbemClassObject* pEnumerator = nullptr;
|
||||
|
||||
FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error = nullptr, FFWmiNamespace wmiNs = FFWmiNamespace::CIMV2);
|
||||
explicit FFWmiQuery(IEnumWbemClassObject* pEnumerator) : pEnumerator(pEnumerator) {}
|
||||
FFWmiQuery(const FFWmiQuery& other) = delete;
|
||||
FFWmiQuery(FFWmiQuery&& other) {
|
||||
*this = (FFWmiQuery&&) other;
|
||||
}
|
||||
~FFWmiQuery() {
|
||||
if (pEnumerator) {
|
||||
pEnumerator->Release();
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator bool() {
|
||||
return !!pEnumerator;
|
||||
}
|
||||
FFWmiQuery& operator=(FFWmiQuery&& other) {
|
||||
if (pEnumerator) {
|
||||
pEnumerator->Release();
|
||||
}
|
||||
pEnumerator = other.pEnumerator;
|
||||
other.pEnumerator = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
FFWmiRecord next() {
|
||||
IWbemClassObject* obj = nullptr;
|
||||
ULONG ret;
|
||||
pEnumerator->Next(instance.config.general.wmiTimeout, 1, &obj, &ret);
|
||||
|
||||
FFWmiRecord result(obj);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
// Win32 COM headers requires C++ compiler
|
||||
#error Must be included in C++ source file
|
||||
#endif //__cplusplus
|
||||
@@ -1,298 +1,384 @@
|
||||
#define INITGUID
|
||||
|
||||
#include "battery.h"
|
||||
|
||||
#include "common/io.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/smbios.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/windows/wmi.h"
|
||||
|
||||
#include <winerror.h>
|
||||
|
||||
typedef void(WINAPI* PINTERFACE_REFERENCE)(PVOID Context);
|
||||
typedef void(WINAPI* PINTERFACE_DEREFERENCE)(PVOID Context);
|
||||
typedef struct _DEVICE_OBJECT* PDEVICE_OBJECT;
|
||||
typedef struct _IRP* PIRP;
|
||||
#ifdef _WINDOWS_
|
||||
#undef _WINDOWS_
|
||||
#endif
|
||||
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <batclass.h>
|
||||
#include <devguid.h>
|
||||
#include <cfgmgr32.h>
|
||||
|
||||
static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results) {
|
||||
// https://learn.microsoft.com/en-us/windows-hardware/drivers/install/using-device-interfaces
|
||||
ULONG cchDeviceInterfaces = 0;
|
||||
if (CM_Get_Device_Interface_List_SizeW(
|
||||
&cchDeviceInterfaces,
|
||||
(LPGUID) &GUID_DEVCLASS_BATTERY,
|
||||
NULL,
|
||||
CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS) {
|
||||
return "CM_Get_Device_Interface_List_SizeW() failed";
|
||||
}
|
||||
#pragma GCC diagnostic ignored "-Wmultichar"
|
||||
|
||||
if (cchDeviceInterfaces <= 1) {
|
||||
return NULL; // Not found
|
||||
}
|
||||
typedef struct FFBatteryWmiEntry {
|
||||
ULONG tag;
|
||||
FFBatteryResult* result;
|
||||
} FFBatteryWmiEntry;
|
||||
|
||||
wchar_t* FF_AUTO_FREE mszDeviceInterfaces = (wchar_t*) malloc(cchDeviceInterfaces * sizeof(wchar_t));
|
||||
if (CM_Get_Device_Interface_ListW(
|
||||
(LPGUID) &GUID_DEVCLASS_BATTERY,
|
||||
NULL,
|
||||
mszDeviceInterfaces,
|
||||
cchDeviceInterfaces,
|
||||
CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CR_SUCCESS) {
|
||||
return "CM_Get_Device_Interface_ListW() failed";
|
||||
}
|
||||
|
||||
for (const wchar_t* p = mszDeviceInterfaces; *p; p += wcslen(p) + 1) {
|
||||
HANDLE FF_AUTO_CLOSE_FD hBattery =
|
||||
CreateFileW(p, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (hBattery == INVALID_HANDLE_VALUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BATTERY_QUERY_INFORMATION bqi = { .InformationLevel = BatteryInformation };
|
||||
|
||||
DWORD dwWait = 0;
|
||||
DWORD dwOut;
|
||||
|
||||
if (!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_TAG, &dwWait, sizeof(dwWait), &bqi.BatteryTag, sizeof(bqi.BatteryTag), &dwOut, NULL) && bqi.BatteryTag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BATTERY_INFORMATION bi = { 0 };
|
||||
if (!DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi, sizeof(bi), &dwOut, NULL)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(bi.Capabilities & BATTERY_SYSTEM_BATTERY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *results);
|
||||
|
||||
if (memcmp(bi.Chemistry, "PbAc", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Lead Acid");
|
||||
} else if (memcmp(bi.Chemistry, "LION", 4) == 0 || memcmp(bi.Chemistry, "Li-I", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Lithium Ion");
|
||||
} else if (memcmp(bi.Chemistry, "NiCd", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Cadmium");
|
||||
} else if (memcmp(bi.Chemistry, "NiMH", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Metal Hydride");
|
||||
} else if (memcmp(bi.Chemistry, "NiZn", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Nickel Zinc");
|
||||
} else if (memcmp(bi.Chemistry, "RAM\0", 4) == 0) {
|
||||
ffStrbufInitStatic(&battery->technology, "Rechargeable Alkaline-Manganese");
|
||||
} else {
|
||||
ffStrbufInitStatic(&battery->technology, "Unknown");
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->modelName);
|
||||
bqi.InformationLevel = BatteryDeviceName;
|
||||
wchar_t name[64];
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL)) {
|
||||
ffStrbufSetWS(&battery->modelName, name);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
bqi.InformationLevel = BatteryManufactureName;
|
||||
wchar_t name[64];
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), name, sizeof(name), &dwOut, NULL)) {
|
||||
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 < 1000 ? date.Year + 1900 : date.Year, 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 = FF_BATTERY_TEMP_UNSET;
|
||||
if (options->temp) {
|
||||
bqi.InformationLevel = BatteryTemperature;
|
||||
ULONG temp;
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &temp, sizeof(temp), &dwOut, NULL)) {
|
||||
battery->temperature = temp / 10.0 - 273.15;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
bqi.InformationLevel = BatteryEstimatedTime;
|
||||
ULONG time;
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &time, sizeof(time), &dwOut, NULL)) {
|
||||
battery->timeRemaining = time == BATTERY_UNKNOWN_TIME ? -1 : (int32_t) time;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
BATTERY_STATUS bs;
|
||||
BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi.BatteryTag };
|
||||
if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws), &bs, sizeof(bs), &dwOut, NULL) && bs.Capacity != BATTERY_UNKNOWN_CAPACITY && bi.FullChargedCapacity != 0) {
|
||||
battery->capacity = bs.Capacity * 100.0 / bi.FullChargedCapacity;
|
||||
|
||||
battery->status = FF_BATTERY_STATUS_NONE;
|
||||
if (bs.PowerState & BATTERY_POWER_ON_LINE) {
|
||||
battery->status |= FF_BATTERY_STATUS_AC_CONNECTED;
|
||||
}
|
||||
if (bs.PowerState & BATTERY_DISCHARGING) {
|
||||
battery->status |= FF_BATTERY_STATUS_DISCHARGING;
|
||||
}
|
||||
if (bs.PowerState & BATTERY_CHARGING) {
|
||||
battery->status |= FF_BATTERY_STATUS_CHARGING;
|
||||
}
|
||||
if (bs.PowerState & BATTERY_CRITICAL) {
|
||||
battery->status |= FF_BATTERY_STATUS_CRITICAL;
|
||||
}
|
||||
} else {
|
||||
battery->status = FF_BATTERY_STATUS_UNKNOWN;
|
||||
battery->capacity = 0;
|
||||
}
|
||||
static FFBatteryWmiEntry* getBatteryEntry(FFlist* entries, FFlist* results, ULONG tag) {
|
||||
FF_LIST_FOR_EACH (FFBatteryWmiEntry, entry, *entries) {
|
||||
if (entry->tag == tag) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
FFBatteryWmiEntry* entry = FF_LIST_ADD(FFBatteryWmiEntry, *entries);
|
||||
entry->tag = tag;
|
||||
FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *results);
|
||||
entry->result = battery;
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->serial);
|
||||
battery->status = FF_BATTERY_STATUS_NONE;
|
||||
battery->capacity = -1;
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
battery->timeRemaining = -1;
|
||||
return entry;
|
||||
}
|
||||
|
||||
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
|
||||
} FF_A_PACKED FFSmbiosPortableBattery;
|
||||
|
||||
static_assert(offsetof(FFSmbiosPortableBattery, OEMSpecific) == 0x16,
|
||||
"FFSmbiosPortableBattery: Wrong struct alignment");
|
||||
|
||||
static const char* detectBySmbios(FFBatteryResult* battery) {
|
||||
const FFSmbiosHeaderTable* smbiosTable = ffGetSmbiosHeaderTable();
|
||||
if (!smbiosTable) {
|
||||
return "Failed to get SMBIOS data";
|
||||
static const char* queryWmiAllData(const GUID* guid, const char* guidStr, PWNODE_ALL_DATA* pAllData, ULONG* pBufferSize) {
|
||||
FF_AUTO_CLOSE_WMI_BLOCK HANDLE hBlock = NULL;
|
||||
ULONG status = WmiOpenBlock(guid, WMIGUID_QUERY, &hBlock);
|
||||
if (status != ERROR_SUCCESS) {
|
||||
FF_DEBUG("WMI: WmiOpenBlock() failed for %s: %s", guidStr, ffDebugWin32Error(status));
|
||||
return "WmiOpenBlock() failed";
|
||||
}
|
||||
|
||||
const FFSmbiosPortableBattery* data = (const FFSmbiosPortableBattery*) (*smbiosTable)[FF_SMBIOS_TYPE_PORTABLE_BATTERY];
|
||||
if (!data) {
|
||||
return "Portable battery section is not found in SMBIOS data";
|
||||
status = WmiQueryAllDataW(hBlock, pBufferSize, NULL);
|
||||
if (status != ERROR_SUCCESS && status != ERROR_INSUFFICIENT_BUFFER) {
|
||||
FF_DEBUG("WMI: first WmiQueryAllDataW() failed: %s", ffDebugWin32Error(status));
|
||||
return "WmiQueryAllDataW(NULL) failed";
|
||||
}
|
||||
|
||||
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)) {
|
||||
int day = data->SbdsManufactureDate & 0b11111;
|
||||
int month = (data->SbdsManufactureDate >> 5) & 0b1111;
|
||||
int year = (data->SbdsManufactureDate >> 9) + 1800;
|
||||
ffStrbufSetF(&battery->manufactureDate, "%.4d-%.2d-%.2d", year, month, day);
|
||||
if (*pBufferSize == 0) {
|
||||
return "WmiQueryAllDataW(NULL) returned no data";
|
||||
}
|
||||
|
||||
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 (*pBufferSize < sizeof(WNODE_ALL_DATA)) {
|
||||
FF_DEBUG("WMI: WmiQueryAllDataW() returned insufficient buffer size: %lu", *pBufferSize);
|
||||
return "WmiQueryAllDataW() returned insufficient data for WNODE_ALL_DATA";
|
||||
}
|
||||
|
||||
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);
|
||||
*pAllData = (PWNODE_ALL_DATA) malloc(*pBufferSize);
|
||||
|
||||
status = WmiQueryAllDataW(hBlock, pBufferSize, *pAllData);
|
||||
if (status != ERROR_SUCCESS) {
|
||||
FF_DEBUG("WMI: second WmiQueryAllDataW failed: %s", ffDebugWin32Error(status));
|
||||
free(*pAllData);
|
||||
*pAllData = NULL;
|
||||
return "WmiQueryAllDataW(*pAllData) failed";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectWithNtApi(FF_A_UNUSED FFBatteryOptions* options, FFlist* results) {
|
||||
static bool getInstanceData(const PWNODE_ALL_DATA allData, ULONG bufferSize, ULONG index, const uint8_t** instanceData, ULONG* instanceLength) {
|
||||
ULONG dataOffset = 0;
|
||||
ULONG dataLength = 0;
|
||||
|
||||
if (allData->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE) {
|
||||
dataLength = allData->FixedInstanceSize;
|
||||
dataOffset = allData->DataBlockOffset + index * dataLength;
|
||||
} else {
|
||||
dataOffset = allData->OffsetInstanceDataAndLength[index].OffsetInstanceData;
|
||||
dataLength = allData->OffsetInstanceDataAndLength[index].LengthInstanceData;
|
||||
}
|
||||
|
||||
if (dataLength == 0 || dataOffset >= bufferSize || dataLength > bufferSize - dataOffset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*instanceData = (const uint8_t*) allData + dataOffset;
|
||||
*instanceLength = dataLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void detectStaticData(FFlist* entries, FFlist* results) {
|
||||
FF_DEBUG("detectStaticData");
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA allData = NULL;
|
||||
ULONG bufferSize = 0;
|
||||
const char* error = queryWmiAllData(&BATTERY_STATIC_DATA_WMI_GUID, "BATTERY_STATIC_DATA_WMI_GUID", &allData, &bufferSize);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < allData->InstanceCount; ++i) {
|
||||
const uint8_t* instanceData = NULL;
|
||||
ULONG instanceLength = 0;
|
||||
if (!getInstanceData(allData, bufferSize, i, &instanceData, &instanceLength) || instanceLength < offsetof(BATTERY_WMI_STATIC_DATA, Strings)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BATTERY_WMI_STATIC_DATA* data = (const BATTERY_WMI_STATIC_DATA*) instanceData;
|
||||
FFBatteryWmiEntry* entry = getBatteryEntry(entries, results, data->Tag);
|
||||
|
||||
FF_DEBUG("chemistry: %.4s", (const char*) &data->Chemistry);
|
||||
#if __BIG_ENDIAN__
|
||||
#define htobe32(x) (x) // Should not happen on Windows, but just in case
|
||||
#else
|
||||
#define htobe32(x) __builtin_bswap32(x)
|
||||
#endif
|
||||
switch (data->Chemistry) {
|
||||
case htobe32('PbAc'):
|
||||
ffStrbufSetStatic(&entry->result->technology, "Lead Acid");
|
||||
break;
|
||||
case htobe32('LION'):
|
||||
case htobe32('Li-I'):
|
||||
ffStrbufSetStatic(&entry->result->technology, "Lithium Ion");
|
||||
break;
|
||||
case htobe32('NiCd'):
|
||||
ffStrbufSetStatic(&entry->result->technology, "Nickel Cadmium");
|
||||
break;
|
||||
case htobe32('NiMH'):
|
||||
ffStrbufSetStatic(&entry->result->technology, "Nickel Metal Hydride");
|
||||
break;
|
||||
case htobe32('NiZn'):
|
||||
ffStrbufSetStatic(&entry->result->technology, "Nickel Zinc");
|
||||
break;
|
||||
case htobe32('RAM\0'):
|
||||
ffStrbufSetStatic(&entry->result->technology, "Rechargeable Alkaline-Manganese");
|
||||
break;
|
||||
default:
|
||||
ffStrbufSetStatic(&entry->result->technology, data->Technology ? "Rechargeable" : "Non Rechargeable");
|
||||
break;
|
||||
}
|
||||
#undef htobe32
|
||||
|
||||
const BATTERY_MANUFACTURE_DATE* manufactureDate = (const BATTERY_MANUFACTURE_DATE*) data->ManufactureDate;
|
||||
if (manufactureDate->Year > 0 && manufactureDate->Month >= 1 && manufactureDate->Month <= 12 && manufactureDate->Day >= 1 && manufactureDate->Day <= 31) {
|
||||
uint16_t year = manufactureDate->Year;
|
||||
ffStrbufSetF(&entry->result->manufactureDate, "%.4u-%.2u-%.2u", (unsigned) (year < 1000 ? (year + 1900) : year), (unsigned) manufactureDate->Month, (unsigned) manufactureDate->Day);
|
||||
}
|
||||
|
||||
// Device Name, Manufacture Name, Serial Number, UniqueID
|
||||
const struct {
|
||||
uint16_t size; // in bytes, including the null terminator
|
||||
wchar_t value[];
|
||||
}* cursor = (const void*) data->Strings;
|
||||
|
||||
FFstrbuf* strings[] = {
|
||||
&entry->result->modelName,
|
||||
&entry->result->manufacturer,
|
||||
&entry->result->serial,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_SIZE(strings); ++i) {
|
||||
if (cursor->size > sizeof(wchar_t)) {
|
||||
ffStrbufSetNWS(strings[i], cursor->size / sizeof(wchar_t) - 1, cursor->value);
|
||||
}
|
||||
cursor = (const void*) ((const uint8_t*) cursor + sizeof(uint16_t) + cursor->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void detectStatus(FFlist* entries, FFlist* results) {
|
||||
FF_DEBUG("detectStatus");
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA allData = NULL;
|
||||
ULONG bufferSize = 0;
|
||||
const char* error = queryWmiAllData(&BATTERY_STATUS_WMI_GUID, "BATTERY_STATUS_WMI_GUID", &allData, &bufferSize);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < allData->InstanceCount; ++i) {
|
||||
const uint8_t* instanceData = NULL;
|
||||
ULONG instanceLength = 0;
|
||||
if (!getInstanceData(allData, bufferSize, i, &instanceData, &instanceLength) || instanceLength < sizeof(BATTERY_WMI_STATUS)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BATTERY_WMI_STATUS* data = (const BATTERY_WMI_STATUS*) instanceData;
|
||||
FFBatteryWmiEntry* entry = getBatteryEntry(entries, results, data->Tag);
|
||||
if (data->RemainingCapacity != BATTERY_UNKNOWN_CAPACITY) {
|
||||
entry->result->capacity = data->RemainingCapacity;
|
||||
}
|
||||
|
||||
entry->result->status = FF_BATTERY_STATUS_NONE;
|
||||
if (data->PowerOnline) {
|
||||
entry->result->status |= FF_BATTERY_STATUS_AC_CONNECTED;
|
||||
}
|
||||
if (data->Charging) {
|
||||
entry->result->status |= FF_BATTERY_STATUS_CHARGING;
|
||||
}
|
||||
if (data->Discharging) {
|
||||
entry->result->status |= FF_BATTERY_STATUS_DISCHARGING;
|
||||
}
|
||||
if (data->Critical) {
|
||||
entry->result->status |= FF_BATTERY_STATUS_CRITICAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void detectRuntime(FFlist* entries, FFlist* results) {
|
||||
FF_DEBUG("detectRuntime");
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA allData = NULL;
|
||||
ULONG bufferSize = 0;
|
||||
const char* error = queryWmiAllData(&BATTERY_RUNTIME_WMI_GUID, "BATTERY_RUNTIME_WMI_GUID", &allData, &bufferSize);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < allData->InstanceCount; ++i) {
|
||||
const uint8_t* instanceData = NULL;
|
||||
ULONG instanceLength = 0;
|
||||
if (!getInstanceData(allData, bufferSize, i, &instanceData, &instanceLength) || instanceLength < sizeof(BATTERY_WMI_RUNTIME)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BATTERY_WMI_RUNTIME* data = (const BATTERY_WMI_RUNTIME*) instanceData;
|
||||
FFBatteryWmiEntry* entry = getBatteryEntry(entries, results, data->Tag);
|
||||
if (data->EstimatedRuntime != BATTERY_UNKNOWN_TIME) {
|
||||
entry->result->timeRemaining = (int32_t) data->EstimatedRuntime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void detectFullChargedCapacity(FFlist* entries, FFlist* results) {
|
||||
FF_DEBUG("detectFullChargedCapacity");
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA allData = NULL;
|
||||
ULONG bufferSize = 0;
|
||||
const char* error = queryWmiAllData(&BATTERY_FULL_CHARGED_CAPACITY_WMI_GUID, "BATTERY_FULL_CHARGED_CAPACITY_WMI_GUID", &allData, &bufferSize);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < allData->InstanceCount; ++i) {
|
||||
const uint8_t* instanceData = NULL;
|
||||
ULONG instanceLength = 0;
|
||||
if (!getInstanceData(allData, bufferSize, i, &instanceData, &instanceLength) || instanceLength < sizeof(BATTERY_WMI_FULL_CHARGED_CAPACITY)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BATTERY_WMI_FULL_CHARGED_CAPACITY* data = (const BATTERY_WMI_FULL_CHARGED_CAPACITY*) instanceData;
|
||||
FFBatteryWmiEntry* entry = getBatteryEntry(entries, results, data->Tag);
|
||||
|
||||
if (data->FullChargedCapacity != BATTERY_UNKNOWN_CAPACITY && entry->result->capacity >= 0) {
|
||||
entry->result->capacity *= 100;
|
||||
entry->result->capacity /= data->FullChargedCapacity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void detectCycleCount(FFlist* entries, FFlist* results) {
|
||||
FF_DEBUG("detectCycleCount");
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA allData = NULL;
|
||||
ULONG bufferSize = 0;
|
||||
const char* error = queryWmiAllData(&BATTERY_CYCLE_COUNT_WMI_GUID, "BATTERY_CYCLE_COUNT_WMI_GUID", &allData, &bufferSize);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < allData->InstanceCount; ++i) {
|
||||
const uint8_t* instanceData = NULL;
|
||||
ULONG instanceLength = 0;
|
||||
if (!getInstanceData(allData, bufferSize, i, &instanceData, &instanceLength) || instanceLength < sizeof(BATTERY_WMI_CYCLE_COUNT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BATTERY_WMI_CYCLE_COUNT* data = (const BATTERY_WMI_CYCLE_COUNT*) instanceData;
|
||||
getBatteryEntry(entries, results, data->Tag)->result->cycleCount = data->CycleCount;
|
||||
}
|
||||
}
|
||||
|
||||
static void detectTemperature(FFlist* entries, FFlist* results) {
|
||||
FF_DEBUG("detectTemperature");
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA allData = NULL;
|
||||
ULONG bufferSize = 0;
|
||||
const char* error = queryWmiAllData(&BATTERY_TEMPERATURE_WMI_GUID, "BATTERY_TEMPERATURE_WMI_GUID", &allData, &bufferSize);
|
||||
if (error) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ULONG i = 0; i < allData->InstanceCount; ++i) {
|
||||
const uint8_t* instanceData = NULL;
|
||||
ULONG instanceLength = 0;
|
||||
if (!getInstanceData(allData, bufferSize, i, &instanceData, &instanceLength) || instanceLength < sizeof(BATTERY_WMI_TEMPERATURE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const BATTERY_WMI_TEMPERATURE* data = (const BATTERY_WMI_TEMPERATURE*) instanceData;
|
||||
getBatteryEntry(entries, results, data->Tag)->result->temperature = data->Temperature / 10.0 - 273.15;
|
||||
}
|
||||
}
|
||||
|
||||
static const char* detectWithNtApi(FFBatteryResult* battery) {
|
||||
// Reports summary battery information, not per battery
|
||||
FF_DEBUG("NtApi: start detection");
|
||||
SYSTEM_BATTERY_STATE info;
|
||||
if (NT_SUCCESS(NtPowerInformation(SystemBatteryState, NULL, 0, &info, sizeof(info))) &&
|
||||
info.BatteryPresent) {
|
||||
FFBatteryResult* battery = FF_LIST_ADD(FFBatteryResult, *results);
|
||||
ffStrbufInit(&battery->modelName);
|
||||
ffStrbufInit(&battery->manufacturer);
|
||||
ffStrbufInit(&battery->manufactureDate);
|
||||
ffStrbufInit(&battery->technology);
|
||||
ffStrbufInit(&battery->serial);
|
||||
battery->temperature = FF_BATTERY_TEMP_UNSET;
|
||||
battery->cycleCount = 0;
|
||||
battery->timeRemaining = info.EstimatedTime == BATTERY_UNKNOWN_TIME ? -1 : (int32_t) info.EstimatedTime;
|
||||
battery->status = FF_BATTERY_STATUS_NONE;
|
||||
|
||||
battery->capacity = info.RemainingCapacity * 100.0 / info.MaxCapacity;
|
||||
if (info.AcOnLine) {
|
||||
battery->status |= FF_BATTERY_STATUS_AC_CONNECTED;
|
||||
}
|
||||
if (info.Charging) {
|
||||
battery->status |= FF_BATTERY_STATUS_CHARGING;
|
||||
}
|
||||
if (info.Discharging) {
|
||||
battery->status |= FF_BATTERY_STATUS_DISCHARGING;
|
||||
}
|
||||
if (info.DefaultAlert1 > 0 && info.RemainingCapacity <= info.DefaultAlert1) {
|
||||
battery->status |= FF_BATTERY_STATUS_CRITICAL;
|
||||
}
|
||||
|
||||
detectBySmbios(battery);
|
||||
|
||||
return NULL;
|
||||
NTSTATUS status = NtPowerInformation(SystemBatteryState, NULL, 0, &info, sizeof(info));
|
||||
if (!NT_SUCCESS(status)) {
|
||||
FF_DEBUG("NtApi: NtPowerInformation(SystemBatteryState) failed: %s", ffDebugNtStatus(status));
|
||||
return "NtPowerInformation(SystemBatteryState) failed";
|
||||
}
|
||||
return "NtPowerInformation(SystemBatteryState) failed";
|
||||
if (!info.BatteryPresent) {
|
||||
FF_DEBUG("NtApi reports no battery present");
|
||||
return "No battery present";
|
||||
}
|
||||
|
||||
if (info.MaxCapacity != BATTERY_UNKNOWN_CAPACITY && info.RemainingCapacity != BATTERY_UNKNOWN_CAPACITY) {
|
||||
battery->capacity = info.RemainingCapacity * 100.0 / info.MaxCapacity;
|
||||
}
|
||||
battery->status = FF_BATTERY_STATUS_NONE;
|
||||
if (info.AcOnLine) {
|
||||
battery->status |= FF_BATTERY_STATUS_AC_CONNECTED;
|
||||
}
|
||||
if (info.Charging) {
|
||||
battery->status |= FF_BATTERY_STATUS_CHARGING;
|
||||
}
|
||||
if (info.Discharging) {
|
||||
battery->status |= FF_BATTERY_STATUS_DISCHARGING;
|
||||
}
|
||||
if (info.DefaultAlert1 > 0 && info.RemainingCapacity <= info.DefaultAlert1) {
|
||||
battery->status |= FF_BATTERY_STATUS_CRITICAL;
|
||||
}
|
||||
battery->timeRemaining = info.EstimatedTime == BATTERY_UNKNOWN_TIME ? -1 : (int32_t) info.EstimatedTime;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBattery(FFBatteryOptions* options, FFlist* results) {
|
||||
return options->useSetupApi
|
||||
? detectWithCmApi(options, results)
|
||||
: detectWithNtApi(options, results);
|
||||
FF_DEBUG("WMI: start detection");
|
||||
|
||||
FF_LIST_AUTO_DESTROY entries = ffListCreate();
|
||||
detectStaticData(&entries, results);
|
||||
if (results->length == 0) {
|
||||
return NULL;
|
||||
} else if (results->length == 1) {
|
||||
// Fast path for single battery
|
||||
detectWithNtApi(FF_LIST_FIRST(FFBatteryWmiEntry, entries)->result);
|
||||
} else {
|
||||
detectStatus(&entries, results);
|
||||
detectFullChargedCapacity(&entries, results);
|
||||
detectRuntime(&entries, results);
|
||||
}
|
||||
detectCycleCount(&entries, results);
|
||||
if (options->temp) {
|
||||
detectTemperature(&entries, results);
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH (FFBatteryWmiEntry, entry, entries) {
|
||||
FF_DEBUG(
|
||||
"WMI: detected battery tag=%lu, name='%s', charge=%.2f%%, status=0x%x, runtime=%d seconds",
|
||||
entry->tag,
|
||||
entry->result->modelName.length ? entry->result->modelName.chars : "<unknown>",
|
||||
entry->result->capacity,
|
||||
entry->result->status,
|
||||
entry->result->timeRemaining);
|
||||
}
|
||||
|
||||
FF_DEBUG("WMI: finished detection, total results=%u", results->length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ static bool detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBlue
|
||||
} else if (ffStrEquals(deviceProperty, "Icon")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->type);
|
||||
} else if (ffStrEquals(deviceProperty, "Percentage")) {
|
||||
uint32_t percentage;
|
||||
uint64_t percentage;
|
||||
if (ffDBusGetUint(dbus, &dictIter, &percentage)) {
|
||||
device->battery = (uint8_t) percentage;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,102 @@
|
||||
#include "bluetooth.h"
|
||||
#include "common/library.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/windows/unicode.h"
|
||||
|
||||
#define INITGUID
|
||||
#include <windows.h>
|
||||
#include <bluetoothapis.h>
|
||||
#include <cfgmgr32.h>
|
||||
#include <devpkey.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wpointer-sign"
|
||||
|
||||
// https://github.com/wine-mirror/wine/blob/ab6f4584b89f28504b0b277c0b4c723a86b4d6b7/include/ddk/bthguid.h#L4
|
||||
/* DEVPROP_TYPE_STRING */
|
||||
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_DeviceAddress, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 1);
|
||||
/* DEVPROP_TYPE_UINT32 */
|
||||
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_ClassOfDevice, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 10);
|
||||
/* DEVPROP_TYPE_FILETIME */
|
||||
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_LastConnectedTime, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 11);
|
||||
/* DEVPROP_TYPE_GUID */
|
||||
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_ServiceGUID, 0x2bd67d8b, 0x8beb, 0x48d5, 0x87, 0xe0, 0x6c, 0xda, 0x34, 0x28, 0x04, 0x0a, 2);
|
||||
/* DEVPROP_TYPE_UINT8 */
|
||||
DEFINE_DEVPROPKEY(DEVPKEY_Bluetooth_BatteryLevel, 0x104ea319, 0x6ee2, 0x4701, 0xbd, 0x47, 0x8d, 0xdb, 0xf4, 0x25, 0xbb, 0xe5, 2);
|
||||
|
||||
// TODO: use CM API to fetch bluetooth devices instead of BluetoothFindFirstDevice, if we find DEVPKEY_Bluetooth_IsConnected or similar
|
||||
#define GUID_DEVCLASS_BLUETOOTH_STRING L"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}" // Found in <devguid.h>
|
||||
#define GUID_DEVCLASS_MEDIA_STRING L"{4d36e96c-e325-11ce-bfc1-08002be10318}" // Found in <devguid.h>
|
||||
|
||||
static const char* ffBluetoothDetectBattery(FFlist* devices) {
|
||||
ULONG idListLength = 0;
|
||||
CONFIGRET status = CM_Get_Device_ID_List_SizeW(&idListLength, GUID_DEVCLASS_MEDIA_STRING, CM_GETIDLIST_FILTER_PRESENT);
|
||||
if (status != CR_SUCCESS) {
|
||||
return "CM_Get_Device_ID_List_SizeW failed";
|
||||
}
|
||||
|
||||
if (idListLength == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t* FF_AUTO_FREE idList = (wchar_t*) malloc((size_t) idListLength * sizeof(wchar_t));
|
||||
if (!idList) {
|
||||
return "malloc() failed";
|
||||
}
|
||||
|
||||
status = CM_Get_Device_ID_ListW(GUID_DEVCLASS_MEDIA_STRING, idList, idListLength, CM_GETIDLIST_FILTER_PRESENT);
|
||||
if (status != CR_SUCCESS) {
|
||||
return "CM_Get_Device_ID_ListW failed";
|
||||
}
|
||||
|
||||
for (const wchar_t* deviceId = idList; *deviceId; deviceId += wcslen(deviceId) + 1) {
|
||||
DEVINST devInst = 0;
|
||||
|
||||
// Hands-Free profile service; headsets often expose battery level through this media device node rather than the Bluetooth device node
|
||||
// BthHFEnum
|
||||
if (CM_Locate_DevNodeW(&devInst, (DEVINSTID_W) deviceId, CM_LOCATE_DEVNODE_NORMAL) != CR_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t battery = 0;
|
||||
{
|
||||
DEVPROPTYPE devPropertyType = DEVPROP_TYPE_EMPTY;
|
||||
ULONG propertySize = sizeof(battery);
|
||||
if (CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Bluetooth_BatteryLevel, &devPropertyType, (PBYTE) &battery, &propertySize, 0) != CR_SUCCESS || devPropertyType != DEVPROP_TYPE_BYTE || propertySize != sizeof(battery)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
WCHAR deviceAddress[13]; // 6 bytes in hex + null terminator
|
||||
{
|
||||
DEVPROPTYPE devPropertyType = DEVPROP_TYPE_EMPTY;
|
||||
ULONG propertySize = sizeof(deviceAddress);
|
||||
if (CM_Get_DevNode_PropertyW(devInst, &DEVPKEY_Bluetooth_DeviceAddress, &devPropertyType, (PBYTE) deviceAddress, &propertySize, 0) != CR_SUCCESS || devPropertyType != DEVPROP_TYPE_STRING || propertySize != sizeof(deviceAddress)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH (FFBluetoothResult, bt, *devices) {
|
||||
if (deviceAddress[0] == bt->address.chars[0] &&
|
||||
deviceAddress[1] == bt->address.chars[1] &&
|
||||
deviceAddress[2] == bt->address.chars[3] &&
|
||||
deviceAddress[3] == bt->address.chars[4] &&
|
||||
deviceAddress[4] == bt->address.chars[6] &&
|
||||
deviceAddress[5] == bt->address.chars[7] &&
|
||||
deviceAddress[6] == bt->address.chars[9] &&
|
||||
deviceAddress[7] == bt->address.chars[10] &&
|
||||
deviceAddress[8] == bt->address.chars[12] &&
|
||||
deviceAddress[9] == bt->address.chars[13] &&
|
||||
deviceAddress[10] == bt->address.chars[15] &&
|
||||
deviceAddress[11] == bt->address.chars[16]) {
|
||||
bt->battery = battery;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FFBluetoothResult */) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(bluetoothapis, "bluetoothapis.dll", 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(bluetoothapis, BluetoothFindFirstDevice)
|
||||
@@ -125,8 +215,9 @@ const char* ffDetectBluetooth(FFBluetoothOptions* options, FFlist* devices /* FF
|
||||
|
||||
ffBluetoothFindDeviceClose(hFind);
|
||||
|
||||
const char* ffBluetoothDetectBattery(FFlist * result);
|
||||
ffBluetoothDetectBattery(devices);
|
||||
if (devices->length > 0) {
|
||||
ffBluetoothDetectBattery(devices);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
extern "C" {
|
||||
#include "bluetooth.h"
|
||||
}
|
||||
#include "common/windows/wmi.hpp"
|
||||
#include "common/windows/unicode.hpp"
|
||||
#include "common/windows/util.hpp"
|
||||
|
||||
extern "C" const char* ffBluetoothDetectBattery(FFlist* devices) {
|
||||
FFWmiQuery query(L"SELECT __PATH FROM Win32_PnPEntity WHERE Service = 'BthHFEnum'", nullptr, FFWmiNamespace::CIMV2);
|
||||
if (!query) {
|
||||
return "Query WMI service failed";
|
||||
}
|
||||
|
||||
IWbemClassObject* pInParams = nullptr;
|
||||
on_scope_exit releaseInParams([&] { pInParams && pInParams->Release(); });
|
||||
{
|
||||
IWbemClassObject* pnpEntityClass = nullptr;
|
||||
|
||||
if (FAILED(query.pService->GetObjectW(bstr_t(L"Win32_PnPEntity"), 0, nullptr, &pnpEntityClass, nullptr))) {
|
||||
return "Failed to get PnP entity class";
|
||||
}
|
||||
on_scope_exit releasePnpEntityClass([&] { pnpEntityClass && pnpEntityClass->Release(); });
|
||||
|
||||
if (FAILED(pnpEntityClass->GetMethod(bstr_t(L"GetDeviceProperties"), 0, &pInParams, NULL))) {
|
||||
return "Failed to get GetDeviceProperties method";
|
||||
}
|
||||
|
||||
FFWmiVariant devicePropertyKeys({ L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress" });
|
||||
if (FAILED(pInParams->Put(L"devicePropertyKeys", 0, &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING))) {
|
||||
return "Failed to put devicePropertyKeys";
|
||||
}
|
||||
}
|
||||
|
||||
while (FFWmiRecord record = query.next()) {
|
||||
IWbemCallResult* pCallResult = nullptr;
|
||||
|
||||
if (FAILED(query.pService->ExecMethod(record.get(L"__PATH").bstrVal, bstr_t(L"GetDeviceProperties"), 0, nullptr, pInParams, nullptr, &pCallResult))) {
|
||||
continue;
|
||||
}
|
||||
on_scope_exit releaseCallResult([&] { pCallResult && pCallResult->Release(); });
|
||||
|
||||
IWbemClassObject* pResultObject = nullptr;
|
||||
if (FAILED(pCallResult->GetResultObject((LONG) WBEM_INFINITE, &pResultObject))) {
|
||||
continue;
|
||||
}
|
||||
on_scope_exit releaseResultObject([&] { pResultObject && pResultObject->Release(); });
|
||||
|
||||
VARIANT propArray;
|
||||
if (FAILED(pResultObject->Get(L"deviceProperties", 0, &propArray, nullptr, nullptr))) {
|
||||
continue;
|
||||
}
|
||||
on_scope_exit releasePropArray([&] { VariantClear(&propArray); });
|
||||
|
||||
if (propArray.vt != (VT_ARRAY | VT_UNKNOWN) ||
|
||||
(propArray.parray->fFeatures & FADF_UNKNOWN) == 0 ||
|
||||
propArray.parray->cDims != 1 ||
|
||||
propArray.parray->rgsabound[0].cElements != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t batt = 0;
|
||||
for (LONG i = 0; i < 2; i++) {
|
||||
IWbemClassObject* object = nullptr;
|
||||
if (FAILED(SafeArrayGetElement(propArray.parray, &i, &object))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFWmiRecord rec(object);
|
||||
auto data = rec.get(L"Data");
|
||||
if (data.vt == VT_EMPTY) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
batt = data.get<uint8_t>();
|
||||
} else {
|
||||
FF_STRBUF_AUTO_DESTROY addr = ffStrbufCreateWSV(data.get<std::wstring_view>()); // MAC address without colon
|
||||
if (__builtin_expect(addr.length != 12, 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FF_LIST_FOR_EACH (FFBluetoothResult, bt, *devices) {
|
||||
if (bt->address.length != 12 + 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (addr.chars[0] == bt->address.chars[0] &&
|
||||
addr.chars[1] == bt->address.chars[1] &&
|
||||
addr.chars[2] == bt->address.chars[3] &&
|
||||
addr.chars[3] == bt->address.chars[4] &&
|
||||
addr.chars[4] == bt->address.chars[6] &&
|
||||
addr.chars[5] == bt->address.chars[7] &&
|
||||
addr.chars[6] == bt->address.chars[9] &&
|
||||
addr.chars[7] == bt->address.chars[10] &&
|
||||
addr.chars[8] == bt->address.chars[12] &&
|
||||
addr.chars[9] == bt->address.chars[13] &&
|
||||
addr.chars[10] == bt->address.chars[15] &&
|
||||
addr.chars[11] == bt->address.chars[16]) {
|
||||
bt->battery = batt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -56,12 +56,15 @@ static const char* detectBluetoothProperty(FFBluetoothRadioResult* device, FFDBu
|
||||
} else if (ffStrEquals(deviceProperty, "Alias")) {
|
||||
ffDBusGetString(dbus, &dictIter, &device->name);
|
||||
} else if (ffStrEquals(deviceProperty, "Manufacturer")) {
|
||||
uint32_t vendorId;
|
||||
uint64_t vendorId;
|
||||
if (ffDBusGetUint(dbus, &dictIter, &vendorId)) {
|
||||
ffStrbufSetStatic(&device->vendor, ffBluetoothRadioGetVendor(vendorId));
|
||||
ffStrbufSetStatic(&device->vendor, ffBluetoothRadioGetVendor((uint32_t) vendorId));
|
||||
}
|
||||
} else if (ffStrEquals(deviceProperty, "Version")) {
|
||||
ffDBusGetUint(dbus, &dictIter, (uint32_t*) &device->lmpVersion);
|
||||
uint64_t version;
|
||||
if (ffDBusGetUint(dbus, &dictIter, &version)) {
|
||||
device->lmpVersion = (int32_t) version;
|
||||
}
|
||||
} else if (ffStrEquals(deviceProperty, "Powered")) {
|
||||
ffDBusGetBool(dbus, &dictIter, &device->enabled);
|
||||
} else if (ffStrEquals(deviceProperty, "Discoverable")) {
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
#include "brightness.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/library.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/windows/wmi.h"
|
||||
#include "common/windows/unicode.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <winternl.h>
|
||||
#include <windows.h>
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI GetPhysicalMonitors(
|
||||
_In_ UNICODE_STRING* pstrDeviceName,
|
||||
_In_ DWORD dwPhysicalMonitorArraySize,
|
||||
_Out_ DWORD* pdwNumPhysicalMonitorHandlesInArray,
|
||||
_Out_ HANDLE* phPhysicalMonitorArray);
|
||||
|
||||
typedef enum _MC_VCP_CODE_TYPE {
|
||||
MC_MOMENTARY,
|
||||
MC_SET_PARAMETER
|
||||
} MC_VCP_CODE_TYPE,
|
||||
*LPMC_VCP_CODE_TYPE;
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DDCCIGetVCPFeature(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwVCPCode,
|
||||
_Out_opt_ LPMC_VCP_CODE_TYPE pvct,
|
||||
_Out_ DWORD* pdwCurrentValue,
|
||||
_Out_opt_ DWORD* pdwMaximumValue);
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DestroyPhysicalMonitorInternal(
|
||||
_In_ HANDLE hMonitor);
|
||||
|
||||
NTSTATUS WINAPI GetPhysicalMonitorDescription(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
|
||||
_Out_ LPWSTR szPhysicalMonitorDescription);
|
||||
|
||||
static const char* detectWithWmi(FFlist* result) {
|
||||
FF_DEBUG("WMI: start detection");
|
||||
|
||||
// https://github.com/tpn/winsdk-10/blob/master/Include/10.0.16299.0/km/wmicore.mof#L21200
|
||||
const GUID WmiMonitorBrightnessGuid = {
|
||||
0xd43412ac, 0x67f9, 0x4fbb, { 0xa0, 0x81, 0x17, 0x52, 0xa2, 0xc3, 0x3e, 0x84 }
|
||||
};
|
||||
|
||||
FF_AUTO_CLOSE_WMI_BLOCK HANDLE hBlock = NULL;
|
||||
|
||||
ULONG status = WmiOpenBlock(&WmiMonitorBrightnessGuid, WMIGUID_QUERY, &hBlock);
|
||||
if (status != 0) {
|
||||
FF_DEBUG("WMI: WmiOpenBlock failed: %s", ffDebugWin32Error(status));
|
||||
return "WmiOpenBlock() failed";
|
||||
}
|
||||
|
||||
ULONG bufferSize = 0;
|
||||
status = WmiQueryAllDataW(hBlock, &bufferSize, NULL);
|
||||
if (status != ERROR_SUCCESS && status != ERROR_INSUFFICIENT_BUFFER) {
|
||||
FF_DEBUG("WMI: first WmiQueryAllDataW failed, bufferSize=%lu: %s", bufferSize, ffDebugWin32Error(status));
|
||||
return "WmiQueryAllDataW() failed";
|
||||
}
|
||||
|
||||
FF_DEBUG("WMI: initial query bufferSize=%lu", bufferSize);
|
||||
|
||||
if (bufferSize == 0) {
|
||||
FF_DEBUG("WMI: WmiQueryAllDataW returned empty buffer");
|
||||
return "WmiQueryAllDataW() returned no data";
|
||||
}
|
||||
|
||||
FF_AUTO_FREE PWNODE_ALL_DATA pAllData = (PWNODE_ALL_DATA) malloc(bufferSize);
|
||||
|
||||
status = WmiQueryAllDataW(hBlock, &bufferSize, pAllData);
|
||||
if (status != ERROR_SUCCESS) {
|
||||
FF_DEBUG("WMI: second WmiQueryAllDataW failed, bufferSize=%lu: %s", bufferSize, ffDebugWin32Error(status));
|
||||
return "WmiQueryAllDataW() failed";
|
||||
}
|
||||
|
||||
if (bufferSize < sizeof(WNODE_ALL_DATA)) {
|
||||
FF_DEBUG("WMI: insufficient buffer for WNODE_ALL_DATA, bufferSize=%lu", bufferSize);
|
||||
return "WmiQueryAllDataW() returned insufficient data for WNODE_ALL_DATA";
|
||||
}
|
||||
|
||||
FF_DEBUG("WMI: instanceCount=%lu, flags=0x%lX", pAllData->InstanceCount, pAllData->WnodeHeader.Flags);
|
||||
|
||||
PULONG pNameOffsets = (PULONG) ((PUCHAR) pAllData + pAllData->OffsetInstanceNameOffsets);
|
||||
|
||||
for (ULONG i = 0; i < pAllData->InstanceCount; i++) {
|
||||
ULONG dataOffset = 0;
|
||||
ULONG dataLength = 0;
|
||||
|
||||
if (pAllData->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE) {
|
||||
dataLength = pAllData->FixedInstanceSize;
|
||||
dataOffset = pAllData->DataBlockOffset + i * dataLength;
|
||||
} else {
|
||||
dataOffset = pAllData->OffsetInstanceDataAndLength[i].OffsetInstanceData;
|
||||
dataLength = pAllData->OffsetInstanceDataAndLength[i].LengthInstanceData;
|
||||
}
|
||||
|
||||
if (dataLength == 0 || dataOffset >= bufferSize || dataLength > bufferSize - dataOffset) {
|
||||
FF_DEBUG("WMI: skip invalid instance %lu (dataOffset=%lu, dataLength=%lu, bufferSize=%lu)", i, dataOffset, dataLength, bufferSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
USHORT nameCharsCount = *(PUSHORT) ((PUCHAR) pAllData + pNameOffsets[i]) / sizeof(WCHAR);
|
||||
PCWSTR pNameChars = (PCWSTR) ((PUCHAR) pAllData + (pNameOffsets[i] + sizeof(USHORT)));
|
||||
|
||||
PUCHAR pDataBlock = (PUCHAR) pAllData + dataOffset;
|
||||
UCHAR currentBrightness = pDataBlock[0];
|
||||
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
brightness->max = 100;
|
||||
brightness->min = 0;
|
||||
brightness->current = currentBrightness;
|
||||
brightness->builtin = true;
|
||||
ffStrbufInitNWS(&brightness->name, nameCharsCount, pNameChars);
|
||||
ffStrbufSubstrAfterFirstC(&brightness->name, '\\');
|
||||
ffStrbufSubstrBeforeFirstC(&brightness->name, '\\');
|
||||
|
||||
FF_DEBUG("WMI: detected builtin display '%s', current=%u", brightness->name.chars, (unsigned) currentBrightness);
|
||||
}
|
||||
|
||||
FF_DEBUG("WMI: finished detection, total results=%u", result->length);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result) {
|
||||
FF_DEBUG("DDC/CI: start detection, displayCount=%u", displayServer->displays.length);
|
||||
|
||||
void* gdi32 = ffLibraryGetModule(L"gdi32.dll");
|
||||
if (!gdi32) {
|
||||
FF_DEBUG("DDC/CI: failed to load gdi32.dll");
|
||||
return "ffLibraryGetModule(gdi32.dll) failed";
|
||||
}
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, GetPhysicalMonitors)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DDCCIGetVCPFeature)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DestroyPhysicalMonitorInternal)
|
||||
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN) {
|
||||
FF_DEBUG("DDC/CI: skip builtin display id=%" PRIu64, display->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
MONITORINFOEXW mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (!GetMonitorInfoW((HMONITOR) (uintptr_t) display->id, (LPMONITORINFO) &mi)) {
|
||||
FF_DEBUG("DDC/CI: GetMonitorInfoW failed for display id=%" PRIu64 ": %s", display->id, ffDebugWin32Error(GetLastError()));
|
||||
continue;
|
||||
}
|
||||
|
||||
UNICODE_STRING deviceName = {
|
||||
.Length = (USHORT) (wcslen(mi.szDevice) * sizeof(wchar_t)),
|
||||
.MaximumLength = 0,
|
||||
.Buffer = mi.szDevice,
|
||||
};
|
||||
HANDLE physicalMonitor;
|
||||
DWORD monitorCount = 0;
|
||||
NTSTATUS monitorStatus = ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor);
|
||||
if (NT_SUCCESS(monitorStatus) && monitorCount >= 1) {
|
||||
DWORD curr = 0, max = 0;
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max))) {
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
if (display->name.length > 0) {
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
} else {
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(gdi32, GetPhysicalMonitorDescription)
|
||||
if (ffGetPhysicalMonitorDescription) {
|
||||
wchar_t description[128 /*MUST be PHYSICAL_MONITOR_DESCRIPTION_SIZE*/];
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description))) {
|
||||
ffStrbufInitWS(&brightness->name, description);
|
||||
}
|
||||
}
|
||||
if (brightness->name.length == 0) {
|
||||
ffStrbufSetNWS(&brightness->name, deviceName.Length / 2, deviceName.Buffer);
|
||||
}
|
||||
}
|
||||
brightness->max = max;
|
||||
brightness->min = 0;
|
||||
brightness->current = curr;
|
||||
brightness->builtin = false;
|
||||
|
||||
FF_DEBUG("DDC/CI: detected external display '%s', current=%u, max=%u", brightness->name.chars, (unsigned) curr, (unsigned) max);
|
||||
} else {
|
||||
FF_DEBUG("DDC/CI: DDCCIGetVCPFeature failed for monitor '%ls': %s", deviceName.Buffer, ffDebugWin32Error(GetLastError()));
|
||||
}
|
||||
|
||||
ffDestroyPhysicalMonitorInternal(physicalMonitor);
|
||||
} else {
|
||||
FF_DEBUG("DDC/CI: GetPhysicalMonitors failed for '%ls', status=0x%08X, monitorCount=%lu, error=%s", deviceName.Buffer, (unsigned) monitorStatus, monitorCount, ffDebugWin32Error(GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
FF_DEBUG("DDC/CI: finished detection, total results=%u", result->length);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hasBuiltinDisplay(const FFDisplayServerResult* displayServer) {
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
FF_DEBUG("start, displayCount=%u", displayServer->displays.length);
|
||||
|
||||
if (hasBuiltinDisplay(displayServer)) {
|
||||
FF_DEBUG("builtin display detected, trying WMI");
|
||||
detectWithWmi(result);
|
||||
}
|
||||
|
||||
if (result->length < displayServer->displays.length) {
|
||||
FF_DEBUG("resultCount=%u < displayCount=%u, trying DDC/CI", result->length, displayServer->displays.length);
|
||||
detectWithDdcci(displayServer, result);
|
||||
}
|
||||
|
||||
FF_DEBUG("finished, resultCount=%u", result->length);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
extern "C" {
|
||||
#include "brightness.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "common/library.h"
|
||||
}
|
||||
#include "common/windows/wmi.hpp"
|
||||
#include "common/windows/unicode.hpp"
|
||||
|
||||
#include <winternl.h>
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI GetPhysicalMonitors(
|
||||
_In_ UNICODE_STRING* pstrDeviceName,
|
||||
_In_ DWORD dwPhysicalMonitorArraySize,
|
||||
_Out_ DWORD* pdwNumPhysicalMonitorHandlesInArray,
|
||||
_Out_ HANDLE* phPhysicalMonitorArray);
|
||||
|
||||
typedef enum _MC_VCP_CODE_TYPE {
|
||||
MC_MOMENTARY,
|
||||
MC_SET_PARAMETER
|
||||
} MC_VCP_CODE_TYPE,
|
||||
*LPMC_VCP_CODE_TYPE;
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DDCCIGetVCPFeature(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwVCPCode,
|
||||
_Out_opt_ LPMC_VCP_CODE_TYPE pvct,
|
||||
_Out_ DWORD* pdwCurrentValue,
|
||||
_Out_opt_ DWORD* pdwMaximumValue);
|
||||
|
||||
NTSYSAPI NTSTATUS WINAPI DestroyPhysicalMonitorInternal(
|
||||
_In_ HANDLE hMonitor);
|
||||
|
||||
NTSTATUS WINAPI GetPhysicalMonitorDescription(
|
||||
_In_ HANDLE hMonitor,
|
||||
_In_ DWORD dwPhysicalMonitorDescriptionSizeInChars,
|
||||
_Out_ LPWSTR szPhysicalMonitorDescription);
|
||||
|
||||
static const char* detectWithWmi(FFlist* result) {
|
||||
FFWmiQuery query(L"SELECT CurrentBrightness, InstanceName FROM WmiMonitorBrightness WHERE Active = true", nullptr, FFWmiNamespace::WMI);
|
||||
if (!query) {
|
||||
return "Query WMI service failed";
|
||||
}
|
||||
|
||||
while (FFWmiRecord record = query.next()) {
|
||||
if (FFWmiVariant vtValue = record.get(L"CurrentBrightness")) {
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
brightness->max = 100;
|
||||
brightness->min = 0;
|
||||
brightness->current = vtValue.get<uint8_t>();
|
||||
brightness->builtin = true;
|
||||
|
||||
ffStrbufInit(&brightness->name);
|
||||
if (FFWmiVariant vtName = record.get(L"InstanceName")) {
|
||||
ffStrbufSetWSV(&brightness->name, vtName.get<std::wstring_view>());
|
||||
ffStrbufSubstrAfterFirstC(&brightness->name, '\\');
|
||||
ffStrbufSubstrBeforeFirstC(&brightness->name, '\\');
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectWithDdcci(const FFDisplayServerResult* displayServer, FFlist* result) {
|
||||
void* gdi32 = ffLibraryGetModule(L"gdi32.dll");
|
||||
if (!gdi32) {
|
||||
return "ffLibraryGetModule(gdi32.dll) failed";
|
||||
}
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, GetPhysicalMonitors)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DDCCIGetVCPFeature)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(gdi32, DestroyPhysicalMonitorInternal)
|
||||
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MONITORINFOEXW mi;
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (!GetMonitorInfoW((HMONITOR) (uintptr_t) display->id, (LPMONITORINFO) &mi)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UNICODE_STRING deviceName = {
|
||||
.Length = (USHORT) (wcslen(mi.szDevice) * sizeof(wchar_t)),
|
||||
.MaximumLength = 0,
|
||||
.Buffer = mi.szDevice,
|
||||
};
|
||||
HANDLE physicalMonitor;
|
||||
DWORD monitorCount = 0;
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitors(&deviceName, 1, &monitorCount, &physicalMonitor)) && monitorCount >= 1) {
|
||||
DWORD curr = 0, max = 0;
|
||||
if (NT_SUCCESS(ffDDCCIGetVCPFeature(physicalMonitor, 0x10 /* luminance */, NULL, &curr, &max))) {
|
||||
FFBrightnessResult* brightness = FF_LIST_ADD(FFBrightnessResult, *result);
|
||||
if (display->name.length > 0) {
|
||||
ffStrbufInitCopy(&brightness->name, &display->name);
|
||||
} else {
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(gdi32, GetPhysicalMonitorDescription)
|
||||
if (ffGetPhysicalMonitorDescription) {
|
||||
wchar_t description[128 /*MUST be PHYSICAL_MONITOR_DESCRIPTION_SIZE*/];
|
||||
if (NT_SUCCESS(ffGetPhysicalMonitorDescription(physicalMonitor, ARRAY_SIZE(description), description))) {
|
||||
ffStrbufInitWS(&brightness->name, description);
|
||||
}
|
||||
}
|
||||
if (brightness->name.length == 0) {
|
||||
ffStrbufSetNWS(&brightness->name, deviceName.Length / 2, deviceName.Buffer);
|
||||
}
|
||||
}
|
||||
brightness->max = max;
|
||||
brightness->min = 0;
|
||||
brightness->current = curr;
|
||||
brightness->builtin = false;
|
||||
}
|
||||
|
||||
ffDestroyPhysicalMonitorInternal(physicalMonitor);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool hasBuiltinDisplay(const FFDisplayServerResult* displayServer) {
|
||||
FF_LIST_FOR_EACH (FFDisplayResult, display, displayServer->displays) {
|
||||
if (display->type == FF_DISPLAY_TYPE_BUILTIN || display->type == FF_DISPLAY_TYPE_UNKNOWN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" const char* ffDetectBrightness(FF_A_UNUSED FFBrightnessOptions* options, FFlist* result) {
|
||||
const FFDisplayServerResult* displayServer = ffConnectDisplayServer();
|
||||
|
||||
if (hasBuiltinDisplay(displayServer)) {
|
||||
detectWithWmi(result);
|
||||
}
|
||||
|
||||
if (result->length < displayServer->displays.length) {
|
||||
detectWithDdcci(displayServer, result);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
extern "C" {
|
||||
#include "camera.h"
|
||||
#include "common/library.h"
|
||||
#include "common/windows/com.h"
|
||||
}
|
||||
#include "common/windows/com.hpp"
|
||||
#include "common/windows/unicode.hpp"
|
||||
#include "common/windows/util.hpp"
|
||||
|
||||
@@ -72,13 +72,13 @@ extern "C" const char* ffDetectCamera(FF_A_UNUSED FFlist* result) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IMFStreamDescriptor* FF_AUTO_RELEASE_COM_OBJECT sd = NULL;
|
||||
IMFStreamDescriptor* FF_AUTO_RELEASE_COM_OBJECT sd = nullptr;
|
||||
BOOL selected;
|
||||
if (FAILED(pd->GetStreamDescriptorByIndex(0, &selected, &sd))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IMFMediaTypeHandler* FF_AUTO_RELEASE_COM_OBJECT handler = NULL;
|
||||
IMFMediaTypeHandler* FF_AUTO_RELEASE_COM_OBJECT handler = nullptr;
|
||||
if (FAILED(sd->GetMediaTypeHandler(&handler))) {
|
||||
continue;
|
||||
}
|
||||
@@ -133,6 +133,9 @@ extern "C" const char* ffDetectCamera(FF_A_UNUSED FFlist* result) {
|
||||
case MFVideoPrimaries_ACES:
|
||||
ffStrbufSetStatic(&camera->colorspace, "ACES");
|
||||
break;
|
||||
case (MFVideoPrimaries) 13: // MFVideoPrimaries_Display_P3
|
||||
ffStrbufSetStatic(&camera->colorspace, "Display P3");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -211,6 +211,45 @@ static const char* getCosmic(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options)
|
||||
return "All methods failed";
|
||||
}
|
||||
|
||||
static const char* getEnlightenmentByDbus(FF_A_UNUSED FFstrbuf* result) {
|
||||
#ifdef FF_HAVE_DBUS
|
||||
FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {};
|
||||
if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) {
|
||||
return "ffDBusLoadData() failed";
|
||||
}
|
||||
|
||||
DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.enlightenment.wm.service", "/org/enlightenment/wm/RemoteObject", "org.enlightenment.wm.Core", "Version", NULL, NULL);
|
||||
if (!reply) {
|
||||
return "ffDBusGetMethodReply() failed";
|
||||
}
|
||||
|
||||
DBusMessageIter rootIterator;
|
||||
if (!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return "dbus_message_iter_init() failed";
|
||||
}
|
||||
if (!ffDBusGetString(&dbus, &rootIterator, result)) {
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
return "ffDBusGetString() failed";
|
||||
}
|
||||
dbus.lib->ffdbus_message_unref(reply);
|
||||
|
||||
return NULL;
|
||||
#else // FF_HAVE_DBUS
|
||||
return "ffDBusLoadData() failed: dbus support not compiled in";
|
||||
#endif // FF_HAVE_DBUS
|
||||
}
|
||||
|
||||
static void getEnlightenment(FFstrbuf* result, FF_A_UNUSED FFDEOptions* options) {
|
||||
getEnlightenmentByDbus(result);
|
||||
|
||||
if (result->length == 0) {
|
||||
if (ffProcessAppendStdOut(result, (char* const[]) { "enlightenment", "--version", NULL }) == NULL) { // ...\nVersion: 0.27.1\n...
|
||||
ffStrbufSubstrAfterFirstS(result, "Version: ");
|
||||
ffStrbufSubstrBeforeFirstC(result, '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOptions* options) {
|
||||
if (!instance.config.general.detectVersion) {
|
||||
return "Disabled by config";
|
||||
@@ -236,6 +275,8 @@ const char* ffDetectDEVersion(const FFstrbuf* deName, FFstrbuf* result, FFDEOpti
|
||||
getTrinity(result, options);
|
||||
} else if (ffStrbufEqualS(deName, "COSMIC")) {
|
||||
getCosmic(result, options);
|
||||
} else if (ffStrbufEqualS(deName, FF_DE_PRETTY_ENLIGHTENMENT)) {
|
||||
getEnlightenment(result, options);
|
||||
} else {
|
||||
return "Unsupported DE";
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#define FF_DE_PRETTY_CDE "CDE"
|
||||
#define FF_DE_PRETTY_UNITY "Unity"
|
||||
#define FF_DE_PRETTY_UKUI "UKUI"
|
||||
#define FF_DE_PRETTY_NEBIDE "NebiDE"
|
||||
#define FF_DE_PRETTY_ENLIGHTENMENT "Enlightenment"
|
||||
|
||||
#define FF_WM_PRETTY_KWIN "KWin"
|
||||
#define FF_WM_PRETTY_MUTTER "Mutter"
|
||||
@@ -40,6 +42,7 @@
|
||||
#define FF_WM_PRETTY_FVWM "fvwm"
|
||||
#define FF_WM_PRETTY_CTWM "ctwm"
|
||||
#define FF_WM_PRETTY_RATPOISON "ratpoison"
|
||||
#define FF_WM_PRETTY_ENLIGHTENMENT "Enlightenment"
|
||||
|
||||
#define FF_WM_PROTOCOL_TTY "TTY"
|
||||
#define FF_WM_PROTOCOL_X11 "X11"
|
||||
|
||||
@@ -71,7 +71,9 @@ static struct zxdg_output_v1_listener zxdgOutputListener = {
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL);
|
||||
const char* api = "wayland-global";
|
||||
uint32_t bindVersion = min(version, WL_OUTPUT_DESCRIPTION_SINCE_VERSION);
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, bindVersion, name, wldata->ffwl_output_interface->name, bindVersion, NULL);
|
||||
if (output == NULL) {
|
||||
return "Failed to create wl_output";
|
||||
}
|
||||
@@ -95,12 +97,14 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
|
||||
}
|
||||
|
||||
if (wldata->zxdgOutputManager) {
|
||||
struct wl_proxy* zxdgOutput = wldata->ffwl_proxy_marshal_constructor_versioned(wldata->zxdgOutputManager, ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, version, NULL, output);
|
||||
uint32_t bindVersion = min(version, ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION);
|
||||
struct wl_proxy* zxdgOutput = wldata->ffwl_proxy_marshal_constructor_versioned(wldata->zxdgOutputManager, ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT, &zxdg_output_v1_interface, bindVersion, NULL, output);
|
||||
|
||||
if (zxdgOutput) {
|
||||
wldata->ffwl_proxy_add_listener(zxdgOutput, (void (**)(void)) &zxdgOutputListener, &display);
|
||||
wldata->ffwl_display_roundtrip(wldata->display);
|
||||
wldata->ffwl_proxy_destroy(zxdgOutput);
|
||||
api = "wayland-global-zxdg";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +136,7 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
|
||||
display.id,
|
||||
(uint32_t) display.physicalWidth,
|
||||
(uint32_t) display.physicalHeight,
|
||||
"wayland-global");
|
||||
api);
|
||||
if (item) {
|
||||
if (display.hdrSupported) {
|
||||
item->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
|
||||
@@ -155,7 +159,8 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry*
|
||||
}
|
||||
|
||||
const char* ffWaylandHandleZxdgOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
|
||||
struct wl_proxy* manager = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zxdg_output_manager_v1_interface, version, name, zxdg_output_manager_v1_interface.name, version, NULL);
|
||||
uint32_t bindVersion = min(version, ZXDG_OUTPUT_MANAGER_V1_GET_XDG_OUTPUT_SINCE_VERSION);
|
||||
struct wl_proxy* manager = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zxdg_output_manager_v1_interface, bindVersion, name, zxdg_output_manager_v1_interface.name, bindVersion, NULL);
|
||||
if (manager == NULL) {
|
||||
return "Failed to create zxdg_output_manager_v1";
|
||||
}
|
||||
|
||||
@@ -249,10 +249,12 @@ kde_output_device_registry_v2_destroy(struct kde_output_device_registry_v2* kde_
|
||||
* request until the kde_output_device_registry_v2.finished event is sent.
|
||||
*/
|
||||
// static inline void
|
||||
// kde_output_device_registry_v2_stop(struct kde_output_device_registry_v2 *kde_output_device_registry_v2)
|
||||
// {
|
||||
// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_device_registry_v2,
|
||||
// KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_device_registry_v2), 0);
|
||||
// kde_output_device_registry_v2_stop(struct kde_output_device_registry_v2* kde_output_device_registry_v2) {
|
||||
// wl_proxy_marshal_flags((struct wl_proxy*) kde_output_device_registry_v2,
|
||||
// KDE_OUTPUT_DEVICE_REGISTRY_V2_STOP,
|
||||
// NULL,
|
||||
// wl_proxy_get_version((struct wl_proxy*) kde_output_device_registry_v2),
|
||||
// 0);
|
||||
// }
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_SUBPIXEL_ENUM
|
||||
@@ -383,6 +385,16 @@ enum kde_output_device_v2_capability {
|
||||
* @since 19
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_AUTO_BRIGHTNESS = 0x4000,
|
||||
/**
|
||||
* if this outputdevice supports HDR ICC profiles
|
||||
* @since 22
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_HDR_ICC_PROFILE = 0x8000,
|
||||
/**
|
||||
* if this outputdevice supports the abm level setting
|
||||
* @since 23
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_ABM_LEVEL = 0x10000,
|
||||
};
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
@@ -432,6 +444,14 @@ enum kde_output_device_v2_capability {
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_AUTO_BRIGHTNESS_SINCE_VERSION 19
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_HDR_ICC_PROFILE_SINCE_VERSION 22
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_ABM_LEVEL_SINCE_VERSION 23
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
|
||||
@@ -772,7 +792,7 @@ struct kde_output_device_v2_listener {
|
||||
struct kde_output_device_v2* kde_output_device_v2,
|
||||
uint32_t policy);
|
||||
/**
|
||||
* describes when auto rotate is used
|
||||
* describes the path to the ICC profile used in SDR mode
|
||||
*
|
||||
*
|
||||
* @since 5
|
||||
@@ -821,7 +841,7 @@ struct kde_output_device_v2_listener {
|
||||
struct kde_output_device_v2* kde_output_device_v2,
|
||||
uint32_t gamut_wideness);
|
||||
/**
|
||||
* describes which source the compositor uses for the color profile on an output
|
||||
* describes which source the compositor uses for the color profile on an output in SDR mode
|
||||
*
|
||||
*
|
||||
* @since 7
|
||||
@@ -983,6 +1003,36 @@ struct kde_output_device_v2_listener {
|
||||
*/
|
||||
void (*removed)(void* data,
|
||||
struct kde_output_device_v2* kde_output_device_v2);
|
||||
/**
|
||||
* describes the path to the ICC profile used in HDR mode
|
||||
*
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
void (*hdr_icc_profile_path)(void* data,
|
||||
struct kde_output_device_v2* kde_output_device_v2,
|
||||
const char* profile_path);
|
||||
/**
|
||||
* describes which source the compositor uses for the color profile on an output in HDR mode
|
||||
*
|
||||
*
|
||||
* @since 22
|
||||
*/
|
||||
void (*hdr_color_profile_source)(void* data,
|
||||
struct kde_output_device_v2* kde_output_device_v2,
|
||||
uint32_t source);
|
||||
/**
|
||||
* allowed level of adaptive backlight modulation
|
||||
*
|
||||
* Adaptive backlight modulation is a feature that reduces the
|
||||
* backlight and increases contrast of colors on the screen to
|
||||
* improve power usage.
|
||||
* @param level 0 is off, 4 is the maximum level
|
||||
* @since 23
|
||||
*/
|
||||
void (*abm_level)(void* data,
|
||||
struct kde_output_device_v2* kde_output_device_v2,
|
||||
uint32_t level);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1147,6 +1197,18 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2* kde_output_device
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_REMOVED_SINCE_VERSION 21
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_HDR_ICC_PROFILE_PATH_SINCE_VERSION 22
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_HDR_COLOR_PROFILE_SOURCE_SINCE_VERSION 22
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_ABM_LEVEL_SINCE_VERSION 23
|
||||
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
@@ -1183,10 +1245,12 @@ kde_output_device_v2_destroy(struct kde_output_device_v2* kde_output_device_v2)
|
||||
* the kde_output_device_v2 object.
|
||||
*/
|
||||
// static inline void
|
||||
// kde_output_device_v2_release(struct kde_output_device_v2 *kde_output_device_v2)
|
||||
// {
|
||||
// wl_proxy_marshal_flags((struct wl_proxy *) kde_output_device_v2,
|
||||
// KDE_OUTPUT_DEVICE_V2_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) kde_output_device_v2), WL_MARSHAL_FLAG_DESTROY);
|
||||
// kde_output_device_v2_release(struct kde_output_device_v2* kde_output_device_v2) {
|
||||
// wl_proxy_marshal_flags((struct wl_proxy*) kde_output_device_v2,
|
||||
// KDE_OUTPUT_DEVICE_V2_RELEASE,
|
||||
// NULL,
|
||||
// wl_proxy_get_version((struct wl_proxy*) kde_output_device_v2),
|
||||
// WL_MARSHAL_FLAG_DESTROY);
|
||||
// }
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_MODE_V2_FLAGS_ENUM
|
||||
|
||||
@@ -45,7 +45,7 @@ static const struct wl_message kde_output_device_registry_v2_events[] = {
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_registry_v2_interface = {
|
||||
"kde_output_device_registry_v2",
|
||||
21,
|
||||
23,
|
||||
1,
|
||||
kde_output_device_registry_v2_requests,
|
||||
2,
|
||||
@@ -94,14 +94,17 @@ static const struct wl_message kde_output_device_v2_events[] = {
|
||||
{ "priority", "18u", kde_output_device_v2_types + 0 },
|
||||
{ "auto_brightness", "20u", kde_output_device_v2_types + 0 },
|
||||
{ "removed", "21", kde_output_device_v2_types + 0 },
|
||||
{ "hdr_icc_profile_path", "22s", kde_output_device_v2_types + 0 },
|
||||
{ "hdr_color_profile_source", "22u", kde_output_device_v2_types + 0 },
|
||||
{ "abm_level", "23u", kde_output_device_v2_types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
|
||||
"kde_output_device_v2",
|
||||
21,
|
||||
23,
|
||||
1,
|
||||
kde_output_device_v2_requests,
|
||||
37,
|
||||
40,
|
||||
kde_output_device_v2_events,
|
||||
};
|
||||
|
||||
@@ -115,7 +118,7 @@ static const struct wl_message kde_output_device_mode_v2_events[] = {
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_mode_v2_interface = {
|
||||
"kde_output_device_mode_v2",
|
||||
21,
|
||||
22,
|
||||
0,
|
||||
NULL,
|
||||
5,
|
||||
|
||||
@@ -176,14 +176,11 @@ static struct kde_output_device_v2_listener outputListener = {
|
||||
.max_bits_per_color_range = (void*) stubListener,
|
||||
.automatic_max_bits_per_color_limit = (void*) stubListener,
|
||||
.edr_policy = (void*) stubListener,
|
||||
.sharpness = (void*) stubListener,
|
||||
.priority = (void*) stubListener,
|
||||
.auto_brightness = (void*) stubListener,
|
||||
.removed = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, version, name, kde_output_device_v2_interface.name, version, NULL);
|
||||
uint32_t bindVersion = min(version, KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION);
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_device_v2_interface, bindVersion, name, kde_output_device_v2_interface.name, bindVersion, NULL);
|
||||
if (output == NULL) {
|
||||
return "Failed to create kde_output_device_v2";
|
||||
}
|
||||
@@ -208,6 +205,16 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return "Failed to roundtrip kde_output_device_v2";
|
||||
}
|
||||
// Destroy any mode proxies that were created during the listeners.
|
||||
// wl proxies created for modes are not automatically freed by destroying
|
||||
// the parent output proxy, so destroy them explicitly to avoid leaks.
|
||||
FF_LIST_FOR_EACH (WaylandKdeMode, m, modes) {
|
||||
if (m->pMode) {
|
||||
wldata->ffwl_proxy_destroy((struct wl_proxy*) m->pMode);
|
||||
m->pMode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
|
||||
if (display.width <= 0 || display.height <= 0 || !display.internal) {
|
||||
@@ -265,17 +272,18 @@ static void waylandKdeOutputOrderListener(void* data, FF_A_UNUSED struct kde_out
|
||||
}
|
||||
}
|
||||
|
||||
static const struct kde_output_order_v1_listener orderListener = {
|
||||
.output = waylandKdeOutputOrderListener,
|
||||
.done = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleKdeOutputOrder(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_order_v1_interface, version, name, kde_output_order_v1_interface.name, version, NULL);
|
||||
uint32_t bindVersion = min(version, KDE_OUTPUT_ORDER_V1_OUTPUT_SINCE_VERSION);
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &kde_output_order_v1_interface, bindVersion, name, kde_output_order_v1_interface.name, bindVersion, NULL);
|
||||
if (output == NULL) {
|
||||
return "Failed to create kde_output_order_v1";
|
||||
}
|
||||
|
||||
struct kde_output_order_v1_listener orderListener = {
|
||||
.output = waylandKdeOutputOrderListener,
|
||||
.done = (void*) stubListener,
|
||||
};
|
||||
|
||||
if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &orderListener, &wldata->primaryDisplayId) < 0) {
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return "Failed to add listener to kde_output_order_v1";
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
|
||||
#include "../displayserver_linux.h"
|
||||
|
||||
static inline uint32_t min(uint32_t a, uint32_t b) {
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
typedef enum FF_A_PACKED WaylandProtocolType {
|
||||
FF_WAYLAND_PROTOCOL_TYPE_NONE,
|
||||
FF_WAYLAND_PROTOCOL_TYPE_GLOBAL,
|
||||
|
||||
@@ -183,18 +183,19 @@ static void waylandHandleZwlrHead(void* data, FF_A_UNUSED struct zwlr_output_man
|
||||
wldata->ffwl_proxy_destroy((void*) head);
|
||||
}
|
||||
|
||||
static const struct zwlr_output_manager_v1_listener outputListener = {
|
||||
.head = waylandHandleZwlrHead,
|
||||
.done = (void*) stubListener,
|
||||
.finished = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleZwlrOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) {
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, version, name, zwlr_output_manager_v1_interface.name, version, NULL);
|
||||
uint32_t bindVersion = min(version, ZWLR_OUTPUT_MANAGER_V1_HEAD_SINCE_VERSION);
|
||||
struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, &zwlr_output_manager_v1_interface, bindVersion, name, zwlr_output_manager_v1_interface.name, bindVersion, NULL);
|
||||
if (output == NULL) {
|
||||
return "Failed to bind zwlr_output_manager_v1";
|
||||
}
|
||||
|
||||
const struct zwlr_output_manager_v1_listener outputListener = {
|
||||
.head = waylandHandleZwlrHead,
|
||||
.done = (void*) stubListener,
|
||||
.finished = (void*) stubListener,
|
||||
};
|
||||
|
||||
if (wldata->ffwl_proxy_add_listener(output, (void (**)(void)) &outputListener, wldata) < 0) {
|
||||
wldata->ffwl_proxy_destroy(output);
|
||||
return "Failed to add listener to zwlr_output_manager_v1";
|
||||
|
||||
@@ -267,6 +267,11 @@ static void applyPrettyNameIfDE(FFDisplayServerResult* result, const char* name)
|
||||
ffStrbufSetS(&result->deProcessName, "unity-session");
|
||||
ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_UNITY);
|
||||
}
|
||||
|
||||
else if (ffStrEqualsIgnCase(name, "Enlightenment")) {
|
||||
ffStrbufSetS(&result->deProcessName, "enlightenment_start");
|
||||
ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_ENLIGHTENMENT);
|
||||
}
|
||||
}
|
||||
|
||||
static const char* getFromProcesses(FFDisplayServerResult* result) {
|
||||
|
||||
@@ -87,13 +87,25 @@ static void detectGTKFromSettings(FFGTKResult* result) {
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) ||
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) ||
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) ||
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE)) {
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) ||
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_NEBIDE)) {
|
||||
themeName = ffSettingsGetGnome("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue;
|
||||
iconsName = ffSettingsGetGnome("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue;
|
||||
fontName = ffSettingsGetGnome("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue;
|
||||
cursorTheme = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue;
|
||||
cursorSize = ffSettingsGetGnome("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue;
|
||||
wallpaper = ffSettingsGetGnome("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue;
|
||||
} else if (
|
||||
ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_ENLIGHTENMENT)) {
|
||||
ffEnlightenmentSettings settings = {};
|
||||
if (ffSettingsGetEnlightenmentProperty(&settings)) {
|
||||
themeName = settings.theme;
|
||||
iconsName = settings.icon_theme;
|
||||
fontName = settings.font;
|
||||
cursorTheme = settings.use_e_cursor ? "Enlightenment" : "Application";
|
||||
cursorSize = settings.cursor_size;
|
||||
wallpaper = settings.desktop_default_background;
|
||||
}
|
||||
}
|
||||
|
||||
applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper);
|
||||
|
||||
@@ -51,12 +51,31 @@ static bool getHostVendor(FFstrbuf* vendor) {
|
||||
|
||||
const char* ffDetectHost(FFHostResult* host) {
|
||||
// This is a hack for Asahi Linux, whose product_family is empty
|
||||
if (ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family)) {
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name);
|
||||
bool productName = ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_name", "/sys/class/dmi/id/product_name", &host->name);
|
||||
bool productFamily = ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_family", "/sys/class/dmi/id/product_family", &host->family);
|
||||
if (productName || productFamily) {
|
||||
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);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/product_serial", "/sys/class/dmi/id/product_serial", &host->serial);
|
||||
ffGetSmbiosValue("/sys/devices/virtual/dmi/id/sys_vendor", "/sys/class/dmi/id/sys_vendor", &host->vendor);
|
||||
|
||||
#if __x86_64__
|
||||
ffHostDetectMac(host);
|
||||
#endif
|
||||
|
||||
// KVM/Qemu virtual machine
|
||||
if (ffStrbufStartsWithS(&host->name, "Standard PC")) {
|
||||
ffStrbufPrependS(&host->name, "KVM/QEMU ");
|
||||
}
|
||||
#if __aarch64__
|
||||
else if (host->family.length == 0 && ffStrbufEqualS(&host->vendor, "Apple Inc.") && ffStrbufStartsWithS(&host->name, "Mac")) {
|
||||
// Hack for Asahi Linux
|
||||
ffStrbufDestroy(&host->family);
|
||||
ffStrbufInitMove(&host->family, &host->name);
|
||||
getHostProductName(&host->name);
|
||||
getHostSerialNumber(&host->serial);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
getHostProductFamily(&host->family);
|
||||
getHostProductName(&host->name);
|
||||
@@ -64,15 +83,6 @@ const char* ffDetectHost(FFHostResult* host) {
|
||||
getHostVendor(&host->vendor);
|
||||
}
|
||||
|
||||
#ifdef __x86_64__
|
||||
ffHostDetectMac(host);
|
||||
#endif
|
||||
|
||||
// KVM/Qemu virtual machine
|
||||
if (ffStrbufStartsWithS(&host->name, "Standard PC")) {
|
||||
ffStrbufPrependS(&host->name, "KVM/QEMU ");
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@@ -23,6 +23,8 @@ const FFMediaResult* ffDetectMedia(bool saveCover) {
|
||||
ffStrbufInit(&result.url);
|
||||
ffStrbufInit(&result.status);
|
||||
ffStrbufInit(&result.cover);
|
||||
result.length = 0;
|
||||
result.position = 0;
|
||||
result.removeCoverAfterUse = false;
|
||||
ffDetectMediaImpl(&result, saveCover);
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ typedef struct FFMediaResult {
|
||||
FFstrbuf url;
|
||||
FFstrbuf status;
|
||||
FFstrbuf cover;
|
||||
uint32_t length; // In milliseconds
|
||||
uint32_t position; // In milliseconds
|
||||
bool removeCoverAfterUse;
|
||||
} FFMediaResult;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/processing.h"
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include "common/time.h"
|
||||
#include "detection/media/media.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@@ -8,17 +9,36 @@
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
||||
// https://github.com/andrewwiik/iOS-Blocks/blob/master/Widgets/Music/MediaRemote.h
|
||||
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void(^callback)(_Nullable CFDictionaryRef info)) FF_A_WEAK_IMPORT;
|
||||
extern void MRMediaRemoteGetNowPlayingInfo(dispatch_queue_t dispatcher, void (^callback)(_Nullable CFDictionaryRef info)) FF_A_WEAK_IMPORT;
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) FF_A_WEAK_IMPORT;
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationDisplayID(dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef displayID)) FF_A_WEAK_IMPORT;
|
||||
extern void MRMediaRemoteGetNowPlayingApplicationDisplayName(int unknown, dispatch_queue_t queue, void (^callback)(_Nullable CFStringRef name)) FF_A_WEAK_IMPORT;
|
||||
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
|
||||
{
|
||||
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingApplicationIsPlaying);
|
||||
#undef FF_TEST_FN_EXISTANCE
|
||||
static uint32_t getTrueElapsedTime(CFDictionaryRef info) {
|
||||
double elapsedTime;
|
||||
if (ffCfDictGetDouble(info, CFSTR("kMRMediaRemoteNowPlayingInfoElapsedTime"), &elapsedTime) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
elapsedTime *= 1000;
|
||||
|
||||
double playbackRate;
|
||||
uint64_t timestampEpoch;
|
||||
if (ffCfDictGetDouble(info, CFSTR("kMRMediaRemoteNowPlayingInfoPlaybackRate"), &playbackRate) == NULL &&
|
||||
ffCfDictGetDateAsEpoch(info, CFSTR("kMRMediaRemoteNowPlayingInfoTimestamp"), ×tampEpoch) == NULL) {
|
||||
uint64_t timeDiff = ffTimeGetNow() - timestampEpoch;
|
||||
elapsedTime += (double) timeDiff * playbackRate;
|
||||
}
|
||||
|
||||
return (uint32_t) elapsedTime;
|
||||
}
|
||||
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover) {
|
||||
#define FF_TEST_FN_EXISTENCE(fn) \
|
||||
if (!fn) return "MediaRemote function " #fn " is not available"
|
||||
FF_TEST_FN_EXISTENCE(MRMediaRemoteGetNowPlayingInfo);
|
||||
FF_TEST_FN_EXISTENCE(MRMediaRemoteGetNowPlayingApplicationIsPlaying);
|
||||
#undef FF_TEST_FN_EXISTENCE
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
|
||||
@@ -26,32 +46,33 @@ static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
|
||||
dispatch_group_enter(group);
|
||||
__block const char* error = NULL;
|
||||
MRMediaRemoteGetNowPlayingInfo(queue, ^(_Nullable CFDictionaryRef info) {
|
||||
if(info != nil)
|
||||
{
|
||||
if (info != nil) {
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoTitle"), &result->song);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtist"), &result->artist);
|
||||
ffCfDictGetString(info, CFSTR("kMRMediaRemoteNowPlayingInfoAlbum"), &result->album);
|
||||
double value;
|
||||
if (ffCfDictGetDouble(info, CFSTR("kMRMediaRemoteNowPlayingInfoDuration"), &value) == NULL) {
|
||||
result->length = (uint32_t) (value * 1000);
|
||||
result->position = getTrueElapsedTime(info);
|
||||
}
|
||||
|
||||
if (saveCover)
|
||||
{
|
||||
if (saveCover) {
|
||||
NSData* artworkData = (__bridge NSData*) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkData"));
|
||||
if (artworkData)
|
||||
{
|
||||
if (artworkData) {
|
||||
CFStringRef mime = (CFStringRef) CFDictionaryGetValue(info, CFSTR("kMRMediaRemoteNowPlayingInfoArtworkMIMEType"));
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mime, NULL);
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef ext = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension);
|
||||
#pragma clang diagnostic pop
|
||||
NSString *tmpDir = NSTemporaryDirectory();
|
||||
NSString *uuid = NSUUID.UUID.UUIDString;
|
||||
NSString *path = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"ff_%@.%@", uuid, ext ? (__bridge NSString *) ext : @"img"]];
|
||||
NSString* tmpDir = NSTemporaryDirectory();
|
||||
NSString* uuid = NSUUID.UUID.UUIDString;
|
||||
NSString* path = [tmpDir stringByAppendingPathComponent:[NSString stringWithFormat:@"ff_%@.%@", uuid, ext ? (__bridge NSString*) ext : @"img"]];
|
||||
if ([artworkData writeToFile:path atomically:NO])
|
||||
ffStrbufSetS(&result->cover, path.UTF8String);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
} else
|
||||
error = "MRMediaRemoteGetNowPlayingInfo() failed";
|
||||
|
||||
dispatch_group_leave(group);
|
||||
@@ -63,8 +84,7 @@ static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
|
||||
dispatch_group_leave(group);
|
||||
});
|
||||
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayID)
|
||||
{
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayID) {
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationDisplayID(queue, ^(_Nullable CFStringRef displayID) {
|
||||
ffCfStrGetString(displayID, &result->playerId);
|
||||
@@ -72,8 +92,7 @@ static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
|
||||
});
|
||||
}
|
||||
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayName)
|
||||
{
|
||||
if (MRMediaRemoteGetNowPlayingApplicationDisplayName) {
|
||||
dispatch_group_enter(group);
|
||||
MRMediaRemoteGetNowPlayingApplicationDisplayName(0, queue, ^(_Nullable CFStringRef name) {
|
||||
ffCfStrGetString(name, &result->player);
|
||||
@@ -84,15 +103,14 @@ static const char* getMediaByMediaRemote(FFMediaResult* result, bool saveCover)
|
||||
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
|
||||
// Don't dispatch_release because we are using ARC
|
||||
|
||||
if(result->song.length > 0)
|
||||
if (result->song.length > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"), used))
|
||||
int ffPrintMediaByMediaRemote(bool saveCover)
|
||||
{
|
||||
__attribute__((visibility("default"), used)) int ffPrintMediaByMediaRemote(bool saveCover) {
|
||||
FFMediaResult media = {
|
||||
.status = ffStrbufCreate(),
|
||||
.song = ffStrbufCreate(),
|
||||
@@ -102,15 +120,28 @@ int ffPrintMediaByMediaRemote(bool saveCover)
|
||||
.player = ffStrbufCreate(),
|
||||
.cover = ffStrbufCreate(),
|
||||
};
|
||||
if (getMediaByMediaRemote(&media, saveCover) != NULL)
|
||||
if (getMediaByMediaRemote(&media, saveCover) != NULL) {
|
||||
return 1;
|
||||
ffStrbufPutTo(&media.status, stdout);
|
||||
ffStrbufPutTo(&media.song, stdout);
|
||||
ffStrbufPutTo(&media.artist, stdout);
|
||||
ffStrbufPutTo(&media.album, stdout);
|
||||
ffStrbufPutTo(&media.playerId, stdout);
|
||||
ffStrbufPutTo(&media.player, stdout);
|
||||
ffStrbufWriteTo(&media.cover, stdout);
|
||||
}
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppend(&media.status, &media.song);
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppend(&media.status, &media.artist);
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppend(&media.status, &media.album);
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppend(&media.status, &media.playerId);
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppend(&media.status, &media.player);
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
if (saveCover) {
|
||||
ffStrbufAppend(&media.status, &media.cover);
|
||||
}
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppendUInt(&media.status, media.position);
|
||||
ffStrbufAppendC(&media.status, '\n');
|
||||
ffStrbufAppendUInt(&media.status, media.length);
|
||||
write(STDOUT_FILENO, media.status.chars, media.status.length);
|
||||
ffStrbufDestroy(&media.status);
|
||||
ffStrbufDestroy(&media.song);
|
||||
ffStrbufDestroy(&media.artist);
|
||||
@@ -121,46 +152,55 @@ int ffPrintMediaByMediaRemote(bool saveCover)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char* getMediaByAuthorizedProcess(FFMediaResult* result, bool saveCover)
|
||||
{
|
||||
static const char* getMediaByAuthorizedProcess(FFMediaResult* result, bool saveCover) {
|
||||
// #1737
|
||||
FF_STRBUF_AUTO_DESTROY script = ffStrbufCreateF("import ctypes;ctypes.CDLL('%s').ffPrintMediaByMediaRemote(%s)", instance.state.platform.exePath.chars, saveCover ? "True" : "False");
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
|
||||
"-c",
|
||||
script.chars,
|
||||
nil
|
||||
});
|
||||
if (error) return error;
|
||||
if (buffer.length == 0) return "No media found";
|
||||
const char* error = ffProcessAppendStdOut(
|
||||
&buffer,
|
||||
(char* const[]) { "/usr/bin/python3", // Must be signed by Apple. Homebrew python doesn't work
|
||||
"-c",
|
||||
script.chars,
|
||||
nil });
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
if (buffer.length == 0) {
|
||||
return "No media found";
|
||||
}
|
||||
|
||||
// status\ntitle\nartist\nalbum\nbundleName\nappName
|
||||
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player, &result->cover };
|
||||
// status\ntitle\nartist\nalbum\nbundleName\nappName\ncoverPath\nelapsedTimeMS\ndurationMS
|
||||
FFstrbuf* const strList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player, &result->cover };
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
|
||||
ffStrbufSetS(varList[i], line);
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(strList) && ffStrbufGetline(&line, &len, &buffer); ++i) {
|
||||
ffStrbufSetS(strList[i], line);
|
||||
}
|
||||
uint32_t* const numList[] = { &result->position, &result->length };
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(numList) && ffStrbufGetline(&line, &len, &buffer); ++i) {
|
||||
*numList[i] = (uint32_t) strtoul(line, NULL, 10);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover)
|
||||
{
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover) {
|
||||
const char* error;
|
||||
if (@available(macOS 15.4, *))
|
||||
if (@available(macOS 15.4, *)) {
|
||||
error = getMediaByAuthorizedProcess(media, saveCover);
|
||||
else
|
||||
} else {
|
||||
error = getMediaByMediaRemote(media, saveCover);
|
||||
if (error)
|
||||
}
|
||||
if (error) {
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
else if (media->player.length == 0 && media->playerId.length > 0)
|
||||
{
|
||||
} else if (media->player.length == 0 && media->playerId.length > 0) {
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufStartsWithIgnCaseS(&media->player, "com."))
|
||||
if (ffStrbufStartsWithIgnCaseS(&media->player, "com.")) {
|
||||
ffStrbufSubstrAfter(&media->player, strlen("com.") - 1);
|
||||
}
|
||||
ffStrbufReplaceAllC(&media->player, '.', ' ');
|
||||
if (media->cover.length > 0)
|
||||
if (media->cover.length > 0) {
|
||||
media->removeCoverAfterUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator,
|
||||
break;
|
||||
}
|
||||
} else if (ffStrStartsWith(key, "mpris:")) {
|
||||
const char* xesam = key + strlen("mpris:");
|
||||
if (ffStrEquals(xesam, "artUrl")) {
|
||||
const char* mpris = key + strlen("mpris:");
|
||||
if (ffStrEquals(mpris, "artUrl")) {
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
ffDBusGetString(data, &dictIterator, &path);
|
||||
if (ffStrbufStartsWithS(&path, "file:///")) {
|
||||
@@ -94,6 +94,11 @@ static bool parseMprisMetadata(FFDBusData* data, DBusMessageIter* rootIterator,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (ffStrEquals(mpris, "length")) {
|
||||
int64_t length = 0; // microseconds
|
||||
if (ffDBusGetInt(data, &dictIterator, &length) && length > 0) {
|
||||
result->length = (uint32_t) (length / 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +142,11 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
|
||||
parseMprisMetadata(data, &dictIterator, result);
|
||||
} else if (ffStrEquals(key, "PlaybackStatus")) {
|
||||
ffDBusGetString(data, &dictIterator, &result->status);
|
||||
} else if (ffStrEquals(key, "Position")) {
|
||||
int64_t position = 0; // microseconds
|
||||
if (ffDBusGetInt(data, &dictIterator, &position) && position > 0) {
|
||||
result->position = (uint32_t) (position / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
@@ -232,7 +242,8 @@ static void getBestBus(FFDBusData* data, FFMediaResult* result) {
|
||||
const char* busName;
|
||||
data->lib->ffdbus_message_iter_get_basic(&arrayIterator, &busName);
|
||||
|
||||
if (!ffStrStartsWith(busName, FF_DBUS_MPRIS_PREFIX)) {
|
||||
if (!ffStrStartsWith(busName, FF_DBUS_MPRIS_PREFIX) ||
|
||||
ffStrEquals(busName + strlen(FF_DBUS_MPRIS_PREFIX), "playerctld")) {
|
||||
FF_DBUS_ITER_CONTINUE(data, &arrayIterator)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
#include "common/library.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "media.h"
|
||||
#include "media_windows.dll.h"
|
||||
|
||||
static const char* getMedia(FFMediaResult* media, bool saveCover) {
|
||||
FF_LIBRARY_LOAD_MESSAGE(libffwinrt, "libffwinrt" FF_LIBRARY_EXTENSION, 0)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libffwinrt, ffWinrtDetectMedia)
|
||||
libffwinrt = NULL; // Don't close libffwinrt or it may crash
|
||||
|
||||
FFWinrtMediaResult result = {};
|
||||
|
||||
const char* error = ffffWinrtDetectMedia(&result, saveCover);
|
||||
if (error) {
|
||||
ffStrbufSetStatic(&media->error, error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ffStrbufSetWS(&media->playerId, result.playerId);
|
||||
if (result.playerName[0]) {
|
||||
ffStrbufSetWS(&media->player, result.playerName);
|
||||
} else {
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe")) {
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
}
|
||||
}
|
||||
ffStrbufSetWS(&media->song, result.song);
|
||||
ffStrbufSetWS(&media->artist, result.artist);
|
||||
ffStrbufSetWS(&media->album, result.album);
|
||||
ffStrbufSetWS(&media->cover, result.cover);
|
||||
ffStrbufSetStatic(&media->status, result.status);
|
||||
if (media->cover.length > 0) {
|
||||
media->removeCoverAfterUse = true;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media, bool saveCover) {
|
||||
const char* error = getMedia(media, saveCover);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
extern "C" {
|
||||
#include "media.h"
|
||||
#include "common/time.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/windows/com.h"
|
||||
}
|
||||
|
||||
#if FF_HAVE_WINRT
|
||||
#include <roapi.h>
|
||||
#include <robuffer.h>
|
||||
#include <winstring.h>
|
||||
#include <asyncinfo.h>
|
||||
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
|
||||
#define FF_BIND_FRONT(method, pobject) std::bind_front(&std::remove_cvref_t<decltype(*(pobject))>::method, (pobject))
|
||||
|
||||
using winrt::impl::abi_t;
|
||||
using winrt::Windows::Foundation::IAsyncOperation;
|
||||
using winrt::Windows::Foundation::IAsyncOperationWithProgress;
|
||||
|
||||
static inline void deleteHstring(HSTRING* pstr) {
|
||||
if (*pstr) {
|
||||
WindowsDeleteString(*pstr);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetHstring(FFstrbuf* destination, HSTRING value) {
|
||||
uint32_t length;
|
||||
const wchar_t* raw = WindowsGetStringRawBuffer(value, &length);
|
||||
ffStrbufSetNWS(destination, length, raw);
|
||||
}
|
||||
|
||||
template <typename Interface>
|
||||
static inline HRESULT ffGetActivationFactory(const wchar_t* className, REFIID iid, Interface** factory) {
|
||||
HSTRING_HEADER header;
|
||||
HSTRING runtimeClass;
|
||||
HRESULT hr = WindowsCreateStringReference(className, (UINT32)::wcslen(className), &header, &runtimeClass);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return RoGetActivationFactory(runtimeClass, iid, reinterpret_cast<void**>(factory));
|
||||
}
|
||||
|
||||
template <typename TargetProjection, typename SourceAbi>
|
||||
static inline HRESULT ffQueryInterface(SourceAbi* source, abi_t<TargetProjection>** target) {
|
||||
return source->QueryInterface(winrt::guid_of<TargetProjection>(), reinterpret_cast<void**>(target));
|
||||
}
|
||||
|
||||
template <typename TOperationAbi, typename TResultAbi>
|
||||
static HRESULT ffWaitForAsyncOperation(TOperationAbi* operation, TResultAbi** result) {
|
||||
IAsyncInfo* FF_AUTO_RELEASE_COM_OBJECT asyncInfo = NULL;
|
||||
HRESULT hr = ffQueryInterface<IAsyncInfo>(operation, &asyncInfo);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
AsyncStatus status = AsyncStatus::Started;
|
||||
|
||||
for (;;) {
|
||||
hr = asyncInfo->get_Status(&status);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
if (status == AsyncStatus::Started) {
|
||||
ffTimeSleep(0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (status != AsyncStatus::Completed) {
|
||||
HRESULT errorCode = E_FAIL;
|
||||
asyncInfo->get_ErrorCode(&errorCode);
|
||||
return FAILED(errorCode) ? errorCode : E_FAIL;
|
||||
}
|
||||
|
||||
return operation->GetResults((void**) result);
|
||||
}
|
||||
|
||||
template <typename TResultProjection, typename TOperation, typename... TArgs>
|
||||
static HRESULT ffRunAndWait(TOperation&& operation, abi_t<TResultProjection>** result, TArgs&&... args) {
|
||||
abi_t<IAsyncOperation<TResultProjection>>* FF_AUTO_RELEASE_COM_OBJECT opResult = NULL;
|
||||
HRESULT hr = operation(std::forward<TArgs>(args)..., reinterpret_cast<void**>(&opResult));
|
||||
if (FAILED(hr) || !opResult) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ffWaitForAsyncOperation(opResult, result);
|
||||
}
|
||||
|
||||
template <typename TResultProjection, typename TOperation, typename... TArgs>
|
||||
static HRESULT ffRunAndWait2(TOperation&& operation, abi_t<TResultProjection>** result, TArgs&&... args) {
|
||||
*result = NULL;
|
||||
|
||||
abi_t<IAsyncOperationWithProgress<TResultProjection, int32_t>>* FF_AUTO_RELEASE_COM_OBJECT opResult = NULL;
|
||||
HRESULT hr = operation(std::forward<TArgs>(args)..., reinterpret_cast<void**>(&opResult));
|
||||
if (FAILED(hr) || !opResult) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
return ffWaitForAsyncOperation(opResult, result);
|
||||
}
|
||||
|
||||
static HRESULT ffSaveThumbnailToTempPath(
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamReference>* thumbnail,
|
||||
FFstrbuf* destination) {
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamWithContentType>* FF_AUTO_RELEASE_COM_OBJECT contentStream = NULL;
|
||||
HRESULT hr = ffRunAndWait<winrt::Windows::Storage::Streams::IRandomAccessStreamWithContentType>(FF_BIND_FRONT(OpenReadAsync, thumbnail), &contentStream);
|
||||
if (FAILED(hr) || !contentStream) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStream>* FF_AUTO_RELEASE_COM_OBJECT randomAccessStream = NULL;
|
||||
hr = ffQueryInterface<winrt::Windows::Storage::Streams::IRandomAccessStream>(contentStream, &randomAccessStream);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
UINT64 size = 0;
|
||||
hr = randomAccessStream->get_Size(&size);
|
||||
if (FAILED(hr) || size == 0) {
|
||||
return FAILED(hr) ? hr : S_FALSE;
|
||||
}
|
||||
|
||||
if (size > 0xFFFFFFFFu) {
|
||||
return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE);
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IBufferFactory>* FF_AUTO_RELEASE_COM_OBJECT bufferFactory = NULL;
|
||||
hr = ffGetActivationFactory(L"Windows.Storage.Streams.Buffer", winrt::guid_of<winrt::Windows::Storage::Streams::IBufferFactory>(), &bufferFactory);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IBuffer>* FF_AUTO_RELEASE_COM_OBJECT buffer = NULL;
|
||||
hr = bufferFactory->Create((UINT32) size, reinterpret_cast<void**>(&buffer));
|
||||
if (FAILED(hr) || !buffer) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IInputStream>* FF_AUTO_RELEASE_COM_OBJECT inputStream = NULL;
|
||||
hr = ffQueryInterface<winrt::Windows::Storage::Streams::IInputStream>(contentStream, &inputStream);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Storage::Streams::IBuffer>* FF_AUTO_RELEASE_COM_OBJECT readBuffer = NULL;
|
||||
hr = ffRunAndWait2<winrt::Windows::Storage::Streams::IBuffer>(FF_BIND_FRONT(ReadAsync, inputStream), &readBuffer, buffer, (uint32_t) size, static_cast<uint32_t>(winrt::Windows::Storage::Streams::InputStreamOptions::None));
|
||||
if (FAILED(hr) || !readBuffer) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
UINT32 length = 0;
|
||||
hr = readBuffer->get_Length(&length);
|
||||
if (FAILED(hr) || length == 0) {
|
||||
return FAILED(hr) ? hr : S_FALSE;
|
||||
}
|
||||
|
||||
Windows::Storage::Streams::IBufferByteAccess* FF_AUTO_RELEASE_COM_OBJECT byteAccess = NULL;
|
||||
hr = readBuffer->QueryInterface(IID_PPV_ARGS(&byteAccess));
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
|
||||
byte* bytes = NULL;
|
||||
hr = byteAccess->Buffer(&bytes);
|
||||
if (FAILED(hr) || !bytes) {
|
||||
return FAILED(hr) ? hr : E_FAIL;
|
||||
}
|
||||
|
||||
wchar_t tempDirectory[MAX_PATH];
|
||||
DWORD tempLength = GetTempPathW(MAX_PATH, tempDirectory);
|
||||
if (tempLength == 0 || tempLength >= MAX_PATH) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
wchar_t tempFilePath[MAX_PATH];
|
||||
if (!GetTempFileNameW(tempDirectory, L"fft", 0, tempFilePath)) {
|
||||
return HRESULT_FROM_WIN32(GetLastError());
|
||||
}
|
||||
|
||||
HANDLE file = CreateFileW(tempFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (file == INVALID_HANDLE_VALUE) {
|
||||
DWORD writeError = GetLastError();
|
||||
DeleteFileW(tempFilePath);
|
||||
return HRESULT_FROM_WIN32(writeError);
|
||||
}
|
||||
|
||||
DWORD written = 0;
|
||||
BOOL writtenOk = WriteFile(file, bytes, length, &written, NULL);
|
||||
NtClose(file);
|
||||
file = NULL;
|
||||
|
||||
if (!writtenOk || written != length) {
|
||||
DWORD writeError = GetLastError();
|
||||
DeleteFileW(tempFilePath);
|
||||
return HRESULT_FROM_WIN32(writtenOk ? ERROR_WRITE_FAULT : writeError);
|
||||
}
|
||||
|
||||
ffStrbufSetWS(destination, tempFilePath);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const char* getMedia(FFMediaResult* result, bool saveCover) {
|
||||
const char* error = ffInitCom();
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
do {
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>* FF_AUTO_RELEASE_COM_OBJECT managerStatics = NULL;
|
||||
HRESULT hr = ffGetActivationFactory(L"Windows.Media.Control.GlobalSystemMediaTransportControlsSessionManager", winrt::guid_of<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManagerStatics>(), &managerStatics);
|
||||
if (FAILED(hr) || !managerStatics) {
|
||||
error = "winrt: RoGetActivationFactory(GlobalSystemMediaTransportControlsSessionManager) failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManager>* FF_AUTO_RELEASE_COM_OBJECT manager = NULL;
|
||||
hr = ffRunAndWait<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionManager>(FF_BIND_FRONT(RequestAsync, managerStatics), &manager);
|
||||
if (FAILED(hr) || !manager) {
|
||||
error = "winrt: RequestAsync().GetResults() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING playerId = NULL;
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSession>* FF_AUTO_RELEASE_COM_OBJECT session = NULL;
|
||||
if (instance.config.general.playerName.length) {
|
||||
abi_t<winrt::Windows::Foundation::Collections::IVectorView<winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSession>>* FF_AUTO_RELEASE_COM_OBJECT sessions = NULL;
|
||||
hr = manager->GetSessions(reinterpret_cast<void**>(&sessions));
|
||||
if (FAILED(hr) || !sessions) {
|
||||
error = "winrt: GetSessions() failed";
|
||||
break;
|
||||
}
|
||||
uint32_t sessionCount = 0;
|
||||
hr = sessions->get_Size(&sessionCount);
|
||||
if (FAILED(hr)) {
|
||||
error = "winrt: GetSessions().get_Size() failed";
|
||||
break;
|
||||
}
|
||||
for (uint32_t i = 0; i < sessionCount; i++) {
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSession>* FF_AUTO_RELEASE_COM_OBJECT currentSession = NULL;
|
||||
hr = sessions->GetAt(i, reinterpret_cast<void**>(¤tSession));
|
||||
if (FAILED(hr) || !currentSession) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hr = currentSession->get_SourceAppUserModelId(reinterpret_cast<void**>(&playerId));
|
||||
if (FAILED(hr) || !playerId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufSetHstring(&result->playerId, playerId);
|
||||
|
||||
if (ffStrbufContainIgnCase(&result->playerId, &instance.config.general.playerName)) {
|
||||
session = currentSession;
|
||||
currentSession = NULL; // Don't release the session object
|
||||
break;
|
||||
}
|
||||
deleteHstring(&playerId);
|
||||
ffStrbufClear(&result->playerId);
|
||||
}
|
||||
|
||||
if (!session) {
|
||||
error = "winrt: No media session found with the specified player name";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
hr = manager->GetCurrentSession(reinterpret_cast<void**>(&session));
|
||||
|
||||
if (FAILED(hr) || !session) {
|
||||
error = "winrt: GetCurrentSession() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
hr = session->get_SourceAppUserModelId(reinterpret_cast<void**>(&playerId));
|
||||
if (FAILED(hr)) {
|
||||
error = "winrt: get_SourceAppUserModelId() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
ffStrbufSetHstring(&result->playerId, playerId);
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionMediaProperties>* FF_AUTO_RELEASE_COM_OBJECT mediaProps = NULL;
|
||||
hr = ffRunAndWait<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionMediaProperties>(FF_BIND_FRONT(TryGetMediaPropertiesAsync, session), &mediaProps);
|
||||
if (FAILED(hr) || !mediaProps) {
|
||||
error = "winrt: TryGetMediaPropertiesAsync().GetResults() failed";
|
||||
break;
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionPlaybackInfo>* FF_AUTO_RELEASE_COM_OBJECT playbackInfo = NULL;
|
||||
hr = session->GetPlaybackInfo(reinterpret_cast<void**>(&playbackInfo));
|
||||
bool isPlaying = false;
|
||||
double playbackRate = 1.0;
|
||||
if (SUCCEEDED(hr) && playbackInfo) {
|
||||
int32_t playbackStatusValue = 0;
|
||||
if (SUCCEEDED(playbackInfo->get_PlaybackStatus(&playbackStatusValue))) {
|
||||
isPlaying = playbackStatusValue == static_cast<int32_t>(winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionPlaybackStatus::Playing);
|
||||
switch (static_cast<winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionPlaybackStatus>(playbackStatusValue)) {
|
||||
#define FF_MEDIA_SET_STATUS(status_code) \
|
||||
case winrt::Windows::Media::Control::GlobalSystemMediaTransportControlsSessionPlaybackStatus::status_code: \
|
||||
ffStrbufSetStatic(&result->status, #status_code); \
|
||||
break;
|
||||
FF_MEDIA_SET_STATUS(Closed)
|
||||
FF_MEDIA_SET_STATUS(Opened)
|
||||
FF_MEDIA_SET_STATUS(Changing)
|
||||
FF_MEDIA_SET_STATUS(Stopped)
|
||||
FF_MEDIA_SET_STATUS(Playing)
|
||||
FF_MEDIA_SET_STATUS(Paused)
|
||||
#undef FF_MEDIA_SET_STATUS
|
||||
}
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Foundation::IReference<double>>* FF_AUTO_RELEASE_COM_OBJECT playbackRateRef = NULL;
|
||||
if (SUCCEEDED(playbackInfo->get_PlaybackRate(reinterpret_cast<void**>(&playbackRateRef))) && playbackRateRef) {
|
||||
if (SUCCEEDED(playbackRateRef->get_Value(&playbackRate)) && playbackRate < 0.0) {
|
||||
playbackRate = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING title = NULL;
|
||||
if (SUCCEEDED(mediaProps->get_Title(reinterpret_cast<void**>(&title)))) {
|
||||
ffStrbufSetHstring(&result->song, title);
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING artist = NULL;
|
||||
if (SUCCEEDED(mediaProps->get_Artist(reinterpret_cast<void**>(&artist)))) {
|
||||
ffStrbufSetHstring(&result->artist, artist);
|
||||
}
|
||||
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING album = NULL;
|
||||
if (SUCCEEDED(mediaProps->get_AlbumTitle(reinterpret_cast<void**>(&album)))) {
|
||||
ffStrbufSetHstring(&result->album, album);
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::Media::Control::IGlobalSystemMediaTransportControlsSessionTimelineProperties>* FF_AUTO_RELEASE_COM_OBJECT timelineProps = NULL;
|
||||
hr = session->GetTimelineProperties(reinterpret_cast<void**>(&timelineProps));
|
||||
if (SUCCEEDED(hr) && timelineProps) {
|
||||
int64_t duration = 0;
|
||||
if (SUCCEEDED(timelineProps->get_EndTime(&duration)) && duration > 0) {
|
||||
result->length = (uint32_t) (duration / 10000); // Convert from 100-nanosecond units to milliseconds
|
||||
|
||||
int64_t position = 0;
|
||||
if (SUCCEEDED(timelineProps->get_Position(&position))) {
|
||||
result->position = (uint32_t) (position / 10000); // Convert from 100-nanosecond units to milliseconds
|
||||
|
||||
int64_t lastUpdatedTime = 0;
|
||||
if (isPlaying && SUCCEEDED(timelineProps->get_LastUpdatedTime(&lastUpdatedTime)) && lastUpdatedTime > 0) {
|
||||
uint64_t lastUpdatedTimeMs = ffFileTimeToUnixMs((uint64_t) lastUpdatedTime);
|
||||
uint64_t nowMs = ffTimeGetNow();
|
||||
if (nowMs > lastUpdatedTimeMs) {
|
||||
result->position += (uint32_t) (((double) (nowMs - lastUpdatedTimeMs)) * playbackRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abi_t<winrt::Windows::ApplicationModel::IAppInfoStatics>* FF_AUTO_RELEASE_COM_OBJECT appInfoStatics = NULL;
|
||||
hr = ffGetActivationFactory(L"Windows.ApplicationModel.AppInfo", winrt::guid_of<winrt::Windows::ApplicationModel::IAppInfoStatics>(), &appInfoStatics);
|
||||
if (SUCCEEDED(hr) && appInfoStatics) {
|
||||
abi_t<winrt::Windows::ApplicationModel::IAppInfo>* FF_AUTO_RELEASE_COM_OBJECT appInfo = NULL;
|
||||
if (SUCCEEDED(appInfoStatics->GetFromAppUserModelId(reinterpret_cast<void*>(playerId), reinterpret_cast<void**>(&appInfo))) && appInfo) {
|
||||
abi_t<winrt::Windows::ApplicationModel::IAppDisplayInfo>* FF_AUTO_RELEASE_COM_OBJECT displayInfo = NULL;
|
||||
if (SUCCEEDED(appInfo->get_DisplayInfo(reinterpret_cast<void**>(&displayInfo))) && displayInfo) {
|
||||
FF_A_CLEANUP(deleteHstring) HSTRING displayName = NULL;
|
||||
if (SUCCEEDED(displayInfo->get_DisplayName(reinterpret_cast<void**>(&displayName)))) {
|
||||
ffStrbufSetHstring(&result->player, displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result->player.length == 0) {
|
||||
ffStrbufSet(&result->player, &result->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&result->player, ".exe")) {
|
||||
ffStrbufSubstrBefore(&result->player, result->player.length - 4);
|
||||
}
|
||||
}
|
||||
|
||||
if (saveCover) {
|
||||
abi_t<winrt::Windows::Storage::Streams::IRandomAccessStreamReference>* FF_AUTO_RELEASE_COM_OBJECT thumbnail = NULL;
|
||||
hr = mediaProps->get_Thumbnail(reinterpret_cast<void**>(&thumbnail));
|
||||
if (SUCCEEDED(hr) && thumbnail) {
|
||||
if (SUCCEEDED(ffSaveThumbnailToTempPath(thumbnail, &result->cover)) && result->cover.length > 0) {
|
||||
result->removeCoverAfterUse = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return error;
|
||||
}
|
||||
#else
|
||||
static const char* getMedia(FFMediaResult* media, bool saveCover) {
|
||||
FF_UNUSED(media, saveCover);
|
||||
return "Fastfetch is not compiled with WinRT support";
|
||||
}
|
||||
#endif // FF_HAVE_WINRT
|
||||
|
||||
extern "C" void ffDetectMediaImpl(FFMediaResult* media, bool saveCover) {
|
||||
const char* error = getMedia(media, saveCover);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.Storage.Streams.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <wchar.h>
|
||||
#include <windows.h>
|
||||
|
||||
extern "C" {
|
||||
#include "media_windows.dll.h"
|
||||
|
||||
const char* ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover) {
|
||||
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
|
||||
// Make it a separate dll in order not to break Windows 7 support
|
||||
using namespace winrt::Windows::Media::Control;
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
|
||||
try {
|
||||
auto manager = GlobalSystemMediaTransportControlsSessionManager::RequestAsync().get();
|
||||
if (!manager) {
|
||||
return "winrt: GlobalSystemMediaTransportControlsSessionManager::RequestAsync() failed";
|
||||
}
|
||||
|
||||
auto session = manager.GetCurrentSession();
|
||||
if (!session) {
|
||||
return "winrt: GetCurrentSession() failed";
|
||||
}
|
||||
|
||||
auto mediaProps = session
|
||||
.TryGetMediaPropertiesAsync()
|
||||
.get();
|
||||
if (!mediaProps) {
|
||||
return "winrt: TryGetMediaPropertiesAsync() failed";
|
||||
}
|
||||
|
||||
if (auto playbackInfo = session.GetPlaybackInfo()) {
|
||||
switch (playbackInfo.PlaybackStatus()) {
|
||||
#define FF_MEDIA_SET_STATUS(status_code) \
|
||||
case GlobalSystemMediaTransportControlsSessionPlaybackStatus::status_code: \
|
||||
result->status = #status_code; \
|
||||
break;
|
||||
FF_MEDIA_SET_STATUS(Closed)
|
||||
FF_MEDIA_SET_STATUS(Opened)
|
||||
FF_MEDIA_SET_STATUS(Changing)
|
||||
FF_MEDIA_SET_STATUS(Stopped)
|
||||
FF_MEDIA_SET_STATUS(Playing)
|
||||
FF_MEDIA_SET_STATUS(Paused)
|
||||
#undef FF_MEDIA_SET_STATUS
|
||||
}
|
||||
}
|
||||
|
||||
::wcsncpy(result->playerId, session.SourceAppUserModelId().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->playerId[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->song[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->artist[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->album[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
try {
|
||||
// Only works for UWP apps
|
||||
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->playerName[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
} catch (...) {}
|
||||
|
||||
if (saveCover) {
|
||||
using namespace winrt::Windows::Storage;
|
||||
using namespace winrt::Windows::Storage::Streams;
|
||||
if (auto thumbRef = mediaProps.Thumbnail()) {
|
||||
try {
|
||||
if (auto stream = thumbRef.OpenReadAsync().get()) {
|
||||
if (stream.Size() > 0) {
|
||||
Buffer buffer(static_cast<uint32_t>(stream.Size()));
|
||||
stream.ReadAsync(buffer, buffer.Capacity(), InputStreamOptions::None).get();
|
||||
|
||||
wchar_t tempPath[MAX_PATH];
|
||||
if (GetTempPathW(MAX_PATH, tempPath) > 0) {
|
||||
auto tempFolder = StorageFolder::GetFolderFromPathAsync(tempPath).get();
|
||||
auto tempFile = tempFolder.CreateFileAsync(L"ff_thumb.img", CreationCollisionOption::GenerateUniqueName).get();
|
||||
FileIO::WriteBufferAsync(tempFile, buffer).get();
|
||||
|
||||
::wcsncpy(result->cover, tempFile.Path().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
result->cover[FF_MEDIA_WIN_RESULT_BUFLEN - 1] = L'\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (...) {
|
||||
// Ignore thumbnail errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} catch (...) {
|
||||
return "A C++ exception is thrown";
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define FF_MEDIA_WIN_RESULT_BUFLEN 256
|
||||
|
||||
typedef struct FFWinrtMediaResult {
|
||||
wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t playerName[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t cover[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
const char* status;
|
||||
} FFWinrtMediaResult;
|
||||
|
||||
__attribute__((__dllexport__))
|
||||
const char*
|
||||
ffWinrtDetectMedia(FFWinrtMediaResult* result, bool saveCover);
|
||||
@@ -94,6 +94,14 @@ FF_A_UNUSED static bool getUbuntuFlavour(FFOSResult* result) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// xdgConfigDirs contains plasma only
|
||||
if (ffPathExists("/var/lib/dpkg/info/ubuntustudio-desktop.list", FF_PATHTYPE_FILE)) {
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-studio");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
|
||||
if (!ffStrSet(xdgConfigDirs)) {
|
||||
return false;
|
||||
@@ -141,9 +149,9 @@ FF_A_UNUSED static bool getUbuntuFlavour(FFOSResult* result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ffStrContains(xdgConfigDirs, "studio")) {
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Studio");
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-studio");
|
||||
if (ffStrContains(xdgConfigDirs, "ukui")) {
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Kylin");
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-kylin");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return false;
|
||||
}
|
||||
@@ -162,6 +170,13 @@ FF_A_UNUSED static bool getUbuntuFlavour(FFOSResult* result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ffStrContains(xdgConfigDirs, "unity")) {
|
||||
ffStrbufSetStatic(&result->name, "Ubuntu Unity");
|
||||
ffStrbufSetStatic(&result->id, "ubuntu-unity");
|
||||
ffStrbufSetStatic(&result->idLike, "ubuntu");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -282,7 +297,7 @@ FF_A_UNUSED static bool detectFedoraVariant(FFOSResult* result) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool detectBedrock(FFOSResult* os) {
|
||||
FF_A_UNUSED static bool detectBedrock(FFOSResult* os) {
|
||||
const char* bedrockRestrict = getenv("BEDROCK_RESTRICT");
|
||||
if (bedrockRestrict && bedrockRestrict[0] == '1') {
|
||||
return false;
|
||||
@@ -290,6 +305,34 @@ static bool detectBedrock(FFOSResult* os) {
|
||||
return parseOsRelease(FASTFETCH_TARGET_DIR_ROOT "/bedrock/strata/bedrock/etc/os-release", os);
|
||||
}
|
||||
|
||||
FF_A_UNUSED static void detectDeepinEnhancement(FFOSResult* result) {
|
||||
if (ffStrbufContainC(&result->prettyName, '(')) {
|
||||
return;
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY minor = ffStrbufCreate();
|
||||
FF_STRBUF_AUTO_DESTROY edition = ffStrbufCreate();
|
||||
|
||||
if (!ffParsePropFileValues(
|
||||
FASTFETCH_TARGET_DIR_ETC "/os-version",
|
||||
2,
|
||||
(FFpropquery[]) {
|
||||
{ "MinorVersion=", &minor },
|
||||
{ "EditionName=", &edition },
|
||||
}) ||
|
||||
minor.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ffStrbufSet(&result->versionID, &minor);
|
||||
|
||||
if (edition.length > 0) {
|
||||
ffStrbufSetF(&result->prettyName, "%s %s (%s)", result->name.chars, minor.chars, edition.chars);
|
||||
} else {
|
||||
ffStrbufSetF(&result->prettyName, "%s %s", result->name.chars, minor.chars);
|
||||
}
|
||||
}
|
||||
|
||||
static void detectOS(FFOSResult* os) {
|
||||
#ifdef FF_CUSTOM_OS_RELEASE_PATH
|
||||
parseOsRelease(FF_STR(FF_CUSTOM_OS_RELEASE_PATH), os);
|
||||
@@ -299,13 +342,16 @@ static void detectOS(FFOSResult* os) {
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
if (detectBedrock(os)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Refer: https://gist.github.com/natefoo/814c5bf936922dad97ff
|
||||
|
||||
parseOsRelease(FASTFETCH_TARGET_DIR_ETC "/os-release", os);
|
||||
|
||||
if (os->id.length == 0 || os->version.length == 0 || os->prettyName.length == 0 || os->codename.length == 0) {
|
||||
parseLsbRelease(FASTFETCH_TARGET_DIR_ETC "/lsb-release", os);
|
||||
}
|
||||
@@ -344,6 +390,8 @@ void ffDetectOSImpl(FFOSResult* os) {
|
||||
ffStrbufSetS(&os->id, "lmde");
|
||||
ffStrbufSetS(&os->idLike, "linuxmint");
|
||||
}
|
||||
} else if (ffStrbufEqualS(&os->id, "deepin")) {
|
||||
detectDeepinEnhancement(os);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "os.h"
|
||||
#include "common/library.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/windows/registry.h"
|
||||
#include "common/windows/unicode.h"
|
||||
@@ -56,6 +55,9 @@ void ffDetectOSImpl(FFOSResult* os) {
|
||||
if (ffStrbufStartsWithS(&os->variant, "Server ")) {
|
||||
ffStrbufAppendS(&os->name, " Server");
|
||||
ffStrbufSubstrAfter(&os->variant, strlen(" Server") - 1);
|
||||
} else if (ffStrbufStartsWithS(&os->variant, "Embedded ")) {
|
||||
ffStrbufAppendS(&os->name, " Embedded");
|
||||
ffStrbufSubstrAfter(&os->variant, strlen(" Embedded") - 1);
|
||||
}
|
||||
|
||||
if (ffStrbufStartsWithIgnCaseS(&os->variant, "(TM) ")) {
|
||||
|
||||
@@ -10,6 +10,7 @@ typedef struct FFPackagesResult {
|
||||
uint32_t appimage;
|
||||
uint32_t brew;
|
||||
uint32_t brewCask;
|
||||
uint32_t cards;
|
||||
uint32_t choco;
|
||||
uint32_t dpkg;
|
||||
uint32_t emerge;
|
||||
|
||||
@@ -537,6 +537,9 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_MOSS_BIT)) {
|
||||
packageCounts->moss += getSQLite3Int(baseDir, "/.moss/db/state", "SELECT COUNT(*) FROM state_selections WHERE state_id = (SELECT MAX(id) FROM state)", "moss");
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_CARDS_BIT)) {
|
||||
packageCounts->cards += getNumElements(baseDir, "/var/lib/pkg/DB", true);
|
||||
}
|
||||
}
|
||||
|
||||
static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "publicip.h"
|
||||
#include "common/networking.h"
|
||||
|
||||
#define FF_UNITIALIZED ((const char*) (uintptr_t) -1)
|
||||
#define FF_UNINITIALIZED ((const char*) (uintptr_t) -1)
|
||||
static FFNetworkingState states[2];
|
||||
static const char* statuses[2] = { FF_UNITIALIZED, FF_UNITIALIZED };
|
||||
static const char* statuses[2] = { FF_UNINITIALIZED, FF_UNINITIALIZED };
|
||||
|
||||
void ffPreparePublicIp(FFPublicIPOptions* options) {
|
||||
FFNetworkingState* state = &states[options->ipv6];
|
||||
const char** status = &statuses[options->ipv6];
|
||||
if (*status != FF_UNITIALIZED) {
|
||||
if (*status != FF_UNINITIALIZED) {
|
||||
fputs("Error: PublicIp module can only be used once due to internal limitations\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ static inline void wrapYyjsonFree(yyjson_doc** doc) {
|
||||
const char* ffDetectPublicIp(FFPublicIPOptions* options, FFPublicIpResult* result) {
|
||||
FFNetworkingState* state = &states[options->ipv6];
|
||||
const char** status = &statuses[options->ipv6];
|
||||
if (*status == FF_UNITIALIZED) {
|
||||
if (*status == FF_UNINITIALIZED) {
|
||||
ffPreparePublicIp(options);
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ const char* ffDetectPublicIp(FFPublicIPOptions* options, FFPublicIpResult* resul
|
||||
const char* error = ffNetworkingRecvHttpResponse(state, &response);
|
||||
|
||||
*state = (FFNetworkingState) {};
|
||||
*status = FF_UNITIALIZED;
|
||||
*status = FF_UNINITIALIZED;
|
||||
|
||||
if (error == NULL) {
|
||||
ffStrbufSubstrAfterFirstS(&response, "\r\n\r\n");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user