diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc4394326b..5c9ea24921 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,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_XFCONF=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_DIRECTX_HEADERS=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_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF - name: build project run: cmake --build . --target package --verbose -j4 @@ -83,7 +83,7 @@ jobs: run: cat /proc/cpuinfo - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev + run: sudo apt-get update && sudo apt-get install -y 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 directx-headers-dev - name: install linuxbrew packages run: | @@ -152,7 +152,7 @@ jobs: run: cat /proc/cpuinfo - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm + run: sudo apt-get update && sudo apt-get install -y 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 directx-headers-dev libchafa-dev libddcutil-dev rpm - name: install linuxbrew packages run: | @@ -216,7 +216,7 @@ jobs: # CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments` wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb} dpkg -i *.deb - apt-get install -y make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm + apt-get install -y make g++ 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 directx-headers-dev rpm cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -252,7 +252,7 @@ jobs: run: | uname -a apt-get update && apt-get install -y wget - apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm + apt-get install -y cmake make g++ 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 directx-headers-dev rpm cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -287,7 +287,7 @@ jobs: githubToken: ${{ github.token }} run: | uname -a - apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev libelf-dev directx-headers-dev rpm + apt-get update && apt-get install -y cmake make g++ 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 libelf-dev directx-headers-dev rpm cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -322,7 +322,7 @@ jobs: githubToken: ${{ github.token }} run: | uname -a - apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm + apt-get update && apt-get install -y cmake make g++ 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 directx-headers-dev rpm cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -357,7 +357,7 @@ jobs: githubToken: ${{ github.token }} run: | uname -a - apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm + apt-get update && apt-get install -y cmake make g++ 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 directx-headers-dev rpm cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -386,7 +386,7 @@ jobs: run: | cat /etc/alpine-release uname -a - apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++ + apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++ shell: alpine.sh --root {0} - name: build @@ -560,7 +560,7 @@ jobs: run: | uname -a sudo pkg update - sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa + sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -596,7 +596,7 @@ jobs: version: '7.7' run: | uname -a - sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa + sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On . cmake --build . --target package --verbose -j4 ./fastfetch --list-features @@ -665,7 +665,7 @@ jobs: prepare: | uname -a pkg update - pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf + pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf run: | cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On . @@ -875,7 +875,7 @@ jobs: - name: download artifacts if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 - name: create release if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release diff --git a/CHANGELOG.md b/CHANGELOG.md index d0cbc2263f..d74114c485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,34 @@ +# 2.52.0 + +Changes: +* New optional build dependencies on Android + * main: chafa dbus glib imagemagick libelf libxcb libxrandr pulseaudio zlib + * x11: dconf (Optional) +* Dependency on `libxfconf` is removed. XFCE related detection now uses `libdbus` instead (Linux) +* The default format of `Display` module is updated to `{width}x{height} @ {scale-factor}x in {inch}", {refresh-rate} Hz` + * Replaced scaled resolution with scale factor for shorter texts and avoiding potential confusion. + +Bugfixes: +* Fixes linking on 32-bit Android (#1939) +* Skips network interfaces without IPs unless MAC address is requested (#1949, LocalIP) +* Fixes unexpected padding when setting `logo.width` with chafa logos (#1947, Logo) + * Regression from v2.51.0 +* Improves Wallpaper detection on XFCE4 (Wallpaper, Linux) +* Ignores process `Relay(xxx)` when detecting terminal on WSL2 (Terminal, Linux) + +Features: +* Enables X11-related info (i.e., WM/DE) detection on Android (Global, Android) + * This requires many dependencies. See above. +* Adds scale factors detection for X11 (Display, Linux) + * X11 doesn't natively report scale factor as Wayland does. Instead, Fastfetch tries to detect `Xft.dpi` (DPI used by X FreeType for scaling fonts), which is usually set by the WM when DPI scaling is enabled. + * It's not always accurate. For example, XFCE4 has a separate config for text scaling, which is unaffected by the global DPI scaling setting. +* Adds `display.fraction.trailingZeros: [always|never]` option for fraction formatting + * The default value of `display.fraction.ndigits` is changed from `-1` (unlimited) to `2` for usability. + * Used for displaying scale factor in Display module mentioned above, alongside other places for printing raw fraction numbers. +* Informs users that module-specific CLI options are no longer supported and provide guidance for transitioning to JSON config +* Adds CPU name detection support for IA64 (CPU, Linux) +* Support Btrfs allocation profile detection (#1941, Btrfs, Linux) + # 2.51.1 Bugfixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 865e3409c9..f3b27dd425 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url project(fastfetch - VERSION 2.51.1 + VERSION 2.52.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" @@ -60,25 +60,23 @@ include(CMakeDependentOption) cmake_dependent_option(ENABLE_VULKAN "Enable vulkan" ON "LINUX OR APPLE OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_WAYLAND "Enable wayland-client" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR GNU" OFF) -cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) -cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) +cmake_dependent_option(ENABLE_XCB_RANDR "Enable xcb-randr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) +cmake_dependent_option(ENABLE_XRANDR "Enable xrandr" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_DRM "Enable libdrm" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) 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 SunOS OR GNU" OFF) -cmake_dependent_option(ENABLE_DCONF "Enable dconf" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR GNU" OFF) -cmake_dependent_option(ENABLE_DBUS "Enable dbus-1" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS OR Haiku OR GNU" OFF) -cmake_dependent_option(ENABLE_XFCONF "Enable libxfconf-0" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR SunOS 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_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) -cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR WIN32 OR SunOS OR Haiku OR GNU" OFF) +cmake_dependent_option(ENABLE_IMAGEMAGICK7 "Enable imagemagick 7" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_IMAGEMAGICK6 "Enable imagemagick 6" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR APPLE OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_CHAFA "Enable chafa" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF) -cmake_dependent_option(ENABLE_ZLIB "Enable zlib" ON "ENABLE_IMAGEMAGICK6 OR ENABLE_IMAGEMAGICK7" OFF) cmake_dependent_option(ENABLE_EGL "Enable egl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR WIN32 OR SunOS OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_GLX "Enable glx" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR ANDROID OR SunOS OR GNU" OFF) cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR FreeBSD OR OpenBSD OR NetBSD OR WIN32 OR ANDROID OR SunOS OR Haiku OR GNU" OFF) cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) -cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR GNU" OFF) +cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR ANDROID OR GNU" OFF) cmake_dependent_option(ENABLE_DDCUTIL "Enable ddcutil" ON "LINUX" OFF) cmake_dependent_option(ENABLE_DIRECTX_HEADERS "Enable DirectX headers for WSL" ON "LINUX" OFF) cmake_dependent_option(ENABLE_ELF "Enable libelf" ON "LINUX OR ANDROID OR DragonFly OR Haiku OR GNU" OFF) @@ -86,6 +84,7 @@ cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND" cmake_dependent_option(ENABLE_LIBZFS "Enable libzfs" ON "LINUX OR FreeBSD OR SunOS" OFF) cmake_dependent_option(ENABLE_PCIACCESS "Enable libpciaccess" ON "NetBSD OR OpenBSD" OFF) +option(ENABLE_ZLIB "Enable zlib" ON) option(ENABLE_SYSTEM_YYJSON "Use system provided (instead of fastfetch embedded) yyjson library" OFF) option(ENABLE_ASAN "Build fastfetch with ASAN (address sanitizer)" OFF) option(ENABLE_LTO "Enable link-time optimization in release mode if supported" ON) @@ -515,6 +514,7 @@ if(LINUX) src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_linux.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c @@ -575,6 +575,7 @@ if(LINUX) ) elseif(ANDROID) list(APPEND LIBFASTFETCH_SRC + src/common/dbus.c src/common/io/io_unix.c src/common/netif/netif_linux.c src/common/networking/networking_linux.c @@ -590,7 +591,7 @@ elseif(ANDROID) src/detection/chassis/chassis_nosupport.c src/detection/cpu/cpu_linux.c src/detection/cpucache/cpucache_linux.c - src/detection/cursor/cursor_nosupport.c + src/detection/cursor/cursor_linux.c src/detection/cpuusage/cpuusage_linux.c src/detection/disk/disk_linux.c src/detection/dns/dns_linux.c @@ -598,10 +599,16 @@ elseif(ANDROID) src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_linux.c src/detection/displayserver/displayserver_android.c - src/detection/font/font_nosupport.c + src/detection/displayserver/linux/common.c + src/detection/displayserver/linux/wmde.c + src/detection/displayserver/linux/xcb.c + src/detection/displayserver/linux/xlib.c + src/detection/gtk_qt/gtk.c + src/detection/gtk_qt/qt.c + src/detection/font/font_linux.c src/detection/gpu/gpu_android.c src/detection/host/host_android.c - src/detection/icons/icons_nosupport.c + src/detection/icons/icons_linux.c src/detection/initsystem/initsystem_linux.c src/detection/keyboard/keyboard_nosupport.c src/detection/libc/libc_android.c @@ -610,7 +617,7 @@ elseif(ANDROID) src/detection/locale/locale_linux.c src/detection/localip/localip_linux.c src/detection/gamepad/gamepad_nosupport.c - src/detection/media/media_nosupport.c + src/detection/media/media_linux.c src/detection/memory/memory_linux.c src/detection/mouse/mouse_nosupport.c src/detection/netio/netio_linux.c @@ -620,20 +627,21 @@ elseif(ANDROID) src/detection/packages/packages_nix.c src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_linux.c - src/detection/sound/sound_nosupport.c + src/detection/sound/sound_linux.c src/detection/swap/swap_linux.c src/detection/terminalfont/terminalfont_android.c + src/detection/terminalfont/terminalfont_linux.c src/detection/terminalshell/terminalshell_linux.c src/detection/terminalsize/terminalsize_linux.c - src/detection/theme/theme_nosupport.c + src/detection/theme/theme_linux.c src/detection/tpm/tpm_nosupport.c src/detection/uptime/uptime_linux.c src/detection/users/users_linux.c - src/detection/wallpaper/wallpaper_nosupport.c + src/detection/wallpaper/wallpaper_linux.c src/detection/wifi/wifi_android.c - src/detection/wm/wm_nosupport.c - src/detection/de/de_nosupport.c - src/detection/wmtheme/wmtheme_nosupport.c + src/detection/wm/wm_linux.c + src/detection/de/de_linux.c + src/detection/wmtheme/wmtheme_linux.c src/detection/camera/camera_android.c src/detection/zpool/zpool_nosupport.c src/util/platform/FFPlatform_unix.c @@ -665,6 +673,7 @@ elseif(FreeBSD) src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_bsd.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c @@ -759,6 +768,7 @@ elseif(NetBSD) src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_nbsd.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c @@ -841,6 +851,7 @@ elseif(OpenBSD) src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_obsd.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c @@ -1069,6 +1080,7 @@ elseif(SunOS) src/detection/physicalmemory/physicalmemory_linux.c src/detection/diskio/diskio_sunos.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c @@ -1220,6 +1232,7 @@ elseif(GNU) src/detection/physicalmemory/physicalmemory_nosupport.c src/detection/diskio/diskio_nosupport.c src/detection/displayserver/linux/displayserver_linux.c + src/detection/displayserver/linux/common.c src/detection/displayserver/linux/drm.c src/detection/displayserver/linux/wayland/wayland.c src/detection/displayserver/linux/wayland/global-output.c @@ -1525,10 +1538,6 @@ ff_lib_enable(DBUS "dbus-1" "DBus" ) -ff_lib_enable(XFCONF - "libxfconf-0" - "XFConf" -) ff_lib_enable(SQLITE3 "sqlite3" "SQLite3" @@ -1728,6 +1737,9 @@ elseif(GNU) PRIVATE "m" ) elseif(ANDROID) + target_link_libraries(libfastfetch + PRIVATE "m" + ) CHECK_LIBRARY_EXISTS(-l:libandroid-wordexp.a wordexp "" HAVE_LIBANDROID_WORDEXP_STATIC) if(HAVE_LIBANDROID_WORDEXP_STATIC) target_link_libraries(libfastfetch diff --git a/doc/json_schema.json b/doc/json_schema.json index 660fe2dd8b..6152dd60df 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -1290,10 +1290,19 @@ "description": "Set how frequency values should be displayed", "properties": { "ndigits": { - "type": "integer", - "description": "Set the number of digits to keep after the decimal point when formatting frequency values\nA positive value will show the frequency in GHz with decimal\n-1 will show the frequency in MHz", - "minimum": -1, - "maximum": 9, + "description": "Set the number of decimal places to display when formatting frequency values", + "oneOf": [ + { + "type": "integer", + "minimum": 0, + "maximum": 9, + "description": "Integer value displays the frequency in GHz with specified decimal places" + }, + { + "type": "null", + "description": "Null value display the frequency as integer MHz" + } + ], "default": 2 }, "spaceBeforeUnit": { @@ -1333,6 +1342,28 @@ "description": "The number of digits will be automatically determined based on the value" } ], + "default": 2 + }, + "trailingZeros": { + "description": "Set when to keep trailing zeros", + "oneOf": [ + { + "type": "null", + "description": "Same as `default`" + }, + { + "const": "default", + "description": "Use the behavior defined internally" + }, + { + "const": "always", + "description": "Always keep trailing zeros" + }, + { + "const": "never", + "description": "Never keep trailing zeros" + } + ], "default": null } } diff --git a/src/common/commandoption.c b/src/common/commandoption.c index a0e2493834..a419a7867c 100644 --- a/src/common/commandoption.c +++ b/src/common/commandoption.c @@ -10,6 +10,65 @@ #include #include +bool ffParseModuleOptions(const char* key, const char* value) +{ + if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false; + if (value && !*value) value = NULL; + for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules) + { + FFModuleBaseInfo* baseInfo = *modules; + const char* subKey = ffOptionTestPrefix(key, baseInfo->name); + if (subKey != NULL) + { + if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-' + { + fprintf(stderr, "Error: unknown module key %s\n", key); + exit(477); + } + + FF_STRBUF_AUTO_DESTROY moduleName = ffStrbufCreateS(baseInfo->name); + ffStrbufLowerCase(&moduleName); + + FF_STRBUF_AUTO_DESTROY jsonKey = ffStrbufCreate(); + bool flag = false; + for (const char* p = subKey; *p; ++p) + { + if (*p == '-') + { + if (flag) + { + fprintf(stderr, "Error: invalid double `-` in module key %s\n", key); + exit(477); + } + flag = true; + } + else + { + if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p)) + { + fprintf(stderr, "Error: invalid character `%c` in module key %s\n", *p, key); + exit(477); + } + + if (flag) + { + flag = false; + ffStrbufAppendC(&jsonKey, (char) toupper((unsigned char) *p)); + } + else + ffStrbufAppendC(&jsonKey, *p); + } + } + fprintf(stderr, "Error: Unsupported module option: %s\n", key); + fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr); + fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ? value : "true", value ? "\"" : ""); + fputs(" See for more information.\n", stderr); + exit(477); + } + } + return false; +} + void ffPrepareCommandOption(FFdata* data) { //If we don't have a custom structure, use the default one diff --git a/src/common/commandoption.h b/src/common/commandoption.h index 98472a13af..696bdb861f 100644 --- a/src/common/commandoption.h +++ b/src/common/commandoption.h @@ -12,3 +12,4 @@ typedef struct FFdata void ffPrepareCommandOption(FFdata* data); void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc); void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc); +bool ffParseModuleOptions(const char* key, const char* value); diff --git a/src/common/dbus.c b/src/common/dbus.c index ea438335cb..a2b46e66f8 100644 --- a/src/common/dbus.c +++ b/src/common/dbus.c @@ -162,14 +162,67 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result) return ffDBusGetUint(dbus, &subIter, result); } -DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg) +bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result) +{ + int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); + + if(argType == DBUS_TYPE_INT16) + { + int16_t value = 0; + dbus->lib->ffdbus_message_iter_get_basic(iter, &value); + *result = value; + return true; + } + + if(argType == DBUS_TYPE_INT32) + { + dbus->lib->ffdbus_message_iter_get_basic(iter, result); + return true; + } + + if(argType == DBUS_TYPE_BYTE) + { + uint8_t value = 0; + dbus->lib->ffdbus_message_iter_get_basic(iter, &value); + *result = value; + return true; + } + + if(argType == DBUS_TYPE_UINT16) + { + uint16_t value = 0; + dbus->lib->ffdbus_message_iter_get_basic(iter, &value); + *result = (int16_t) value; + return true; + } + + if(argType == DBUS_TYPE_UINT32) + { + dbus->lib->ffdbus_message_iter_get_basic(iter, result); + return true; + } + + if(argType != DBUS_TYPE_VARIANT) + return false; + + DBusMessageIter subIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); + return ffDBusGetInt(dbus, &subIter, result); +} + +DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2) { DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method); if(message == NULL) return NULL; - if (arg) - dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); + if (arg1) + { + if (arg2) + dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID); + else + dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID); + } DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL); diff --git a/src/common/dbus.h b/src/common/dbus.h index 35a1672f8e..cb55f7680f 100644 --- a/src/common/dbus.h +++ b/src/common/dbus.h @@ -31,14 +31,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); //Returns an 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); -DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg); +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); static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface) { - return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface); + return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL); } #endif // FF_HAVE_DBUS diff --git a/src/common/format.c b/src/common/format.c index f6cbcab8b1..82baaa180b 100644 --- a/src/common/format.c +++ b/src/common/format.c @@ -32,10 +32,10 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg) ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value); break; case FF_FORMAT_ARG_TYPE_FLOAT: - ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits); + ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER); break; case FF_FORMAT_ARG_TYPE_DOUBLE: - ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits); + ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER); break; case FF_FORMAT_ARG_TYPE_BOOL: ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false"); diff --git a/src/common/frequency.c b/src/common/frequency.c index ccb3b707f5..ae13189699 100644 --- a/src/common/frequency.c +++ b/src/common/frequency.c @@ -11,7 +11,7 @@ bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result) if (ndigits >= 0) { - ffStrbufAppendDouble(result, mhz / 1000., ndigits); + ffStrbufAppendDouble(result, mhz / 1000., ndigits, true); if (spaceBeforeUnit) ffStrbufAppendC(result, ' '); ffStrbufAppendS(result, "GHz"); } diff --git a/src/common/init.c b/src/common/init.c index 220dbae053..9735c96ed2 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -208,9 +208,6 @@ void ffListFeatures(void) #if FF_HAVE_ZLIB "zlib\n" #endif - #if FF_HAVE_XFCONF - "xfconf\n" - #endif #if FF_HAVE_SQLITE3 "sqlite3\n" #endif diff --git a/src/common/settings.c b/src/common/settings.c index 63623d550a..1bdae2e603 100644 --- a/src/common/settings.c +++ b/src/common/settings.c @@ -184,7 +184,7 @@ FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type) } #endif //FF_HAVE_DCONF -FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type) +FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type) { FFvariant gsettings = ffSettingsGetGSettings(gsettingsSchemaName, gsettingsPath, gsettingsKey, type); @@ -196,77 +196,151 @@ FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, c return ffSettingsGetDConf(dconfKey, type); } -#ifdef FF_HAVE_XFCONF -#include +#ifdef FF_HAVE_DBUS +#include "common/dbus.h" -typedef struct XFConfData +FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) { - FF_LIBRARY_SYMBOL(xfconf_channel_get) - FF_LIBRARY_SYMBOL(xfconf_channel_has_property) - FF_LIBRARY_SYMBOL(xfconf_channel_get_string) - FF_LIBRARY_SYMBOL(xfconf_channel_get_bool) - FF_LIBRARY_SYMBOL(xfconf_channel_get_int) - FF_LIBRARY_SYMBOL(xfconf_init) + FFDBusData dbus; + if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) + return FF_VARIANT_NULL; - bool inited; -} XFConfData; + DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetProperty", channelName, propertyName); + if(!reply) + return FF_VARIANT_NULL; -static const XFConfData* getXFConfData(void) -{ - static XFConfData data; + DBusMessageIter rootIterator; + if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator)) + { + dbus.lib->ffdbus_message_unref(reply); + return FF_VARIANT_NULL; + } - if (!data.inited) + if(type == FF_VARIANT_TYPE_INT) { - data.inited = true; - FF_LIBRARY_LOAD(libxfconf, NULL, "libxfconf-0" FF_LIBRARY_EXTENSION, 4); - - FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get, NULL) - FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_has_property, NULL) - FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_string, NULL) - FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_bool, NULL) - FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_channel_get_int, NULL) - FF_LIBRARY_LOAD_SYMBOL_VAR(libxfconf, data, xfconf_init, NULL) - if(!data.ffxfconf_init(NULL)) - data.ffxfconf_init = NULL; - else - libxfconf = NULL; + int32_t value; + if (ffDBusGetInt(&dbus, &rootIterator, &value)) + { + dbus.lib->ffdbus_message_unref(reply); + return (FFvariant) { .intValue = value }; + } + return FF_VARIANT_NULL; } - if(!data.ffxfconf_init) - return NULL; + if(type == FF_VARIANT_TYPE_STRING) + { + FFstrbuf value = ffStrbufCreate(); + if (ffDBusGetString(&dbus, &rootIterator, &value)) + { + dbus.lib->ffdbus_message_unref(reply); + return (FFvariant) { .strValue = value.chars }; // Leaks value.chars + } + return FF_VARIANT_NULL; + } - return &data; + if(type == FF_VARIANT_TYPE_BOOL) + { + bool value; + if (ffDBusGetBool(&dbus, &rootIterator, &value)) + { + dbus.lib->ffdbus_message_unref(reply); + return (FFvariant) { .boolValue = value, .boolValueSet = true }; + } + } + + return FF_VARIANT_NULL; } -FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) +#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \ + { \ + if(!(dbus).lib->ffdbus_message_iter_next(iterator)) \ + break; \ + continue; \ + } + +FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb) { - const XFConfData* data = getXFConfData(); - if(data == NULL) + FFDBusData dbus; + if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) return FF_VARIANT_NULL; - XfconfChannel* channel = data->ffxfconf_channel_get(channelName); // Never fails according to documentation but rather returns an empty channel + DBusMessage* reply = ffDBusGetMethodReply(&dbus, "org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "GetAllProperties", channelName, propertyPrefix); + if(!reply) + return FF_VARIANT_NULL; - if(!data->ffxfconf_channel_has_property(channel, propertyName)) + DBusMessageIter rootIterator; + if(!dbus.lib->ffdbus_message_iter_init(reply, &rootIterator)) + { + dbus.lib->ffdbus_message_unref(reply); return FF_VARIANT_NULL; + } - if(type == FF_VARIANT_TYPE_INT) - return (FFvariant) {.intValue = data->ffxfconf_channel_get_int(channel, propertyName, 0)}; + DBusMessageIter arrayIterator; + dbus.lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator); - if(type == FF_VARIANT_TYPE_STRING) - return (FFvariant) {.strValue = data->ffxfconf_channel_get_string(channel, propertyName, NULL)}; + while(true) + { + if(dbus.lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) + FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator) + + DBusMessageIter dictIterator; + dbus.lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator); + + const char* key; + dbus.lib->ffdbus_message_iter_get_basic(&dictIterator, &key); + + if (cb(data, key)) FF_DBUS_ITER_CONTINUE(dbus, &arrayIterator) + dbus.lib->ffdbus_message_iter_next(&dictIterator); + + if(type == FF_VARIANT_TYPE_INT) + { + int32_t value; + if (ffDBusGetInt(&dbus, &dictIterator, &value)) + { + dbus.lib->ffdbus_message_unref(reply); + return (FFvariant) { .intValue = value }; + } + return FF_VARIANT_NULL; + } + + if(type == FF_VARIANT_TYPE_STRING) + { + FFstrbuf value = ffStrbufCreate(); + if (ffDBusGetString(&dbus, &dictIterator, &value)) + { + dbus.lib->ffdbus_message_unref(reply); + return (FFvariant) { .strValue = value.chars }; // Leaks value.chars + } + return FF_VARIANT_NULL; + } + + if(type == FF_VARIANT_TYPE_BOOL) + { + bool value; + if (ffDBusGetBool(&dbus, &dictIterator, &value)) + { + dbus.lib->ffdbus_message_unref(reply); + return (FFvariant) { .boolValue = value, .boolValueSet = true }; + } + } - if(type == FF_VARIANT_TYPE_BOOL) - return (FFvariant) {.boolValue = data->ffxfconf_channel_get_bool(channel, propertyName, false), .boolValueSet = true}; + return FF_VARIANT_NULL; + } return FF_VARIANT_NULL; } -#else //FF_HAVE_XFCONF +#else //FF_HAVE_DBUS FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) { FF_UNUSED(channelName, propertyName, type) return FF_VARIANT_NULL; } -#endif //FF_HAVE_XFCONF +FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb) +{ + FF_UNUSED(channelName, propertyPrefix, type, data, cb); + return FF_VARIANT_NULL; +} +#endif //FF_HAVE_DBUS #ifdef FF_HAVE_SQLITE3 #include diff --git a/src/common/settings.h b/src/common/settings.h index cfe6d093ec..86fd66313d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -24,8 +24,10 @@ typedef union FFvariant FFvariant ffSettingsGetDConf(const char* key, FFvarianttype type); FFvariant ffSettingsGetGSettings(const char* schemaName, const char* path, const char* key, FFvarianttype type); -FFvariant ffSettingsGet(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type); +FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFvarianttype type); FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type); +typedef bool FFTestXfconfPropCallback(void* data, const char* propertyName); // Return false to break loop +FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb); int ffSettingsGetSQLite3Int(const char* dbPath, const char* query); bool ffSettingsGetSQLite3String(const char* dbPath, const char* query, FFstrbuf* result); diff --git a/src/common/size.c b/src/common/size.c index eafe46a53c..07ce86da58 100644 --- a/src/common/size.c +++ b/src/common/size.c @@ -17,7 +17,7 @@ static void appendNum(FFstrbuf* result, uint64_t bytes, uint32_t base, const cha if (counter == 0) ffStrbufAppendUInt(result, bytes); else - ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits); + ffStrbufAppendDouble(result, size, (int8_t) options->sizeNdigits, true); if (options->sizeSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER) ffStrbufAppendC(result, ' '); ffStrbufAppendS(result, prefixes[counter]); diff --git a/src/data/help.json b/src/data/help.json index e99c6867f8..40382f2d8a 100644 --- a/src/data/help.json +++ b/src/data/help.json @@ -846,6 +846,18 @@ "default": -1 } }, + { + "long": "fraction-trailing-zeros", + "desc": "Set when to keep trailing zeros", + "arg": { + "type": "enum", + "enum": { + "default": "Use the behavior defined internally", + "always": "Always keep trailing zeros", + "never": "Never keep trailing zeros" + } + } + }, { "long": "temp-unit", "desc": "Set the temperature unit", diff --git a/src/detection/bluetooth/bluetooth_linux.c b/src/detection/bluetooth/bluetooth_linux.c index ede0bb79da..c56b38558b 100644 --- a/src/detection/bluetooth/bluetooth_linux.c +++ b/src/detection/bluetooth/bluetooth_linux.c @@ -196,7 +196,7 @@ static const char* detectBluetooth(FFlist* devices, int32_t connectedCount) if(error) return error; - DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL); + DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", NULL, NULL); if(!managedObjects) return "Failed to call GetManagedObjects"; diff --git a/src/detection/bluetoothradio/bluetoothradio_linux.c b/src/detection/bluetoothradio/bluetoothradio_linux.c index 50427e57ff..1eb0e4e094 100644 --- a/src/detection/bluetoothradio/bluetoothradio_linux.c +++ b/src/detection/bluetoothradio/bluetoothradio_linux.c @@ -77,7 +77,7 @@ static const char* detectBluetoothRoot(FFBluetoothRadioResult* device, const cha char objPath[300]; snprintf(objPath, sizeof(objPath), "/org/bluez/%s", hciName); - DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1"); + DBusMessage* properties = ffDBusGetMethodReply(dbus, "org.bluez", objPath, "org.freedesktop.DBus.Properties", "GetAll", "org.bluez.Adapter1", NULL); if(!properties) return "Failed to call org.freedesktop.DBus.Properties.GetAll"; diff --git a/src/detection/btrfs/btrfs.h b/src/detection/btrfs/btrfs.h index 8940ebc8ab..3fca957845 100644 --- a/src/detection/btrfs/btrfs.h +++ b/src/detection/btrfs/btrfs.h @@ -8,7 +8,8 @@ typedef struct FFBtrfsDiskUsage uint64_t total; uint64_t used; const char* type; - bool dup; + const char* profile; // single / dup / raidx + uint8_t copies; } FFBtrfsDiskUsage; typedef struct FFBtrfsResult diff --git a/src/detection/btrfs/btrfs_linux.c b/src/detection/btrfs/btrfs_linux.c index e3f6267173..e48496fff7 100644 --- a/src/detection/btrfs/btrfs_linux.c +++ b/src/detection/btrfs/btrfs_linux.c @@ -73,20 +73,40 @@ static const char* detectAllocation(FFBtrfsResult* item, int dfd, FFstrbuf* buff item->globalReservationUsed = ffStrbufToUInt(buffer, 0); item->globalReservationUsed = item->globalReservationTotal - item->globalReservationUsed; - #define FF_BTRFS_DETECT_TYPE(index, _type) \ - if (ffReadFileBufferRelative(subfd, #_type "/total_bytes", buffer)) \ - item->allocation[index].total = ffStrbufToUInt(buffer, 0); \ - \ - if (ffReadFileBufferRelative(subfd, #_type "/bytes_used", buffer)) \ - item->allocation[index].used = ffStrbufToUInt(buffer, 0); \ - \ - item->allocation[index].dup = faccessat(subfd, #_type "/dup/", F_OK, 0) == 0; \ - \ - item->allocation[index].type = #_type; - - FF_BTRFS_DETECT_TYPE(0, data); - FF_BTRFS_DETECT_TYPE(1, metadata); - FF_BTRFS_DETECT_TYPE(2, system); + #define FF_BTRFS_DETECT_PROFILE(_index, _type, _profile, _copies) \ + else if (faccessat(subfd, _type "/" _profile "/", F_OK, 0) == 0) { \ + item->allocation[_index].profile = _profile; \ + item->allocation[_index].copies = _copies; \ + } + + #define FF_BTRFS_DETECT_TYPE(_index, _type) \ + do { \ + item->allocation[_index].type = _type; \ + if (ffReadFileBufferRelative(subfd, _type "/total_bytes", buffer)) \ + item->allocation[_index].total = ffStrbufToUInt(buffer, 0); \ + \ + if (ffReadFileBufferRelative(subfd, _type "/bytes_used", buffer)) \ + item->allocation[_index].used = ffStrbufToUInt(buffer, 0); \ + \ + if (false) {} \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "single", 1) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "dup", 2) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid0", 1) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1", 2) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid10", 2) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c3", 3) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid1c4", 4) \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid5", 1) /* (n-1)/n */ \ + FF_BTRFS_DETECT_PROFILE(_index, _type, "raid6", 1) /* (n-2)/n */ \ + else { \ + item->allocation[_index].profile = "unknown"; \ + item->allocation[_index].copies = 1; \ + } \ + } while (0) + + FF_BTRFS_DETECT_TYPE(0, "data"); + FF_BTRFS_DETECT_TYPE(1, "metadata"); + FF_BTRFS_DETECT_TYPE(2, "system"); #undef FF_BTRFS_DETECT_TYPE diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 0c4cda4097..112bced88c 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -353,6 +353,10 @@ static const char* parseCpuInfo( (cpu->name.length == 0 && ffParsePropLine(line, "processor 0:", &cpu->name)) || (cpu->vendor.length == 0 && ffParsePropLine(line, "vendor_id :", &cpu->vendor)) || (cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz static :", cpuMHz)) || // This one cannot be detected because of early return + #elif __ia64__ + (cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) || + (cpu->vendor.length == 0 && ffParsePropLine(line, "vendor :", &cpu->vendor)) || + (cpuMHz->length == 0 && ffParsePropLine(line, "cpu MHz :", cpuMHz)) || #else (cpu->name.length == 0 && ffParsePropLine(line, "model name :", &cpu->name)) || (cpu->name.length == 0 && ffParsePropLine(line, "model :", &cpu->name)) || diff --git a/src/detection/displayserver/displayserver.h b/src/detection/displayserver/displayserver.h index f502f175a3..3e9efea084 100644 --- a/src/detection/displayserver/displayserver.h +++ b/src/detection/displayserver/displayserver.h @@ -44,6 +44,7 @@ #define FF_WM_PROTOCOL_TTY "TTY" #define FF_WM_PROTOCOL_X11 "X11" #define FF_WM_PROTOCOL_WAYLAND "Wayland" +#define FF_WM_PROTOCOL_SURFACEFLINGER "SurfaceFlinger" typedef enum __attribute__((__packed__)) FFDisplayType { FF_DISPLAY_TYPE_UNKNOWN, diff --git a/src/detection/displayserver/displayserver_android.c b/src/detection/displayserver/displayserver_android.c index abe7235fbc..04070565df 100644 --- a/src/detection/displayserver/displayserver_android.c +++ b/src/detection/displayserver/displayserver_android.c @@ -1,6 +1,7 @@ #include "displayserver.h" #include "common/settings.h" #include "common/processing.h" +#include "linux/displayserver_linux.h" #include @@ -82,13 +83,10 @@ static void detectWithDumpsys(FFDisplayServerResult* ds) ffStrbufRecalculateLength(&name); FFDisplayResult* display = ffdsAppendDisplay(ds, - (uint32_t)width, - (uint32_t)height, + (uint32_t)width, (uint32_t)height, refreshRate, - 0, - 0, - 0, - 0, + 0, 0, + 0, 0, 0, 0, &name, @@ -121,13 +119,10 @@ static bool detectWithGetprop(FFDisplayServerResult* ds) ffStrbufSubstrAfterFirstC(&buffer, ','); double scaleFactor = (double) ffStrbufToUInt(&buffer, 0) / 160.; FFDisplayResult* display = ffdsAppendDisplay(ds, - width, - height, - 0, - (uint32_t) (width / scaleFactor + .5), - (uint32_t) (height / scaleFactor + .5), - 0, + width, height, 0, + (uint32_t) (width / scaleFactor + .5), (uint32_t) (height / scaleFactor + .5), + 0, 0, 0, 0, NULL, @@ -147,8 +142,19 @@ static bool detectWithGetprop(FFDisplayServerResult* ds) void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) { - ffStrbufSetStatic(&ds->wmProcessName, "surfaceflinger"); - ffStrbufSetStatic(&ds->wmPrettyName, "SurfaceFlinger"); + const char* error = ffdsConnectXcbRandr(ds); + if (error) + error = ffdsConnectXrandr(ds); + if (!error) + { + ffdsDetectWMDE(ds); + return; + } + + // https://source.android.com/docs/core/graphics/surfaceflinger-windowmanager + ffStrbufSetStatic(&ds->wmProcessName, "system_server"); + ffStrbufSetStatic(&ds->wmPrettyName, "WindowManager"); // A system service managed by system_server + ffStrbufSetStatic(&ds->wmProtocolName, FF_WM_PROTOCOL_SURFACEFLINGER); if (!detectWithGetprop(ds)) detectWithDumpsys(ds); diff --git a/src/detection/displayserver/linux/common.c b/src/detection/displayserver/linux/common.c new file mode 100644 index 0000000000..71abee2b97 --- /dev/null +++ b/src/detection/displayserver/linux/common.c @@ -0,0 +1,16 @@ +#include "displayserver_linux.h" +#include "util/stringUtils.h" + +FFDisplayType ffdsGetDisplayType(const char* name) +{ + if(ffStrStartsWith(name, "eDP-") || ffStrStartsWith(name, "LVDS-")) + return FF_DISPLAY_TYPE_BUILTIN; + else if(ffStrStartsWith(name, "HDMI-") || + ffStrStartsWith(name, "DP-") || + ffStrStartsWith(name, "DisplayPort-") || + ffStrStartsWith(name, "DVI-") || + ffStrStartsWith(name, "VGA-")) + return FF_DISPLAY_TYPE_EXTERNAL; + + return FF_DISPLAY_TYPE_UNKNOWN; +} diff --git a/src/detection/displayserver/linux/displayserver_linux.c b/src/detection/displayserver/linux/displayserver_linux.c index 63b2c83152..f86105c0bf 100644 --- a/src/detection/displayserver/linux/displayserver_linux.c +++ b/src/detection/displayserver/linux/displayserver_linux.c @@ -95,17 +95,3 @@ void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) ffdsDetectWMDE(ds); } } - -FFDisplayType ffdsGetDisplayType(const char* name) -{ - if(ffStrStartsWith(name, "eDP-") || ffStrStartsWith(name, "LVDS-")) - return FF_DISPLAY_TYPE_BUILTIN; - else if(ffStrStartsWith(name, "HDMI-") || - ffStrStartsWith(name, "DP-") || - ffStrStartsWith(name, "DisplayPort-") || - ffStrStartsWith(name, "DVI-") || - ffStrStartsWith(name, "VGA-")) - return FF_DISPLAY_TYPE_EXTERNAL; - - return FF_DISPLAY_TYPE_UNKNOWN; -} diff --git a/src/detection/displayserver/linux/drm.c b/src/detection/displayserver/linux/drm.c index d3a5e99549..141b49466f 100644 --- a/src/detection/displayserver/linux/drm.c +++ b/src/detection/displayserver/linux/drm.c @@ -396,13 +396,10 @@ static const char* drmConnectLibdrm(FFDisplayServerResult* result) } FFDisplayResult* item = ffdsAppendDisplay(result, - width, - height, + width, height, refreshRate, - 0, - 0, - preferredWidth, - preferredHeight, + 0, 0, + preferredWidth, preferredHeight, preferredRefreshRate, 0, &name, diff --git a/src/detection/displayserver/linux/wayland/global-output.c b/src/detection/displayserver/linux/wayland/global-output.c index 206dc14f22..36a9ff22d2 100644 --- a/src/detection/displayserver/linux/wayland/global-output.c +++ b/src/detection/displayserver/linux/wayland/global-output.c @@ -128,8 +128,8 @@ const char* ffWaylandHandleGlobalOutput(WaylandData* wldata, struct wl_registry* (uint32_t) display.width, (uint32_t) display.height, display.refreshRate / 1000.0, - (uint32_t) (display.width / display.scale), - (uint32_t) (display.height / display.scale), + (uint32_t) (display.width / display.scale + .5), + (uint32_t) (display.height / display.scale + .5), (uint32_t) display.preferredWidth, (uint32_t) display.preferredHeight, display.preferredRefreshRate / 1000.0, diff --git a/src/detection/displayserver/linux/wayland/kde-output.c b/src/detection/displayserver/linux/wayland/kde-output.c index 59be773dfb..9b18f9061e 100644 --- a/src/detection/displayserver/linux/wayland/kde-output.c +++ b/src/detection/displayserver/linux/wayland/kde-output.c @@ -220,8 +220,8 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re (uint32_t) display.width, (uint32_t) display.height, display.refreshRate / 1000.0, - (uint32_t) (display.width / display.scale), - (uint32_t) (display.height / display.scale), + (uint32_t) (display.width / display.scale + .5), + (uint32_t) (display.height / display.scale + .5), (uint32_t) display.preferredWidth, (uint32_t) display.preferredHeight, display.preferredRefreshRate / 1000.0, diff --git a/src/detection/displayserver/linux/wmde.c b/src/detection/displayserver/linux/wmde.c index 8310c4bc9a..164cf5aaee 100644 --- a/src/detection/displayserver/linux/wmde.c +++ b/src/detection/displayserver/linux/wmde.c @@ -65,7 +65,7 @@ static const char* parseEnv(void) if(getenv("SWAYSOCK") != NULL) return "Sway"; - #ifdef __linux__ + #if __linux__ && !__ANDROID__ if( getenv("WAYLAND_DISPLAY") != NULL && ffPathExists("/mnt/wslg/", FF_PATHTYPE_DIRECTORY) @@ -433,6 +433,11 @@ static const char* getFromProcesses(FFDisplayServerResult* result) void ffdsDetectWMDE(FFDisplayServerResult* result) { + #if __ANDROID__ + if(ffStrbufIgnCaseEqualS(&result->wmProtocolName, FF_WM_PROTOCOL_SURFACEFLINGER)) + return; // Only supported when connected to X11 + #endif + const char* env = parseEnv(); if(result->wmProcessName.length > 0) diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 796ef8632e..795e46bf2c 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -3,7 +3,7 @@ #ifdef FF_HAVE_XCB_RANDR #include "common/library.h" -#include "common/time.h" +#include "common/properties.h" #include "util/edidHelper.h" #include "util/mallocHelper.h" #include "util/stringUtils.h" @@ -56,7 +56,7 @@ static void* xcbGetProperty(XcbPropertyData* data, xcb_connection_t* connection, if(requestAtomReply == NULL) return NULL; - xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 64); + xcb_get_property_cookie_t propertyCookie = data->ffxcb_get_property(connection, false, window, requestAtomReply->atom, XCB_ATOM_ANY, 0, 8 * 1024); FF_AUTO_FREE xcb_get_property_reply_t* propertyReply = data->ffxcb_get_property_reply(connection, propertyCookie, NULL); if(propertyReply == NULL) @@ -138,14 +138,38 @@ typedef struct XcbRandrData xcb_connection_t* connection; FFDisplayServerResult* result; XcbPropertyData propData; - - //init per screen - xcb_randr_get_screen_resources_current_reply_t* screenResources; } XcbRandrData; -static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrbuf* name, bool primary, xcb_randr_get_output_info_reply_t* output, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength) +static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor) { - xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, crtc, XCB_CURRENT_TIME); + xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME); + FF_AUTO_FREE xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL); + if(outputInfoReply == NULL) + return false; + + xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen("EDID"), "EDID"); + FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL); + FF_AUTO_FREE xcb_randr_get_output_property_reply_t* outputPropertyReply = NULL; + uint8_t* edidData = NULL; + uint32_t edidLength = 0; + if(requestAtomReply) + { + xcb_randr_get_output_property_cookie_t outputPropertyCookie = data->ffxcb_randr_get_output_property(data->connection, output, requestAtomReply->atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 100, false, false); + outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); + if(outputPropertyReply) + { + int len = data->ffxcb_randr_get_output_property_data_length(outputPropertyReply); + if(len >= 128) + { + ffStrbufClear(name); + edidData = data->ffxcb_randr_get_output_property_data(outputPropertyReply); + ffEdidGetName(edidData, name); + edidLength = (uint32_t) len; + } + } + } + + xcb_randr_get_crtc_info_cookie_t crtcInfoCookie = data->ffxcb_randr_get_crtc_info(data->connection, outputInfoReply->crtc, XCB_CURRENT_TIME); FF_AUTO_FREE xcb_randr_get_crtc_info_reply_t* crtcInfoReply = data->ffxcb_randr_get_crtc_info_reply(data->connection, crtcInfoCookie, NULL); if(crtcInfoReply == NULL) return false; @@ -170,11 +194,11 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb xcb_randr_mode_info_t* currentMode = NULL; xcb_randr_mode_info_t* preferredMode = NULL; - if(data->screenResources) + if(screenResources) { - xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(data->screenResources); + xcb_randr_mode_info_iterator_t modesIterator = data->ffxcb_randr_get_screen_resources_current_modes_iterator(screenResources); - if (output->num_preferred > 0) + if (outputInfoReply->num_preferred > 0) preferredMode = modesIterator.data; while (modesIterator.rem > 0) @@ -194,8 +218,8 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb (uint32_t) crtcInfoReply->width, (uint32_t) crtcInfoReply->height, currentMode ? (double) currentMode->dot_clock / (double) ((uint32_t) currentMode->htotal * currentMode->vtotal) : 0, - (uint32_t) crtcInfoReply->width, - (uint32_t) crtcInfoReply->height, + (uint32_t) (crtcInfoReply->width / scaleFactor + .5), + (uint32_t) (crtcInfoReply->height / scaleFactor + .5), preferredMode ? (uint32_t) preferredMode->width : 0, preferredMode ? (uint32_t) preferredMode->height : 0, preferredMode ? (double) preferredMode->dot_clock / (double) ((uint32_t) preferredMode->htotal * preferredMode->vtotal) : 0, @@ -204,54 +228,21 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc, FFstrb displayType, primary, 0, - (uint32_t) output->mm_width, - (uint32_t) output->mm_height, + (uint32_t) outputInfoReply->mm_width, + (uint32_t) outputInfoReply->mm_height, "xcb-randr-crtc" ); if (item && edidLength) { item->hdrStatus = ffEdidGetHdrCompatible(edidData, (uint32_t) edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + item->bitDepth = bitDepth; } return !!item; } -static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, FFstrbuf* name, bool primary, FFDisplayType displayType) -{ - xcb_randr_get_output_info_cookie_t outputInfoCookie = data->ffxcb_randr_get_output_info(data->connection, output, XCB_CURRENT_TIME); - FF_AUTO_FREE xcb_randr_get_output_info_reply_t* outputInfoReply = data->ffxcb_randr_get_output_info_reply(data->connection, outputInfoCookie, NULL); - if(outputInfoReply == NULL) - return false; - - xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen("EDID"), "EDID"); - FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL); - FF_AUTO_FREE xcb_randr_get_output_property_reply_t* outputPropertyReply = NULL; - uint8_t* edidData = NULL; - uint32_t edidLength = 0; - if(requestAtomReply) - { - xcb_randr_get_output_property_cookie_t outputPropertyCookie = data->ffxcb_randr_get_output_property(data->connection, output, requestAtomReply->atom, XCB_GET_PROPERTY_TYPE_ANY, 0, 100, false, false); - outputPropertyReply = data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); - if(outputPropertyReply) - { - int len = data->ffxcb_randr_get_output_property_data_length(outputPropertyReply); - if(len >= 128) - { - ffStrbufClear(name); - edidData = data->ffxcb_randr_get_output_property_data(outputPropertyReply); - ffEdidGetName(edidData, name); - edidLength = (uint32_t) len; - } - } - } - - bool res = xcbRandrHandleCrtc(data, outputInfoReply->crtc, name, primary, outputInfoReply, displayType, edidData, edidLength); - - return res; -} - -static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor) +static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* monitor, struct xcb_randr_get_screen_resources_current_reply_t* screenResources, uint8_t bitDepth, double scaleFactor) { //for some reasons, we have to construct this our self xcb_randr_output_iterator_t outputIterator = { @@ -275,18 +266,20 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* while(outputIterator.rem > 0) { - if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType)) + if(xcbRandrHandleOutput(data, *outputIterator.data, &name, monitor->primary, displayType, screenResources, bitDepth, scaleFactor)) foundOutput = true; data->ffxcb_randr_output_next(&outputIterator); - }; + } - return foundOutput ? true : !!ffdsAppendDisplay( + if (foundOutput) return true; + + FFDisplayResult* display = ffdsAppendDisplay( data->result, (uint32_t) monitor->width, (uint32_t) monitor->height, 0, - (uint32_t) monitor->width, - (uint32_t) monitor->height, + (uint32_t) (monitor->width / scaleFactor + .5), + (uint32_t) (monitor->height / scaleFactor + .5), 0, 0, 0, 0, &name, @@ -297,6 +290,8 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* (uint32_t) monitor->height_in_millimeters, "xcb-randr-monitor" ); + if (display) display->bitDepth = bitDepth; + return !!display; } static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen) @@ -306,13 +301,27 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen) if(monitorsReply == NULL) return false; + //Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible. + xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root); + FF_AUTO_FREE struct xcb_randr_get_screen_resources_current_reply_t* screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL); + + double scaleFactor = 1; + FF_AUTO_FREE const char* resourceManager = xcbGetProperty(&data->propData, data->connection, screen->root, "RESOURCE_MANAGER"); + if (resourceManager) + { + FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate(); + if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi)) + scaleFactor = ffStrbufToDouble(&dpi, 96) / 96; + } + uint8_t bitDepth = (uint8_t) (screen->root_depth / 3); + xcb_randr_monitor_info_iterator_t monitorInfoIterator = data->ffxcb_randr_get_monitors_monitors_iterator(monitorsReply); bool foundMonitor = false; while(monitorInfoIterator.rem > 0) { - if(xcbRandrHandleMonitor(data, monitorInfoIterator.data)) + if(xcbRandrHandleMonitor(data, monitorInfoIterator.data, screenResources, bitDepth, scaleFactor)) foundMonitor = true; data->ffxcb_randr_monitor_info_next(&monitorInfoIterator); } @@ -322,17 +331,8 @@ static bool xcbRandrHandleMonitors(XcbRandrData* data, xcb_screen_t* screen) static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen) { - //Init screen resources. They are used to iterate over all modes. xcbRandrHandleMode checks for " == NULL", to fail as late as possible. - xcb_randr_get_screen_resources_current_cookie_t screenResourcesCookie = data->ffxcb_randr_get_screen_resources_current(data->connection, screen->root); - - data->screenResources = data->ffxcb_randr_get_screen_resources_current_reply(data->connection, screenResourcesCookie, NULL); - //With all the initialisation done, start the detection - bool ret = xcbRandrHandleMonitors(data, screen); - - free(data->screenResources); - - if(ret) + if(xcbRandrHandleMonitors(data, screen)) return; //If detetction failed, fallback to screen = monitor, like in the libxcb.so implementation @@ -348,7 +348,7 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen) NULL, FF_DISPLAY_TYPE_UNKNOWN, false, - 0, + (uint64_t) screen->root, (uint32_t) screen->width_in_millimeters, (uint32_t) screen->height_in_millimeters, "xcb-randr-screen" diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index c0381231cf..bc2e83a774 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -3,7 +3,7 @@ #ifdef FF_HAVE_XRANDR #include "common/library.h" -#include "common/parsing.h" +#include "common/properties.h" #include "util/edidHelper.h" #include "util/stringUtils.h" @@ -70,8 +70,6 @@ static void x11FetchServerVendor(X11PropertyData* data, Display* display, FFDisp if (serverVendor && !ffStrEquals(serverVendor, "The X.Org Foundation")) { ffStrbufSetS(&result->wmProtocolName, serverVendor); } - - } typedef struct XrandrData @@ -92,18 +90,16 @@ typedef struct XrandrData //Init once Display* display; FFDisplayServerResult* result; - - //Init per screen - XRRScreenResources* screenResources; + X11PropertyData* propData; } XrandrData; -static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength) +static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* name, bool primary, FFDisplayType displayType, uint8_t* edidData, uint32_t edidLength, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor) { //We do the check here, because we want the best fallback display if this call failed - if(data->screenResources == NULL) + if(screenResources == NULL) return false; - XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, data->screenResources, output->crtc); + XRRCrtcInfo* crtcInfo = data->ffXRRGetCrtcInfo(data->display, screenResources, output->crtc); if(crtcInfo == NULL) return false; @@ -125,27 +121,24 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* } XRRModeInfo* currentMode = NULL; - if (data->screenResources) + for(int i = 0; i < screenResources->nmode; i++) { - for(int i = 0; i < data->screenResources->nmode; i++) + if(screenResources->modes[i].id == crtcInfo->mode) { - if(data->screenResources->modes[i].id == crtcInfo->mode) - { - currentMode = &data->screenResources->modes[i]; - break; - } + currentMode = &screenResources->modes[i]; + break; } } - XRRModeInfo* preferredMode = data->screenResources && output->npreferred > 0 ? &data->screenResources->modes[0] : NULL; + XRRModeInfo* preferredMode = output->npreferred > 0 ? &screenResources->modes[0] : NULL; FFDisplayResult* item = ffdsAppendDisplay( data->result, (uint32_t) crtcInfo->width, (uint32_t) crtcInfo->height, currentMode ? (double) currentMode->dotClock / (double) ((uint32_t) currentMode->hTotal * currentMode->vTotal) : 0, - (uint32_t) crtcInfo->width, - (uint32_t) crtcInfo->height, + (uint32_t) (crtcInfo->width / scaleFactor + .5), + (uint32_t) (crtcInfo->height / scaleFactor + .5), preferredMode ? (uint32_t) preferredMode->width : 0, preferredMode ? (uint32_t) preferredMode->height : 0, preferredMode ? (double) preferredMode->dotClock / (double) ((uint32_t) preferredMode->hTotal * preferredMode->vTotal) : 0, @@ -159,19 +152,23 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* "xlib-randr-crtc" ); - if (item && edidLength) + if (item) { - item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; - ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + if (edidLength) + { + item->hdrStatus = ffEdidGetHdrCompatible(edidData, edidLength) ? FF_DISPLAY_HDR_STATUS_SUPPORTED : FF_DISPLAY_HDR_STATUS_UNSUPPORTED; + ffEdidGetSerialAndManufactureDate(edidData, &item->serial, &item->manufactureYear, &item->manufactureWeek); + } + item->bitDepth = bitDepth; } data->ffXRRFreeCrtcInfo(crtcInfo); return !!item; } -static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType) +static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name, bool primary, FFDisplayType displayType, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor) { - XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, data->screenResources, output); + XRROutputInfo* outputInfo = data->ffXRRGetOutputInfo(data->display, screenResources, output); if(outputInfo == NULL) return false; @@ -195,7 +192,7 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name } } - bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength); + bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength, screenResources, bitDepth, scaleFactor); if (edidData) data->ffXFree(edidData); @@ -204,7 +201,7 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name return res; } -static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo) +static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo, XRRScreenResources* screenResources, uint8_t bitDepth, double scaleFactor) { bool foundOutput = false; char* xname = data->ffXGetAtomName(data->display, monitorInfo->name); @@ -213,17 +210,19 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo) FFDisplayType displayType = ffdsGetDisplayType(name.chars); for(int i = 0; i < monitorInfo->noutput; i++) { - if(xrandrHandleOutput(data, monitorInfo->outputs[i], &name, monitorInfo->primary, displayType)) + if(xrandrHandleOutput(data, monitorInfo->outputs[i], &name, monitorInfo->primary, displayType, screenResources, bitDepth, scaleFactor)) foundOutput = true; } - return foundOutput ? true : !!ffdsAppendDisplay( + if (foundOutput) return true; + + FFDisplayResult* display = ffdsAppendDisplay( data->result, (uint32_t) monitorInfo->width, (uint32_t) monitorInfo->height, 0, - (uint32_t) monitorInfo->width, - (uint32_t) monitorInfo->height, + (uint32_t) (monitorInfo->width / scaleFactor + .5), + (uint32_t) (monitorInfo->height / scaleFactor + .5), 0, 0, 0, 0, &name, @@ -234,6 +233,8 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo) (uint32_t) monitorInfo->mheight, "xlib-randr-monitor" ); + if (display) display->bitDepth = bitDepth; + return !!display; } static bool xrandrHandleMonitors(XrandrData* data, Screen* screen) @@ -243,29 +244,36 @@ static bool xrandrHandleMonitors(XrandrData* data, Screen* screen) if(monitorInfos == NULL) return false; + XRRScreenResources* screenResources = data->ffXRRGetScreenResourcesCurrent(data->display, RootWindowOfScreen(screen)); + + double scaleFactor = 1; + char* resourceManager = (char*) x11GetProperty(data->propData, data->display, screen->root, "RESOURCE_MANAGER"); + if (resourceManager) + { + FF_STRBUF_AUTO_DESTROY dpi = ffStrbufCreate(); + if (ffParsePropLines(resourceManager, "Xft.dpi:", &dpi)) + scaleFactor = ffStrbufToDouble(&dpi, 96) / 96; + data->ffXFree(resourceManager); + } + uint8_t bitDepth = (uint8_t) (screen->root_depth / 3); + bool foundAMonitor = false; for(int i = 0; i < numberOfMonitors; i++) { - if(xrandrHandleMonitor(data, &monitorInfos[i])) + if(xrandrHandleMonitor(data, &monitorInfos[i], screenResources, bitDepth, scaleFactor)) foundAMonitor = true; } data->ffXRRFreeMonitors(monitorInfos); + data->ffXRRFreeScreenResources(screenResources); return foundAMonitor; } static void xrandrHandleScreen(XrandrData* data, Screen* screen) { - //Init screen resources - data->screenResources = data->ffXRRGetScreenResourcesCurrent(data->display, RootWindowOfScreen(screen)); - - bool ret = xrandrHandleMonitors(data, screen); - - data->ffXRRFreeScreenResources(data->screenResources); - - if(ret) + if(xrandrHandleMonitors(data, screen)) return; //Fallback to screen @@ -281,7 +289,7 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen) NULL, FF_DISPLAY_TYPE_UNKNOWN, false, - 0, + RootWindowOfScreen(screen), (uint32_t) WidthMMOfScreen(screen), (uint32_t) HeightMMOfScreen(screen), "xlib-randr-screen" @@ -312,6 +320,7 @@ const char* ffdsConnectXrandr(FFDisplayServerResult* result) X11PropertyData propertyData; bool propertyDataInitialized = x11InitPropertyData(xrandr, &propertyData); + data.propData = &propertyData; data.display = ffXOpenDisplay(NULL); if(data.display == NULL) diff --git a/src/detection/font/font_linux.c b/src/detection/font/font_linux.c index 4d58392c96..e3253379cf 100644 --- a/src/detection/font/font_linux.c +++ b/src/detection/font/font_linux.c @@ -28,7 +28,7 @@ const char* ffDetectFontImpl(FFFontResult* result) { const FFDisplayServerResult* wmde = ffConnectDisplayServer(); - if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) + if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY)) return "Font isn't supported in TTY"; FFfont qt; diff --git a/src/detection/gtk_qt/gtk.c b/src/detection/gtk_qt/gtk.c index da3bbd02b1..575568ada9 100644 --- a/src/detection/gtk_qt/gtk.c +++ b/src/detection/gtk_qt/gtk.c @@ -34,6 +34,13 @@ static inline void applyGTKSettings(FFGTKResult* result, const char* themeName, ffStrbufAppendS(&result->wallpaper, wallpaper); } +static bool testXfconfWallpaperPropKey(FF_MAYBE_UNUSED void* data, const char* key) +{ + int count = 0; + sscanf(key, "/backdrop/screen0/monitor%*[^/]/workspace0/last-image%n", &count); + return count == 0; +} + static void detectGTKFromSettings(FFGTKResult* result) { static const char* themeName = NULL; @@ -55,47 +62,45 @@ static void detectGTKFromSettings(FFGTKResult* result) const FFDisplayServerResult* wmde = ffConnectDisplayServer(); - if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4) == 0) + if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4)) { themeName = ffSettingsGetXFConf("xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue; iconsName = ffSettingsGetXFConf("xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue; fontName = ffSettingsGetXFConf("xsettings", "/Gtk/FontName", FF_VARIANT_TYPE_STRING).strValue; cursorTheme = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue; cursorSize = ffSettingsGetXFConf("xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue; - wallpaper = ffSettingsGetXFConf("xfce4-desktop", "/backdrop/screen0/monitor0/workspace0/last-image", FF_VARIANT_TYPE_STRING).strValue; - if (!wallpaper) // FIXME: find a way to enumerate possible properties - wallpaper = ffSettingsGetXFConf("xfce4-desktop", "/backdrop/screen0/monitoreDP-1/workspace0/last-image", FF_VARIANT_TYPE_STRING).strValue; + wallpaper = ffSettingsGetXFConfFirstMatch("xfce4-desktop", "/backdrop/screen0", FF_VARIANT_TYPE_STRING, NULL, testXfconfWallpaperPropKey).strValue; } - else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON) == 0) + else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON)) { - themeName = ffSettingsGet("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; - iconsName = ffSettingsGet("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; - fontName = ffSettingsGet("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; - cursorTheme = ffSettingsGet("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; - cursorSize = ffSettingsGet("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; - wallpaper = ffSettingsGet("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue; + themeName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; + iconsName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; + fontName = ffSettingsGetGnome("/org/cinnamon/desktop/interface/font-name", "org.cinnamon.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; + cursorTheme = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; + cursorSize = ffSettingsGetGnome("/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; + wallpaper = ffSettingsGetGnome("/org/cinnamon/desktop/background/picture-uri", "org.cinnamon.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue; } - else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_MATE) == 0) + else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, FF_DE_PRETTY_MATE)) { - themeName = ffSettingsGet("/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; - iconsName = ffSettingsGet("/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; - fontName = ffSettingsGet("/org/mate/interface/font-name", "org.mate.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; - cursorTheme = ffSettingsGet("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; - cursorSize = ffSettingsGet("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; - wallpaper = ffSettingsGet("/org/mate/desktop/background", "org.mate.background", NULL, "picture-filename", FF_VARIANT_TYPE_STRING).strValue; + themeName = ffSettingsGetGnome("/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; + iconsName = ffSettingsGetGnome("/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; + fontName = ffSettingsGetGnome("/org/mate/interface/font-name", "org.mate.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; + cursorTheme = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-theme", "org.mate.peripherals-mouse", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; + cursorSize = ffSettingsGetGnome("/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; + wallpaper = ffSettingsGetGnome("/org/mate/desktop/background", "org.mate.background", NULL, "picture-filename", FF_VARIANT_TYPE_STRING).strValue; } else if( - ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) == 0 || - ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) == 0 || - ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) == 0 || - ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) == 0 + 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) ) { - themeName = ffSettingsGet("/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; - iconsName = ffSettingsGet("/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; - fontName = ffSettingsGet("/org/gnome/desktop/interface/font-name", "org.gnome.desktop.interface", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; - cursorTheme = ffSettingsGet("/org/gnome/desktop/interface/cursor-theme", "org.gnome.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; - cursorSize = ffSettingsGet("/org/gnome/desktop/interface/cursor-size", "org.gnome.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; - wallpaper = ffSettingsGet("/org/gnome/desktop/background/picture-uri", "org.gnome.desktop.background", NULL, "picture-uri", FF_VARIANT_TYPE_STRING).strValue; + 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; } applyGTKSettings(result, themeName, iconsName, fontName, cursorTheme, cursorSize, wallpaper); diff --git a/src/detection/icons/icons_linux.c b/src/detection/icons/icons_linux.c index 623e0813da..e5727b1955 100644 --- a/src/detection/icons/icons_linux.c +++ b/src/detection/icons/icons_linux.c @@ -7,7 +7,7 @@ const char* ffDetectIcons(FFIconsResult* result) { const FFDisplayServerResult* wmde = ffConnectDisplayServer(); - if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) + if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY)) return "Icons aren't supported in TTY"; const FFstrbuf* plasma = &ffDetectQt()->icons; diff --git a/src/detection/localip/localip_linux.c b/src/detection/localip/localip_linux.c index 36604bd206..962e259c09 100644 --- a/src/detection/localip/localip_linux.c +++ b/src/detection/localip/localip_linux.c @@ -414,6 +414,13 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) FF_DEBUG("Processing adapter %s (IPv4 entries: %u, IPv6 entries: %u)", adapter->mac->ifa_name, adapter->ipv4.length, adapter->ipv6.length); + if (adapter->ipv4.length == 0 && adapter->ipv6.length == 0 && + !(options->showType & FF_LOCALIP_TYPE_MAC_BIT) ) + { + FF_DEBUG("Skipping interface %s (no IP addresses)", adapter->mac->ifa_name); + continue; + } + FFLocalIpResult* item = FF_LIST_ADD(FFLocalIpResult, *results); ffStrbufInitS(&item->name, adapter->mac->ifa_name); ffStrbufInit(&item->ipv4); diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index 16ba329a08..adc600f0fd 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -191,7 +191,7 @@ static void getBestBus(FFDBusData* data, FFMediaResult* result) getBusProperties(data, FF_DBUS_MPRIS_PREFIX "plasma-browser-integration", result) ) return; - DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", NULL); + DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", NULL, NULL); if(reply == NULL) return; diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index fe1f8e52c1..847788fb10 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -266,7 +266,7 @@ static bool detectRio(FFTerminalFontResult* terminalFont) return true; } -void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont); +bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont); static bool detectTerminalFontCommon(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { diff --git a/src/detection/terminalfont/terminalfont_android.c b/src/detection/terminalfont/terminalfont_android.c index 318c321f2e..9727fb6b61 100644 --- a/src/detection/terminalfont/terminalfont_android.c +++ b/src/detection/terminalfont/terminalfont_android.c @@ -13,6 +13,12 @@ const char* detectTermux(FFTerminalFontResult* terminalFont) { + if(!ffPathExists(FF_TERMUX_FONT_PATH, FF_PATHTYPE_FILE)) + { + ffFontInitCopy(&terminalFont->font, "monospace"); + return NULL; + } + #ifdef FF_HAVE_FREETYPE FF_LIBRARY_LOAD(freetype, "dlopen libfreetype"FF_LIBRARY_EXTENSION " failed", "libfreetype"FF_LIBRARY_EXTENSION, 2) @@ -53,19 +59,15 @@ const char* detectTermux(FFTerminalFontResult* terminalFont) #endif } -void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) +bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { - if(ffStrbufCompS(&terminal->processName, "com.termux") != 0) + if(ffStrbufEqualS(&terminal->processName, "com.termux")) + ffStrbufSetS(&terminalFont->error, detectTermux(terminalFont)); + else { - ffStrbufSetS(&terminalFont->error, "Unsupported terminal"); - return; - } - - if(!ffPathExists(FF_TERMUX_FONT_PATH, FF_PATHTYPE_FILE)) - { - ffFontInitCopy(&terminalFont->font, "monospace"); - return; + bool ffDetectTerminalFontPlatformLinux(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont); + return ffDetectTerminalFontPlatformLinux(terminal, terminalFont); } - ffStrbufSetS(&terminalFont->error, detectTermux(terminalFont)); + return true; } diff --git a/src/detection/terminalfont/terminalfont_apple.m b/src/detection/terminalfont/terminalfont_apple.m index 90fed7fd16..2ee70007b7 100644 --- a/src/detection/terminalfont/terminalfont_apple.m +++ b/src/detection/terminalfont/terminalfont_apple.m @@ -91,7 +91,7 @@ static void detectWarpTerminal(FFTerminalFontResult* terminalFont) ffFontInitValues(&terminalFont->font, fontName.UTF8String, fontSize.UTF8String); } -void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) +bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { if(ffStrbufIgnCaseEqualS(&terminal->processName, "iterm.app") || ffStrbufStartsWithIgnCaseS(&terminal->processName, "iTermServer-")) @@ -100,4 +100,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo detectAppleTerminal(terminalFont); else if(ffStrbufIgnCaseEqualS(&terminal->processName, "WarpTerminal")) detectWarpTerminal(terminalFont); + else + return false; + return true; } diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index ef762e9618..8e1151a49c 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -16,26 +16,26 @@ static const char* getSystemMonospaceFont(void) if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, "Cinnamon")) { - const char* systemMonospaceFont = ffSettingsGet("/org/cinnamon/desktop/interface/monospace-font-name", "org.cinnamon.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue; + const char* systemMonospaceFont = ffSettingsGetGnome("/org/cinnamon/desktop/interface/monospace-font-name", "org.cinnamon.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue; if(ffStrSet(systemMonospaceFont)) return systemMonospaceFont; } else if(ffStrbufIgnCaseEqualS(&wmde->dePrettyName, "Mate")) { - const char* systemMonospaceFont = ffSettingsGet("/org/mate/interface/monospace-font-name", "org.mate.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue; + const char* systemMonospaceFont = ffSettingsGetGnome("/org/mate/interface/monospace-font-name", "org.mate.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue; if(ffStrSet(systemMonospaceFont)) return systemMonospaceFont; } - return ffSettingsGet("/org/gnome/desktop/interface/monospace-font-name", "org.gnome.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue; + return ffSettingsGetGnome("/org/gnome/desktop/interface/monospace-font-name", "org.gnome.desktop.interface", NULL, "monospace-font-name", FF_VARIANT_TYPE_STRING).strValue; } static void detectKgx(FFTerminalFontResult* terminalFont) { // kgx (gnome console) doesn't support profiles - if(!ffSettingsGet("/org/gnome/Console/use-system-font", "org.gnome.Console", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) + if(!ffSettingsGetGnome("/org/gnome/Console/use-system-font", "org.gnome.Console", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) { - FF_AUTO_FREE const char* fontName = ffSettingsGet("/org/gnome/Console/custom-font", "org.gnome.Console", NULL, "custom-font", FF_VARIANT_TYPE_STRING).strValue; + FF_AUTO_FREE const char* fontName = ffSettingsGetGnome("/org/gnome/Console/custom-font", "org.gnome.Console", NULL, "custom-font", FF_VARIANT_TYPE_STRING).strValue; if(ffStrSet(fontName)) ffFontInitPango(&terminalFont->font, fontName); else @@ -53,9 +53,9 @@ static void detectKgx(FFTerminalFontResult* terminalFont) static void detectPtyxis(FFTerminalFontResult* terminalFont) { - if(!ffSettingsGet("/org/gnome/Ptyxis/use-system-font", "org.gnome.Ptyxis", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) + if(!ffSettingsGetGnome("/org/gnome/Ptyxis/use-system-font", "org.gnome.Ptyxis", NULL, "use-system-font", FF_VARIANT_TYPE_BOOL).boolValue) { - FF_AUTO_FREE const char* fontName = ffSettingsGet("/org/gnome/Ptyxis/font-name", "org.gnome.Ptyxis", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; + FF_AUTO_FREE const char* fontName = ffSettingsGetGnome("/org/gnome/Ptyxis/font-name", "org.gnome.Ptyxis", NULL, "font-name", FF_VARIANT_TYPE_STRING).strValue; if(ffStrSet(fontName)) ffFontInitPango(&terminalFont->font, fontName); else @@ -167,7 +167,7 @@ static void detectXFCETerminal(FFTerminalFontResult* terminalFont) }); } - if(configFound && (useSysFont.length == 0 || ffStrbufIgnCaseCompS(&useSysFont, "false") == 0)) + if(configFound && (useSysFont.length == 0 || ffStrbufIgnCaseEqualS(&useSysFont, "false"))) { if(fontName.length == 0) ffStrbufAppendF(&terminalFont->error, "Couldn't find FontName in %s", path); @@ -433,7 +433,13 @@ static void detectHaikuTerminal(FFTerminalFontResult* terminalFont) } #endif -void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) +bool +#ifdef __ANDROID__ +ffDetectTerminalFontPlatformLinux +#else +ffDetectTerminalFontPlatform +#endif +(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { if(ffStrbufIgnCaseEqualS(&terminal->processName, "konsole")) detectKonsole(terminalFont, "konsolerc"); @@ -477,4 +483,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo #endif else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "termite")) detectFromConfigFile("termite/config", "font =", terminalFont); + else + return false; + return true; } diff --git a/src/detection/terminalfont/terminalfont_windows.c b/src/detection/terminalfont/terminalfont_windows.c index 8c541603e3..059e1ac511 100644 --- a/src/detection/terminalfont/terminalfont_windows.c +++ b/src/detection/terminalfont/terminalfont_windows.c @@ -274,7 +274,7 @@ static void detectWarp(FFTerminalFontResult* terminalFont) ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars); } -void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) +bool ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFontResult* terminalFont) { if(ffStrbufIgnCaseEqualS(&terminal->processName, "Windows Terminal") || ffStrbufIgnCaseEqualS(&terminal->processName, "WindowsTerminal.exe")) @@ -287,4 +287,7 @@ void ffDetectTerminalFontPlatform(const FFTerminalResult* terminal, FFTerminalFo detectConEmu(terminalFont); else if(ffStrbufStartsWithIgnCaseS(&terminal->processName, "warp")) detectWarp(terminalFont); + else + return false; + return true; } diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 0f50b04521..03b4711d50 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -111,6 +111,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid) ffStrbufEqualS(&result->processName, "proot") || ffStrbufEqualS(&result->processName, "script") || #ifdef __linux__ + ffStrbufStartsWithS(&result->processName, "Relay(") || // Unknown process in WSL2 ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707 #endif ffStrbufEndsWithS(&result->processName, ".sh") diff --git a/src/detection/theme/theme_linux.c b/src/detection/theme/theme_linux.c index 4b4844286f..650130775f 100644 --- a/src/detection/theme/theme_linux.c +++ b/src/detection/theme/theme_linux.c @@ -7,7 +7,7 @@ const char* ffDetectTheme(FFThemeResult* result) { const FFDisplayServerResult* wmde = ffConnectDisplayServer(); - if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) + if(ffStrbufIgnCaseEqualS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY)) return "Theme isn't supported in TTY"; const FFQtResult* plasma = ffDetectQt(); diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index b76ebc82a7..1826c656c3 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -57,7 +57,7 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { FF_DEBUG("Getting device by IP interface name"); - DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars); + DBusMessage* device = ffDBusGetMethodReply(&dbus, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager", "GetDeviceByIpIface", item->inf.description.chars, NULL); if(!device) { FF_DEBUG("GetDeviceByIpIface failed for interface %s", item->inf.description.chars); diff --git a/src/detection/wm/wm_linux.c b/src/detection/wm/wm_linux.c index 6e7cc97852..4697976e8a 100644 --- a/src/detection/wm/wm_linux.c +++ b/src/detection/wm/wm_linux.c @@ -13,6 +13,17 @@ const char* ffDetectWMPlugin(FF_MAYBE_UNUSED FFstrbuf* pluginName) return "Not supported on this platform"; } +static bool extractCommonWmVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata) +{ + int count = 0; + sscanf(line, "%*d.%*d.%*d%n", &count); + if (count == 0) return true; + + ffStrbufSetNS((FFstrbuf*) userdata, len, line); + return false; +} + +#if !__ANDROID__ static bool extractHyprlandVersion(const char* line, uint32_t len, void *userdata) { if (line[0] != 'v') return true; @@ -128,23 +139,13 @@ static const char* getSway(FFstrbuf* result) return "Failed to run command `sway --version`"; } -static bool extractI3Version(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata) -{ - int count = 0; - sscanf(line, "%*d.%*d%n", &count); - if (count == 0) return true; - - ffStrbufSetNS((FFstrbuf*) userdata, len, line); - return false; -} - -static const char* getI3(FFstrbuf* result) +static const char* getLabwc(FFstrbuf* result) { FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); - const char* error = ffFindExecutableInPath("i3", &path); - if (error) return "Failed to find i3 executable path"; + const char* error = ffFindExecutableInPath("labwc", &path); + if (error) return "Failed to find labwc executable path"; - ffBinaryExtractStrings(path.chars, extractI3Version, result, (uint32_t) strlen("0.0")); + ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0")); if (result->length > 0) return NULL; if (ffProcessAppendStdOut(result, (char* const[]){ @@ -152,15 +153,16 @@ static const char* getI3(FFstrbuf* result) "--version", NULL }) == NULL) - { // i3 version 1.10 C 2009... - ffStrbufSubstrAfterFirstS(result, "version "); + { // labwc 0.9.0 (+xwayland +nls +rsvg +libsfdo) + ffStrbufSubstrAfterFirstC(result, ' '); ffStrbufSubstrBeforeFirstC(result, ' '); return NULL; } - return "Failed to run command `i3 --version`"; + return "Failed to run command `labwc --version`"; } +#ifdef __linux__ static const char* getWslg(FFstrbuf* result) { if (!ffAppendFileBuffer("/mnt/wslg/versions.txt", result)) @@ -175,17 +177,43 @@ static const char* getWslg(FFstrbuf* result) ffStrbufTrimLeft(result, ' '); return NULL; } +#endif -static bool extractCommonWmVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata) +#endif // !__ANDROID__ + +static bool extractI3Version(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata) { int count = 0; - sscanf(line, "%*d.%*d.%*d%n", &count); + sscanf(line, "%*d.%*d%n", &count); if (count == 0) return true; ffStrbufSetNS((FFstrbuf*) userdata, len, line); return false; } +static const char* getI3(FFstrbuf* result) +{ + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); + const char* error = ffFindExecutableInPath("i3", &path); + if (error) return "Failed to find i3 executable path"; + + ffBinaryExtractStrings(path.chars, extractI3Version, result, (uint32_t) strlen("0.0")); + if (result->length > 0) return NULL; + + if (ffProcessAppendStdOut(result, (char* const[]){ + path.chars, + "--version", + NULL + }) == NULL) + { // i3 version 1.10 C 2009... + ffStrbufSubstrAfterFirstS(result, "version "); + ffStrbufSubstrBeforeFirstC(result, ' '); + return NULL; + } + + return "Failed to run command `i3 --version`"; +} + static const char* getCtwm(FFstrbuf* result) { FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); @@ -255,45 +283,31 @@ static const char* getOpenbox(FFstrbuf* result) return "Failed to run command `openbox --version`"; } -static const char* getLabwc(FFstrbuf* result) -{ - FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); - const char* error = ffFindExecutableInPath("labwc", &path); - if (error) return "Failed to find labwc executable path"; - - ffBinaryExtractStrings(path.chars, extractCommonWmVersion, result, (uint32_t) strlen("0.0.0")); - if (result->length > 0) return NULL; - - if (ffProcessAppendStdOut(result, (char* const[]){ - path.chars, - "--version", - NULL - }) == NULL) - { // labwc 0.9.0 (+xwayland +nls +rsvg +libsfdo) - ffStrbufSubstrAfterFirstC(result, ' '); - ffStrbufSubstrBeforeFirstC(result, ' '); - return NULL; - } - - return "Failed to run command `labwc --version`"; -} - const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options) { if (!wmName) return "No WM detected"; + #if !__ANDROID__ + // Wayland compositors if (ffStrbufIgnCaseEqualS(wmName, "Hyprland")) return getHyprland(result); if (ffStrbufEqualS(wmName, "sway")) return getSway(result); - if (ffStrbufEqualS(wmName, "i3")) - return getI3(result); + if (ffStrbufEqualS(wmName, "labwc")) + return getLabwc(result); + #if __linux__ if (ffStrbufEqualS(wmName, "WSLg")) return getWslg(result); + #endif + #endif + + // X11 WMs + if (ffStrbufEqualS(wmName, "i3")) + return getI3(result); if (ffStrbufEqualS(wmName, "ctwm")) return getCtwm(result); @@ -304,8 +318,5 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE if (ffStrbufEqualS(wmName, "Openbox")) return getOpenbox(result); - if (ffStrbufEqualS(wmName, "labwc")) - return getLabwc(result); - return "Unsupported WM"; } diff --git a/src/detection/wmtheme/wmtheme_linux.c b/src/detection/wmtheme/wmtheme_linux.c index bed430c435..2c4d1694aa 100644 --- a/src/detection/wmtheme/wmtheme_linux.c +++ b/src/detection/wmtheme/wmtheme_linux.c @@ -44,7 +44,7 @@ static bool detectWMThemeFromConfigFile(const char* configFile, const char* them static bool detectWMThemeFromSettings(const char* dconfKey, const char* gsettingsSchemaName, const char* gsettingsPath, const char* gsettingsKey, FFstrbuf* themeOrError) { - const char* theme = ffSettingsGet(dconfKey, gsettingsSchemaName, gsettingsPath, gsettingsKey, FF_VARIANT_TYPE_STRING).strValue; + const char* theme = ffSettingsGetGnome(dconfKey, gsettingsSchemaName, gsettingsPath, gsettingsKey, FF_VARIANT_TYPE_STRING).strValue; if(!ffStrSet(theme)) { @@ -80,7 +80,7 @@ static bool detectGTKThemeAsWMTheme(FFstrbuf* themeOrError) static bool detectMutter(FFstrbuf* themeOrError) { - const char* theme = ffSettingsGet("/org/gnome/shell/extensions/user-theme/name", "org.gnome.shell.extensions.user-theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; + const char* theme = ffSettingsGetGnome("/org/gnome/shell/extensions/user-theme/name", "org.gnome.shell.extensions.user-theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; if(ffStrSet(theme)) { ffStrbufAppendS(themeOrError, theme); @@ -92,8 +92,8 @@ static bool detectMutter(FFstrbuf* themeOrError) static bool detectMuffin(FFstrbuf* themeOrError) { - FF_AUTO_FREE const char* name = ffSettingsGet("/org/cinnamon/theme/name", "org.cinnamon.theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; - FF_AUTO_FREE const char* theme = ffSettingsGet("/org/cinnamon/desktop/wm/preferences/theme", "org.cinnamon.desktop.wm.preferences", NULL, "theme", FF_VARIANT_TYPE_STRING).strValue; + FF_AUTO_FREE const char* name = ffSettingsGetGnome("/org/cinnamon/theme/name", "org.cinnamon.theme", NULL, "name", FF_VARIANT_TYPE_STRING).strValue; + FF_AUTO_FREE const char* theme = ffSettingsGetGnome("/org/cinnamon/desktop/wm/preferences/theme", "org.cinnamon.desktop.wm.preferences", NULL, "theme", FF_VARIANT_TYPE_STRING).strValue; if(name == NULL && theme == NULL) { @@ -135,9 +135,9 @@ static bool detectOpenbox(const FFstrbuf* dePrettyName, FFstrbuf* themeOrError) { FF_STRBUF_AUTO_DESTROY absolutePath = ffStrbufCreateA(64); const char *configFileSubpath = "openbox/rc.xml"; - if (ffStrbufIgnCaseCompS(dePrettyName, "LXQt") == 0) + if (ffStrbufIgnCaseEqualS(dePrettyName, "LXQt")) configFileSubpath = "openbox/lxqt-rc.xml"; - else if (ffStrbufIgnCaseCompS(dePrettyName, "LXDE") == 0) + else if (ffStrbufIgnCaseEqualS(dePrettyName, "LXDE")) configFileSubpath = "openbox/lxde-rc.xml"; if (!ffSearchUserConfigFile(&instance.state.platform.configDirs, configFileSubpath, &absolutePath)) @@ -197,16 +197,19 @@ bool ffDetectWmTheme(FFstrbuf* themeOrError) return false; } - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_KWIN) == 0) + if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_KWIN)) return detectWMThemeFromConfigFile("kwinrc", "theme =", "Breeze", themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_XFWM4) == 0) + if( + ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_XFWM4) || + (ffStrbufIgnCaseEqualS(&wm->wmPrettyName, "labwc") && ffStrbufIgnCaseEqualS(&wm->dePrettyName, FF_DE_PRETTY_XFCE4)) + ) return detectXFWM4(themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MUTTER) == 0) + if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_MUTTER)) { if( - ffStrbufIgnCaseCompS(&wm->dePrettyName, FF_DE_PRETTY_GNOME) == 0 || + ffStrbufIgnCaseEqualS(&wm->dePrettyName, FF_DE_PRETTY_GNOME) || ffStrbufIgnCaseEqualS(&wm->dePrettyName, FF_DE_PRETTY_GNOME_CLASSIC) ) return detectMutter(themeOrError); @@ -214,13 +217,13 @@ bool ffDetectWmTheme(FFstrbuf* themeOrError) return detectGTKThemeAsWMTheme(themeOrError); } - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MUFFIN) == 0) + if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_MUFFIN)) return detectMuffin(themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MARCO) == 0) + if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_MARCO)) return detectWMThemeFromSettings("/org/mate/Marco/general/theme", "org.mate.Marco.general", NULL, "theme", themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_OPENBOX) == 0) + if(ffStrbufIgnCaseEqualS(&wm->wmPrettyName, FF_WM_PRETTY_OPENBOX)) return detectOpenbox(&wm->dePrettyName, themeOrError); ffStrbufAppendS(themeOrError, "Unknown WM: "); diff --git a/src/fastfetch.c b/src/fastfetch.c index cd8210cd33..961af21f96 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -681,7 +681,8 @@ static void parseOption(FFdata* data, const char* key, const char* value) else if( ffOptionsParseGeneralCommandLine(&instance.config.general, key, value) || ffOptionsParseLogoCommandLine(&instance.config.logo, key, value) || - ffOptionsParseDisplayCommandLine(&instance.config.display, key, value) + ffOptionsParseDisplayCommandLine(&instance.config.display, key, value) || + ffParseModuleOptions(key, value) ) {} else diff --git a/src/logo/logo.c b/src/logo/logo.c index cc6814b168..a0d64b72f5 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -114,7 +114,7 @@ static bool ffLogoPrintCharsRaw(const char* data, size_t length, bool printError static uint32_t logoAppendChars(const char* data, bool doColorReplacement, FFstrbuf* result) { FFOptionsLogo* options = &instance.config.logo; - uint32_t currentlineLength = options->width; + uint32_t currentlineLength = options->type == FF_LOGO_TYPE_IMAGE_CHAFA ? 0 : options->width; // For chafa, unit of options->width is pixels uint32_t logoHeight = 0; if (result) @@ -260,7 +260,7 @@ static uint32_t logoAppendChars(const char* data, bool doColorReplacement, FFstr if(currentlineLength > instance.state.logoWidth) instance.state.logoWidth = currentlineLength; - return options->height > logoHeight ? options->height : logoHeight; + return options->type != FF_LOGO_TYPE_IMAGE_CHAFA && options->height > logoHeight ? options->height : logoHeight; } void ffLogoPrintChars(const char* data, bool doColorReplacement) diff --git a/src/modules/btrfs/btrfs.c b/src/modules/btrfs/btrfs.c index e021d8035d..b3f968d881 100644 --- a/src/modules/btrfs/btrfs.c +++ b/src/modules/btrfs/btrfs.c @@ -27,9 +27,9 @@ static void printBtrfs(FFBtrfsOptions* options, FFBtrfsResult* result, uint8_t i } uint64_t used = 0, allocated = 0, total = result->totalSize; - for (int i = 0; i < 3; ++i) + for (uint32_t i = 0; i < ARRAY_SIZE(result->allocation); ++i) { - uint64_t times = result->allocation[i].dup ? 2 : 1; + uint64_t times = result->allocation[i].copies; used += result->allocation[i].used * times; allocated += result->allocation[i].total * times; } @@ -180,11 +180,12 @@ bool ffGenerateBtrfsJsonResult(FF_MAYBE_UNUSED FFBtrfsOptions* options, yyjson_m yyjson_mut_obj_add_uint(doc, obj, "sectorSize", btrfs->sectorSize); yyjson_mut_obj_add_uint(doc, obj, "totalSize", btrfs->totalSize); yyjson_mut_val* allocation = yyjson_mut_obj_add_arr(doc, obj, "allocation"); - for (int i = 0; i < 3; ++i) + for (uint32_t i = 0; i < ARRAY_SIZE(btrfs->allocation); ++i) { yyjson_mut_val* item = yyjson_mut_arr_add_obj(doc, allocation); yyjson_mut_obj_add_str(doc, item, "type", btrfs->allocation[i].type); - yyjson_mut_obj_add_bool(doc, item, "dup", btrfs->allocation[i].dup); + yyjson_mut_obj_add_str(doc, item, "profile", btrfs->allocation[i].profile); + yyjson_mut_obj_add_uint(doc, item, "copies", btrfs->allocation[i].copies); yyjson_mut_obj_add_uint(doc, item, "used", btrfs->allocation[i].used); yyjson_mut_obj_add_uint(doc, item, "total", btrfs->allocation[i].total); } diff --git a/src/modules/display/display.c b/src/modules/display/display.c index c8f81f84e3..7d8e80d962 100644 --- a/src/modules/display/display.c +++ b/src/modules/display/display.c @@ -101,6 +101,7 @@ bool ffPrintDisplay(FFDisplayOptions* options) FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate(); double inch = sqrt(result->physicalWidth * result->physicalWidth + result->physicalHeight * result->physicalHeight) / 25.4; + double scaleFactor = (double) result->height / (double) result->scaledHeight; if(options->moduleArgs.outputFormat.length == 0) { @@ -108,23 +109,28 @@ bool ffPrintDisplay(FFDisplayOptions* options) ffStrbufAppendF(&buffer, "%ix%i", result->width, result->height); - if(result->refreshRate > 0) - { - const char* space = instance.config.display.freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " "; - if(options->preciseRefreshRate) - ffStrbufAppendF(&buffer, " @ %g%sHz", ((int) (result->refreshRate * 1000 + 0.5)) / 1000.0, space); - else - ffStrbufAppendF(&buffer, " @ %i%sHz", (uint32_t) (result->refreshRate + 0.5), space); - } - if( result->scaledWidth > 0 && result->scaledWidth != result->width && result->scaledHeight > 0 && result->scaledHeight != result->height) - ffStrbufAppendF(&buffer, " (as %ix%i)", result->scaledWidth, result->scaledHeight); + { + ffStrbufAppendS(&buffer, " @ "); + ffStrbufAppendDouble(&buffer, scaleFactor, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS); + ffStrbufAppendC(&buffer, 'x'); + } if (inch > 1) ffStrbufAppendF(&buffer, " in %i\"", (uint32_t) (inch + 0.5)); + if(result->refreshRate > 0) + { + ffStrbufAppendS(&buffer, ", "); + if(options->preciseRefreshRate) + ffStrbufAppendDouble(&buffer, result->refreshRate, 3, false); + else + ffStrbufAppendSInt(&buffer, (int) (result->refreshRate + 0.5)); + ffStrbufAppendS(&buffer, instance.config.display.freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "Hz" : " Hz"); + } + bool flag = false; if (result->type != FF_DISPLAY_TYPE_UNKNOWN) { @@ -185,8 +191,6 @@ bool ffPrintDisplay(FFDisplayOptions* options) else buf[0] = '\0'; - double scaleFactor = (double) result->height / (double) result->scaledHeight; - FF_PRINT_FORMAT_CHECKED(key.chars, 0, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY, ((FFformatarg[]) { FF_FORMAT_ARG(result->width, "width"), FF_FORMAT_ARG(result->height, "height"), diff --git a/src/modules/localip/localip.c b/src/modules/localip/localip.c index 95c94d5065..6b72669407 100644 --- a/src/modules/localip/localip.c +++ b/src/modules/localip/localip.c @@ -37,17 +37,13 @@ static void appendSpeed(FFLocalIpResult* ip, FFstrbuf* strbuf) { if (ip->speed >= 1000000) { - if (instance.config.display.fractionNdigits >= 0) - ffStrbufAppendF(strbuf, "%.*f Tbps", instance.config.display.fractionNdigits, ip->speed / 1000000.0); - else - ffStrbufAppendF(strbuf, "%g Tbps", ip->speed / 1000000.0); + ffStrbufAppendDouble(strbuf, ip->speed / 1e6, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS); + ffStrbufAppendS(strbuf, " Tbps"); } else if (ip->speed >= 1000) { - if (instance.config.display.fractionNdigits >= 0) - ffStrbufAppendF(strbuf, "%.*f Gbps", instance.config.display.fractionNdigits, ip->speed / 1000.0); - else - ffStrbufAppendF(strbuf, "%g Gbps", ip->speed / 1000.0); + ffStrbufAppendDouble(strbuf, ip->speed / 1e3, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros == FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS); + ffStrbufAppendS(strbuf, " Gbps"); } else ffStrbufAppendF(strbuf, "%u Mbps", (unsigned) ip->speed); diff --git a/src/options/display.c b/src/options/display.c index 5bb2a888e1..ab9d4c372a 100644 --- a/src/options/display.c +++ b/src/options/display.c @@ -136,7 +136,15 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va } yyjson_val* ndigits = yyjson_obj_get(val, "ndigits"); - if (ndigits) options->sizeNdigits = (uint8_t) yyjson_get_uint(ndigits); + if (ndigits) + { + if (!yyjson_is_uint(ndigits)) + return "display.size.ndigits must be an unsigned integer"; + uint64_t val = yyjson_get_uint(ndigits); + if (val > 9) + return "display.size.ndigits must be between 0 and 9"; + options->sizeNdigits = (uint8_t) val; + } yyjson_val* spaceBeforeUnit = yyjson_obj_get(val, "spaceBeforeUnit"); if (spaceBeforeUnit) @@ -177,7 +185,15 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va } yyjson_val* ndigits = yyjson_obj_get(val, "ndigits"); - if (ndigits) options->tempNdigits = (uint8_t) yyjson_get_uint(ndigits); + if (ndigits) + { + if (!yyjson_is_uint(ndigits)) + return "display.temperature.ndigits must be an unsigned integer"; + uint64_t val = yyjson_get_uint(ndigits); + if (val > 9) + return "display.temperature.ndigits must be between 0 and 9"; + options->tempNdigits = (uint8_t) val; + } yyjson_val* color = yyjson_obj_get(val, "color"); if (color) @@ -222,7 +238,15 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va } yyjson_val* ndigits = yyjson_obj_get(val, "ndigits"); - if (ndigits) options->percentNdigits = (uint8_t) yyjson_get_uint(ndigits); + if (ndigits) + { + if (!yyjson_is_uint(ndigits)) + return "display.percent.ndigits must be an unsigned integer"; + uint64_t val = yyjson_get_uint(ndigits); + if (val > 9) + return "display.percent.ndigits must be between 0 and 9"; + options->percentNdigits = (uint8_t) val; + } yyjson_val* color = yyjson_obj_get(val, "color"); if (color) @@ -376,9 +400,33 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va { if (yyjson_is_null(ndigits)) options->fractionNdigits = -1; - else if (!yyjson_is_int(ndigits)) - return "display.fraction.ndigits must be an integer"; - options->fractionNdigits = (int8_t) yyjson_get_int(ndigits); + else + { + if (!yyjson_is_int(ndigits)) + return "display.fraction.ndigits must be an integer"; + int64_t val = yyjson_get_int(ndigits); + if (val < -1 || val > 9) + return "display.fraction.ndigits must be between -1 and 9"; + options->fractionNdigits = (int8_t) val; + } + } + yyjson_val* trailingZeros = yyjson_obj_get(val, "trailingZeros"); + if (trailingZeros) + { + if (yyjson_is_null(trailingZeros)) + options->fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT; + else + { + int value; + const char* error = ffJsonConfigParseEnum(trailingZeros, &value, (FFKeyValuePair[]) { + { "default", FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT }, + { "always", FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS }, + { "never", FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER }, + {}, + }); + if (error) return error; + options->fractionTrailingZeros = (FFFractionTrailingZerosType) value; + } } } else @@ -431,7 +479,20 @@ const char* ffOptionsParseDisplayJsonConfig(FFOptionsDisplay* options, yyjson_va return "display.freq must be an object"; yyjson_val* ndigits = yyjson_obj_get(val, "ndigits"); - if (ndigits) options->freqNdigits = (int8_t) yyjson_get_int(ndigits); + if (ndigits) + { + if (yyjson_is_null(ndigits)) + options->freqNdigits = -1; + else + { + if (!yyjson_is_int(ndigits)) + return "display.freq.ndigits must be an integer"; + int64_t val = yyjson_get_int(ndigits); + if (val < -1 || val > 9) + return "display.freq.ndigits must be between -1 and 9"; + options->freqNdigits = (int8_t) val; + } + } yyjson_val* spaceBeforeUnit = yyjson_obj_get(val, "spaceBeforeUnit"); if (spaceBeforeUnit) @@ -690,6 +751,15 @@ bool ffOptionsParseDisplayCommandLine(FFOptionsDisplay* options, const char* key } else if(ffStrEqualsIgnCase(key, "--fraction-ndigits")) options->fractionNdigits = (int8_t) ffOptionParseInt32(key, value); + else if(ffStrEqualsIgnCase(key, "--fraction-trailing-zeros")) + { + options->fractionTrailingZeros = (FFFractionTrailingZerosType) ffOptionParseEnum(key, value, (FFKeyValuePair[]) { + { "default", FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT }, + { "always", FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS }, + { "never", FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER }, + {}, + }); + } else if(ffStrEqualsIgnCase(key, "--no-buffer")) options->noBuffer = ffOptionParseBoolean(value); else if(ffStrStartsWithIgnCase(key, "--bar-")) @@ -809,7 +879,8 @@ void ffOptionsInitDisplay(FFOptionsDisplay* options) options->freqNdigits = 2; options->freqSpaceBeforeUnit = FF_SPACE_BEFORE_UNIT_DEFAULT; - options->fractionNdigits = -1; + options->fractionNdigits = 2; + options->fractionTrailingZeros = FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT; ffListInit(&options->constants, sizeof(FFstrbuf)); } diff --git a/src/options/display.h b/src/options/display.h index 4193cd2c6e..4c29845e11 100644 --- a/src/options/display.h +++ b/src/options/display.h @@ -25,6 +25,13 @@ typedef enum __attribute__((__packed__)) FFSpaceBeforeUnitType FF_SPACE_BEFORE_UNIT_NEVER, } FFSpaceBeforeUnitType; +typedef enum __attribute__((__packed__)) FFFractionTrailingZerosType +{ + FF_FRACTION_TRAILING_ZEROS_TYPE_DEFAULT, + FF_FRACTION_TRAILING_ZEROS_TYPE_ALWAYS, + FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER, +} FFFractionTrailingZerosType; + typedef struct FFOptionsDisplay { //If one of those is empty, ffLogoPrint will set them @@ -81,6 +88,7 @@ typedef struct FFOptionsDisplay int8_t freqNdigits; FFSpaceBeforeUnitType freqSpaceBeforeUnit; int8_t fractionNdigits; + FFFractionTrailingZerosType fractionTrailingZeros; FFlist constants; // list of FFstrbuf } FFOptionsDisplay; diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index f0f85e61ed..45db80a4c4 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -571,7 +571,7 @@ void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value) strbuf->length += (uint32_t)(end - start); } -void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision) +void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros) { assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point @@ -598,18 +598,29 @@ void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision) return; } - if (precision > 1) + if (trailingZeros) { - for (char* p = end - 1; *p != '.' && p > start; --p) - --precision; - if (precision > 0) - ffStrbufAppendNC(strbuf, (uint32_t) precision, '0'); + if (precision > 1) + { + for (char* p = end - 1; *p != '.' && p > start; --p) + --precision; + if (precision > 0) + ffStrbufAppendNC(strbuf, (uint32_t) precision, '0'); + } + else if (precision == 0 || (precision < 0 && end[-1] == '0')) + { + goto removeDecimalPoint; + } } - else if (precision == 0 || (precision < 0 && end[-1] == '0')) + else { - // yyjson always appends ".0", so we need to remove it - strbuf->length -= 2; - strbuf->chars[strbuf->length] = '\0'; + if (end[-1] == '0') + { + removeDecimalPoint: + // yyjson always appends ".0" to make it a float point number. We need to remove it + strbuf->length -= 2; + strbuf->chars[strbuf->length] = '\0'; + } } } diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 704f2a332e..7d50d6ad77 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -107,7 +107,7 @@ void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value); void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value); // Appends a double value to the string buffer with the specified precision (0~15). // if `precision < 0`, let yyjson decide the precision -void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision); +void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros); FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate) { diff --git a/tests/strbuf.c b/tests/strbuf.c index 39c845a3bc..f51f00cde1 100644 --- a/tests/strbuf.c +++ b/tests/strbuf.c @@ -744,115 +744,230 @@ int main(void) } { - ffStrbufAppendDouble(&strbuf, 120.0, 0); + ffStrbufAppendDouble(&strbuf, 120.0, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.0, 1); + ffStrbufAppendDouble(&strbuf, 120.0, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "120.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.0, 5); + ffStrbufAppendDouble(&strbuf, 120.0, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "120.00000")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123456789, 5); + ffStrbufAppendDouble(&strbuf, 120.123456789, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "120.12346")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.888888, 0); + ffStrbufAppendDouble(&strbuf, 120.888888, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "121")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.999999, 2); + ffStrbufAppendDouble(&strbuf, 120.999999, 2, true); VERIFY(ffStrbufEqualS(&strbuf, "121.00")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123456789, 0); + ffStrbufAppendDouble(&strbuf, 120.123456789, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123456789, -1); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 120.123, 5); + ffStrbufAppendDouble(&strbuf, 120.123, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "120.12300")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.0, 0); + ffStrbufAppendDouble(&strbuf, -120.0, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.0, 1); + ffStrbufAppendDouble(&strbuf, -120.0, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.0, 5); + ffStrbufAppendDouble(&strbuf, -120.0, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.00000")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123456789, 5); + ffStrbufAppendDouble(&strbuf, -120.123456789, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.12346")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123456789, 0); + ffStrbufAppendDouble(&strbuf, -120.123456789, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-120")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123456789, -1); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.123, 5); + ffStrbufAppendDouble(&strbuf, -120.123, 5, true); VERIFY(ffStrbufEqualS(&strbuf, "-120.12300")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.888888, 0); + ffStrbufAppendDouble(&strbuf, -120.888888, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-121")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -120.999999, 2); + ffStrbufAppendDouble(&strbuf, -120.999999, 2, true); VERIFY(ffStrbufEqualS(&strbuf, "-121.00")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e50, 1); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e50, 1); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e50, 0); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e50, 0); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e50, -1); + ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e50, -1); + ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, true); VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, 1.2345e20, 1); + ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -1.2345e20, 1); + ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, true); VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000.0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, +0.0, 0); + ffStrbufAppendDouble(&strbuf, +0.0, 0, true); VERIFY(ffStrbufEqualS(&strbuf, "0")); ffStrbufClear(&strbuf); - ffStrbufAppendDouble(&strbuf, -0.0, 0); + ffStrbufAppendDouble(&strbuf, -0.0, 0, true); + VERIFY(ffStrbufEqualS(&strbuf, "-0")); + + ffStrbufDestroy(&strbuf); + } + + { + ffStrbufAppendDouble(&strbuf, 120.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.0, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.888888, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.999999, 2, false); + VERIFY(ffStrbufEqualS(&strbuf, "121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123456789, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 120.123, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "120.123")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.0, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.12346")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123456789, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123456789")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.123, 5, false); + VERIFY(ffStrbufEqualS(&strbuf, "-120.123")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.888888, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -120.999999, 2, false); + VERIFY(ffStrbufEqualS(&strbuf, "-121")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e50, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e50, -1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-1.2345e50")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, 1.2345e20, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "123450000000000000000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -1.2345e20, 1, false); + VERIFY(ffStrbufEqualS(&strbuf, "-123450000000000000000")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, +0.0, 0, false); + VERIFY(ffStrbufEqualS(&strbuf, "0")); + + ffStrbufClear(&strbuf); + ffStrbufAppendDouble(&strbuf, -0.0, 0, false); VERIFY(ffStrbufEqualS(&strbuf, "-0")); ffStrbufDestroy(&strbuf);