diff --git a/.github/ISSUE_TEMPLATE/bug_report_crash.yml b/.github/ISSUE_TEMPLATE/bug_report_crash.yml index 1806e598f1..cd9678c2db 100644 --- a/.github/ISSUE_TEMPLATE/bug_report_crash.yml +++ b/.github/ISSUE_TEMPLATE/bug_report_crash.yml @@ -16,6 +16,15 @@ body: options: - label: I have checked the FAQ but the issue is not covered required: true + - type: checkboxes + attributes: + label: Not a known issue + description: Please check if the issue is already known and being worked on. + options: + - label: I have checked the existing issues but the issue is not covered + required: true + - label: My issue is not about crashing on Fedora and KDE 6.6 + required: true - type: markdown attributes: value: "### General description of the bug" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d46ae320f..d371317c8d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,12 +93,12 @@ jobs: run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - name: install required packages - run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev libchafa-dev directx-headers-dev rpm ninja-build + run: sudo apt-get update && sudo apt-get install -y gcc-13 g++-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev rpm ninja-build - name: install linuxbrew packages run: | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - /home/linuxbrew/.linuxbrew/bin/brew install imagemagick --ignore-dependencies + /home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies - name: Initialize CodeQL if: matrix.arch == 'amd64' @@ -151,7 +151,7 @@ jobs: cpack -V - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-linux-${{ matrix.arch }} path: ./fastfetch-*.* @@ -217,7 +217,7 @@ jobs: run: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-linux-i686 path: ./fastfetch-*.* @@ -257,7 +257,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-linux-armv7l path: ./fastfetch-*.* @@ -293,7 +293,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-linux-armv6l path: ./fastfetch-*.* @@ -336,7 +336,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-linux-${{ matrix.arch }} path: ./fastfetch-*.* @@ -374,7 +374,7 @@ jobs: shell: alpine.sh {0} - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-musl-amd64 path: ./fastfetch-*.* @@ -428,7 +428,7 @@ jobs: run: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-macos-${{ matrix.arch }} path: ./fastfetch-*.* @@ -444,6 +444,7 @@ jobs: uses: vmactions/omnios-vm@v1 with: usesh: true + envs: 'CMAKE_BUILD_TYPE' prepare: | uname -a pkg update --accept @@ -462,7 +463,7 @@ jobs: cpack -V - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-omnios-amd64 path: ./fastfetch-*.* @@ -478,6 +479,7 @@ jobs: uses: vmactions/solaris-vm@v1 with: usesh: true + envs: 'CMAKE_BUILD_TYPE' release: "11.4-gcc-14" prepare: | uname -a @@ -497,7 +499,7 @@ jobs: cpack -V - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-solaris-amd64 path: ./fastfetch-*.* @@ -520,6 +522,7 @@ jobs: cpu_count: 4 shell: bash version: '15.0' + environment_variables: 'CMAKE_BUILD_TYPE' run: | uname -a sudo pkg update @@ -534,7 +537,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-freebsd-amd64 path: ./fastfetch-*.* @@ -557,6 +560,7 @@ jobs: cpu_count: 4 shell: bash version: '7.8' + environment_variables: 'CMAKE_BUILD_TYPE' run: | uname -a sudo pkg_add -u @@ -571,7 +575,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-openbsd-amd64 path: ./fastfetch-*.* @@ -594,6 +598,7 @@ jobs: cpu_count: 4 shell: bash version: '10.1' + environment_variables: 'CMAKE_BUILD_TYPE' run: | uname -a sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick @@ -607,7 +612,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-netbsd-amd64 path: ./fastfetch-*.* @@ -626,6 +631,7 @@ jobs: uses: vmactions/dragonflybsd-vm@v1 with: usesh: yes + envs: 'CMAKE_BUILD_TYPE' prepare: | uname -a pkg update @@ -642,7 +648,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-dragonfly-amd64 path: ./fastfetch-*.* @@ -665,6 +671,7 @@ jobs: architecture: x86-64 cpu_count: 4 shell: bash + environment_variables: 'CMAKE_BUILD_TYPE' run: | uname -a pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 @@ -677,7 +684,7 @@ jobs: ctest --output-on-failure - name: upload artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-haiku-amd64 path: ./fastfetch-*.* @@ -759,7 +766,7 @@ jobs: - if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch' id: upload-unsigned-artifact name: upload artifacts for signing - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }} path: | @@ -786,7 +793,7 @@ jobs: run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets - name: upload true artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }} path: ./fastfetch-windows-${{ matrix.arch }}${{ matrix.win7-compat-postfix }}.* @@ -823,7 +830,7 @@ jobs: - name: download artifacts if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release - uses: actions/download-artifact@v5 + uses: actions/download-artifact@v8 - name: create release if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release diff --git a/CHANGELOG.md b/CHANGELOG.md index d053e5ec1c..8a92a792a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,35 @@ +# 2.60.0 + +Changes: +* The CMake option `ENABLE_WIN7_COMPAT:BOOLEAN` now defaults to `OFF` and will be removed in v2.61.0, effectively dropping support for Windows 7 in the next release. + * This follows the Windows 7 deprecation notice introduced in v2.57.0. +* `wm.detectPlugin` now defaults to `true` (WM) + +Features: +* Adds `{cwd}` for custom title formatting, which displays the current working directory (Title) +* Adds support for detecting the Zed version (#2200, Editor) +* Adds support for detecting `moss` packages (Packages, Linux) +* Adds support for detecting komorebi, FancyWM, and GlazeWM (WM, Windows) +* Adds support for WM plugin version detection on macOS (WM, macOS) +* Adds support for retrieving the executable path on OpenBSD (#2195, OpenBSD) + +Bugfixes: +* Fixes a potential segmentation fault caused by dereferencing a negative index (#2198) +* Fixes `tempSensor` parsing so that it accepts only string values (#2202, CPU) +* Fixes an issue that unexpectedly caused fewer devices to be reported (Keyboard, Linux) +* Improves WM detection on LXQt by querying WM settings only when no WM has already been detected (#2199, WM, Linux) +* Fixes memory leaks in DBus connection handling and in the OpenGL EGL context lifecycle +* Fixes niri version detection on Fedora (WM, Linux) +* Includes various internal cleanups and optimizations + +Logos: +* Adds `RengeOS` (#2170) +* Adds `Emmabuntüs` (#2207) +* Updates Artix Linux (#2157) +* Updates Linux Mint (#2186) +* Renames `Refracted Devuan` to `Refracta` +* Renames `ExodiaPredator` to `ExodiaOS` + # 2.59.0 Changes: @@ -35,7 +67,7 @@ Features: * Honors the `DBPath` and `RootDir` settings in `pacman.conf` when detecting Pacman packages (#2154, Packages, Linux) Bugfixes: -* Fixes a crash issues on KDE Plasma 6.6 (Display, Linux) +* Fixes a crash issue on KDE Plasma 6.6 (Display, Linux) * Fixes the Command module not working with `--dynamic-interval` (#2152, Command) * Fixes Quartz Compositor version detection. It now correctly reports the version of `WindowServer` (`SkyLight`) instead of `WindowManager`. (WM, macOS) @@ -62,7 +94,7 @@ Deprecation notice: * Support for Windows 7 (and 8.x) is deprecated and will be removed in a future release. Extended support for Windows 7 (and 8.1) ended on January 10, 2023. These versions do not officially support ANSI escape codes (running fastfetch on them requires a third-party terminal such as ConEmu). In addition, Windows 7 lacks some APIs used by fastfetch. Fastfetch currently loads these APIs dynamically at runtime to maintain compatibility, but this adds complexity to the codebase and increases the maintenance burden. * A CMake flag `ENABLE_WIN7_COMPAT:BOOLEAN` has been introduced (defaults to `ON` for now). If set to `OFF`, Windows 7 compatibility code is excluded, and the resulting binaries will support only Windows 10 (version 1607 and later) and Windows 11. * The main prebuilt Windows binaries on the Release page (`fastfetch-windows-amd64.*`) are built with `ENABLE_WIN7_COMPAT=OFF`. These are the binaries used by `scoop` and `winget`. Users who need Windows 7 (or 8.x) support can download the `-win7` variant instead. - * The `ENABLE_WIN7_COMPAT` CMake option and the `-win7` variant binaries are planned to be removed in 2.60.0. + * ~~The `ENABLE_WIN7_COMPAT` CMake option and the `-win7` variant binaries are planned to be removed in 2.60.0~~. Features: * Supports COSMIC DE version detection (DE, Linux) diff --git a/CMakeLists.txt b/CMakeLists.txt index 725b2b668d..063457b059 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.59.0 + VERSION 2.60.0 LANGUAGES C DESCRIPTION "Fast neofetch-like system information tool" HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch" @@ -107,7 +107,7 @@ option(ENABLE_EMBEDDED_AMDGPUIDS "Embed amdgpu.ids into fastfetch, requires `pyt option(ENABLE_WORDEXP "Enable using of wordexp(3) if available, instead of glob(3)" ON) option(ENABLE_LIBZFS "Enable libzfs" ON) if(WIN32 AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") - option(ENABLE_WIN7_COMPAT "Enable Windows 7 compatibility" ON) + option(ENABLE_WIN7_COMPAT "Enable Windows 7 compatibility" OFF) endif() if(APPLE) option(ENABLE_APPLE_MEMSIZE_USABLE "Use usable memory size as total memory size in Memory module, to match other systems" OFF) @@ -398,7 +398,6 @@ set(LIBFASTFETCH_SRC src/common/impl/base64.c src/common/impl/FFlist.c src/common/impl/FFstrbuf.c - src/common/impl/kmod.c src/common/impl/path.c src/common/impl/FFPlatform.c src/common/impl/smbiosHelper.c @@ -523,6 +522,7 @@ if(LINUX) src/common/impl/processing_linux.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_linux.c src/detection/battery/battery_linux.c src/detection/bios/bios_linux.c src/detection/board/board_linux.c @@ -607,6 +607,7 @@ elseif(ANDROID) src/common/impl/processing_linux.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_linux.c src/detection/battery/battery_android.c src/detection/bios/bios_android.c src/detection/bluetooth/bluetooth_nosupport.c @@ -681,6 +682,7 @@ elseif(FreeBSD) src/common/impl/sysctl.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_bsd.c src/detection/battery/battery_bsd.c src/detection/bios/bios_bsd.c src/detection/bluetoothradio/bluetoothradio_nosupport.c @@ -774,6 +776,7 @@ elseif(NetBSD) src/common/impl/sysctl.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_nbsd.c src/detection/battery/battery_nbsd.c src/detection/bios/bios_nbsd.c src/detection/bluetooth/bluetooth_bsd.c @@ -857,6 +860,7 @@ elseif(OpenBSD) src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c src/common/impl/smbiosHelper.c + src/common/impl/kmod_nosupport.c src/detection/battery/battery_obsd.c src/detection/bios/bios_windows.c src/detection/bluetooth/bluetooth_nosupport.c @@ -938,6 +942,7 @@ elseif(APPLE) src/common/impl/sysctl.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_apple.c + src/common/impl/kmod_apple.c src/common/apple/cf_helpers.c src/common/apple/osascript.m src/common/apple/smc_temps.c @@ -1009,11 +1014,13 @@ elseif(WIN32) src/common/impl/FFPlatform_windows.c src/common/impl/binary_windows.c src/common/impl/debug_windows.c + src/common/impl/kmod_windows.c src/common/windows/getline.c src/common/windows/com.cpp src/common/windows/registry.c src/common/windows/unicode.c src/common/windows/wmi.cpp + src/common/windows/variant.cpp src/common/windows/version.c src/detection/battery/battery_windows.c src/detection/bios/bios_windows.c @@ -1053,7 +1060,7 @@ elseif(WIN32) src/detection/physicalmemory/physicalmemory_linux.c src/detection/netio/netio_windows.c src/detection/opengl/opengl_windows.c - src/detection/os/os_windows.cpp + src/detection/os/os_windows.c src/detection/packages/packages_windows.c src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_windows.c @@ -1068,7 +1075,7 @@ elseif(WIN32) src/detection/users/users_windows.c src/detection/wallpaper/wallpaper_windows.c src/detection/wifi/wifi_windows.c - src/detection/wm/wm_windows.cpp + src/detection/wm/wm_windows.c src/detection/de/de_nosupport.c src/detection/wmtheme/wmtheme_windows.c src/detection/camera/camera_windows.cpp @@ -1082,6 +1089,7 @@ elseif(SunOS) src/common/impl/processing_linux.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_sunos.c src/detection/battery/battery_nosupport.c src/detection/bios/bios_windows.c src/detection/board/board_windows.c @@ -1163,6 +1171,7 @@ elseif(Haiku) src/common/impl/processing_linux.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_nosupport.c src/common/haiku/version.cpp src/detection/battery/battery_haiku.c src/detection/bios/bios_windows.c @@ -1232,6 +1241,7 @@ elseif(GNU) src/common/impl/processing_linux.c src/common/impl/FFPlatform_unix.c src/common/impl/binary_linux.c + src/common/impl/kmod_nosupport.c src/detection/battery/battery_nosupport.c src/detection/bios/bios_nosupport.c src/detection/board/board_nosupport.c @@ -1715,7 +1725,6 @@ elseif(APPLE) ) elseif(WIN32) target_link_libraries(libfastfetch - PRIVATE "dwmapi" PRIVATE "gdi32" PRIVATE "iphlpapi" PRIVATE "ole32" @@ -1725,9 +1734,8 @@ elseif(WIN32) PRIVATE "version" PRIVATE "hid" PRIVATE "wtsapi32" - PRIVATE "imagehlp" PRIVATE "cfgmgr32" - PRIVATE "propsys" + PRIVATE "winbrand" PRIVATE "secur32" ) if(NOT ENABLE_WIN7_COMPAT) diff --git a/README.md b/README.md index 7fc0a17051..23143a2f1e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/fastfetch-cli/fastfetch) [![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-red)](README-cn.md) -Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, illumos (SunOS), and Solaris. +Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS (illumos, Solaris). diff --git a/doc/json_schema.json b/doc/json_schema.json index dac6715f52..8627d3223c 100644 --- a/doc/json_schema.json +++ b/doc/json_schema.json @@ -442,7 +442,7 @@ "type": "string" }, "packagesFormat": { - "description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {kiss}: Number of kiss packages\n 44. {nix-all}: Total number of all nix packages\n 45. {flatpak-all}: Total number of all flatpak app packages\n 46. {brew-all}: Total number of all brew packages\n 47. {guix-all}: Total number of all guix packages\n 48. {hpkg-all}: Total number of all hpkg packages", + "description": "Output format of the module `Packages`. See Wiki for formatting syntax\n 1. {all}: Number of all packages\n 2. {pacman}: Number of pacman packages\n 3. {pacman-branch}: Pacman branch on manjaro\n 4. {dpkg}: Number of dpkg packages\n 5. {rpm}: Number of rpm packages\n 6. {emerge}: Number of emerge packages\n 7. {eopkg}: Number of eopkg packages\n 8. {xbps}: Number of xbps packages\n 9. {nix-system}: Number of nix-system packages\n 10. {nix-user}: Number of nix-user packages\n 11. {nix-default}: Number of nix-default packages\n 12. {apk}: Number of apk packages\n 13. {pkg}: Number of pkg packages\n 14. {flatpak-system}: Number of flatpak-system app packages\n 15. {flatpak-user}: Number of flatpak-user app packages\n 16. {snap}: Number of snap packages\n 17. {brew}: Number of brew packages\n 18. {brew-cask}: Number of brew-cask packages\n 19. {macports}: Number of macports packages\n 20. {scoop-user}: Number of scoop-user packages\n 21. {scoop-global}: Number of scoop-global packages\n 22. {choco}: Number of choco packages\n 23. {pkgtool}: Number of pkgtool packages\n 24. {paludis}: Number of paludis packages\n 25. {winget}: Number of winget packages\n 26. {opkg}: Number of opkg packages\n 27. {am-system}: Number of am-system packages\n 28. {sorcery}: Number of sorcery packages\n 29. {lpkg}: Number of lpkg packages\n 30. {lpkgbuild}: Number of lpkgbuild packages\n 31. {guix-system}: Number of guix-system packages\n 32. {guix-user}: Number of guix-user packages\n 33. {guix-home}: Number of guix-home packages\n 34. {linglong}: Number of linglong packages\n 35. {pacstall}: Number of pacstall packages\n 36. {mport}: Number of mport packages\n 37. {am-user}: Number of am-user (aka appman) packages\n 38. {pkgsrc}: Number of pkgsrc packages\n 39. {hpkg-system}: Number of hpkg-system packages\n 40. {hpkg-user}: Number of hpkg-user packages\n 41. {pisi}: Number of pisi packages\n 42. {soar}: Number of soar packages\n 43. {kiss}: Number of kiss packages\n 44. {moss}: Number of moss packages\n 45. {nix-all}: Total number of all nix packages\n 46. {flatpak-all}: Total number of all flatpak app packages\n 47. {brew-all}: Total number of all brew packages\n 48. {guix-all}: Total number of all guix packages\n 49. {hpkg-all}: Total number of all hpkg packages", "type": "string" }, "physicaldiskFormat": { @@ -498,7 +498,7 @@ "type": "string" }, "titleFormat": { - "description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name\n 10. {user-id}: UID (*nix) / SID (Windows)\n 11. {pid}: PID of current process", + "description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name\n 10. {user-id}: UID (*nix) / SID (Windows)\n 11. {pid}: PID of current process\n 12. {cwd}: CWD with home dir replaced by `~`", "type": "string" }, "themeFormat": { @@ -1521,7 +1521,7 @@ "description": "Print battery capacity, status, etc" }, "useSetupApi": { - "description": "Set if `SetupAPI` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only", + "description": "Set if `CM API` should be used on Windows to detect battery info, which supports multi batteries, but slower. Windows only", "type": "boolean", "default": false }, @@ -2518,11 +2518,6 @@ "const": "de", "description": "Print desktop environment name" }, - "slowVersionDetection": { - "type": "boolean", - "description": "Set if DE version should be detected with slow operations.\nShould be unnecessary for most cases.\nThis is only used as a fallback method. Please file a bug report if you encounter any issues.", - "default": false - }, "key": { "$ref": "#/$defs/key" }, @@ -4487,7 +4482,7 @@ "detectPlugin": { "description": "Set if window manager plugin should be detected on supported platforms", "type": "boolean", - "default": false + "default": true }, "key": { "$ref": "#/$defs/key" diff --git a/presets/examples/25.jsonc b/presets/examples/25.jsonc index c00265716a..ddb3fdf2da 100644 --- a/presets/examples/25.jsonc +++ b/presets/examples/25.jsonc @@ -9,25 +9,26 @@ // Constants are reusable strings referenced by {$1}, {$2}, etc. // These contain ANSI escape codes for cursor positioning "constants": [ - "──────────────────────────────────────────────", // {$1} - horizontal line for borders + "──────────────────────────────────────────────", // {$1} - horizontal line for inner borders "\u001b[47D", // {$2} - move cursor left 47 columns "\u001b[47C", // {$3} - move cursor right 47 columns - "\u001b[46C" // {$4} - move cursor right 46 columns + "\u001b[46C", // {$4} - move cursor right 46 columns + "══════════════════════════════════════════════" // {$5} - horizontal line for outer borders ], "brightColor": false }, "modules": [ { "type": "version", - "key": "┌───────────────┬─{$1}┐\u001b[41D", + "key": "╔═══════════════╦═{$5}╗\u001b[41D", "format": "\u001b[1m{#keys} {1} - {2} " }, { "type": "os", // Key format breakdown for OS module: - // "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}" + // "║ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}║{$2}" // - // │ - Left border of key block + // ║ - Left border of key block // {icon} - OS icon (defined internally by fastfetch) // \u001b[s - ANSI escape: save cursor position (ESC[s) // {sysname} - Format variable: system name (e.g., "Linux", "Darwin") @@ -36,28 +37,28 @@ // \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C) // │ - Right border of key block (always 10 columns from left border) // {$3} - Reference to constants[2]: move cursor right 47 columns - // │ - Right border of value block + // ║ - Right border of value block // {$2} - Reference to constants[1]: move cursor left 47 columns // // This creates a fixed-width layout where the key block is exactly 10 columns wide, // regardless of the actual content length. The cursor manipulation ensures proper // alignment for the table-like structure. - "key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}" + "key": "║ {icon} \u001b[s{sysname}\u001b[u\u001b[10C║{$3}║{$2}" }, { "type": "datetime", - "key": "│ {icon} Fetched │{$3}│{$2}", + "key": "║ {icon} Fetched ║{$3}║{$2}", "format": "{year}-{month-pretty}-{day-pretty} {hour-pretty}:{minute-pretty}:{second-pretty} {timezone-name}" }, { "type": "locale", - "key": "│ {icon} Locale │{$3}│{$2}" + "key": "║ {icon} Locale ║{$3}║{$2}" }, // Hardware section with cyan color theme { "type": "custom", - "key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D", + "key": "║{#cyan}┌──────────────┬{$1}┐{#keys}║\u001b[37D", "format": "{#bright_cyan} Hardware " }, { @@ -66,113 +67,113 @@ // │{#cyan}│ - Left border with cyan color // {icon} - Chassis icon // Chassis - Fixed label text - // │{$4}│{#keys}│{$2} - Positioning and borders for value area - "key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}" + // │{$4}│{#keys}║{$2} - Positioning and borders for value area + "key": "║{#cyan}│ {icon} Chassis │{$4}│{#keys}║{$2}" }, { "type": "memory", - "key": "│{#cyan}│ {icon} RAM │{$4}│{#keys}│{$2}" + "key": "║{#cyan}│ {icon} RAM │{$4}│{#keys}║{$2}" }, { "type": "swap", - "key": "│{#cyan}│ {icon} SWAP │{$4}│{#keys}│{$2}" + "key": "║{#cyan}│ {icon} SWAP │{$4}│{#keys}║{$2}" }, { "type": "cpu", - "key": "│{#cyan}│ {icon} CPU │{$4}│{#keys}│{$2}", + "key": "║{#cyan}│ {icon} CPU │{$4}│{#keys}║{$2}", "showPeCoreCount": true }, { "type": "gpu", - "key": "│{#cyan}│ {icon} GPU │{$4}│{#keys}│{$2}" + "key": "║{#cyan}│ {icon} GPU │{$4}│{#keys}║{$2}" }, { "type": "disk", - "key": "│{#cyan}│ {icon} Disk │{$4}│{#keys}│{$2}", + "key": "║{#cyan}│ {icon} Disk │{$4}│{#keys}║{$2}", "format": "{size-used} \/ {size-total} ({size-percentage}) - {filesystem}", }, { "type": "battery", - "key": "│{#cyan}│ {icon} Battery │{$4}│{#keys}│{$2}" + "key": "║{#cyan}│ {icon} Battery │{$4}│{#keys}║{$2}" }, { "type": "custom", - "key": "│{#cyan}└──────────────┴{$1}┘{#keys}│", + "key": "║{#cyan}└──────────────┴{$1}┘{#keys}║", "format": "" }, // Desktop section with green color theme { "type": "custom", - "key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D", + "key": "║{#green}┌──────────────┬{$1}┐{#keys}║\u001b[37D", "format": "{#bright_green} Desktop " }, { "type": "de", - "key": "│{#green}│ {icon} Desktop │{$4}│{#keys}│{$2}" + "key": "║{#green}│ {icon} Desktop │{$4}│{#keys}║{$2}" }, { "type": "wm", - "key": "│{#green}│ {icon} Session │{$4}│{#keys}│{$2}" + "key": "║{#green}│ {icon} Session │{$4}│{#keys}║{$2}" }, { "type": "display", - "key": "│{#green}│ {icon} Display │{$4}│{#keys}│{$2}", + "key": "║{#green}│ {icon} Display │{$4}│{#keys}║{$2}", "compactType": "original-with-refresh-rate" }, { "type": "gpu", - "key": "│{#green}│ {icon} G-Driver │{$4}│{#keys}│{$2}", + "key": "║{#green}│ {icon} G-Driver │{$4}│{#keys}║{$2}", "format": "{driver}" }, { "type": "custom", - "key": "│{#green}└──────────────┴{$1}┘{#keys}│", + "key": "║{#green}└──────────────┴{$1}┘{#keys}║", "format": "" }, // Terminal section with yellow color theme { "type": "custom", - "key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D", + "key": "║{#yellow}┌──────────────┬{$1}┐{#keys}║\u001b[37D", "format": "{#bright_yellow} Terminal " }, { "type": "shell", - "key": "│{#yellow}│ {icon} Shell │{$4}│{#keys}│{$2}" + "key": "║{#yellow}│ {icon} Shell │{$4}│{#keys}║{$2}" }, { "type": "terminal", - "key": "│{#yellow}│ {icon} Terminal │{$4}│{#keys}│{$2}" + "key": "║{#yellow}│ {icon} Terminal │{$4}│{#keys}║{$2}" }, { "type": "terminalfont", - "key": "│{#yellow}│ {icon} Term Font │{$4}│{#keys}│{$2}" + "key": "║{#yellow}│ {icon} Term Font │{$4}│{#keys}║{$2}" }, { "type": "terminaltheme", - "key": "│{#yellow}│ {icon} Colors │{$4}│{#keys}│{$2}" + "key": "║{#yellow}│ {icon} Colors │{$4}│{#keys}║{$2}" }, { "type": "packages", - "key": "│{#yellow}│ {icon} Packages │{$4}│{#keys}│{$2}" + "key": "║{#yellow}│ {icon} Packages │{$4}│{#keys}║{$2}" }, { "type": "custom", - "key": "│{#yellow}└──────────────┴{$1}┘{#keys}│", + "key": "║{#yellow}└──────────────┴{$1}┘{#keys}║", "format": "" }, // Development section with red color theme { "type": "custom", - "key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D", + "key": "║{#red}┌──────────────┬{$1}┐{#keys}║\u001b[39D", "format": "{#bright_red} Development " }, { "type": "command", "keyIcon": "", // Custom icon override - "key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} Rust │{$4}│{#keys}║{$2}", "text": "rustc --version", "format": "rustc {~6,13}" // Print 6th to 13th characters (version number) }, @@ -182,7 +183,7 @@ "!system": "Windows" // Posix version }, "keyIcon": "", - "key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} Clang │{$4}│{#keys}║{$2}", "text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'", "format": "clang {}" }, @@ -192,67 +193,67 @@ "system": "Windows" // Windows version }, "keyIcon": "", - "key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} Clang │{$4}│{#keys}║{$2}", "text": "clang --version | findstr version", // Finds the line with "version" "format": "clang {~-6}" // Prints the last 6 characters (version number) }, { "type": "command", "keyIcon": "", - "key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} NodeJS │{$4}│{#keys}║{$2}", "text": "node --version", "format": "node {~1}" // {~1} removes first character (v) }, { "type": "command", "keyIcon": "", - "key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} Go │{$4}│{#keys}║{$2}", "text": "go version | cut -d' ' -f3", "format": "go {~2}" // {~2} removes first 2 characters (go) }, { "type": "command", "keyIcon": "", - "key": "│{#red}│ {icon} Zig │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} Zig │{$4}│{#keys}║{$2}", "text": "zig version", "format": "zig {}" }, { "type": "editor", - "key": "│{#red}│ {icon} Editor │{$4}│{#keys}│{$2}" + "key": "║{#red}│ {icon} Editor │{$4}│{#keys}║{$2}" }, { "type": "command", "keyIcon": "󰊢", - "key": "│{#red}│ {icon} Git │{$4}│{#keys}│{$2}", + "key": "║{#red}│ {icon} Git │{$4}│{#keys}║{$2}", "text": "git version", "format": "git {~12}" }, { "type": "font", - "key": "│{#red}│ {icon} Interface │{$4}│{#keys}│{$2}" + "key": "║{#red}│ {icon} Interface │{$4}│{#keys}║{$2}" }, { "type": "custom", - "key": "│{#red}└──────────────┴{$1}┘{#keys}│", + "key": "║{#red}└──────────────┴{$1}┘{#keys}║", "format": "" }, // Uptime section with magenta color theme { "type": "custom", - "key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D", + "key": "║{#magenta}┌──────────────┬{$1}┐{#keys}║\u001b[36D", "format": "{#bright_magenta} Uptime " }, { "type": "uptime", - "key": "│{#magenta}│ {icon} Uptime │{$4}│{#keys}│{$2}" + "key": "║{#magenta}│ {icon} Uptime │{$4}│{#keys}║{$2}" }, { "type": "users", "myselfOnly": true, // Only show current user "keyIcon": "", - "key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}" + "key": "║{#magenta}│ {icon} Login │{$4}│{#keys}║{$2}" }, { "condition": { // Conditional module: only show on non-macOS @@ -260,7 +261,7 @@ }, "type": "disk", "keyIcon": "", - "key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}", + "key": "║{#magenta}│ {icon} OS Age │{$4}│{#keys}║{$2}", "folders": "/", // Check root filesystem "format": "{create-time:10} [{days} days]" // Show creation time and age in days }, @@ -270,18 +271,18 @@ }, "type": "disk", "keyIcon": "", - "key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}", + "key": "║{#magenta}│ {icon} OS Age │{$4}│{#keys}║{$2}", "folders": "/System/Volumes/VM", // Work around for APFS on macOS "format": "{create-time:10} [{days} days]" }, { "type": "custom", - "key": "│{#magenta}└──────────────┴{$1}┘{#keys}│", + "key": "║{#magenta}└──────────────┴{$1}┘{#keys}║", "format": "" }, { "type": "custom", - "key": "└─────────────────{$1}┘", // Bottom border of the entire layout + "key": "╚═════════════════{$5}╝", // Bottom border of the entire layout "format": "" }, diff --git a/presets/examples/32.jsonc b/presets/examples/32.jsonc new file mode 100644 index 0000000000..ff69333b2b --- /dev/null +++ b/presets/examples/32.jsonc @@ -0,0 +1,57 @@ +// Inspired by microfetch +{ + "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json", + "logo": { + "type": "small" + }, + "general": { + "detectVersion": false + }, + "display": { + "separator": "  ", + "brightColor": false, + "key": { + "type": "both-2" + } + }, + "modules": [ + { + "type": "title", + "format": "{user-name-colored}{#light_red}@{host-name-colored} {#}{cwd}" + }, + { + "type": "os", + "key": "System " + }, + { + "type": "kernel", + "key": "Kernel " + }, + { + "type": "shell", + "key": "Shell " + }, + { + "type": "uptime", + "key": "Uptime " + }, + { + "type": "wm", + "key": "Desktop " + }, + { + "type": "memory", + "key": "Memory " + }, + { + "type": "disk", + "key": "Storage (/) ", + "folders": "/" + }, + { + "type": "colors", + "key": "Colors ", + "symbol": "circle" + } + ] +} diff --git a/src/common/FFPlatform.h b/src/common/FFPlatform.h index c714b5dda8..75e81713c3 100644 --- a/src/common/FFPlatform.h +++ b/src/common/FFPlatform.h @@ -19,6 +19,7 @@ typedef struct FFPlatform FFlist configDirs; // List of FFstrbuf, trailing slash included FFlist dataDirs; // List of FFstrbuf, trailing slash included FFstrbuf exePath; // The real path of current exe (empty if unavailable) + FFstrbuf cwd; // Trailing slash included uint32_t pid; #ifndef _WIN32 diff --git a/src/common/dbus.h b/src/common/dbus.h index ee5eb432ca..cecd744cbc 100644 --- a/src/common/dbus.h +++ b/src/common/dbus.h @@ -19,6 +19,7 @@ typedef struct FFDBusLibrary FF_LIBRARY_SYMBOL(dbus_message_iter_next) FF_LIBRARY_SYMBOL(dbus_message_unref) FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply_and_block) + FF_LIBRARY_SYMBOL(dbus_connection_unref) } FFDBusLibrary; typedef struct FFDBusData @@ -36,10 +37,13 @@ DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result); bool 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); +void ffDBusDestroyData(FFDBusData* data); 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, NULL); } +#define FF_DBUS_AUTO_DESTROY_DATA __attribute__((__cleanup__(ffDBusDestroyData))) + #endif // FF_HAVE_DBUS diff --git a/src/common/impl/FFPlatform.c b/src/common/impl/FFPlatform.c index 0c42a649f3..f84ab5878b 100644 --- a/src/common/impl/FFPlatform.c +++ b/src/common/impl/FFPlatform.c @@ -10,6 +10,7 @@ void ffPlatformInit(FFPlatform* platform) ffListInit(&platform->configDirs, sizeof(FFstrbuf)); ffListInit(&platform->dataDirs, sizeof(FFstrbuf)); ffStrbufInit(&platform->exePath); + ffStrbufInit(&platform->cwd); ffStrbufInit(&platform->userName); ffStrbufInit(&platform->fullUserName); @@ -49,6 +50,7 @@ void ffPlatformDestroy(FFPlatform* platform) ffStrbufDestroy(dir); ffListDestroy(&platform->dataDirs); ffStrbufDestroy(&platform->exePath); + ffStrbufDestroy(&platform->cwd); ffStrbufDestroy(&platform->userName); ffStrbufDestroy(&platform->hostName); diff --git a/src/common/impl/FFPlatform_unix.c b/src/common/impl/FFPlatform_unix.c index 985494bf9e..c93c863bde 100644 --- a/src/common/impl/FFPlatform_unix.c +++ b/src/common/impl/FFPlatform_unix.c @@ -1,5 +1,6 @@ #include "FFPlatform_private.h" #include "common/FFstrbuf.h" +#include "common/arrayUtils.h" #include "common/stringUtils.h" #include "common/io.h" #include "fastfetch_config.h" @@ -11,10 +12,14 @@ #include #ifdef __APPLE__ - #include + #include #include -#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#elif defined(__FreeBSD__) || defined(__NetBSD__) #include +#elif defined(__OpenBSD__) + #include + #include + #include "common/path.h" #elif defined(__HAIKU__) #include #include @@ -28,7 +33,11 @@ static void getExePath(FFPlatform* platform) if (exePathLen >= 0) exePath[exePathLen] = '\0'; #elif defined(__APPLE__) - int exePathLen = proc_pidpath((pid_t) platform->pid, exePath, sizeof(exePath)); + uint32_t exePathLen = sizeof(exePath); + if (_NSGetExecutablePath(exePath, &exePathLen) == 0) + exePathLen = (uint32_t) strlen(exePath); + else + exePathLen = 0; #elif defined(__FreeBSD__) || defined(__NetBSD__) size_t exePathLen = sizeof(exePath); if(sysctl( @@ -46,7 +55,81 @@ static void getExePath(FFPlatform* platform) else exePathLen--; // remove terminating NUL #elif defined(__OpenBSD__) + // OpenBSD doesn't have a reliable way to get the executable path. + // Current implementation uses argv[0], which can be easily spoofed. + // See #2195 size_t exePathLen = 0; + kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL); + if (kd) + { + int kpCount; + struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount); + if (kp && kpCount == 1) + { + char** argv = kvm_getargv(kd, kp, 0); + if (argv && argv[0]) + { + char* arg0 = argv[0]; + if (arg0[0]) + { + if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative) + { + exePathLen = strlen(arg0); + if (exePathLen < ARRAY_SIZE(exePath)) + { + memcpy(exePath, arg0, exePathLen); + exePath[exePathLen] = '\0'; + } + else + exePathLen = 0; + } + else + { + FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate(); + if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath)) + { + memcpy(exePath, tmpPath.chars, tmpPath.length + 1); + exePathLen = tmpPath.length; + } + } + + if (exePathLen > 0) + { + struct stat st; + if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode)) + { + int cntp; + struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp); + if (kf) + { + int i; + for (i = 0; i < cntp; i++) + { + if (kf[i].fd_fd == KERN_FILE_TEXT) + { + // KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list. + if (st.st_dev != (dev_t)kf[i].va_fsid || st.st_ino != (ino_t)kf[i].va_fileid) + i = -1; + break; + } + } + if (i < 0) + exePathLen = 0; + } + else + { + // If we can't get the list of open files, we can't verify that the file is actually the executable + // Assume it is + } + } + else + exePathLen = 0; + } + } + } + } + kvm_close(kd); + } #elif defined(__sun) ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1); if (exePathLen >= 0) @@ -224,6 +307,16 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts) #endif } +static void getCwd(FFPlatform* platform) +{ + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != NULL) + { + ffStrbufSetS(&platform->cwd, cwd); + ffStrbufEnsureEndsWithC(&platform->cwd, '/'); + } +} + void ffPlatformInitImpl(FFPlatform* platform) { platform->pid = (uint32_t) getpid(); @@ -235,6 +328,7 @@ void ffPlatformInitImpl(FFPlatform* platform) memset(&uts, 0, sizeof(uts)); getExePath(platform); + getCwd(platform); getHomeDir(platform, pwd); getCacheDir(platform); getConfigDirs(platform); diff --git a/src/common/impl/FFPlatform_windows.c b/src/common/impl/FFPlatform_windows.c index c09cdc2770..d502ee1ccb 100644 --- a/src/common/impl/FFPlatform_windows.c +++ b/src/common/impl/FFPlatform_windows.c @@ -208,10 +208,6 @@ static const char* detectWine(void) static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) { - RTL_OSVERSIONINFOW osVersion = { .dwOSVersionInfoSize = sizeof(osVersion) }; - if (!NT_SUCCESS(RtlGetVersion(&osVersion))) - return; - FF_HKEY_AUTO_DESTROY hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL)) return; @@ -221,40 +217,41 @@ static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) ffStrbufAppendF(&info->release, "%u.%u.%u.%u", - (unsigned) osVersion.dwMajorVersion, - (unsigned) osVersion.dwMinorVersion, - (unsigned) osVersion.dwBuildNumber, + (unsigned) SharedUserData->NtMajorVersion, + (unsigned) SharedUserData->NtMinorVersion, + (unsigned) SharedUserData->NtBuildNumber, (unsigned) ubr); ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL); const char* wineVersion = detectWine(); if (wineVersion) - ffStrbufSetF(&info->name, "Wine_%s", wineVersion); - else { - switch (osVersion.dwPlatformId) - { - case VER_PLATFORM_WIN32s: - ffStrbufSetStatic(&info->name, "WIN32s"); - break; - case VER_PLATFORM_WIN32_WINDOWS: - ffStrbufSetStatic(&info->name, "WIN32_WINDOWS"); - break; - case VER_PLATFORM_WIN32_NT: - ffStrbufSetStatic(&info->name, "WIN32_NT"); - break; - } + if (instance.config.general.detectVersion) + ffStrbufSetF(&info->name, "Wine_%s", wineVersion); + else + ffStrbufSetStatic(&info->name, "Wine"); } + else + ffStrbufSetStatic(&info->name, "WIN32_NT"); } -static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info) +static void getSystemPageSize(FFPlatformSysinfo* info) { - SYSTEM_INFO sysInfo; - GetNativeSystemInfo(&sysInfo); + SYSTEM_BASIC_INFORMATION sbi; + if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL))) + info->pageSize = sbi.PhysicalPageSize; + else + info->pageSize = 4096; +} - switch(sysInfo.wProcessorArchitecture) +static void getSystemArchitecture(FFPlatformSysinfo* info) +{ + SYSTEM_PROCESSOR_INFORMATION spi; + if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL))) { + switch (spi.ProcessorArchitecture) + { case PROCESSOR_ARCHITECTURE_AMD64: ffStrbufSetStatic(&info->architecture, "x86_64"); break; @@ -262,7 +259,7 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info) ffStrbufSetStatic(&info->architecture, "ia64"); break; case PROCESSOR_ARCHITECTURE_INTEL: - switch (sysInfo.wProcessorLevel) + switch (spi.ProcessorLevel) { case 4: ffStrbufSetStatic(&info->architecture, "i486"); @@ -300,15 +297,28 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info) default: ffStrbufSetStatic(&info->architecture, "unknown"); break; + } } +} - info->pageSize = sysInfo.dwPageSize; +static void getCwd(FFPlatform* platform) +{ + #if _WIN64 + static_assert( + offsetof(RTL_USER_PROCESS_PARAMETERS, Reserved2[5]) == 0x38, + "CurrentDirectory should be at offset 0x38 in RTL_USER_PROCESS_PARAMETERS. Structure layout mismatch detected."); + #endif + PCURDIR cwd = (PCURDIR) &NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Reserved2[5]; + ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer); + ffStrbufReplaceAllC(&platform->cwd, '\\', '/'); + ffStrbufEnsureEndsWithC(&platform->cwd, '/'); } void ffPlatformInitImpl(FFPlatform* platform) { platform->pid = (uint32_t) GetCurrentProcessId(); getExePath(platform); + getCwd(platform); getHomeDir(platform); getCacheDir(platform); getConfigDirs(platform); @@ -319,5 +329,6 @@ void ffPlatformInitImpl(FFPlatform* platform) getUserShell(platform); getSystemReleaseAndVersion(&platform->sysinfo); - getSystemArchitectureAndPageSize(&platform->sysinfo); + getSystemArchitecture(&platform->sysinfo); + getSystemPageSize(&platform->sysinfo); } diff --git a/src/common/impl/binary_windows.c b/src/common/impl/binary_windows.c index b6f0bb1faa..980c0d3132 100644 --- a/src/common/impl/binary_windows.c +++ b/src/common/impl/binary_windows.c @@ -1,10 +1,9 @@ #include "common/binary.h" #include "common/io.h" #include "common/stringUtils.h" -#include "common/mallocHelper.h" +#include "common/windows/nt.h" #include -#include #include #include @@ -17,19 +16,33 @@ */ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength) { - // Use MapAndLoad with cleanup attribute to ensure proper unloading - __attribute__((__cleanup__(UnMapAndLoad))) LOADED_IMAGE loadedImage = {}; - if (!MapAndLoad(peFile, NULL, &loadedImage, FALSE, TRUE)) - return "File could not be loaded"; + FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return "CreateFileA() failed"; - // Iterate through all sections in the PE file - for (ULONG i = 0; i < loadedImage.NumberOfSections; ++i) + FF_AUTO_CLOSE_FD HANDLE hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (!hMap) + return "CreateFileMappingW() failed"; + + void* base = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + if (!base) + return "MapViewOfFile() failed"; + + PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader(base); + if (!ntHeaders) + { + UnmapViewOfFile(base); + return "RtlImageNtHeader() failed"; + } + + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders); + for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section) { - PIMAGE_SECTION_HEADER section = &loadedImage.Sections[i]; // Look for initialized data sections with the name ".rdata" which typically contains string literals if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata")) { - uint8_t *data = (uint8_t *) loadedImage.MappedAddress + section->PointerToRawData; + uint8_t *data = (uint8_t *) base + section->PointerToRawData; // Scan the section for string literals for (size_t off = 0; off < section->SizeOfRawData; ++off) @@ -48,5 +61,6 @@ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *st } } + UnmapViewOfFile(base); return NULL; } diff --git a/src/common/impl/dbus.c b/src/common/impl/dbus.c index 87aacdf85e..cf45700a99 100644 --- a/src/common/impl/dbus.c +++ b/src/common/impl/dbus.c @@ -19,6 +19,7 @@ static bool loadLibSymbols(FFDBusLibrary* lib) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false) dbus = NULL; // don't auto dlclose return true; } @@ -51,6 +52,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) return NULL; } +void ffDBusDestroyData(FFDBusData* data) +{ + if (data->connection != NULL) + { + data->lib->ffdbus_connection_unref(data->connection); + data->connection = NULL; + } +} + bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result) { int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); diff --git a/src/common/impl/format.c b/src/common/impl/format.c index 469aceed48..7a5a14a79e 100644 --- a/src/common/impl/format.c +++ b/src/common/impl/format.c @@ -87,7 +87,7 @@ static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs, for (uint32_t i = 0; i < numArgs; ++i) { const FFformatarg* arg = &arguments[i]; - if (arg->name && strcasecmp(placeholderValue, arg->name) == 0) + if (arg->name && ffStrEqualsIgnCase(placeholderValue, arg->name)) return i + 1; } } @@ -204,7 +204,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments); // testing for an invalid index - if (index > numArgs) + if (index > numArgs || index < 1) { appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length); continue; @@ -230,7 +230,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments); // testing for an invalid index - if (index > numArgs) + if (index > numArgs || index < 1) { appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length); continue; diff --git a/src/common/impl/kmod.c b/src/common/impl/kmod.c deleted file mode 100644 index 145c6ab78b..0000000000 --- a/src/common/impl/kmod.c +++ /dev/null @@ -1,95 +0,0 @@ -#include "common/kmod.h" - -#if __linux__ -#include "common/io.h" - -bool ffKmodLoaded(const char* modName) -{ - static FFstrbuf modules; - if (modules.chars == NULL) - { - ffStrbufInitS(&modules, "\n"); - ffAppendFileBuffer("/proc/modules", &modules); - } - - if (modules.length == 0) return false; - - uint32_t len = (uint32_t) strlen(modName); - if (len > 250) return false; - - char temp[256]; - temp[0] = '\n'; - memcpy(temp + 1, modName, len); - temp[1 + len] = ' '; - return memmem(modules.chars, modules.length, temp, len + 2) != NULL; -} -#elif __FreeBSD__ -#include -#include - -bool ffKmodLoaded(const char* modName) -{ - return modfind(modName) >= 0; -} -#elif __NetBSD__ -#include "common/stringUtils.h" - -#include -#include - -typedef struct __attribute__((__packed__)) FFNbsdModList -{ - int len; - modstat_t mods[]; -} FFNbsdModList; - -bool ffKmodLoaded(const char* modName) -{ - static FFNbsdModList* list = NULL; - - if (list == NULL) - { - struct iovec iov = {}; - - for (size_t len = 8192;; len = iov.iov_len) - { - iov.iov_len = len; - iov.iov_base = realloc(iov.iov_base, len); - if (modctl(MODCTL_STAT, &iov) < 0) - { - free(iov.iov_base); - return true; // ignore errors - } - - if (len >= iov.iov_len) break; - } - list = (FFNbsdModList*) iov.iov_base; - } - - for (int i = 0; i < list->len; i++) - { - if (ffStrEquals(list->mods[i].ms_name, modName)) - return true; - } - - return false; -} -#elif __APPLE__ -#include "common/apple/cf_helpers.h" -#include -#include - -bool ffKmodLoaded(const char* modName) -{ - FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8); - FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks); - FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL); - FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys); - return CFDictionaryContainsKey(kextInfo, name); -} -#else -bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName) -{ - return true; // Don't generate kernel module related errors -} -#endif diff --git a/src/common/impl/kmod_apple.c b/src/common/impl/kmod_apple.c new file mode 100644 index 0000000000..eb28faee69 --- /dev/null +++ b/src/common/impl/kmod_apple.c @@ -0,0 +1,13 @@ +#include "common/kmod.h" +#include "common/apple/cf_helpers.h" +#include +#include + +bool ffKmodLoaded(const char* modName) +{ + FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8); + FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks); + FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL); + FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys); + return CFDictionaryContainsKey(kextInfo, name); +} diff --git a/src/common/impl/kmod_bsd.c b/src/common/impl/kmod_bsd.c new file mode 100644 index 0000000000..99ebafda7b --- /dev/null +++ b/src/common/impl/kmod_bsd.c @@ -0,0 +1,8 @@ +#include "common/kmod.h" +#include +#include + +bool ffKmodLoaded(const char* modName) +{ + return modfind(modName) >= 0; +} diff --git a/src/common/impl/kmod_linux.c b/src/common/impl/kmod_linux.c new file mode 100644 index 0000000000..940093b5db --- /dev/null +++ b/src/common/impl/kmod_linux.c @@ -0,0 +1,23 @@ +#include "common/kmod.h" +#include "common/io.h" + +bool ffKmodLoaded(const char* modName) +{ + static FFstrbuf modules; + if (modules.chars == NULL) + { + ffStrbufInitS(&modules, "\n"); + ffAppendFileBuffer("/proc/modules", &modules); + } + + if (modules.length == 0) return false; + + uint32_t len = (uint32_t) strlen(modName); + if (len > 250) return false; + + char temp[256]; + temp[0] = '\n'; + memcpy(temp + 1, modName, len); + temp[1 + len] = ' '; + return memmem(modules.chars, modules.length, temp, len + 2) != NULL; +} diff --git a/src/common/impl/kmod_nbsd.c b/src/common/impl/kmod_nbsd.c new file mode 100644 index 0000000000..f4e78eed8f --- /dev/null +++ b/src/common/impl/kmod_nbsd.c @@ -0,0 +1,43 @@ +#include "common/kmod.h" +#include "common/stringUtils.h" + +#include +#include + +typedef struct __attribute__((__packed__)) FFNbsdModList +{ + int len; + modstat_t mods[]; +} FFNbsdModList; + +bool ffKmodLoaded(const char* modName) +{ + static FFNbsdModList* list = NULL; + + if (list == NULL) + { + struct iovec iov = {}; + + for (size_t len = 8192;; len = iov.iov_len) + { + iov.iov_len = len; + iov.iov_base = realloc(iov.iov_base, len); + if (modctl(MODCTL_STAT, &iov) < 0) + { + free(iov.iov_base); + return true; // ignore errors + } + + if (len >= iov.iov_len) break; + } + list = (FFNbsdModList*) iov.iov_base; + } + + for (int i = 0; i < list->len; i++) + { + if (ffStrEquals(list->mods[i].ms_name, modName)) + return true; + } + + return false; +} diff --git a/src/common/impl/kmod_nosupport.c b/src/common/impl/kmod_nosupport.c new file mode 100644 index 0000000000..1ae3b0b33f --- /dev/null +++ b/src/common/impl/kmod_nosupport.c @@ -0,0 +1,6 @@ +#include "common/kmod.h" + +bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName) +{ + return true; // Don't generate kernel module related errors +} diff --git a/src/common/impl/kmod_sunos.c b/src/common/impl/kmod_sunos.c new file mode 100644 index 0000000000..e6c403c82f --- /dev/null +++ b/src/common/impl/kmod_sunos.c @@ -0,0 +1,24 @@ +#include "common/kmod.h" +#include "common/stringUtils.h" + +#include +#include + +bool ffKmodLoaded(const char* modName) +{ + struct modinfo modinfo = { + .mi_id = -1, + .mi_nextid = -1, + .mi_info = MI_INFO_ALL, + }; + + for (int id = -1; modctl(MODINFO, id, &modinfo) == 0; id = modinfo.mi_id) + { + modinfo.mi_name[MODMAXNAMELEN - 1] = '\0'; + + if (ffStrEquals(modinfo.mi_name, modName)) + return true; + } + + return !(errno == EINVAL || errno == ENOENT); +} diff --git a/src/common/impl/kmod_windows.c b/src/common/impl/kmod_windows.c new file mode 100644 index 0000000000..3eb275760c --- /dev/null +++ b/src/common/impl/kmod_windows.c @@ -0,0 +1,27 @@ +#include "common/kmod.h" +#include "common/windows/nt.h" +#include "common/mallocHelper.h" +#include "common/stringUtils.h" + +bool ffKmodLoaded(const char* modName) +{ + ULONG bufferSize = 0; + NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &bufferSize); + if (bufferSize == 0) + return true; // ignore errors + + FF_AUTO_FREE RTL_PROCESS_MODULES* buffer = malloc(bufferSize); + + if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, buffer, bufferSize, &bufferSize))) + return true; // ignore errors + + for (ULONG i = 0; i < buffer->NumberOfModules; i++) + { + const char* name = (const char*) buffer->Modules[i].FullPathName + buffer->Modules[i].OffsetToFileName; + + if (ffStrEqualsIgnCase(name, modName)) + return true; + } + + return false; +} diff --git a/src/common/impl/percent.c b/src/common/impl/percent.c index 1ab0c1e570..a367bce57b 100644 --- a/src/common/impl/percent.c +++ b/src/common/impl/percent.c @@ -261,6 +261,8 @@ bool ffPercentParseCommandOptions(const char* key, const char* subkey, const cha bool ffPercentParseJsonObject(yyjson_val* key, yyjson_val* value, FFPercentageModuleConfig* config) { + assert(key); + if (!unsafe_yyjson_equals_str(key, "percent")) return false; diff --git a/src/common/impl/processing_windows.c b/src/common/impl/processing_windows.c index f0dc096cd1..0faf27b41b 100644 --- a/src/common/impl/processing_windows.c +++ b/src/common/impl/processing_windows.c @@ -7,7 +7,6 @@ #include #include #include -#include enum { FF_PIPE_BUFSIZ = 8192 }; @@ -220,9 +219,6 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst if (hProcess == NULL) return false; - if (gui) - *gui = GetGuiResources(hProcess, GR_GDIOBJECTS) > 0; - if(ppid) { PROCESS_BASIC_INFORMATION info = {}; @@ -235,26 +231,41 @@ bool ffProcessGetInfoWindows(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFst else return false; } + if(exe) { // TODO: It's possible to query the command line with `NtQueryInformationProcess(60/*ProcessCommandLineInformation*/)` since Windows 8.1 - alignas(alignof(UNICODE_STRING)) uint8_t buffer[4096]; + alignas(UNICODE_STRING) uint8_t buffer[4096]; ULONG size; if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, &buffer, sizeof(buffer), &size))) { - UNICODE_STRING* imageName = (UNICODE_STRING*)buffer; - ffStrbufSetNWS(exe, imageName->Length / sizeof(wchar_t), imageName->Buffer); + UNICODE_STRING* imagePath = (UNICODE_STRING*)buffer; + ffStrbufSetNWS(exe, imagePath->Length / sizeof(wchar_t), imagePath->Buffer); if (exePath) ffStrbufSet(exePath, exe); + + if (pname && exeName) + { + *exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1; + ffStrbufSetS(pname, *exeName); + } } else return false; } - if(pname && exeName) + + if (gui) { - *exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1; - ffStrbufSetS(pname, *exeName); + SECTION_IMAGE_INFORMATION info = {}; + ULONG size; + if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size))) + { + assert(size == sizeof(info)); + *gui = info.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI; + } + else + return false; } return true; diff --git a/src/common/impl/settings.c b/src/common/impl/settings.c index bb7d820cf1..acb42195b1 100644 --- a/src/common/impl/settings.c +++ b/src/common/impl/settings.c @@ -201,7 +201,7 @@ FFvariant ffSettingsGetGnome(const char* dconfKey, const char* gsettingsSchemaNa FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvarianttype type) { - FFDBusData dbus; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) return FF_VARIANT_NULL; @@ -260,7 +260,7 @@ FFvariant ffSettingsGetXFConf(const char* channelName, const char* propertyName, FFvariant ffSettingsGetXFConfFirstMatch(const char* channelName, const char* propertyPrefix, FFvarianttype type, void* data, FFTestXfconfPropCallback* cb) { - FFDBusData dbus; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) return FF_VARIANT_NULL; diff --git a/src/common/impl/smbiosHelper.c b/src/common/impl/smbiosHelper.c index ba573b181b..2e7af8dd51 100644 --- a/src/common/impl/smbiosHelper.c +++ b/src/common/impl/smbiosHelper.c @@ -109,7 +109,7 @@ typedef struct FFSmbios20EntryPoint uint8_t SmbiosBcdRevision; } __attribute__((__packed__)) FFSmbios20EntryPoint; static_assert(offsetof(FFSmbios20EntryPoint, SmbiosBcdRevision) == 0x1E, - "FFSmbios30EntryPoint: Wrong struct alignment"); + "FFSmbios20EntryPoint: Wrong struct alignment"); typedef struct FFSmbios30EntryPoint { @@ -434,7 +434,7 @@ const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() return &table; } #elif defined(_WIN32) -#include +#include "common/windows/nt.h" #pragma GCC diagnostic ignored "-Wmultichar" @@ -450,36 +450,52 @@ typedef struct FFRawSmbiosData const FFSmbiosHeaderTable* ffGetSmbiosHeaderTable() { - static FFRawSmbiosData* buffer; + static SYSTEM_FIRMWARE_TABLE_INFORMATION* buffer; static FFSmbiosHeaderTable table; if (!buffer) { FF_DEBUG("Initializing Windows SMBIOS buffer"); - const DWORD signature = 'RSMB'; + FF_DEBUG("Querying system firmware table size with signature 'RSMB'"); - uint32_t bufSize = GetSystemFirmwareTable(signature, 0, NULL, 0); - if (bufSize <= sizeof(FFRawSmbiosData)) { - FF_DEBUG("Invalid firmware table size: %u (must be > %zu)", - bufSize, sizeof(FFRawSmbiosData)); + SYSTEM_FIRMWARE_TABLE_INFORMATION sfti = { + .ProviderSignature = 'RSMB', + .Action = SystemFirmwareTableGet, + }; + ULONG bufSize = 0; + NtQuerySystemInformation(SystemFirmwareTableInformation, &sfti, sizeof(sfti), &bufSize); + if (bufSize <= sizeof(FFRawSmbiosData) + sizeof(sfti)) { + FF_DEBUG("Invalid firmware table size: %lu (must be > %zu)", bufSize, sizeof(FFRawSmbiosData) + sizeof(sfti)); + return NULL; + } + if (bufSize != sfti.TableBufferLength + (ULONG) sizeof(sfti)) { + FF_DEBUG("Firmware table size mismatch: NtQuerySystemInformation returned %lu but expected %lu", + bufSize, sfti.TableBufferLength + (ULONG) sizeof(sfti)); return NULL; } - FF_DEBUG("Firmware table size: %u bytes", bufSize); + FF_DEBUG("Firmware table size: %lu bytes", bufSize); - buffer = (FFRawSmbiosData*) malloc(bufSize); - assert(buffer); + buffer = malloc(bufSize); + *buffer = sfti; FF_DEBUG("Allocated buffer for SMBIOS data"); - FF_MAYBE_UNUSED uint32_t resultSize = GetSystemFirmwareTable(signature, 0, buffer, bufSize); - assert(resultSize == bufSize); + if (!NT_SUCCESS(NtQuerySystemInformation(SystemFirmwareTableInformation, buffer, bufSize, &bufSize))) + { + FF_DEBUG("NtQuerySystemInformation(SystemFirmwareTableInformation) failed"); + free(buffer); + buffer = NULL; + return NULL; + } + FFRawSmbiosData* rawData = (FFRawSmbiosData*) buffer->TableBuffer; + FF_DEBUG("Successfully retrieved SMBIOS data: version %u.%u, length %u bytes", - buffer->SMBIOSMajorVersion, buffer->SMBIOSMinorVersion, buffer->Length); + rawData->SMBIOSMajorVersion, rawData->SMBIOSMinorVersion, rawData->Length); FF_DEBUG("Parsing SMBIOS table structures"); FF_MAYBE_UNUSED int structureCount = 0; for ( - const FFSmbiosHeader* header = (const FFSmbiosHeader*) buffer->SMBIOSTableData; - (const uint8_t*) header < buffer->SMBIOSTableData + buffer->Length; + const FFSmbiosHeader* header = (const FFSmbiosHeader*) rawData->SMBIOSTableData; + (const uint8_t*) header < rawData->SMBIOSTableData + rawData->Length; header = ffSmbiosNextEntry(header) ) { diff --git a/src/common/impl/temps.c b/src/common/impl/temps.c index c3c6f47f30..29d705aa41 100644 --- a/src/common/impl/temps.c +++ b/src/common/impl/temps.c @@ -109,6 +109,8 @@ bool ffTempsParseCommandOptions(const char* key, const char* subkey, const char* bool ffTempsParseJsonObject(yyjson_val* key, yyjson_val* value, bool* useTemp, FFColorRangeConfig* config) { + assert(key); + if (!unsafe_yyjson_equals_str(key, "temp")) return false; diff --git a/src/common/time.h b/src/common/time.h index d8506d3b87..b4e0587d74 100644 --- a/src/common/time.h +++ b/src/common/time.h @@ -4,17 +4,9 @@ #include #include #ifdef _WIN32 - #include #include + #include "common/windows/nt.h" #include - #include - - NTSYSCALLAPI - NTSTATUS - NTAPI - NtDelayExecution( - _In_ BOOLEAN Alertable, - _In_ PLARGE_INTEGER DelayInterval); #elif defined(__HAIKU__) #include #endif @@ -40,8 +32,7 @@ static inline double ffTimeGetTick(void) //In msec static inline uint64_t ffTimeGetNow(void) { #ifdef _WIN32 - uint64_t timeNow; - GetSystemTimeAsFileTime((FILETIME*) &timeNow); + uint64_t timeNow = ffKSystemTimeToUInt64(&SharedUserData->SystemTime); return (timeNow - 116444736000000000ull) / 10000ull; #elif defined(__HAIKU__) return (uint64_t) real_time_clock_usecs() / 1000u; @@ -58,7 +49,7 @@ static inline bool ffTimeSleep(uint32_t msec) #ifdef _WIN32 LARGE_INTEGER interval; interval.QuadPart = -(int64_t) msec * 10000; // Relative time in 100-nanosecond intervals - return NtDelayExecution(TRUE, &interval) == STATUS_SUCCESS; + return NT_SUCCESS(NtDelayExecution(TRUE, &interval)); #else return nanosleep(&(struct timespec){ msec / 1000, (long) (msec % 1000) * 1000000 }, NULL) == 0; #endif diff --git a/src/common/windows/manifest.xml b/src/common/windows/manifest.xml index 86d6231443..ed9a326347 100644 --- a/src/common/windows/manifest.xml +++ b/src/common/windows/manifest.xml @@ -16,7 +16,8 @@ UTF-8 - false + true/pm + PerMonitor SegmentHeap diff --git a/src/common/windows/nt.h b/src/common/windows/nt.h index b4d83d66aa..446bd271fc 100644 --- a/src/common/windows/nt.h +++ b/src/common/windows/nt.h @@ -1,7 +1,18 @@ #pragma once -#include +#include #include +#include +#include +#include + +enum { + SystemModuleInformation = 11, + SystemFirmwareTableInformation = 76, + SystemBootEnvironmentInformation = 90, + SystemLogicalProcessorAndGroupInformation = 107, + SystemSecureBootInformation = 146, +}; #define D3DKMT_ALIGN64 __attribute__((aligned(8))) @@ -270,3 +281,392 @@ typedef struct _PROCESS_DEVICEMAP_INFORMATION_EX #ifndef NtCurrentProcess #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) #endif + +typedef struct _CURDIR +{ + UNICODE_STRING DosPath; + HANDLE Handle; +} CURDIR, *PCURDIR; + +PIMAGE_NT_HEADERS NTAPI RtlImageNtHeader(IN PVOID BaseOfImage); + +/** + * The SECTION_IMAGE_INFORMATION structure contains detailed information about an image section. + */ +typedef struct _SECTION_IMAGE_INFORMATION +{ + PVOID TransferAddress; // The address of the image entry point function. + ULONG ZeroBits; // The number of high-order address bits that must be zero in the image base address. + SIZE_T MaximumStackSize; // The maximum stack size of threads from the PE file header. + SIZE_T CommittedStackSize; // The initial stack size of threads from the PE file header. + ULONG SubSystemType; // The image subsystem from the PE file header (e.g., Windows GUI, Windows CUI, POSIX). + union + { + struct + { + USHORT SubSystemMinorVersion; + USHORT SubSystemMajorVersion; + }; + ULONG SubSystemVersion; + }; + union + { + struct + { + USHORT MajorOperatingSystemVersion; + USHORT MinorOperatingSystemVersion; + }; + ULONG OperatingSystemVersion; + }; + USHORT ImageCharacteristics; // The image characteristics from the PE file header. + USHORT DllCharacteristics; // The DLL characteristics flags (e.g., ASLR, NX compatibility). + USHORT Machine; // The image architecture (e.g., x86, x64, ARM). + BOOLEAN ImageContainsCode; // The image contains native executable code. + union + { + UCHAR ImageFlags; + struct + { + UCHAR ComPlusNativeReady : 1; // The image contains precompiled .NET assembly generated by NGEN (Native Image Generator). + UCHAR ComPlusILOnly : 1; // the image contains only Microsoft Intermediate Language (IL) assembly. + UCHAR ImageDynamicallyRelocated : 1; // The image was mapped using a random base address rather than the preferred base address. + UCHAR ImageMappedFlat : 1; // The image was mapped using a single contiguous region, rather than separate regions for each section. + UCHAR BaseBelow4gb : 1; // The image was mapped using a base address below the 4 GB boundary. + UCHAR ComPlusPrefer32bit : 1; // The image prefers to run as a 32-bit process, even on a 64-bit system. + UCHAR Reserved : 2; + }; + }; + ULONG LoaderFlags; // Reserved by ntdll.dll for the Windows loader. + ULONG ImageFileSize; // The size of the image, in bytes, including all headers. + ULONG CheckSum; // The image file checksum, from the PE optional header. +} SECTION_IMAGE_INFORMATION, *PSECTION_IMAGE_INFORMATION; + +typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION +{ + GUID BootIdentifier; + FIRMWARE_TYPE FirmwareType; + union + { + ULONGLONG BootFlags; + struct + { + ULONGLONG DbgMenuOsSelection : 1; // REDSTONE4 + ULONGLONG DbgHiberBoot : 1; + ULONGLONG DbgSoftBoot : 1; + ULONGLONG DbgMeasuredLaunch : 1; + ULONGLONG DbgMeasuredLaunchCapable : 1; // 19H1 + ULONGLONG DbgSystemHiveReplace : 1; + ULONGLONG DbgMeasuredLaunchSmmProtections : 1; + ULONGLONG DbgMeasuredLaunchSmmLevel : 7; // 20H1 + ULONGLONG DbgBugCheckRecovery : 1; // 24H2 + ULONGLONG DbgFASR : 1; + ULONGLONG DbgUseCachedBcd : 1; + }; + }; +} SYSTEM_BOOT_ENVIRONMENT_INFORMATION; + +typedef struct _RTL_PROCESS_MODULE_INFORMATION +{ + PVOID Section; + PVOID MappedBase; + PVOID ImageBase; + ULONG ImageSize; + ULONG Flags; + USHORT LoadOrderIndex; + USHORT InitOrderIndex; + USHORT LoadCount; + USHORT OffsetToFileName; + UCHAR FullPathName[256]; +} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; + +typedef struct _RTL_PROCESS_MODULES +{ + ULONG NumberOfModules; + _Field_size_(NumberOfModules) RTL_PROCESS_MODULE_INFORMATION Modules[1]; +} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; + +NTSTATUS NTAPI NtQuerySystemEnvironmentValueEx( + _In_ PCUNICODE_STRING VariableName, + _In_ const GUID* VendorGuid, + _Out_writes_bytes_opt_(*BufferLength) PVOID Buffer, + _Inout_ PULONG BufferLength, + _Out_opt_ PULONG Attributes // EFI_VARIABLE_* +); + +NTSTATUS NTAPI RtlGUIDFromString(IN PCUNICODE_STRING GuidString, OUT GUID* Guid); + +typedef struct _SYSTEM_SECUREBOOT_INFORMATION +{ + BOOLEAN SecureBootEnabled; + BOOLEAN SecureBootCapable; +} SYSTEM_SECUREBOOT_INFORMATION, *PSYSTEM_SECUREBOOT_INFORMATION; + +NTSTATUS NTAPI NtQuerySystemInformationEx( + _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass, + _In_reads_bytes_(InputBufferLength) PVOID InputBuffer, + _In_ ULONG InputBufferLength, + _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation, + _In_ ULONG SystemInformationLength, + _Out_opt_ PULONG ReturnLength +); + +typedef enum _SYSTEM_FIRMWARE_TABLE_ACTION +{ + SystemFirmwareTableEnumerate, + SystemFirmwareTableGet, + SystemFirmwareTableMax +} SYSTEM_FIRMWARE_TABLE_ACTION; + +typedef struct _SYSTEM_FIRMWARE_TABLE_INFORMATION +{ + ULONG ProviderSignature; // (same as the GetSystemFirmwareTable function) + SYSTEM_FIRMWARE_TABLE_ACTION Action; + ULONG TableID; + ULONG TableBufferLength; + _Field_size_bytes_(TableBufferLength) UCHAR TableBuffer[]; +} SYSTEM_FIRMWARE_TABLE_INFORMATION, *PSYSTEM_FIRMWARE_TABLE_INFORMATION; + +NTSTATUS NTAPI NtDelayExecution(_In_ BOOLEAN Alertable, _In_ PLARGE_INTEGER DelayInterval); + +/** + * The KSYSTEM_TIME structure represents interrupt time, system time, and time zone bias. + */ +typedef struct _KSYSTEM_TIME +{ + ULONG LowPart; + LONG High1Time; + LONG High2Time; +} KSYSTEM_TIME, *PKSYSTEM_TIME; + +/** + * PROCESSOR_FEATURE_MAX defines the maximum number of processor feature flags + * that may be reported by the system. + */ +#define PROCESSOR_FEATURE_MAX 64 + +/** + * The KUSER_SHARED_DATA structure contains information shared with user-mode. + * + * \sa https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data + */ +typedef struct _KUSER_SHARED_DATA +{ + // + // Current low 32-bit of tick count and tick count multiplier. + // + // N.B. The tick count is updated each time the clock ticks. + // + + ULONG TickCountLowDeprecated; + ULONG TickCountMultiplier; + + // + // Current 64-bit interrupt time in 100ns units. + // + + volatile KSYSTEM_TIME InterruptTime; + + // + // Current 64-bit system time in 100ns units. + // + + volatile KSYSTEM_TIME SystemTime; + + // + // Current 64-bit time zone bias. + // + + volatile KSYSTEM_TIME TimeZoneBias; + + // + // Support image magic number range for the host system. + // + // N.B. This is an inclusive range. + // + + USHORT ImageNumberLow; + USHORT ImageNumberHigh; + + // + // Copy of system root in unicode. + // + // N.B. This field must be accessed via the RtlGetNtSystemRoot API for + // an accurate result. + // + + WCHAR NtSystemRoot[260]; + + // + // Maximum stack trace depth if tracing enabled. + // + + ULONG MaxStackTraceDepth; + + // + // Crypto exponent value. + // + + ULONG CryptoExponent; + + // + // Time zone ID. + // + + ULONG TimeZoneId; + + // + // Minimum size of a large page on the system, in bytes. + // + // N.B. Returned by GetLargePageMinimum() function. + // + + ULONG LargePageMinimum; + + // + // This value controls the Application Impact Telemetry (AIT) Sampling rate. + // + // This value determines how frequently the system records AIT events, + // which are used by the Application Experience and compatibility + // subsystems to evaluate application behavior, performance, and + // potential compatibility issues. + // + // Lower values increase sampling frequency, while higher values reduce it. + // The kernel updates this field as part of its internal telemetry and + // heuristics logic. + // + + ULONG AitSamplingValue; + + // + // This value controls Application Compatibility (AppCompat) switchback processing. + // + + union + { + ULONG AppCompatFlag; + struct + { + ULONG SwitchbackEnabled : 1; // Basic switchback processing + ULONG ExtendedHeuristics : 1; // Extended switchback heuristics + ULONG TelemetryFallback : 1; // Telemetry-driven fallback + ULONG Reserved : 29; + } AppCompatFlags; + }; + + // + // Current Kernel Root RNG state seed version + // + + ULONGLONG RNGSeedVersion; + + // + // This value controls assertion failure handling. + // + // Historically (prior to Windows 10), this value was also used by + // Code Integrity (CI), AppLocker, and related security components to + // determine the minimum validation requirements for executable images, + // drivers, and privileged operations. + // + // In modern Windows versions, this field is used primarily by the kernel's + // diagnostic and validation infrastructure to decide how assertion failures + // should be handled (e.g., logging, debugger break-in, or bugcheck). + + ULONG GlobalValidationRunlevel; + + // + // Monotonic stamp incremented by the kernel whenever the system's + // time zone bias value changes. + // + // N.B. This field must be accessed via the RtlGetSystemTimeAndBias API for + // an accurate result. + // This value is read before and after accessing the bias fields to determine + // whether the time zone data changed during the read. If the stamp differs, + // the caller must re-read the bias values to ensure consistency. + // + + volatile LONG TimeZoneBiasStamp; + + // + // The shared collective build number undecorated with C or F. + // GetVersionEx hides the real number + // + + ULONG NtBuildNumber; + + // + // Product type. + // + // N.B. This field must be accessed via the RtlGetNtProductType API for + // an accurate result. + // + + NT_PRODUCT_TYPE NtProductType; + BOOLEAN ProductTypeIsValid; + BOOLEAN Reserved0[1]; + + // + // Native hardware processor architecture of the running system. + // + // N.B. User-mode components read this field to determine the true system + // architecture, especially in WOW64 scenarios where the process architecture + // differs from the native one. + // + + USHORT NativeProcessorArchitecture; + + // + // The NT Version. + // + // N. B. Note that each process sees a version from its PEB, but if the + // process is running with an altered view of the system version, + // the following two fields are used to correctly identify the + // version + // + + ULONG NtMajorVersion; + ULONG NtMinorVersion; + + // + // Processor features. + // + + BOOLEAN ProcessorFeatures[PROCESSOR_FEATURE_MAX]; + + // ... more fields follow, but we don't need them +} KUSER_SHARED_DATA, *PKUSER_SHARED_DATA; + +#define SharedUserData ((const KUSER_SHARED_DATA*) 0x7FFE0000UL) + +static inline uint64_t ffKSystemTimeToUInt64(const volatile KSYSTEM_TIME* pTime) +{ + #if _WIN64 + + return *(uint64_t*) pTime; + + #else + + uint32_t low, high1, high2; + + do { + high1 = pTime->High1Time; + low = pTime->LowPart; + high2 = pTime->High2Time; + } while (high1 != high2); + + return ((uint64_t) high1 << 32) | low; + #endif +} + +static inline bool ffIsWindows10OrGreater() +{ + #if FF_WIN7_COMPAT + return SharedUserData->NtMajorVersion >= 10; + #else + return true; + #endif +} + +static inline bool ffIsWindows11OrGreater() +{ + return ffIsWindows10OrGreater() && SharedUserData->NtBuildNumber >= 22000; +} diff --git a/src/common/windows/variant.cpp b/src/common/windows/variant.cpp new file mode 100644 index 0000000000..fa3b9a0e54 --- /dev/null +++ b/src/common/windows/variant.cpp @@ -0,0 +1,21 @@ +#include "variant.hpp" + +#include + +FFWmiVariant::FFWmiVariant(std::initializer_list strings): FFWmiVariant() +{ + SAFEARRAYBOUND bound = { + .cElements = (ULONG) strings.size(), + .lLbound = 0, + }; + SAFEARRAY* psa = SafeArrayCreate(VT_BSTR, 1, &bound); + + LONG i = 0; + for (PCWSTR str : strings) { + SafeArrayPutElement(psa, &i, bstr_t(str)); + ++i; + } + + this->vt = VT_ARRAY | VT_BSTR; + this->parray = psa; +} diff --git a/src/common/windows/variant.hpp b/src/common/windows/variant.hpp index 84a471ff9c..b2e68cfa8f 100644 --- a/src/common/windows/variant.hpp +++ b/src/common/windows/variant.hpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include template struct FFBaseVariant: TVariant @@ -137,6 +139,7 @@ struct FFWmiVariant: FFBaseVariant FFWmiVariant(const FFWmiVariant&) = delete; FFWmiVariant(FFWmiVariant&&); // don't define it to enforce NRVO optimization explicit FFWmiVariant() { VariantInit(this); } + explicit FFWmiVariant(std::initializer_list strings); ~FFWmiVariant() { VariantClear(this); } }; static_assert(sizeof(FFWmiVariant) == sizeof(VARIANT), ""); @@ -149,3 +152,18 @@ struct FFPropVariant: FFBaseVariant ~FFPropVariant() { PropVariantClear(this); } }; static_assert(sizeof(FFPropVariant) == sizeof(PROPVARIANT), ""); + +namespace +{ + // Provide our bstr_t to avoid libstdc++ dependency + struct bstr_t + { + explicit bstr_t(const wchar_t* str) noexcept: _bstr(SysAllocString(str)) {} + ~bstr_t(void) noexcept { SysFreeString(_bstr); } + explicit operator const wchar_t*(void) const noexcept { return _bstr; } + operator BSTR(void) const noexcept { return _bstr; } + + private: + BSTR _bstr; + }; +} diff --git a/src/common/windows/version.c b/src/common/windows/version.c index 4019edb849..6d5ceefa18 100644 --- a/src/common/windows/version.c +++ b/src/common/windows/version.c @@ -4,6 +4,8 @@ #include +#define FF_VERSION_LANG_EN_US L"040904b0" + bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrbuf* version) { DWORD handle; @@ -19,40 +21,25 @@ bool ffGetFileVersion(const wchar_t* filePath, const wchar_t* stringName, FFstrb UINT len; if (VerQueryValueW(versionData, L"\\", (void **)&verInfo, &len) && len && verInfo->dwSignature == 0xFEEF04BD) { - ffStrbufAppendF(version, "%u.%u.%u.%u", - (unsigned)((verInfo->dwProductVersionMS >> 16) & 0xffff), - (unsigned)((verInfo->dwProductVersionMS >> 0) & 0xffff), - (unsigned)((verInfo->dwProductVersionLS >> 16) & 0xffff), - (unsigned)((verInfo->dwProductVersionLS >> 0) & 0xffff)); + ffStrbufSetF(version, "%u.%u.%u.%u", + (unsigned)((verInfo->dwProductVersionMS >> 16) & 0xffff), + (unsigned)((verInfo->dwProductVersionMS >> 0) & 0xffff), + (unsigned)((verInfo->dwProductVersionLS >> 16) & 0xffff), + (unsigned)((verInfo->dwProductVersionLS >> 0) & 0xffff)); return true; } } else { - struct - { - WORD language; - WORD codePage; - }* translations; - - UINT translationsLen; + wchar_t* value; + UINT valueLen; - if (VerQueryValueW(versionData, L"\\VarFileInfo\\Translation", - (void **) &translations, &translationsLen) && - translationsLen >= sizeof(*translations)) + wchar_t subBlock[128] = L"\\StringFileInfo\\" FF_VERSION_LANG_EN_US L"\\"; + wcscat_s(subBlock, ARRAY_SIZE(subBlock), stringName); + if (VerQueryValueW(versionData, subBlock, (void **)&value, &valueLen) && valueLen > 0) { - wchar_t subBlock[128]; - snwprintf(subBlock, ARRAY_SIZE(subBlock), L"\\StringFileInfo\\%04x%04x\\%ls", - translations[0].language, translations[0].codePage, stringName); - - wchar_t* value; - UINT valueLen; - - if (VerQueryValueW(versionData, subBlock, (void **)&value, &valueLen) && valueLen > 0) - { - ffStrbufSetWS(version, value); - return true; - } + ffStrbufSetWS(version, value); + return true; } } } diff --git a/src/common/windows/wmi.hpp b/src/common/windows/wmi.hpp index c506a8868d..a72a72dccf 100644 --- a/src/common/windows/wmi.hpp +++ b/src/common/windows/wmi.hpp @@ -8,7 +8,6 @@ extern "C" { #include #include -#include #include "variant.hpp" @@ -74,21 +73,6 @@ struct FFWmiQuery } }; -namespace -{ - // Provide our bstr_t to avoid libstdc++ dependency - struct bstr_t - { - explicit bstr_t(const wchar_t* str) noexcept: _bstr(SysAllocString(str)) {} - ~bstr_t(void) noexcept { SysFreeString(_bstr); } - explicit operator const wchar_t*(void) const noexcept { return _bstr; } - operator BSTR(void) const noexcept { return _bstr; } - - private: - BSTR _bstr; - }; -} - #else // Win32 COM headers requires C++ compiler #error Must be included in C++ source file diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index ba0111d3a0..3196885115 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -11,7 +11,6 @@ #include #include #include -#include static const char* detectWithCmApi(FFBatteryOptions* options, FFlist* results) { diff --git a/src/detection/bios/bios_windows.c b/src/detection/bios/bios_windows.c index 059ebce464..716add3704 100644 --- a/src/detection/bios/bios_windows.c +++ b/src/detection/bios/bios_windows.c @@ -5,28 +5,7 @@ #include "common/windows/registry.h" #include -#include - -typedef struct _SYSTEM_BOOT_ENVIRONMENT_INFORMATION -{ - GUID BootIdentifier; - FIRMWARE_TYPE FirmwareType; - union - { - ULONGLONG BootFlags; - struct - { - ULONGLONG DbgMenuOsSelection : 1; // REDSTONE4 - ULONGLONG DbgHiberBoot : 1; - ULONGLONG DbgSoftBoot : 1; - ULONGLONG DbgMeasuredLaunch : 1; - ULONGLONG DbgMeasuredLaunchCapable : 1; // 19H1 - ULONGLONG DbgSystemHiveReplace : 1; - ULONGLONG DbgMeasuredLaunchSmmProtections : 1; - ULONGLONG DbgMeasuredLaunchSmmLevel : 7; // 20H1 - }; - }; -} SYSTEM_BOOT_ENVIRONMENT_INFORMATION; +#include "common/windows/nt.h" #elif __OpenBSD__ #include "common/io.h" @@ -90,7 +69,7 @@ const char* ffDetectBios(FFBiosResult* bios) // Same as GetFirmwareType, but support (?) Windows 7 // https://ntdoc.m417z.com/system_information_class SYSTEM_BOOT_ENVIRONMENT_INFORMATION sbei; - if (NT_SUCCESS(NtQuerySystemInformation(90 /*SystemBootEnvironmentInformation*/, &sbei, sizeof(sbei), NULL))) + if (NT_SUCCESS(NtQuerySystemInformation(SystemBootEnvironmentInformation, &sbei, sizeof(sbei), NULL))) { switch (sbei.FirmwareType) { diff --git a/src/detection/bluetooth/bluetooth_linux.c b/src/detection/bluetooth/bluetooth_linux.c index 162e60a51c..4f8c1c8039 100644 --- a/src/detection/bluetooth/bluetooth_linux.c +++ b/src/detection/bluetooth/bluetooth_linux.c @@ -191,7 +191,7 @@ static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIt static const char* detectBluetooth(FFlist* devices, int32_t connectedCount) { - FFDBusData dbus; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); if(error) return error; diff --git a/src/detection/bluetooth/bluetooth_windows.cpp b/src/detection/bluetooth/bluetooth_windows.cpp index b54882d613..3109037f4d 100644 --- a/src/detection/bluetooth/bluetooth_windows.cpp +++ b/src/detection/bluetooth/bluetooth_windows.cpp @@ -6,8 +6,6 @@ extern "C" #include "common/windows/unicode.hpp" #include "common/windows/util.hpp" -STDAPI InitVariantFromStringArray(_In_reads_(cElems) PCWSTR *prgsz, _In_ ULONG cElems, _Out_ VARIANT *pvar); - extern "C" const char* ffBluetoothDetectBattery(FFlist* devices) { @@ -27,13 +25,7 @@ const char* ffBluetoothDetectBattery(FFlist* devices) if (FAILED(pnpEntityClass->GetMethod(bstr_t(L"GetDeviceProperties"), 0, &pInParams, NULL))) return "Failed to get GetDeviceProperties method"; - VARIANT devicePropertyKeys; - PCWSTR props[] = { L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress" }; - - if (FAILED(InitVariantFromStringArray(props, ARRAY_SIZE(props), &devicePropertyKeys))) - return "Failed to init variant from string array"; - on_scope_exit releaseDevicePropertyKeys([&] { VariantClear(&devicePropertyKeys); }); - + FFWmiVariant devicePropertyKeys({ L"{104EA319-6EE2-4701-BD47-8DDBF425BBE5} 2", L"DEVPKEY_Bluetooth_DeviceAddress" }); if (FAILED(pInParams->Put(L"devicePropertyKeys", 0, &devicePropertyKeys, CIM_FLAG_ARRAY | CIM_STRING))) return "Failed to put devicePropertyKeys"; } diff --git a/src/detection/bluetoothradio/bluetoothradio_linux.c b/src/detection/bluetoothradio/bluetoothradio_linux.c index f7f3971ba8..1583d43d08 100644 --- a/src/detection/bluetoothradio/bluetoothradio_linux.c +++ b/src/detection/bluetoothradio/bluetoothradio_linux.c @@ -112,7 +112,7 @@ static const char* detectBluetooth(FFlist* devices) if(dirp == NULL) return "Failed to open /sys/class/bluetooth"; - FFDBusData dbus; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); if(error) return error; diff --git a/src/detection/bootmgr/bootmgr_windows.c b/src/detection/bootmgr/bootmgr_windows.c index 3fe46b161f..e8aced1372 100644 --- a/src/detection/bootmgr/bootmgr_windows.c +++ b/src/detection/bootmgr/bootmgr_windows.c @@ -34,21 +34,30 @@ const char* ffDetectBootmgr(FFBootmgrResult* result) if (enablePrivilege(L"SeSystemEnvironmentPrivilege") != NULL) return "Failed to enable SeSystemEnvironmentPrivilege"; - if (GetFirmwareEnvironmentVariableW(L"BootCurrent", L"{" FF_EFI_GLOBAL_GUID L"}", &result->order, sizeof(result->order)) != 2) - return "GetFirmwareEnvironmentVariableW(BootCurrent) failed"; + GUID efiGlobalGuid; + if (!NT_SUCCESS(RtlGUIDFromString(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"{" FF_EFI_GLOBAL_GUID L"}"), &efiGlobalGuid))) + return "RtlGUIDFromString() failed"; + + ULONG size = sizeof(result->order); + if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(L"BootCurrent"), &efiGlobalGuid, &result->order, &size, NULL))) + return "NtQuerySystemEnvironmentValueEx(BootCurrent) failed"; + if (size != sizeof(result->order)) + return "NtQuerySystemEnvironmentValueEx(BootCurrent) returned unexpected size"; uint8_t buffer[2048]; - wchar_t key[16]; + wchar_t key[9]; swprintf(key, ARRAY_SIZE(key), L"Boot%04X", result->order); - uint32_t size = GetFirmwareEnvironmentVariableW(key, L"{" FF_EFI_GLOBAL_GUID L"}", buffer, sizeof(buffer)); + size = sizeof(buffer); + if (!NT_SUCCESS(NtQuerySystemEnvironmentValueEx(&(UNICODE_STRING) RTL_CONSTANT_STRING(key), &efiGlobalGuid, buffer, &size, NULL))) + return "NtQuerySystemEnvironmentValueEx(Boot####) failed"; if (size < sizeof(FFEfiLoadOption) || size == ARRAY_SIZE(buffer)) - return "GetFirmwareEnvironmentVariableW(Boot####) failed"; + return "NtQuerySystemEnvironmentValueEx(Boot####) returned unexpected size"; ffEfiFillLoadOption((FFEfiLoadOption *)buffer, result); - DWORD uefiSecureBootEnabled = 0, bufSize = 0; - if (RegGetValueW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Control\\SecureBoot\\State", L"UEFISecureBootEnabled", RRF_RT_REG_DWORD, NULL, &uefiSecureBootEnabled, &bufSize) == ERROR_SUCCESS) - result->secureBoot = !!uefiSecureBootEnabled; + SYSTEM_SECUREBOOT_INFORMATION ssi; + if (NT_SUCCESS(NtQuerySystemInformation(SystemSecureBootInformation, &ssi, sizeof(ssi), NULL))) + result->secureBoot = ssi.SecureBootEnabled; return NULL; } diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 1e1333d9c0..c0555ec21d 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -6,6 +6,7 @@ #include #include "common/windows/perflib_.h" +#include "common/windows/nt.h" #include static inline void ffPerfCloseQueryHandle(HANDLE* phQuery) @@ -212,15 +213,16 @@ static const char* detectMaxSpeedBySmbios(FFCPUResult* cpu) static const char* detectNCores(FFCPUResult* cpu) { - DWORD length = 0; - GetLogicalProcessorInformationEx(RelationAll, NULL, &length); + LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationAll; + ULONG length = 0; + NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length); if (length == 0) return "GetLogicalProcessorInformationEx(RelationAll, NULL, &length) failed"; SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); - if (!pProcessorInfo || !GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length)) + if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length))) return "GetLogicalProcessorInformationEx(RelationAll, pProcessorInfo, &length) failed"; for( diff --git a/src/detection/cpucache/cpucache_windows.c b/src/detection/cpucache/cpucache_windows.c index e04f276e01..537a69a75f 100644 --- a/src/detection/cpucache/cpucache_windows.c +++ b/src/detection/cpucache/cpucache_windows.c @@ -1,19 +1,19 @@ #include "cpucache.h" #include "common/mallocHelper.h" - -#include +#include "common/windows/nt.h" const char* ffDetectCPUCache(FFCPUCacheResult* result) { + LOGICAL_PROCESSOR_RELATIONSHIP lpr = RelationCache; DWORD length = 0; - GetLogicalProcessorInformationEx(RelationCache, NULL, &length); + NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), NULL, 0, &length); if (length == 0) return "GetLogicalProcessorInformationEx(RelationCache, NULL, &length) failed"; SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX* FF_AUTO_FREE pProcessorInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(length); - if (!pProcessorInfo || !GetLogicalProcessorInformationEx(RelationCache, pProcessorInfo, &length)) + if (!NT_SUCCESS(NtQuerySystemInformationEx(SystemLogicalProcessorAndGroupInformation, &lpr, sizeof(lpr), pProcessorInfo, length, &length))) return "GetLogicalProcessorInformationEx(RelationCache, pProcessorInfo, &length) failed"; for( diff --git a/src/detection/cpuusage/cpuusage_windows.c b/src/detection/cpuusage/cpuusage_windows.c index 89ce1a1a09..1e96f43d54 100644 --- a/src/detection/cpuusage/cpuusage_windows.c +++ b/src/detection/cpuusage/cpuusage_windows.c @@ -1,13 +1,12 @@ -#include "fastfetch.h" #include "detection/cpuusage/cpuusage.h" - #include "common/mallocHelper.h" +#include "common/debug.h" #include -#include #include #include #include "common/windows/perflib_.h" +#include "common/windows/nt.h" static const char* getInfoByNqsi(FFlist* cpuTimes) { @@ -155,20 +154,17 @@ static const char* getInfoByPerflib(FFlist* cpuTimes) const char* ffGetCpuUsageInfo(FFlist* cpuTimes) { - #if !FF_WIN7_COMPAT - static uint8_t winver = 10; // Assume Windows 10 or later for WoA - #else - static uint8_t winver = 0; - if (winver == 0) - winver = (uint8_t) ffStrbufToUInt(&instance.state.platform.sysinfo.release, 1); - #endif - - if (winver >= 10) + const char* error = NULL; + + if (ffIsWindows10OrGreater()) { - if (getInfoByPerflib(cpuTimes) == NULL) return NULL; + error = getInfoByPerflib(cpuTimes); + FF_DEBUG("Get CPU usage info by Perflib: %s", error ?: "success"); + if (!error) return NULL; ffListClear(cpuTimes); - winver = 1; // Fall back to NQSI } - return getInfoByNqsi(cpuTimes); + error = getInfoByNqsi(cpuTimes); + FF_DEBUG("Get CPU usage info by NtQuerySystemInformation: %s", error ?: "success"); + return error; } diff --git a/src/detection/de/de_linux.c b/src/detection/de/de_linux.c index ee2aeafcc5..b7ac7a6edc 100644 --- a/src/detection/de/de_linux.c +++ b/src/detection/de/de_linux.c @@ -58,7 +58,7 @@ static void getKDE(FFstrbuf* result, FF_MAYBE_UNUSED FFDEOptions* options) static const char* getGnomeByDbus(FF_MAYBE_UNUSED FFstrbuf* result) { #ifdef FF_HAVE_DBUS - FFDBusData dbus; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; if (ffDBusLoadData(DBUS_BUS_SESSION, &dbus) != NULL) return "ffDBusLoadData() failed"; diff --git a/src/detection/disk/disk_windows.c b/src/detection/disk/disk_windows.c index 47cd3f504e..50545338e5 100644 --- a/src/detection/disk/disk_windows.c +++ b/src/detection/disk/disk_windows.c @@ -18,9 +18,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks) // For cross-platform portability; used by `presets/examples/13.jsonc` if (options->folders.length == 1 && options->folders.chars[0] == '/') { - wchar_t path[MAX_PATH + 1]; - GetSystemWindowsDirectoryW(path, ARRAY_SIZE(path)); - options->folders.chars[0] = (char) path[0]; + options->folders.chars[0] = (char) SharedUserData->NtSystemRoot[0]; ffStrbufAppendS(&options->folders, ":\\"); } diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index b18e502dbd..ab2cfbd1c8 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -2,41 +2,30 @@ #include "common/windows/unicode.h" #include "common/edidHelper.h" -#include -#include -#include +#include +#include -typedef struct FFMonitorInfo -{ - HMONITOR handle; - MONITORINFOEXW info; -} FFMonitorInfo; - -static CALLBACK BOOL MonitorEnumProc( - HMONITOR hMonitor, - FF_MAYBE_UNUSED HDC hdc, - FF_MAYBE_UNUSED LPRECT lpRect, - LPARAM lParam -) -{ - FFlist* monitors = (FFlist*) lParam; - FFMonitorInfo* newMonitor = ffListAdd(monitors); - newMonitor->handle = hMonitor; - newMonitor->info.cbSize = sizeof(newMonitor->info); - - return GetMonitorInfoW(hMonitor, (MONITORINFO*) &newMonitor->info); -} +// http://undoc.airesoft.co.uk/user32.dll/IsThreadDesktopComposited.php +BOOL WINAPI IsThreadDesktopComposited(); +BOOL WINAPI GetDpiForMonitorInternal(HMONITOR hmonitor, MONITOR_DPI_TYPE dpiType, UINT* dpiX, UINT* dpiY); static void detectDisplays(FFDisplayServerResult* ds) { - FF_LIST_AUTO_DESTROY monitors = ffListCreate(sizeof(FFMonitorInfo)); - EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM) &monitors); - #if FF_WIN7_COMPAT - HDC hdc = GetDC(NULL); - uint32_t systemDpi = (uint32_t) GetDeviceCaps(hdc, LOGPIXELSX); - if (systemDpi == 0) systemDpi = 96; - ReleaseDC(NULL, hdc); + static __typeof__(GetDpiForMonitorInternal)* ffGetDpiForMonitor; + if (!ffGetDpiForMonitor) + { + HMODULE user32 = GetModuleHandleW(L"user32.dll"); + if (user32) + { + // GetDpiForMonitorInternal (returns BOOL) is in user32, while GetDpiForMonitor (returns HRESULT) is in shcore. + // Both are available since Windows 8.1. Not sure why Microsoft decided to put them in different DLLs, but whatever. + // Use GetDpiForMonitorInternal for loading one less dll + ffGetDpiForMonitor = (void*) GetProcAddress(user32, "GetDpiForMonitorInternal"); + } + } + #else + #define ffGetDpiForMonitor GetDpiForMonitorInternal #endif DISPLAYCONFIG_PATH_INFO paths[128]; @@ -54,7 +43,8 @@ static void detectDisplays(FFDisplayServerResult* ds) { for (uint32_t i = 0; i < pathCount; ++i) { - DISPLAYCONFIG_PATH_INFO* path = &paths[i]; + const DISPLAYCONFIG_PATH_INFO* path = &paths[i]; + const DISPLAYCONFIG_SOURCE_MODE* sourceMode = &modes[path->sourceInfo.modeInfoIdx].sourceMode; DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName = { .header = { @@ -65,20 +55,6 @@ static void detectDisplays(FFDisplayServerResult* ds) }, }; - FFMonitorInfo* monitorInfo = NULL; - if (DisplayConfigGetDeviceInfo(&sourceName.header) == ERROR_SUCCESS) - { - FF_LIST_FOR_EACH(FFMonitorInfo, item, monitors) - { - if (wcsncmp(item->info.szDevice, sourceName.viewGdiDeviceName, ARRAY_SIZE(sourceName.viewGdiDeviceName)) == 0) - { - monitorInfo = item; - break; - } - } - } - if (!monitorInfo) continue; - FF_STRBUF_AUTO_DESTROY name = ffStrbufCreate(); uint32_t physicalWidth = 0, physicalHeight = 0; @@ -131,8 +107,8 @@ static void detectDisplays(FFDisplayServerResult* ds) } } - uint32_t width = modes[path->sourceInfo.modeInfoIdx].sourceMode.width; - uint32_t height = modes[path->sourceInfo.modeInfoIdx].sourceMode.height; + uint32_t width = sourceMode->width; + uint32_t height = sourceMode->height; if (path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE90 || path->targetInfo.rotation == DISPLAYCONFIG_ROTATION_ROTATE270) { @@ -168,21 +144,32 @@ static void detectDisplays(FFDisplayServerResult* ds) preferredRefreshRate = freq.Numerator / (double) freq.Denominator; } - uint32_t scaledWidth = (uint32_t) (monitorInfo->info.rcMonitor.right - monitorInfo->info.rcMonitor.left); - uint32_t scaledHeight = (uint32_t) (monitorInfo->info.rcMonitor.bottom - monitorInfo->info.rcMonitor.top); + uint32_t systemDpi = 0; + + if (ffGetDpiForMonitor) + { + HMONITOR hMonitor = MonitorFromPoint(*(POINT*)&sourceMode->position, MONITOR_DEFAULTTONULL); + if (hMonitor) + { + UINT ignored; + ffGetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &systemDpi, &ignored); + } + } + + if (systemDpi == 0) + { + HDC hdc = GetDC(NULL); + systemDpi = (uint32_t) GetDeviceCaps(hdc, LOGPIXELSX); + if (systemDpi == 0) systemDpi = 96; + ReleaseDC(NULL, hdc); + } FFDisplayResult* display = ffdsAppendDisplay(ds, width, height, path->targetInfo.refreshRate.Numerator / (double) path->targetInfo.refreshRate.Denominator, - #if FF_WIN7_COMPAT - // Windows 7 always reports scaled width as the real width, as I tested on VM with 200% scaling. - scaledWidth == width ? width * 96 / systemDpi : scaledWidth, - scaledHeight == height ? height * 96 / systemDpi : scaledHeight, - #else - scaledWidth, - scaledHeight, - #endif + width * 96 / systemDpi, + height * 96 / systemDpi, preferredMode.width, preferredMode.height, preferredRefreshRate, @@ -193,8 +180,8 @@ static void detectDisplays(FFDisplayServerResult* ds) path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED || path->targetInfo.outputTechnology == DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED ? FF_DISPLAY_TYPE_BUILTIN : FF_DISPLAY_TYPE_EXTERNAL, - !!(monitorInfo->info.dwFlags & MONITORINFOF_PRIMARY), - (uint64_t)(uintptr_t) monitorInfo->handle, + sourceMode->position.x == 0 && sourceMode->position.y == 0, + path->sourceInfo.id, physicalWidth, physicalHeight, "GDI" @@ -253,8 +240,7 @@ static void detectDisplays(FFDisplayServerResult* ds) void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) { - BOOL enabled; - if(SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled) + if (IsThreadDesktopComposited()) { ffStrbufSetStatic(&ds->wmProcessName, "dwm.exe"); ffStrbufSetStatic(&ds->wmPrettyName, "Desktop Window Manager"); diff --git a/src/detection/displayserver/linux/wmde.c b/src/detection/displayserver/linux/wmde.c index 5037215894..8454e51f66 100644 --- a/src/detection/displayserver/linux/wmde.c +++ b/src/detection/displayserver/linux/wmde.c @@ -226,9 +226,12 @@ static void applyPrettyNameIfDE(FFDisplayServerResult* result, const char* name) ) { ffStrbufSetS(&result->deProcessName, "lxqt-session"); ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_LXQT); - FF_STRBUF_AUTO_DESTROY wmProcessNameBuffer = ffStrbufCreate(); - ffParsePropFileConfig("lxqt/session.conf", "window_manager =", &wmProcessNameBuffer); - applyBetterWM(result, wmProcessNameBuffer.chars); + if (result->wmProcessName.length == 0) + { + FF_STRBUF_AUTO_DESTROY wmProcessNameBuffer = ffStrbufCreate(); + ffParsePropFileConfig("lxqt/session.conf", "window_manager =", &wmProcessNameBuffer); + applyBetterWM(result, wmProcessNameBuffer.chars); + } } else if( diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 7d24448b54..ce19f02c17 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -78,6 +78,19 @@ static void* xcbGetProperty(XcbRandrData* data, xcb_window_t window, const char* return replyValue; } +static xcb_randr_get_output_property_reply_t* xcbRandrGetProperty(XcbRandrData* data, xcb_randr_output_t output, const char* name) +{ + xcb_intern_atom_cookie_t requestAtomCookie = data->ffxcb_intern_atom(data->connection, true, (uint16_t) strlen(name), name); + FF_AUTO_FREE xcb_intern_atom_reply_t* requestAtomReply = data->ffxcb_intern_atom_reply(data->connection, requestAtomCookie, NULL); + + 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); + return data->ffxcb_randr_get_output_property_reply(data->connection, outputPropertyCookie, NULL); + } + return NULL; +} + static void xcbDetectWMfromEWMH(XcbRandrData* data, xcb_window_t rootWindow, FFDisplayServerResult* result) { if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0) @@ -121,28 +134,34 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, 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; + FF_AUTO_FREE xcb_randr_get_output_property_reply_t* edidReply = xcbRandrGetProperty(data, output, "EDID"); uint8_t* edidData = NULL; uint32_t edidLength = 0; - if(requestAtomReply) + if(edidReply) { - 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(edidReply); + if(len >= 128) { - 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; - } + edidData = data->ffxcb_randr_get_output_property_data(edidReply); + edidLength = (uint32_t) len; } } + if(edidData) + { + ffStrbufClear(name); + ffEdidGetName(edidData, name); + } + + uint8_t randrEmulation = 0; + FF_AUTO_FREE xcb_randr_get_output_property_reply_t* randrEmulationReply = xcbRandrGetProperty(data, output, "RANDR Emulation"); + if(randrEmulationReply) + { + int len = data->ffxcb_randr_get_output_property_data_length(randrEmulationReply); + if(len >= 1) + randrEmulation = data->ffxcb_randr_get_output_property_data(randrEmulationReply)[0]; + } + 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) @@ -204,9 +223,12 @@ static bool xcbRandrHandleOutput(XcbRandrData* data, xcb_randr_output_t output, 0, (uint32_t) outputInfoReply->mm_width, (uint32_t) outputInfoReply->mm_height, - currentMode ? "xcb-randr-mode" : "xcb-randr-crtc" + randrEmulation + ? (currentMode ? "xcb-randr-emu-mode" : "xcb-randr-emu-crtc") + : (currentMode ? "xcb-randr-mode" : "xcb-randr-crtc") + ); - if (item && edidLength) + if (item && edidData && edidLength >= 128) { 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); diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 8820ad9355..eb407f7b5b 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -48,6 +48,32 @@ static unsigned char* x11GetProperty(XrandrData* data, Display* display, Window return result; } +static uint8_t* xrandrGetProperty(XrandrData* data, RROutput output, const char* name, uint32_t* bufSize) +{ + unsigned long size = 0; + uint8_t* result = NULL; + Atom atomEdid = data->ffXInternAtom(data->display, name, true); + if (atomEdid != None) + { + int actual_format = 0; + unsigned long bytes_after = 0; + Atom actual_type = None; + if (data->ffXRRGetOutputProperty(data->display, output, atomEdid, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &size, &bytes_after, &result) == Success) + { + if (size == 0) + data->ffXFree(result); + else + { + if (bufSize) + *bufSize = (uint32_t) size; + return result; + } + } + } + + return NULL; +} + static void x11DetectWMFromEWMH(XrandrData* data, FFDisplayServerResult* result) { if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0) @@ -75,7 +101,7 @@ static void x11FetchServerVendor(XrandrData* data, FFDisplayServerResult* result ffStrbufSetS(&result->wmProtocolName, serverVendor); } -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) +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, bool randrEmulation) { //We do the check here, because we want the best fallback display if this call failed if(screenResources == NULL) @@ -131,7 +157,9 @@ static bool xrandrHandleCrtc(XrandrData* data, XRROutputInfo* output, FFstrbuf* 0, (uint32_t) output->mm_width, (uint32_t) output->mm_height, - currentMode ? "xlib-randr-mode" : "xlib-randr-crtc" + randrEmulation + ? (currentMode ? "xlib-randr-emu-mode" : "xlib-randr-emu-crtc") + : (currentMode ? "xlib-randr-mode" : "xlib-randr-crtc") ); if (item) @@ -154,30 +182,25 @@ static bool xrandrHandleOutput(XrandrData* data, RROutput output, FFstrbuf* name if(outputInfo == NULL) return false; - uint8_t* edidData = NULL; - unsigned long edidLength = 0; - Atom atomEdid = data->ffXInternAtom(data->display, "EDID", true); - if (atomEdid != None) + uint32_t edidLength = 0; + uint8_t* edidData = xrandrGetProperty(data, output, RR_PROPERTY_RANDR_EDID, &edidLength); + + if (edidLength >= 128) { - int actual_format = 0; - unsigned long bytes_after = 0; - Atom actual_type = None; - if (data->ffXRRGetOutputProperty(data->display, output, atomEdid, 0, 100, false, false, AnyPropertyType, &actual_type, &actual_format, &edidLength, &bytes_after, &edidData) == Success) - { - if (edidLength >= 128) - { - ffStrbufClear(name); - ffEdidGetName(edidData, name); - } - else - edidLength = 0; - } + ffStrbufClear(name); + ffEdidGetName(edidData, name); } + else + edidLength = 0; + + uint8_t* randrEmulation = xrandrGetProperty(data, output, "RANDR Emulation", NULL); - bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, (uint32_t) edidLength, screenResources, bitDepth, scaleFactor); + bool res = xrandrHandleCrtc(data, outputInfo, name, primary, displayType, edidData, edidLength, screenResources, bitDepth, scaleFactor, randrEmulation ? !!randrEmulation[0] : false); if (edidData) data->ffXFree(edidData); + if (randrEmulation) + data->ffXFree(randrEmulation); data->ffXRRFreeOutputInfo(outputInfo); return res; diff --git a/src/detection/editor/editor.c b/src/detection/editor/editor.c index d8221f42f3..576938d47c 100644 --- a/src/detection/editor/editor.c +++ b/src/detection/editor/editor.c @@ -115,7 +115,8 @@ const char* ffDetectEditor(FFEditorResult* result) ffStrbufEqualS(&result->exe, "hx") || ffStrbufEqualS(&result->exe, "code") || ffStrbufEqualS(&result->exe, "pluma") || - ffStrbufEqualS(&result->exe, "sublime_text") + ffStrbufEqualS(&result->exe, "sublime_text") || + ffStrbufEqualS(&result->exe, "zeditor") ) param = "--version"; else if ( ffStrbufEqualS(&result->exe, "kak") || diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 853cb5217f..dfb24d8fff 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -352,11 +352,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* D3DKMT_ADAPTERTYPE adapterType = {}; D3DKMT_QUERYADAPTERINFO queryAdapterInfo = { .hAdapter = openAdapterFromLuid.hAdapter, - .Type = KMTQAITYPE_ADAPTERTYPE, + .Type = KMTQAITYPE_ADAPTERTYPE, // Windows 8 and later .pPrivateDriverData = &adapterType, .PrivateDriverDataSize = sizeof(adapterType), }; - if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) // Vista and later + if (NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) { FF_DEBUG("Queried adapter type - HybridDiscrete: %d, HybridIntegrated: %d", adapterType.HybridDiscrete, adapterType.HybridIntegrated); if (adapterType.HybridDiscrete) @@ -369,7 +369,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* FF_DEBUG("Failed to query adapter type"); } - if (gpu->frequency == FF_GPU_FREQUENCY_UNSET) + if (gpu->frequency == FF_GPU_FREQUENCY_UNSET && ffIsWindows11OrGreater()) { FF_DEBUG("Trying to get GPU frequency information"); for (ULONG nodeIdx = 0; ; nodeIdx++) @@ -379,14 +379,14 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* }; queryAdapterInfo = (D3DKMT_QUERYADAPTERINFO) { .hAdapter = openAdapterFromLuid.hAdapter, - .Type = KMTQAITYPE_NODEMETADATA, + .Type = KMTQAITYPE_NODEMETADATA, // Windows 10 and later .pPrivateDriverData = &nodeMetadata, .PrivateDriverDataSize = sizeof(nodeMetadata), }; if (!NT_SUCCESS(D3DKMTQueryAdapterInfo(&queryAdapterInfo))) { FF_DEBUG("No more nodes to query (index %lu)", nodeIdx); - break; // Windows 10 and later + break; } if (nodeMetadata.NodeData.EngineType != DXGK_ENGINE_TYPE_3D) { @@ -395,11 +395,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* } D3DKMT_QUERYSTATISTICS queryStatistics = { - .Type = D3DKMT_QUERYSTATISTICS_NODE2, + .Type = D3DKMT_QUERYSTATISTICS_NODE2, // Windows 11 (22H2) and later .AdapterLuid = *(LUID*)&adapterLuid, .QueryNode2 = { .PhysicalAdapterIndex = 0, .NodeOrdinal = (UINT16) nodeIdx }, }; - if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) // Windows 11 (22H2) and later + if (NT_SUCCESS(D3DKMTQueryStatistics(&queryStatistics))) { gpu->frequency = (uint32_t) (queryStatistics.QueryResult.NodeInformation.NodePerfData.MaxFrequency / 1000 / 1000); FF_DEBUG("Found GPU frequency: %u MHz", gpu->frequency); @@ -422,11 +422,11 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* FF_DEBUG("Failed to open adapter from LUID"); } - if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET) + if (options->temp && gpu->temperature == FF_GPU_TEMP_UNSET && ffIsWindows10OrGreater()) { FF_DEBUG("Trying to get GPU temperature"); D3DKMT_QUERYSTATISTICS queryStatistics = { - .Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER, + .Type = D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER, // Windows 10 (1803) and later .AdapterLuid = *(LUID*)&adapterLuid, .QueryPhysAdapter = { .PhysicalAdapterIndex = 0 }, }; diff --git a/src/detection/keyboard/keyboard_linux.c b/src/detection/keyboard/keyboard_linux.c index 8d1c9ed20b..9492710b58 100644 --- a/src/detection/keyboard/keyboard_linux.c +++ b/src/detection/keyboard/keyboard_linux.c @@ -19,9 +19,9 @@ const char* ffDetectKeyboard(FFlist* devices /* List of FFKeyboardDevice */) if (!ffStrEndsWith(entry->d_name, "-event-kbd")) continue; - char buffer[32]; // `../eventX` + char buffer[32]; // `../eventXX` ssize_t len = readlinkat(dirfd(dirp), entry->d_name, buffer, ARRAY_SIZE(buffer) - 1); - if (len != strlen("../eventX") || !ffStrStartsWith(buffer, "../event")) continue; + if (len <= (ssize_t) strlen("../event") || !ffStrStartsWith(buffer, "../event")) continue; buffer[len] = 0; const char* eventid = buffer + strlen("../event"); @@ -30,8 +30,8 @@ const char* ffDetectKeyboard(FFlist* devices /* List of FFKeyboardDevice */) uint32_t index = (uint32_t) strtoul(eventid, &pend, 10); if (pend == eventid) continue; - // Ignore duplicate entries - if (flags & (1UL << index)) + // Ignore duplicate entries (flags supports up to 64 event indices) + if (index >= 64 || (flags & (1UL << index))) continue; flags |= (1UL << index); @@ -41,7 +41,7 @@ const char* ffDetectKeyboard(FFlist* devices /* List of FFKeyboardDevice */) if (ffAppendFileBuffer(path.chars, &name)) { ffStrbufTrimRightSpace(&name); - ffStrbufSubstrBefore(&path, path.length - 4); + ffStrbufSubstrBefore(&path, path.length - (uint32_t) strlen("name")); FFKeyboardDevice* device = (FFKeyboardDevice*) ffListAdd(devices); ffStrbufInitMove(&device->name, &name); diff --git a/src/detection/keyboard/keyboard_windows.c b/src/detection/keyboard/keyboard_windows.c index c02d1f5a1e..1853d72fbc 100644 --- a/src/detection/keyboard/keyboard_windows.c +++ b/src/detection/keyboard/keyboard_windows.c @@ -5,7 +5,6 @@ #include "common/mallocHelper.h" #include "common/windows/unicode.h" -#include #include #include #include diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index e7d5f0ad02..67b434d4e9 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -180,6 +180,7 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul ffStrbufClear(&result->album); ffStrbufClear(&result->url); ffStrbufClear(&result->status); + data->lib->ffdbus_message_unref(reply); return false; } } @@ -261,7 +262,7 @@ static void getBestBus(FFDBusData* data, FFMediaResult* result) static const char* getMedia(FFMediaResult* result) { - FFDBusData data; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData data = {}; const char* error = ffDBusLoadData(DBUS_BUS_SESSION, &data); if(error != NULL) return error; diff --git a/src/detection/mouse/mouse_windows.c b/src/detection/mouse/mouse_windows.c index 73c6c79555..0bc9b35d25 100644 --- a/src/detection/mouse/mouse_windows.c +++ b/src/detection/mouse/mouse_windows.c @@ -5,7 +5,6 @@ #include "common/mallocHelper.h" #include "common/windows/unicode.h" -#include #include #include #include diff --git a/src/detection/opengl/opengl_shared.c b/src/detection/opengl/opengl_shared.c index fa70abf748..a3ee920f3e 100644 --- a/src/detection/opengl/opengl_shared.c +++ b/src/detection/opengl/opengl_shared.c @@ -98,6 +98,9 @@ static const char* eglHandleSurface(FFOpenGLResult* result, EGLData* data, bool const char* error = eglHandleContext(result, data); FF_DEBUG("eglHandleContext() returns: %s", error ?: "success"); + FF_DEBUG("Releasing current EGL context"); + data->ffeglMakeCurrent(data->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + FF_DEBUG("Destroying EGL context"); data->ffeglDestroyContext(data->display, data->context); return error; diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index 14c06a7750..2e58c3e4e5 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -269,6 +269,15 @@ FF_MAYBE_UNUSED static bool detectDebianDerived(FFOSResult* result) ffStrbufSetStatic(&result->prettyName, "TrueNAS Scale"); return true; } + else if (ffPathExists("/usr/bin/emmabuntus_config.sh", FF_PATHTYPE_FILE)) + { + // Emmabuntüs + ffStrbufSetStatic(&result->id, "emmabuntus"); + ffStrbufSetStatic(&result->idLike, "debian"); + ffStrbufSetStatic(&result->name, "Emmabuntüs"); + getDebianVersion(result); + return true; + } else { // Hack for MX Linux. See #847 diff --git a/src/detection/os/os_windows.cpp b/src/detection/os/os_windows.c similarity index 75% rename from src/detection/os/os_windows.cpp rename to src/detection/os/os_windows.c index d56cdd7b36..bdb979d309 100644 --- a/src/detection/os/os_windows.cpp +++ b/src/detection/os/os_windows.c @@ -1,31 +1,10 @@ -extern "C" { #include "os.h" #include "common/library.h" #include "common/stringUtils.h" #include "common/windows/registry.h" -} -#include "common/windows/unicode.hpp" -#include "common/windows/wmi.hpp" - -static const char* getOsNameByWmi(FFstrbuf* osName) -{ - FFWmiQuery query(L"SELECT Caption FROM Win32_OperatingSystem"); - if(!query) - return "Query WMI service failed"; +#include "common/windows/unicode.h" - if(FFWmiRecord record = query.next()) - { - if(auto vtCaption = record.get(L"Caption")) - { - ffStrbufSetWSV(osName, vtCaption.get()); - ffStrbufTrimRight(osName, ' '); - return NULL; - } - return "Get Caption failed"; - } - - return "No WMI result returned"; -} +#include PWSTR WINAPI BrandingFormatString(PCWSTR format); @@ -45,24 +24,13 @@ static bool getCodeName(FFOSResult* os) return true; } -static const char* getOsNameByWinbrand(FFstrbuf* osName) +void ffDetectOSImpl(FFOSResult* os) { //https://dennisbabkin.com/blog/?t=how-to-tell-the-real-version-of-windows-your-app-is-running-on#ver_string - FF_LIBRARY_LOAD_MESSAGE(winbrand, "winbrand" FF_LIBRARY_EXTENSION, 1); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(winbrand, BrandingFormatString); - - const wchar_t* rawName = ffBrandingFormatString(L"%WINDOWS_LONG%"); - ffStrbufSetWS(osName, rawName); + const wchar_t* rawName = BrandingFormatString(L"%WINDOWS_LONG%"); + ffStrbufSetWS(&os->variant, rawName); GlobalFree((HGLOBAL)rawName); - return NULL; -} - -extern "C" -void ffDetectOSImpl(FFOSResult* os) -{ - if(getOsNameByWinbrand(&os->variant) && getOsNameByWmi(&os->variant)) - return; - + ffStrbufSet(&os->prettyName, &os->variant); ffStrbufTrimRight(&os->variant, ' '); //WMI returns the "Microsoft" prefix while BrandingFormatString doesn't. Make them consistent. diff --git a/src/detection/packages/packages.h b/src/detection/packages/packages.h index 12e9879330..8b8a435d95 100644 --- a/src/detection/packages/packages.h +++ b/src/detection/packages/packages.h @@ -27,6 +27,7 @@ typedef struct FFPackagesResult uint32_t lpkgbuild; uint32_t macports; uint32_t mport; + uint32_t moss; uint32_t nixDefault; uint32_t nixSystem; uint32_t nixUser; diff --git a/src/detection/packages/packages_linux.c b/src/detection/packages/packages_linux.c index 07998bc91a..8d9c9b0beb 100644 --- a/src/detection/packages/packages_linux.c +++ b/src/detection/packages/packages_linux.c @@ -492,6 +492,7 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts, if (!(options->disabled & FF_PACKAGES_FLAG_PACSTALL_BIT)) packageCounts->pacstall += getNumElements(baseDir, "/var/lib/pacstall/metadata", false); if (!(options->disabled & FF_PACKAGES_FLAG_PISI_BIT)) packageCounts->pisi += getNumElements(baseDir, "/var/lib/pisi/package", true); if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT)) packageCounts->pkgsrc += getNumElements(baseDir, "/usr/pkg/pkgdb", DT_DIR); + if (!(options->disabled & FF_PACKAGES_FLAG_MOSS_BIT)) packageCounts->moss += getSQLite3Int(baseDir, "/.moss/db/state", "SELECT COUNT(*) FROM state_selections WHERE state_id = (SELECT MAX(id) FROM state)", "moss"); } static void getPackageCountsRegular(FFstrbuf* baseDir, FFPackagesResult* packageCounts, FFPackagesOptions* options) diff --git a/src/detection/swap/swap_windows.c b/src/detection/swap/swap_windows.c index 0909267ecf..ced111f6cb 100644 --- a/src/detection/swap/swap_windows.c +++ b/src/detection/swap/swap_windows.c @@ -1,5 +1,4 @@ #include "swap.h" -#include "common/mallocHelper.h" #include "common/windows/unicode.h" #include diff --git a/src/detection/terminalfont/terminalfont_windows.c b/src/detection/terminalfont/terminalfont_windows.c index 9cf9945714..2d8c087c74 100644 --- a/src/detection/terminalfont/terminalfont_windows.c +++ b/src/detection/terminalfont/terminalfont_windows.c @@ -1,5 +1,6 @@ #include "common/library.h" #include "common/io.h" +#include "common/path.h" #include "common/processing.h" #include "common/properties.h" #include "common/windows/unicode.h" @@ -94,45 +95,52 @@ static void detectFromWindowsTerminal(const FFstrbuf* terminalExe, FFTerminalFon FF_STRBUF_AUTO_DESTROY json = ffStrbufCreate(); const char* error = NULL; - if(terminalExe && terminalExe->length > 0 && !ffStrbufEqualS(terminalExe, "Windows Terminal")) + if(terminalExe && ffIsAbsolutePath(terminalExe->chars)) { - char jsonPath[MAX_PATH + 1]; - char* pathEnd = ffStrCopy(jsonPath, terminalExe->chars, ffStrbufLastIndexC(terminalExe, '\\') + 1); - ffStrCopy(pathEnd, ".portable", ARRAY_SIZE(jsonPath) - (size_t) (pathEnd - jsonPath) - 1); + FF_STRBUF_AUTO_DESTROY jsonPath = ffStrbufCreateA(MAX_PATH); + ffStrbufAppendNS(&jsonPath, ffStrbufLastIndexC(terminalExe, '\\') + 1, terminalExe->chars); + ffStrbufAppendS(&jsonPath, ".portable"); - if(ffPathExists(jsonPath, FF_PATHTYPE_ANY)) + if(ffPathExists(jsonPath.chars, FF_PATHTYPE_ANY)) { - ffStrCopy(pathEnd, "settings\\settings.json", ARRAY_SIZE(jsonPath) - (size_t) (pathEnd - jsonPath) - 1); - if(!ffAppendFileBuffer(jsonPath, &json)) + ffStrbufSubstrBefore(&jsonPath, jsonPath.length - strlen(".portable")); + ffStrbufAppendS(&jsonPath, "settings\\settings.json"); + if(!ffAppendFileBuffer(jsonPath.chars, &json)) error = "Error reading Windows Terminal portable settings JSON file"; } - else if(SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, jsonPath))) + else { - size_t remaining = ARRAY_SIZE(jsonPath) - strlen(jsonPath) - 1; - if(ffStrbufContainIgnCaseS(terminalExe, "_8wekyb3d8bbwe\\")) + PWSTR localAppDataW = NULL; + if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, &localAppDataW))) { - // Microsoft Store version - if(ffStrbufContainIgnCaseS(terminalExe, ".WindowsTerminalPreview_")) + ffStrbufSetWS(&jsonPath, localAppDataW); + CoTaskMemFree(localAppDataW); + + if(ffStrbufContainIgnCaseS(terminalExe, "_8wekyb3d8bbwe\\")) { - // Preview version - strncat(jsonPath, "\\Packages\\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\\LocalState\\settings.json", remaining); - if(!ffAppendFileBuffer(jsonPath, &json)) - error = "Error reading Windows Terminal Preview settings JSON file"; + // Microsoft Store version + if(ffStrbufContainIgnCaseS(terminalExe, ".WindowsTerminalPreview_")) + { + // Preview version + ffStrbufAppendS(&jsonPath, "\\Packages\\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\\LocalState\\settings.json"); + if(!ffAppendFileBuffer(jsonPath.chars, &json)) + error = "Error reading Windows Terminal Preview settings JSON file"; + } + else + { + // Stable version + ffStrbufAppendS(&jsonPath, "\\Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json"); + if(!ffAppendFileBuffer(jsonPath.chars, &json)) + error = "Error reading Windows Terminal settings JSON file"; + } } else { - // Stable version - strncat(jsonPath, "\\Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\settings.json", remaining); - if(!ffAppendFileBuffer(jsonPath, &json)) + ffStrbufAppendS(&jsonPath, "\\Microsoft\\Windows Terminal\\settings.json"); + if(!ffAppendFileBuffer(jsonPath.chars, &json)) error = "Error reading Windows Terminal settings JSON file"; } } - else - { - strncat(jsonPath, "\\Microsoft\\Windows Terminal\\settings.json", remaining); - if(!ffAppendFileBuffer(jsonPath, &json)) - error = "Error reading Windows Terminal settings JSON file"; - } } } diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index b412d5800f..f180d2894d 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -22,26 +22,29 @@ bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) { uint32_t ppid = 0; + bool gui = false; - while (pid != 0 && ffProcessGetInfoWindows(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, NULL)) + while (pid != 0 && ffProcessGetInfoWindows(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, &gui)) { ffStrbufSet(&result->prettyName, &result->processName); - if(ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) + if (ffStrbufEndsWithIgnCaseS(&result->prettyName, ".exe")) ffStrbufSubstrBefore(&result->prettyName, result->prettyName.length - 4); //Common programs that are between terminal and own process, but are not the shell - if( + if ( + !gui && ( ffStrbufIgnCaseEqualS(&result->prettyName, "sudo") || ffStrbufIgnCaseEqualS(&result->prettyName, "su") || ffStrbufIgnCaseEqualS(&result->prettyName, "gdb") || ffStrbufIgnCaseEqualS(&result->prettyName, "lldb") || + ffStrbufIgnCaseEqualS(&result->prettyName, "lldb-dap") || ffStrbufIgnCaseEqualS(&result->prettyName, "python") || // python on windows generates shim executables ffStrbufIgnCaseEqualS(&result->prettyName, "fastfetch") || // scoop warps the real binaries with a "shim" exe ffStrbufIgnCaseEqualS(&result->prettyName, "flashfetch") || ffStrbufContainIgnCaseS(&result->prettyName, "debug") || ffStrbufContainIgnCaseS(&result->prettyName, "time") || - ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmu") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 - ) { + ffStrbufStartsWithIgnCaseS(&result->prettyName, "ConEmuC") // https://github.com/fastfetch-cli/fastfetch/issues/488#issuecomment-1619982014 + )) { ffStrbufClear(&result->processName); ffStrbufClear(&result->prettyName); ffStrbufClear(&result->exe); @@ -51,13 +54,18 @@ static uint32_t getShellInfo(FFShellResult* result, uint32_t pid) } result->pid = pid; - result->ppid = ppid; - if(ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) + if (gui) { - ffStrbufSetS(&result->prettyName, "Windows Explorer"); // Started without shell + // Started without shell // In this case, terminal process will be created by fastfetch itself. ppid = 0; + if (ffStrbufIgnCaseEqualS(&result->prettyName, "explorer")) + ffStrbufSetS(&result->prettyName, "Windows Explorer"); + } + else + { + result->ppid = ppid; } break; @@ -90,9 +98,11 @@ static void setShellInfoDetails(FFShellResult* result) { if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0) { - ffStrbufAppendS(&result->prettyName, " (with Clink "); - ffGetFileVersion(module.szExePath, NULL, &result->prettyName); - ffStrbufAppendC(&result->prettyName, ')'); + FF_STRBUF_AUTO_DESTROY clinkVersion = ffStrbufCreate(); + if (ffGetFileVersion(module.szExePath, NULL, &clinkVersion)) + ffStrbufAppendF(&result->prettyName, " (with Clink %s)", clinkVersion.chars); + else + ffStrbufAppendS(&result->prettyName, " (with Clink)"); break; } } @@ -250,11 +260,11 @@ static uint32_t getTerminalInfo(FFTerminalResult* result, uint32_t pid) } uint32_t ppid = 0; - bool hasGui; + bool gui; - while (pid != 0 && ffProcessGetInfoWindows(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, &hasGui)) + while (pid != 0 && ffProcessGetInfoWindows(pid, &ppid, &result->processName, &result->exe, &result->exeName, &result->exePath, &gui)) { - if(!hasGui || ffStrbufIgnCaseEqualS(&result->processName, "far.exe")) // Far includes GUI objects... + if (!gui) { //We are in nested shell ffStrbufClear(&result->processName); diff --git a/src/detection/uptime/uptime_windows.c b/src/detection/uptime/uptime_windows.c index c5cd7245ad..c5a4d423f1 100644 --- a/src/detection/uptime/uptime_windows.c +++ b/src/detection/uptime/uptime_windows.c @@ -1,34 +1,18 @@ #include "uptime.h" #include "common/time.h" -#include "common/library.h" - -#include -#include +#include "common/windows/nt.h" const char* ffDetectUptime(FFUptimeResult* result) { - #if FF_WIN7_COMPAT - HMODULE hKernelBase = GetModuleHandleW(L"KernelBase.dll"); - if (__builtin_expect(!!hKernelBase, true)) - { - FF_LIBRARY_LOAD_SYMBOL_LAZY(hKernelBase, QueryInterruptTime); - if (ffQueryInterruptTime) // Windows 10 and later - { - uint64_t uptime; - ffQueryInterruptTime(&uptime); - result->uptime = uptime / 10000; // Convert from 100-nanosecond intervals to milliseconds - goto ok; - } - } - - result->uptime = GetTickCount64(); -ok: + // GetInterruptTime with Win7 support + uint64_t interruptTime = ffKSystemTimeToUInt64(&SharedUserData->InterruptTime); - #else - uint64_t uptime; - QueryInterruptTime(&uptime); - result->uptime = uptime / 10000; // Convert from 100-nanosecond intervals to milliseconds - #endif + result->uptime = interruptTime / 10000; // Convert from 100-nanosecond intervals to milliseconds result->bootTime = ffTimeGetNow() - result->uptime; + + // Alternatively, `NtQuerySystemInformation(SystemTimeOfDayInformation)` reports the boot time directly, + // whose result exactly equals what WMI `Win32_OperatingSystem` reports + // with much lower accuracy (0.5 seconds) + return NULL; } diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index 62fd017710..00b02aa843 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -47,7 +47,7 @@ typedef enum { static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) { FF_DEBUG("Starting NetworkManager wifi detection for interface %s", item->inf.description.chars); - FFDBusData dbus; + FF_DBUS_AUTO_DESTROY_DATA FFDBusData dbus = {}; const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus); if(error) { @@ -254,6 +254,7 @@ static const char* detectWifiWithNm(FFWifiResult* item, FFstrbuf* buffer) } FF_DEBUG("NetworkManager wifi detection completed successfully"); + dbus.lib->ffdbus_message_unref(reply); return NULL; } #endif // FF_HAVE_DBUS diff --git a/src/detection/wm/wm_apple.m b/src/detection/wm/wm_apple.m index 2036cfd12c..bf40cc93fb 100644 --- a/src/detection/wm/wm_apple.m +++ b/src/detection/wm/wm_apple.m @@ -5,6 +5,7 @@ #include "common/stringUtils.h" #include +#include #import const char* ffDetectWMPlugin(FFstrbuf* pluginName) @@ -20,9 +21,10 @@ for(size_t i = 0; i < length / sizeof(struct kinfo_proc); i++) { - if (processes[i].kp_eproc.e_ppid != 1) continue; + const struct kinfo_proc* proc = &processes[i]; + if (proc->kp_eproc.e_ppid != 1) continue; - const char* comm = processes[i].kp_proc.p_comm; + const char* comm = proc->kp_proc.p_comm; if( !ffStrEqualsIgnCase(comm, "spectacle") && @@ -34,6 +36,42 @@ !ffStrEqualsIgnCase(comm, "rectangle") ) continue; + if (instance.config.general.detectVersion) + { + char buf[PROC_PIDPATHINFO_MAXSIZE]; + int length = proc_pidpath(proc->kp_proc.p_pid, buf, ARRAY_SIZE(buf) - strlen("Info.plist")); + if (length > 0) + { + char* lastSlash = strrchr(buf, '/'); + if (lastSlash) + { + *lastSlash = '\0'; + if (ffStrEndsWith(buf, ".app/Contents/MacOS")) + { + lastSlash -= strlen("MacOS"); + strcpy(lastSlash, "Info.plist"); // X.app/Contents/Info.plist + NSError* error; + NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@(buf)] + error:&error]; + if (dict) + { + NSString* name = dict[@"CFBundleDisplayName"] ?: dict[@"CFBundleName"]; + ffStrbufSetS(pluginName, name.UTF8String ?: comm); + + NSString* version = dict[@"CFBundleShortVersionString"]; + if (version) + { + ffStrbufAppendC(pluginName, ' '); + ffStrbufAppendS(pluginName, version.UTF8String); + } + + break; + } + } + } + } + } + ffStrbufAppendS(pluginName, comm); pluginName->chars[0] = (char) toupper(pluginName->chars[0]); break; @@ -50,16 +88,16 @@ if (ffStrbufEqualS(wmName, "WindowServer")) { NSError* error; - NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:@"file:///System/Library/PrivateFrameworks/SkyLight.framework/Resources/version.plist"] + NSDictionary* dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@"/System/Library/PrivateFrameworks/SkyLight.framework/Resources/version.plist" isDirectory:NO] error:&error]; if (!dict) { - dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL URLWithString:@"file:///System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/version.plist"] + dict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:@"/System/Library/Frameworks/ApplicationServices.framework/Frameworks/CoreGraphics.framework/Resources/version.plist" isDirectory:NO] error:&error]; } if (dict) - ffStrbufInitS(result, ((NSString*) dict[@"CFBundleShortVersionString"]).UTF8String); + ffStrbufSetS(result, ((NSString*) dict[@"CFBundleShortVersionString"]).UTF8String); } return NULL; diff --git a/src/detection/wm/wm_linux.c b/src/detection/wm/wm_linux.c index 56d8926e8d..2547c1f63f 100644 --- a/src/detection/wm/wm_linux.c +++ b/src/detection/wm/wm_linux.c @@ -170,8 +170,8 @@ static const char* getNiri(FFstrbuf* result) NULL }) == NULL) { // niri 25.11 (b35bcae) - ffStrbufSubstrBeforeLastC(result, ' '); ffStrbufSubstrAfterFirstC(result, ' '); + ffStrbufSubstrBeforeLastC(result, ' '); return NULL; } diff --git a/src/detection/wm/wm_windows.c b/src/detection/wm/wm_windows.c new file mode 100644 index 0000000000..b1b6268c92 --- /dev/null +++ b/src/detection/wm/wm_windows.c @@ -0,0 +1,204 @@ +#include "wm.h" +#include "common/mallocHelper.h" +#include "common/io.h" +#include "common/library.h" +#include "common/processing.h" +#include "common/windows/nt.h" +#include "common/windows/unicode.h" +#include "common/windows/version.h" + +#include +#include +#include +#include +#include + +typedef enum { + FF_PROCESS_TYPE_NONE, + FF_PROCESS_TYPE_SIGNED = 1 << 0, + FF_PROCESS_TYPE_WINDOWS_STORE = 1 << 1, + FF_PROCESS_TYPE_GUI = 1 << 2, + FF_PROCESS_TYPE_CUI = 1 << 3, +} FFProcessType; + +static bool verifySignature(const wchar_t* filePath) +{ + FF_LIBRARY_LOAD(wintrust, true, "wintrust" FF_LIBRARY_EXTENSION, -1) + FF_LIBRARY_LOAD_SYMBOL(wintrust, WinVerifyTrustEx, true) + + WINTRUST_FILE_INFO fileInfo = { + .cbStruct = sizeof(fileInfo), + .pcwszFilePath = filePath, + }; + + GUID actionID = WINTRUST_ACTION_GENERIC_VERIFY_V2; + + WINTRUST_DATA trustData = { + .cbStruct = sizeof(trustData), + .dwUIChoice = WTD_UI_NONE, + .fdwRevocationChecks = WTD_REVOKE_NONE, + .dwUnionChoice = WTD_CHOICE_FILE, + .pFile = &fileInfo, + .dwStateAction = WTD_STATEACTION_VERIFY, + .dwProvFlags = WTD_SAFER_FLAG, + }; + + LONG status = ffWinVerifyTrustEx(NULL, &actionID, &trustData); + trustData.dwStateAction = WTD_STATEACTION_CLOSE; + ffWinVerifyTrustEx(NULL, &actionID, &trustData); + + return status == ERROR_SUCCESS; +} + +static bool isProcessTrusted(DWORD processId, FFProcessType processType, UNICODE_STRING* buffer, size_t bufSize) +{ + FF_AUTO_CLOSE_FD HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId); + if (!hProcess) + return false; + + ULONG size; + if(!NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageFileNameWin32, buffer, (ULONG) bufSize, &size)) || + buffer->Length == 0) return false; + assert(buffer->MaximumLength >= buffer->Length + 2); // NULL terminated + + if (processType & FF_PROCESS_TYPE_WINDOWS_STORE) + { + static wchar_t windowsAppsPath[MAX_PATH]; + static uint32_t windowsAppsPathLen; + if (windowsAppsPathLen == 0) + { + PWSTR pPath = NULL; + if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &pPath))) + { + windowsAppsPathLen = (uint32_t) wcslen(pPath); + memcpy(windowsAppsPath, pPath, windowsAppsPathLen * sizeof(wchar_t)); + memcpy(windowsAppsPath + windowsAppsPathLen, L"\\WindowsApps\\", sizeof(L"\\WindowsApps\\")); + windowsAppsPathLen += strlen("\\WindowsApps\\"); + } + else + { + windowsAppsPathLen = -1u; + } + CoTaskMemFree(pPath); + } + if (windowsAppsPathLen != -1u && + (buffer->Length <= windowsAppsPathLen * sizeof(wchar_t) || // Path is too short to be in WindowsApps + _wcsnicmp(buffer->Buffer, windowsAppsPath, windowsAppsPathLen) != 0) // Path does not start with WindowsApps + ) return false; + } + + if (processType & FF_PROCESS_TYPE_SIGNED) + { + if (!verifySignature(buffer->Buffer)) return false; + } + + if (processType & (FF_PROCESS_TYPE_GUI | FF_PROCESS_TYPE_CUI)) + { + SECTION_IMAGE_INFORMATION info = {}; + if(!NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessImageInformation, &info, sizeof(info), &size)) || + size != sizeof(info)) return false; + + if ((processType & FF_PROCESS_TYPE_GUI) && info.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI) + return false; + if ((processType & FF_PROCESS_TYPE_CUI) && info.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI) + return false; + } + + return true; +} + +#define ffStrEqualNWS(str, compareTo) (_wcsnicmp(str, L ## compareTo, sizeof(compareTo) - 1) == 0) + +const char* ffDetectWMPlugin(FFstrbuf* pluginName) +{ + alignas(UNICODE_STRING) uint8_t buffer[4096]; + UNICODE_STRING* filePath = (UNICODE_STRING*) buffer; + SYSTEM_PROCESS_INFORMATION* FF_AUTO_FREE pstart = NULL; + + // Multiple attempts in case processes change while + // we are in the middle of querying them. + ULONG size = 0; + for (int attempts = 0;; ++attempts) + { + if (size) + { + pstart = (SYSTEM_PROCESS_INFORMATION*)realloc(pstart, size); + assert(pstart); + } + NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, pstart, size, &size); + if(NT_SUCCESS(status)) + break; + else if(status == STATUS_INFO_LENGTH_MISMATCH && attempts < 4) + size += sizeof(SYSTEM_PROCESS_INFORMATION) * 5; + else + return "NtQuerySystemInformation(SystemProcessInformation) failed"; + } + + for (SYSTEM_PROCESS_INFORMATION* ptr = pstart; ; ptr = (SYSTEM_PROCESS_INFORMATION*)((uint8_t*)ptr + ptr->NextEntryOffset)) + { + assert(ptr->ImageName.Length == 0 || ptr->ImageName.MaximumLength >= ptr->ImageName.Length + 2); // NULL terminated + if (ptr->ImageName.Length == strlen("FancyWM-GUI.exe") * sizeof(wchar_t) && + ffStrEqualNWS(ptr->ImageName.Buffer, "FancyWM-GUI.exe") && + isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_WINDOWS_STORE | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer)) + ) { + if (instance.config.general.detectVersion && ffGetFileVersion(filePath->Buffer, NULL, pluginName)) + ffStrbufPrependS(pluginName, "FancyWM "); + else + ffStrbufSetStatic(pluginName, "FancyWM"); + break; + } + else if (ptr->ImageName.Length == strlen("glazewm-watcher.exe") * sizeof(wchar_t) && + ffStrEqualNWS(ptr->ImageName.Buffer, "glazewm-watcher.exe") && + isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_SIGNED | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer)) + ) { + if (instance.config.general.detectVersion && ffGetFileVersion(filePath->Buffer, NULL, pluginName)) + ffStrbufPrependS(pluginName, "GlazeWM "); + else + ffStrbufSetStatic(pluginName, "GlazeWM"); + break; + } + else if (ptr->ImageName.Length == strlen("komorebi.exe") * sizeof(wchar_t) && + ffStrEqualNWS(ptr->ImageName.Buffer, "komorebi.exe") && + isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_CUI, filePath, sizeof(buffer)) + ) { + if (instance.config.general.detectVersion) + { + FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateNWS(filePath->Length / sizeof(wchar_t), filePath->Buffer); + if (ffProcessAppendStdOut(pluginName, (char *const[]) { + path.chars, + "--version", + NULL, + }) == NULL) + ffStrbufSubstrBeforeFirstC(pluginName, '\n'); + } + if (pluginName->length == 0) + ffStrbufSetStatic(pluginName, "Komorebi"); + break; + } + + if (ptr->NextEntryOffset == 0) break; + } + + return NULL; +} + +const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options) +{ + if (!wmName) + return "No WM detected"; + + if (ffStrbufEqualS(wmName, "dwm.exe")) + { + PWSTR pPath = NULL; + if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_System, KF_FLAG_DEFAULT, NULL, &pPath))) + { + wchar_t fullPath[MAX_PATH]; + wcscpy(fullPath, pPath); + wcscat(fullPath, L"\\dwm.exe"); + ffGetFileVersion(fullPath, NULL, result); + } + CoTaskMemFree(pPath); + return NULL; + } + return "Not supported on this platform"; +} diff --git a/src/detection/wm/wm_windows.cpp b/src/detection/wm/wm_windows.cpp deleted file mode 100644 index 84ee1bde2f..0000000000 --- a/src/detection/wm/wm_windows.cpp +++ /dev/null @@ -1,79 +0,0 @@ -extern "C" -{ -#include "wm.h" -#include "common/io.h" -#include "common/windows/version.h" -#include "detection/terminalshell/terminalshell.h" -} - -#include "common/windows/com.hpp" -#include "common/windows/util.hpp" - -#include -#include -#include -#include - -extern "C" -const char* ffDetectWMPlugin(FFstrbuf* pluginName) -{ - DWORD pid = ffDetectTerminal()->pid; // Whatever GUI program - if (pid == 0) return "Unable to find a GUI program"; - - FF_AUTO_CLOSE_FD HANDLE snapshot = NULL; - while(!(snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid)) && GetLastError() == ERROR_BAD_LENGTH) {} - - if(!snapshot) - return "CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid) failed"; - - if (ffInitCom()) - return "ffInitCom() failed"; - - MODULEENTRY32W module; - module.dwSize = sizeof(module); - for(BOOL success = Module32FirstW(snapshot, &module); success; success = Module32NextW(snapshot, &module)) - { - if(wcscmp(module.szModule, L"wbhelp64.dll") == 0 || wcscmp(module.szModule, L"wbhelp.dll") == 0) - { - IShellItem2* shellItem = NULL; - if (FAILED(SHCreateItemFromParsingName(module.szExePath, NULL, IID_IShellItem2, (void**) &shellItem))) - continue; - - on_scope_exit destroyShellItem([=] { shellItem->Release(); }); - - wchar_t* desc = NULL; - if (FAILED(shellItem->GetString(PKEY_FileDescription, &desc))) - continue; - - on_scope_exit destroyDesc([=] { CoTaskMemFree(desc); }); - - if (wcscmp(desc, L"WindowBlinds Helper DLL") == 0) - { - ffStrbufSetStatic(pluginName, "WindowBlinds"); - break; - } - } - } - return NULL; -} - -const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options) -{ - if (!wmName) - return "No WM detected"; - - if (ffStrbufEqualS(wmName, "dwm.exe")) - { - PWSTR pPath = NULL; - if(SUCCEEDED(SHGetKnownFolderPath(FOLDERID_System, KF_FLAG_DEFAULT, NULL, &pPath))) - { - wchar_t fullPath[MAX_PATH]; - wcscpy(fullPath, pPath); - wcscat(fullPath, L"\\dwm.exe"); - ffGetFileVersion(fullPath, NULL, result); - } - CoTaskMemFree(pPath); - return NULL; - } - return "Not supported on this platform"; -} diff --git a/src/logo/ascii/artix2.txt b/src/logo/ascii/artix2.txt new file mode 100644 index 0000000000..0e87beb2e4 --- /dev/null +++ b/src/logo/ascii/artix2.txt @@ -0,0 +1,20 @@ + .: + .==: + .====: + .======: + .========: + .==========: + .============: + .-===========: + .:-========: + .-:. .:======: + .======:.. :-===. + .============:.. .:=. + .==================:.. + .=======================: + .====================::. . + ================::. :-=== + ============-:. .:======== + ========-:. :-========== + =====:. ..:-===== + =::. ..:: diff --git a/src/logo/ascii/artix2_small.txt b/src/logo/ascii/artix2_small.txt index 22459ee538..9f9052febf 100644 --- a/src/logo/ascii/artix2_small.txt +++ b/src/logo/ascii/artix2_small.txt @@ -1,13 +1,7 @@ - ' - 'A' - 'ooo' - 'ookxo' - `ookxxo' - '. `ooko' - 'ooo`. `oo' - 'ooxxxoo`. `' - 'ookxxxkooo.` . - 'ookxxkoo'` .'oo' - 'ooxoo'` .:ooxxo' - 'io'` `'oo' -'` `' \ No newline at end of file + /\ + / \ + /`'.,\ + / ', + / ,`\ + / ,.'`. \ +/.,'` `'.\ diff --git a/src/logo/ascii/artix_small.txt b/src/logo/ascii/artix_small.txt index 7e016d82c3..14e70835aa 100644 --- a/src/logo/ascii/artix_small.txt +++ b/src/logo/ascii/artix_small.txt @@ -1,7 +1,13 @@ - /\ - / \ - /`'.,\ - / ', - / ,`\ - / ,.'`. \ -/.,'` `'.\ \ No newline at end of file + ' + 'A' + 'ooo' + 'ookxo' + `ookxxo' + '. `ooko' + 'ooo`. `oo' + 'ooxxxoo`. `' + 'ookxxxkooo.` . + 'ookxxkoo'` .'oo' + 'ooxoo'` .:ooxxo' + 'io'` `'oo' +'` `' diff --git a/src/logo/ascii/emmabuntus.txt b/src/logo/ascii/emmabuntus.txt new file mode 100644 index 0000000000..8b5aa21c56 --- /dev/null +++ b/src/logo/ascii/emmabuntus.txt @@ -0,0 +1,15 @@ + _~~_ + nmmmmmmm/$2/**\$1\ + nmHhHMMMHh\$2\__/$1/ + nm zot $2__$1 t*~~*n + m b $2_+*´cc`*+_$1 p m + m & $2/%cc,;;,cc%\$1 & m + _~~_ & $2c__ +cc$1 & n +/$2/**\$1\& $2cc;$1 & m +\$2\__/$1/& $2c~~ +cc´$1 & n + *~~* & $2\cc%*--*%cc/$1 & m + m b $2`+.cccc.+´$1 p m + nm zo o_~~_ + nmHhHMMMHhH/$2/**\$1\ + nmmmmmmmm\$2\__/$1/ + *~~* diff --git a/src/logo/ascii/linuxmint.txt b/src/logo/ascii/linuxmint.txt index ed7e6f4c6d..c6be56829b 100644 --- a/src/logo/ascii/linuxmint.txt +++ b/src/logo/ascii/linuxmint.txt @@ -1,19 +1,19 @@ - $2...-:::::-... - .-MMMMMMMMMMMMMMM-. - .-MMMM$1`..-:::::::-..`$2MMMM-. - .:MMMM$1.:MMMMMMMMMMMMMMM:.$2MMMM:. - -MMM$1-M---MMMMMMMMMMMMMMMMMMM.$2MMM- - `:MMM$1:MM` :MMMM:....::-...-MMMM:$2MMM:` - :MMM$1:MMM` :MM:` `` `` `:MMM:$2MMM: -.MMM$1.MMMM` :MM. -MM. .MM- `MMMM.$2MMM. -:MMM$1:MMMM` :MM. -MM- .MM: `MMMM-$2MMM: -:MMM$1:MMMM` :MM. -MM- .MM: `MMMM:$2MMM: -:MMM$1:MMMM` :MM. -MM- .MM: `MMMM-$2MMM: -.MMM$1.MMMM` :MM:--:MM:--:MM: `MMMM.$2MMM. - :MMM$1:MMM- `-MMMMMMMMMMMM-` -MMM-$2MMM: - :MMM$1:MMM:` `:MMM:$2MMM: - .MMM$1.MMMM:--------------:MMMM.$2MMM. - '-MMMM$1.-MMMMMMMMMMMMMMM-.$2MMMM-' - '.-MMMM$1``--:::::--``$2MMMM-.' - '-MMMMMMMMMMMMM-' - ``-:::::-`` \ No newline at end of file + $2_.-ppOOOOOOqq-._ + .oOOOOPPPPPPPPPPOOOOo. + .oOOOO$1.=oOOOOOOOOOOo=.$2OOOOo. + .:OOO$1.=oOOOOOOOOOOOOOOOOo=.$2OOO:. + .OOO$1.OOOOOOOOOOOOOOOOOOOOOOOO.$2OOO. + .OOO$1.OO OOO:´ `::´ `:OOO.$2OO: + .OOO$1.OOO OO OOO.$2OOO: + OOO$1.OOOO OO oo oo OOOO.$2OOO +:OOO$1:OOOO OO OO OO OOOO:$2OOO: +:OOO$1:OOOO OO OO OO OOOO:$2OOO: +'OOO$1'OOOO OO OO OO OOOO'$2OOO' + OOO$1'OOOO OO____OO____OO OOOO'$2OOO' + 'OOO$1'OOO 'OOOOOOOOOOOO' OOOO'$2OOO + 'OOO$1'OOO .OOO'$2OOO' + 'OOO$1'OOOO:ooooooooooooooo:OOOO'$2OOO' + ':OOOo$1'=OOOOOOOOOOOOOOOOO='$2oOOO:' + ':OOOOo$1'=OOOOOOOOOOO='$2oOOOO:' + ``-OOOOooooooooooOOOO-´´ + ```-=:OOOO:=-´´´ diff --git a/src/logo/ascii/linuxmint2.txt b/src/logo/ascii/linuxmint2.txt new file mode 100644 index 0000000000..c14451d3c4 --- /dev/null +++ b/src/logo/ascii/linuxmint2.txt @@ -0,0 +1,19 @@ + $2...-:::::-... + .-MMMMMMMMMMMMMMM-. + .-MMMM$1`..-:::::::-..`$2MMMM-. + .:MMMM$1.:MMMMMMMMMMMMMMM:.$2MMMM:. + -MMM$1-M---MMMMMMMMMMMMMMMMMMM.$2MMM- + :MMM$1:MM` :MMMM:....::-...-MMMM:$2MMM: + :MMM$1:MMM` :MM:` `` `` `:MMM:$2MMM: +.MMM$1.MMMM` :MM. -MM. .MM- `MMMM.$2MMM. +:MMM$1:MMMM` :MM. -MM- .MM: `MMMM-$2MMM: +:MMM$1:MMMM` :MM. -MM- .MM: `MMMM:$2MMM: +:MMM$1:MMMM` :MM. -MM- .MM: `MMMM-$2MMM: +.MMM$1.MMMM` :MM:--:MM:--:MM: `MMMM.$2MMM. + :MMM$1:MMM- `-MMMMMMMMMMMM-` -MMM-$2MMM: + :MMM$1:MMM:` `:MMM:$2MMM: + .MMM$1.MMMM:--------------:MMMM.$2MMM. + '-MMMM$1.-MMMMMMMMMMMMMMM-.$2MMMM-' + '.-MMMM$1``--:::::--``$2MMMM-.' + '-MMMMMMMMMMMMM-' + ``-:::::-`` \ No newline at end of file diff --git a/src/logo/ascii/refracta.txt b/src/logo/ascii/refracta.txt new file mode 100644 index 0000000000..6e8f484f15 --- /dev/null +++ b/src/logo/ascii/refracta.txt @@ -0,0 +1,18 @@ + A + VW + VVW\ + .yWWW\ +,;,,u,;yy;;v;uyyyyyyy ,WWWWW^ + *WWWWWWWWWWWWWWWW/ $VWWWWw , + ^*%WWWWWWVWWX $WWWW** ,yy + , "**WWW/' **' ,yy/WWW*` + &WWWWwy `*` <,ywWW%VWWW* + yWWWWWWWWWW* ., "**WW%W + ,&WWWWWM*"` ,y/ &WWWww ^* + XWWX*^ ,yWWWW09 .WWWWWWWWwy, +*` &WWWWWM WWWWWWWWWWWWWww, + (WWWWW` /#####WWW*********** + ^WWWW + VWW + Wh. + V/ \ No newline at end of file diff --git a/src/logo/ascii/refracted_devuan.txt b/src/logo/ascii/refracted_devuan.txt deleted file mode 100644 index 9e2ba7202c..0000000000 --- a/src/logo/ascii/refracted_devuan.txt +++ /dev/null @@ -1,18 +0,0 @@ - A - VW - VVW\ - .yWWW\ - ,;,,u,;yy;;v;uyyyyyyy ,WWWWW^ - *WWWWWWWWWWWWWWWW/ $VWWWWw , - ^*%WWWWWWVWWX $WWWW** ,yy - , "**WWW/' **' ,yy/WWW*` - &WWWWwy `*` <,ywWW%VWWW* - yWWWWWWWWWW* ., "**WW%W - ,&WWWWWM*"` ,y/ &WWWww ^* - XWWX*^ ,yWWWW09 .WWWWWWWWwy, - *` &WWWWWM WWWWWWWWWWWWWww, - (WWWWW` /#####WWW*********** - ^WWWW - VWW - Wh. - V/ \ No newline at end of file diff --git a/src/logo/ascii/rengeos.txt b/src/logo/ascii/rengeos.txt new file mode 100644 index 0000000000..995af0bdd9 --- /dev/null +++ b/src/logo/ascii/rengeos.txt @@ -0,0 +1,16 @@ + .. + .:~!. + ...::^~!!7?J?: + ..::^^~~!!!7?JYYYYYYY?. + .::::..::^!7?JJYYYJYY! +:~~~:.. .:~!?JJYYYYYYYJ!?J^ + :!?JJ?7!!7?JYYYYYYYYYYYJ~.~?: + :~?YYYYYYYYYYYYYYY?~. ^7. + .~?YYYYYYYYYY?^ .~ + ..:~!7?JYYYYYYYY?^ +.^~!7777777JYYYYY7: + ^YYYJ7: + :YYJ!: + :JJ!. + .7~. + .. \ No newline at end of file diff --git a/src/logo/ascii/secureblue.txt b/src/logo/ascii/secureblue.txt index ce91b51b3b..859cdf160e 100644 --- a/src/logo/ascii/secureblue.txt +++ b/src/logo/ascii/secureblue.txt @@ -2,10 +2,10 @@ :========++++++++++++: ===============+++++++++++ ====================++++++++++ - :=============$3#%@@%$1======++++++++- - -============$3%@%+++*$3@@$1========+++++= - -============$3%@#======$3@@$1==========+++- - =============$3%@+======$3@@$1==============. + :=============$3#%@@@%$1=====++++++++- + -============$3%@%$1====$3%@@$1========+++++ + -============$3%@#$1======$3@@$1==========+++- +.=============$3%@+$1======$3@@$1==============. $2--$1=========$3+@@@@@@@@@@@@@@@%+$1==========- $2------$1=====$3%@@@@@@@@@@@@@@@@*$1=========== $2---------$1==$3%@@@@@@@%%@@@@@@@*$1=========== @@ -17,4 +17,4 @@ $2:----------$3%@@@@@#$1===$3+%@@@@@*$1==========- $2-------------------------$1====- $2-------------------------- .--------------------. - ------------ \ No newline at end of file + ------------ diff --git a/src/logo/builtin.c b/src/logo/builtin.c index c2f220778c..5315fdd45a 100644 --- a/src/logo/builtin.c +++ b/src/logo/builtin.c @@ -527,7 +527,7 @@ static const FFlogo A[] = { }, // Artix { - .names = {"artix", "artixlinux", "artix-linux"}, + .names = {"artix"}, .lines = FASTFETCH_DATATEXT_LOGO_ARTIX, .colors = { FF_COLOR_FG_CYAN, @@ -537,7 +537,7 @@ static const FFlogo A[] = { }, // ArtixSmall { - .names = {"artix_small", "artixlinux_small"}, + .names = {"artix_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_ARTIX_SMALL, .colors = { @@ -548,7 +548,7 @@ static const FFlogo A[] = { }, // Artix2Small { - .names = {"artix2_small", "artixlinux2_small"}, + .names = {"artix2_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT | FF_LOGO_LINE_TYPE_ALTER_BIT, .lines = FASTFETCH_DATATEXT_LOGO_ARTIX2_SMALL, .colors = { @@ -557,9 +557,9 @@ static const FFlogo A[] = { .colorKeys = FF_COLOR_FG_CYAN, .colorTitle = FF_COLOR_FG_CYAN, }, - // ArcoLinux + // ArcoLinux (Discontinued) { - .names = {"arco", "arcolinux", "arco-linux"}, + .names = {"arco", "arcolinux"}, // ID=arcolinux .lines = FASTFETCH_DATATEXT_LOGO_ARCO, .colors = { FF_COLOR_FG_BLUE, @@ -570,7 +570,7 @@ static const FFlogo A[] = { }, // ArcoLinuxSmall { - .names = {"arco_small", "arcolinux_small", "arco-linux_small"}, + .names = {"arco_small", "arcolinux_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_ARCO_SMALL, .colors = { @@ -1383,7 +1383,7 @@ static const FFlogo D[] = { }, // Debian { - .names = {"Debian", "debian-linux"}, + .names = {"Debian"}, .lines = FASTFETCH_DATATEXT_LOGO_DEBIAN, .colors = { FF_COLOR_FG_RED, @@ -1394,7 +1394,7 @@ static const FFlogo D[] = { }, // DebianSmall { - .names = {"Debian_small", "debian-linux_small"}, + .names = {"Debian_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_DEBIAN_SMALL, .colors = { @@ -1403,9 +1403,9 @@ static const FFlogo D[] = { .colorKeys = FF_COLOR_FG_RED, .colorTitle = FF_COLOR_FG_RED, }, - // deepin + // Deepin { - .names = {"deepin", "deepin-linux"}, + .names = {"Deepin"}, .lines = FASTFETCH_DATATEXT_LOGO_DEEPIN, .colors = { FF_COLOR_FG_BLUE, @@ -1573,6 +1573,15 @@ static const FFlogo E[] = { .colorKeys = FF_COLOR_FG_DEFAULT, .colorTitle = FF_COLOR_FG_CYAN, }, + // Emmabuntüs + { + .names = {"Emmabuntus"}, + .lines = FASTFETCH_DATATEXT_LOGO_EMMABUNTUS, + .colors = { + FF_COLOR_FG_BLUE, + FF_COLOR_FG_YELLOW, + }, + }, // EmperorOS { .names = {"Emperor"}, @@ -1699,7 +1708,7 @@ static const FFlogo E[] = { }, // Exherbo { - .names = {"Exherbo", "exherbo-linux"}, + .names = {"Exherbo"}, .lines = FASTFETCH_DATATEXT_LOGO_EXHERBO, .colors = { FF_COLOR_FG_BLUE, @@ -1709,9 +1718,9 @@ static const FFlogo E[] = { .colorKeys = FF_COLOR_FG_BLUE, .colorTitle = FF_COLOR_FG_BLUE, }, - // ExodiaPredator + // ExodiaOS { - .names = {"Exodia Predator", "exodia-predator", "Exodia Predator OS"}, + .names = {"Exodia"}, .lines = FASTFETCH_DATATEXT_LOGO_EXODIA_PREDATOR, .colors = { FF_COLOR_FG_MAGENTA, @@ -2747,9 +2756,9 @@ static const FFlogo L[] = { .colorKeys = FF_COLOR_FG_DEFAULT, .colorTitle = FF_COLOR_FG_DEFAULT, }, - // LinuxLight + // LinuxLite { - .names = {"LinuxLite", "Linux Lite", "linux_lite"}, + .names = {"LinuxLite"}, .lines = FASTFETCH_DATATEXT_LOGO_LINUXLITE, .colors = { FF_COLOR_FG_GREEN, @@ -2758,9 +2767,9 @@ static const FFlogo L[] = { .colorKeys = FF_COLOR_FG_GREEN, .colorTitle = FF_COLOR_FG_DEFAULT, }, - // LinuxLightSmall + // LinuxLiteSmall { - .names = {"LinuxLite_small", "Linux Lite_small"}, + .names = {"LinuxLite_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_LINUXLITE_SMALL, .colors = { @@ -2772,7 +2781,7 @@ static const FFlogo L[] = { }, // LinuxMint { - .names = {"linuxmint", "linux-mint"}, + .names = {"linuxmint"}, .lines = FASTFETCH_DATATEXT_LOGO_LINUXMINT, .colors = { FF_COLOR_FG_GREEN, @@ -2783,7 +2792,7 @@ static const FFlogo L[] = { }, // LinuxMintSmall { - .names = {"linuxmint_small", "linux-mint_small"}, + .names = {"linuxmint_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_LINUXMINT_SMALL, .colors = { @@ -2793,9 +2802,21 @@ static const FFlogo L[] = { .colorKeys = FF_COLOR_FG_GREEN, .colorTitle = FF_COLOR_FG_GREEN, }, + // LinuxMint2 + { + .names = {"linuxmint2"}, + .type = FF_LOGO_LINE_TYPE_ALTER_BIT, + .lines = FASTFETCH_DATATEXT_LOGO_LINUXMINT2, + .colors = { + FF_COLOR_FG_GREEN, + FF_COLOR_FG_WHITE, + }, + .colorKeys = FF_COLOR_FG_GREEN, + .colorTitle = FF_COLOR_FG_GREEN, + }, // LinuxMintOld { - .names = {"linuxmint_old", "linux-mint_old"}, + .names = {"linuxmint_old"}, .type = FF_LOGO_LINE_TYPE_ALTER_BIT, .lines = FASTFETCH_DATATEXT_LOGO_LINUXMINT_OLD, .colors = { @@ -3004,7 +3025,7 @@ static const FFlogo M[] = { }, // Magix { - .names = {"Magix","MagixOS"}, + .names = {"Magix", "MagixOS"}, .lines = FASTFETCH_DATATEXT_LOGO_MAGIX, .colors = { FF_COLOR_FG_LIGHT_MAGENTA, @@ -3060,7 +3081,7 @@ static const FFlogo M[] = { }, // MassOS { - .names = {"MassOS", "mass"}, + .names = {"MassOS"}, .lines = FASTFETCH_DATATEXT_LOGO_MASSOS, .colors = { FF_COLOR_FG_DEFAULT, @@ -3177,7 +3198,7 @@ static const FFlogo M[] = { }, // MiracleLinux { - .names = {"MIRACLE LINUX", "miracle_linux"}, + .names = {"miraclelinux"}, .lines = FASTFETCH_DATATEXT_LOGO_MIRACLE_LINUX, .colors = { FF_COLOR_FG_256 "29", @@ -3208,7 +3229,7 @@ static const FFlogo M[] = { }, // MX { - .names = {"MX", "MX Linux"}, + .names = {"MX"}, .lines = FASTFETCH_DATATEXT_LOGO_MX, .colors = { FF_COLOR_FG_DEFAULT, @@ -3218,7 +3239,7 @@ static const FFlogo M[] = { }, // MXSmall { - .names = {"MX_small", "mx linux_small"}, + .names = {"MX_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_MX_SMALL, .colors = { @@ -3382,7 +3403,7 @@ static const FFlogo N[] = { }, // Nobara { - .names = {"nobara", "nobara-linux"}, + .names = {"nobara"}, .lines = FASTFETCH_DATATEXT_LOGO_NOBARA, .colors = { FF_COLOR_FG_DEFAULT, @@ -4168,7 +4189,7 @@ static const FFlogo R[] = { }, // Raspbian { - .names = {"raspbian", "raspi", "raspberrypi", "raspberrypios"}, + .names = {"raspbian"}, .lines = FASTFETCH_DATATEXT_LOGO_RASPBIAN, .colors = { FF_COLOR_FG_RED, @@ -4179,7 +4200,7 @@ static const FFlogo R[] = { }, // RaspbianSmall { - .names = {"raspbian_small", "raspi_small", "raspberrypi_small", "raspberrypios_small"}, + .names = {"raspbian_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_RASPBIAN_SMALL, .colors = { @@ -4263,7 +4284,7 @@ static const FFlogo R[] = { }, // RedOS { - .names = {"RedOS", "RED OS", "red-os", "redos"}, + .names = {"RedOS"}, .lines = FASTFETCH_DATATEXT_LOGO_REDOS, .colors = { FF_COLOR_FG_RED, @@ -4274,7 +4295,7 @@ static const FFlogo R[] = { }, // RedOS small { - .names = {"RedOS_small", "RED OS_small", "red-os_small", "redos_small"}, + .names = {"RedOS_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_REDOS_SMALL, .colors = { @@ -4294,10 +4315,10 @@ static const FFlogo R[] = { .colorKeys = FF_COLOR_FG_RED, .colorTitle = FF_COLOR_FG_RED, }, - // Refracted Devuan + // Refracta { - .names = {"Refracted Devuan", "refracted-devuan"}, - .lines = FASTFETCH_DATATEXT_LOGO_REFRACTED_DEVUAN, + .names = {"Refracta"}, + .lines = FASTFETCH_DATATEXT_LOGO_REFRACTA, .colors = { FF_COLOR_FG_WHITE, FF_COLOR_FG_LIGHT_BLACK, @@ -4338,7 +4359,7 @@ static const FFlogo R[] = { }, // RockyLinux { - .names = {"rocky", "rocky-linux", "rockylinux"}, + .names = {"rocky"}, .lines = FASTFETCH_DATATEXT_LOGO_ROCKY, .colors = { FF_COLOR_FG_GREEN, @@ -4348,7 +4369,7 @@ static const FFlogo R[] = { }, // RockyLinuxSmall { - .names = {"rocky_small", "rocky-linux_small", "rockylinux_small"}, + .names = {"rocky_small"}, .type = FF_LOGO_LINE_TYPE_SMALL_BIT, .lines = FASTFETCH_DATATEXT_LOGO_ROCKY_SMALL, .colors = { @@ -4381,6 +4402,14 @@ static const FFlogo R[] = { .colorKeys = FF_COLOR_FG_MAGENTA, .colorTitle = FF_COLOR_FG_MAGENTA, }, + { + .names = {"RengeOS"}, + .lines = FASTFETCH_DATATEXT_LOGO_RENGEOS, + .colors = { + FF_COLOR_FG_MAGENTA, + FF_COLOR_FG_MAGENTA, + }, + }, // LAST {}, }; diff --git a/src/modules/cpu/cpu.c b/src/modules/cpu/cpu.c index 1e2e753787..5066d8515f 100644 --- a/src/modules/cpu/cpu.c +++ b/src/modules/cpu/cpu.c @@ -136,7 +136,7 @@ void ffParseCPUJsonObject(FFCPUOptions* options, yyjson_val* module) if (unsafe_yyjson_equals_str(key, "tempSensor")) { - ffStrbufSetS(&options->tempSensor, unsafe_yyjson_get_str(val)); + ffStrbufSetJsonVal(&options->tempSensor, val); continue; } diff --git a/src/modules/packages/option.h b/src/modules/packages/option.h index f39541388c..45c049710e 100644 --- a/src/modules/packages/option.h +++ b/src/modules/packages/option.h @@ -37,6 +37,7 @@ typedef enum __attribute__((__packed__)) FFPackagesFlags FF_PACKAGES_FLAG_PISI_BIT = 1ULL << 29, FF_PACKAGES_FLAG_SOAR_BIT = 1ULL << 30, FF_PACKAGES_FLAG_KISS_BIT = 1ULL << 31, + FF_PACKAGES_FLAG_MOSS_BIT = 1ULL << 32, FF_PACKAGES_FLAG_FORCE_UNSIGNED = UINT64_MAX, } FFPackagesFlags; static_assert(sizeof(FFPackagesFlags) == sizeof(uint64_t), ""); diff --git a/src/modules/packages/packages.c b/src/modules/packages/packages.c index c9d3d55802..f94337182c 100644 --- a/src/modules/packages/packages.c +++ b/src/modules/packages/packages.c @@ -147,6 +147,7 @@ bool ffPrintPackages(FFPackagesOptions* options) FF_PRINT_PACKAGE(mport) FF_PRINT_PACKAGE(pisi) FF_PRINT_PACKAGE(soar) + FF_PRINT_PACKAGE(moss) putchar('\n'); } @@ -196,6 +197,7 @@ bool ffPrintPackages(FFPackagesOptions* options) FF_FORMAT_ARG(counts.pisi, "pisi"), FF_FORMAT_ARG(counts.soar, "soar"), FF_FORMAT_ARG(counts.kiss, "kiss"), + FF_FORMAT_ARG(counts.moss, "moss"), FF_FORMAT_ARG(nixAll, "nix-all"), FF_FORMAT_ARG(flatpakAll, "flatpak-all"), FF_FORMAT_ARG(brewAll, "brew-all"), @@ -281,6 +283,7 @@ void ffParsePackagesJsonObject(FFPackagesOptions* options, yyjson_val* module) case 'M': if (false); FF_TEST_PACKAGE_NAME(MACPORTS) FF_TEST_PACKAGE_NAME(MPORT) + FF_TEST_PACKAGE_NAME(MOSS) break; case 'N': if (false); FF_TEST_PACKAGE_NAME(NIX) @@ -357,6 +360,7 @@ void ffGeneratePackagesJsonConfig(FFPackagesOptions* options, yyjson_mut_doc* do FF_TEST_PACKAGE_NAME(LPKGBUILD) FF_TEST_PACKAGE_NAME(MACPORTS) FF_TEST_PACKAGE_NAME(MPORT) + FF_TEST_PACKAGE_NAME(MOSS) FF_TEST_PACKAGE_NAME(NIX) FF_TEST_PACKAGE_NAME(OPKG) FF_TEST_PACKAGE_NAME(PACMAN) @@ -412,8 +416,11 @@ bool ffGeneratePackagesJsonResult(FF_MAYBE_UNUSED FFPackagesOptions* options, yy FF_APPEND_PACKAGE_COUNT(guixHome) FF_APPEND_PACKAGE_COUNT(hpkgSystem) FF_APPEND_PACKAGE_COUNT(hpkgUser) + FF_APPEND_PACKAGE_COUNT(kiss) FF_APPEND_PACKAGE_COUNT(linglong) + FF_APPEND_PACKAGE_COUNT(macports) FF_APPEND_PACKAGE_COUNT(mport) + FF_APPEND_PACKAGE_COUNT(moss) FF_APPEND_PACKAGE_COUNT(nixDefault) FF_APPEND_PACKAGE_COUNT(nixSystem) FF_APPEND_PACKAGE_COUNT(nixUser) @@ -425,13 +432,11 @@ bool ffGeneratePackagesJsonResult(FF_MAYBE_UNUSED FFPackagesOptions* options, yy FF_APPEND_PACKAGE_COUNT(pkg) FF_APPEND_PACKAGE_COUNT(pkgtool) FF_APPEND_PACKAGE_COUNT(pkgsrc) - FF_APPEND_PACKAGE_COUNT(macports) FF_APPEND_PACKAGE_COUNT(rpm) FF_APPEND_PACKAGE_COUNT(scoopUser) FF_APPEND_PACKAGE_COUNT(scoopGlobal) FF_APPEND_PACKAGE_COUNT(snap) FF_APPEND_PACKAGE_COUNT(soar) - FF_APPEND_PACKAGE_COUNT(kiss) FF_APPEND_PACKAGE_COUNT(sorcery) FF_APPEND_PACKAGE_COUNT(winget) FF_APPEND_PACKAGE_COUNT(xbps) @@ -506,6 +511,7 @@ FFModuleBaseInfo ffPackagesModuleInfo = { {"Number of pisi packages", "pisi"}, {"Number of soar packages", "soar"}, {"Number of kiss packages", "kiss"}, + {"Number of moss packages", "moss"}, {"Total number of all nix packages", "nix-all"}, {"Total number of all flatpak app packages", "flatpak-all"}, {"Total number of all brew packages", "brew-all"}, diff --git a/src/modules/title/title.c b/src/modules/title/title.c index b3948429a3..89320a32c5 100644 --- a/src/modules/title/title.c +++ b/src/modules/title/title.c @@ -54,6 +54,22 @@ bool ffPrintTitle(FFTitleOptions* options) } else { + FF_STRBUF_AUTO_DESTROY cwdTilde = ffStrbufCreate(); + if ( + #if _WIN32 + ffStrbufStartsWithIgnCase + #else + ffStrbufStartsWith + #endif + (&instance.state.platform.cwd, &instance.state.platform.homeDir)) + { + ffStrbufAppendS(&cwdTilde, "~/"); + ffStrbufAppendNS(&cwdTilde, instance.state.platform.cwd.length - instance.state.platform.homeDir.length, &instance.state.platform.cwd.chars[instance.state.platform.homeDir.length]); + } + else + ffStrbufSet(&cwdTilde, &instance.state.platform.cwd); + if (cwdTilde.length > 1) ffStrbufTrimRight(&cwdTilde, '/'); + FF_PRINT_FORMAT_CHECKED(FF_TITLE_MODULE_NAME, 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]){ FF_FORMAT_ARG(instance.state.platform.userName, "user-name"), FF_FORMAT_ARG(hostName, "host-name"), @@ -70,6 +86,7 @@ bool ffPrintTitle(FFTitleOptions* options) FF_FORMAT_ARG(instance.state.platform.sid, "user-id"), #endif FF_FORMAT_ARG(instance.state.platform.pid, "pid"), + FF_FORMAT_ARG(cwdTilde, "cwd"), })); } @@ -139,6 +156,7 @@ bool ffGenerateTitleJsonResult(FF_MAYBE_UNUSED FFTitleOptions* options, yyjson_m yyjson_mut_obj_add_strbuf(doc, obj, "exePath", &instance.state.platform.exePath); yyjson_mut_obj_add_strbuf(doc, obj, "userShell", &instance.state.platform.userShell); yyjson_mut_obj_add_uint(doc, obj, "pid", instance.state.platform.pid); + yyjson_mut_obj_add_strbuf(doc, obj, "cwd", &instance.state.platform.cwd); return true; } @@ -183,5 +201,6 @@ FFModuleBaseInfo ffTitleModuleInfo = { {"Full user name", "full-user-name"}, {"UID (*nix) / SID (Windows)", "user-id"}, {"PID of current process", "pid"}, + {"CWD with home dir replaced by `~`", "cwd"}, })) }; diff --git a/src/modules/wm/wm.c b/src/modules/wm/wm.c index fbfa6c10be..94a440bc5b 100644 --- a/src/modules/wm/wm.c +++ b/src/modules/wm/wm.c @@ -122,7 +122,7 @@ bool ffGenerateWMJsonResult(FF_MAYBE_UNUSED FFWMOptions* options, yyjson_mut_doc void ffInitWMOptions(FFWMOptions* options) { ffOptionInitModuleArg(&options->moduleArgs, ""); - options->detectPlugin = false; + options->detectPlugin = true; } void ffDestroyWMOptions(FFWMOptions* options)