diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 3fefdb776..f1bbf2b83 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -5,9 +5,44 @@ on: - pull_request jobs: + linux-buildtest: + name: Linux build test + permissions: + contents: read + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, ubuntu-20.04] + compiler: [gcc, clang] + enableFeatures: [ON, OFF] + runs-on: ${{ matrix.os }} + steps: + - name: checkout repository + uses: actions/checkout@v3 + + - name: install required packages + run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libcjson-dev libnm-dev libpulse-dev + + - name: configure project + env: + CC: ${{ matrix.compiler }} + run: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_LIBPCI=${{ matrix.enableFeatures }} -DENABLE_VULKAN=${{ matrix.enableFeatures }} -DENABLE_WAYLAND=${{ matrix.enableFeatures }} -DENABLE_XCB_RANDR=${{ matrix.enableFeatures }} -DENABLE_XCB=${{ matrix.enableFeatures }} -DENABLE_XRANDR=${{ matrix.enableFeatures }} -DENABLE_X11=${{ matrix.enableFeatures }} -DENABLE_GIO=${{ matrix.enableFeatures }} -DENABLE_DCONF=${{ matrix.enableFeatures }} -DENABLE_DBUS=${{ matrix.enableFeatures }} -DENABLE_XFCONF=${{ matrix.enableFeatures }} -DENABLE_SQLITE3=${{ matrix.enableFeatures }} -DENABLE_RPM=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK7=${{ matrix.enableFeatures }} -DENABLE_IMAGEMAGICK6=${{ matrix.enableFeatures }} -DENABLE_CHAFA=${{ matrix.enableFeatures }} -DENABLE_ZLIB=${{ matrix.enableFeatures }} -DENABLE_EGL=${{ matrix.enableFeatures }} -DENABLE_GLX=${{ matrix.enableFeatures }} -DENABLE_OSMESA=${{ matrix.enableFeatures }} -DENABLE_OPENCL=${{ matrix.enableFeatures }} -DENABLE_LIBCJSON=${{ matrix.enableFeatures }} -DENABLE_LIBNM=${{ matrix.enableFeatures }} -DENABLE_PULSE=${{ matrix.enableFeatures }} . + + - name: build project + run: cmake --build . + + - name: run tests + run: ctest + + - name: run fastfetch + run: ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all + + - name: run flashfetch + run: ./flashfetch + linux: name: Linux - runs-on: ubuntu-latest + runs-on: ubuntu-20.04 # 22.04 ships a newer version of glibc than debian stable, allow those people to use the debian package permissions: security-events: write contents: read @@ -18,7 +53,7 @@ jobs: uses: actions/checkout@v3 - name: install required packages - run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libcjson-dev libnm-dev + run: sudo apt-get update && sudo apt-get install -y libpci-dev libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev rpm librpm-dev libzstd-dev libegl-dev libglx-dev libosmesa6-dev ocl-icd-opencl-dev libcjson-dev libnm-dev libpulse-dev - name: Initialize CodeQL uses: github/codeql-action/init@v2 @@ -130,8 +165,8 @@ jobs: name: fastfetch-freebsd path: ./fastfetch-*.* - windows: - name: Windows + win64: + name: Win64 runs-on: windows-latest permissions: security-events: write @@ -153,22 +188,6 @@ jobs: - name: print msys version run: uname -a - # https://github.com/msys2/MINGW-packages/issues/13524#event-7555720785 - - name: create OpenCL.pc - run: | - cat > /clang64/lib/pkgconfig/OpenCL.pc << EOF - prefix=/clang64 - exec_prefix=${prefix} - libdir=${exec_prefix}/lib - includedir=${prefix}/include - - Name: OpenCL - Description: Open Computing Language generic Installable Client Driver Loader - Version: 2022.09.30-1 - Libs: -L${libdir} -lOpenCL.dll - Cflags: -I${includedir} - EOF - - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: @@ -184,7 +203,7 @@ jobs: uses: github/codeql-action/analyze@v2 - name: copy necessary dlls - run: cp /clang64/bin/{libcjson,libOpenCL,vulkan-1}.dll . + run: cp /clang64/bin/{libcjson,OpenCL,vulkan-1}.dll . - name: list features run: ./fastfetch --list-features @@ -199,13 +218,71 @@ jobs: run: ctest - name: create zip archive - run: zip fastfetch-$(./fastfetch --version-raw)-Windows.zip *.dll fastfetch.exe flashfetch.exe + run: zip fastfetch-$(./fastfetch --version-raw)-Win64.zip *.dll fastfetch.exe flashfetch.exe - name: upload artifacts uses: actions/upload-artifact@v3 with: - name: fastfetch-windows - path: ./fastfetch-*-Windows.zip + name: fastfetch-win64 + path: ./fastfetch-*-Win64.zip + + win32: + name: Win32 + runs-on: windows-latest + permissions: + security-events: write + contents: read + defaults: + run: + shell: msys2 {0} + steps: + - name: checkout repository + uses: actions/checkout@v3 + + - name: setup-msys2 + uses: msys2/setup-msys2@v2 + with: + msystem: CLANG32 + update: true + install: git zip mingw-w64-clang-i686-cmake mingw-w64-clang-i686-clang mingw-w64-clang-i686-cjson mingw-w64-clang-i686-vulkan-loader mingw-w64-clang-i686-opencl-icd + + - name: print msys version + run: uname -a + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: c, cpp + + - name: configure project + run: env PKG_CONFIG_PATH=/clang32/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On . + + - name: build project + run: cmake --build . + + - name: perform CodeQL analysis + uses: github/codeql-action/analyze@v2 + + - name: copy necessary dlls + run: cp /clang32/bin/{libcjson,OpenCL,vulkan-1}.dll . + + - name: run fastfetch + run: time ./fastfetch --disable-linewrap false --hide-cursor false --show-errors true --load-config presets/all + + - name: run flashfetch + run: time ./flashfetch + + - name: run tests + run: ctest + + - name: create zip archive + run: zip fastfetch-$(./fastfetch --version-raw)-win32.zip *.dll fastfetch.exe flashfetch.exe + + - name: upload artifacts + uses: actions/upload-artifact@v3 + with: + name: fastfetch-win32 + path: ./fastfetch-*-win32.zip release: if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'LinusDierheimer/fastfetch' @@ -215,7 +292,8 @@ jobs: - linux - macos - freebsd - - windows + - win64 + - win32 permissions: contents: write steps: @@ -235,4 +313,4 @@ jobs: tag: ${{ needs.linux.outputs.ffversion }} commit: ${{ github.sha }} artifactErrorsFailBuild: true - artifacts: fastfetch-linux/*,fastfetch-macos/*,fastfetch-freebsd/*,fastfetch-windows/* + artifacts: fastfetch-linux/*,fastfetch-macos/*,fastfetch-freebsd/*,fastfetch-win64/*,fastfetch-win32/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 273bc02a0..425678945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,37 @@ +# 1.10.0 + +Notable Changes: + +* With the support of Win32 platform, original Windows 64bit artifact file is renamed to Win64 to avoid possible confusion + +Features: +* Bluetooth module +* Sound module +* Gamepad module +* Support colored percentage numbers output (#409) +* Support `--localip-compact-type` option (#408) +* Terminator terminal font detection (@Zerogiven, #415) +* Windows 32bit compatibility +* Support global configuration in MSYS2 environment (Windows) +* Support GPU driver version detection on Windows 11 +* Support scaled resolution detection for wayland (Linux) + +Bugfixes: + +* Fix build with older libnm versions +* Fix a rare case that fails to detect terminal +* Fix Muffin detection (@Zerogiven, #411) +* Fix IPv6 detection (Windows) +* Fix scoop package count detection when scoop is installed in non-default path (Windows, #417) +* Fix UB reported by clang +* Honor $SCOOP when detecting scoop packages (#417) + +Other: + +* Simplified wmtheme output format (Windows) +* Improved GPU detection performance on Windows 11 +* Lastest Mac model identifier support (macOS) + # 1.9.1 Bugfixes: diff --git a/CMakeLists.txt b/CMakeLists.txt index 072394f28..6cd942949 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 1.9.1 + VERSION 1.10.0 LANGUAGES C DESCRIPTION "Fast system information tool" HOMEPAGE_URL "https://github.com/LinusDierheimer/fastfetch" @@ -70,10 +70,10 @@ cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" cmake_dependent_option(ENABLE_LIBCJSON "Enable libcjson" ON "LINUX OR WIN32" OFF) cmake_dependent_option(ENABLE_LIBNM "Enable libnm" ON "LINUX" OFF) cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) +cmake_dependent_option(ENABLE_PULSE "Enable pulse" ON "LINUX OR BSD" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND AND NOT ANDROID" OFF) cmake_dependent_option(ENABLE_BUFFER "Enable stdout buffer" ON "LINUX OR APPLE OR BSD OR WIN32 OR ANDROID" OFF) cmake_dependent_option(USE_WIN_NTAPI "Allow using internal NTAPI" ON "WIN32" OFF) -cmake_dependent_option(USE_WIN_GPU_DXGI "Use DXGI to detect GPUs instead of WMI. Faster, but may ignore GPUs that only support DX9" ON "WIN32" OFF) option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds @@ -117,7 +117,7 @@ if(NOT WIN32) set(FASTFETCH_FLAGS_DEBUG "${FASTFETCH_FLAGS_DEBUG} -fsanitize=address -fsanitize=undefined") endif() set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FASTFETCH_FLAGS_DEBUG}") -set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} ${FASTFETCH_FLAGS_DEBUG} -rdynamic") +set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FASTFETCH_FLAGS_DEBUG} -rdynamic") if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") include(CheckIPOSupported) @@ -226,15 +226,15 @@ set(LIBFASTFETCH_SRC src/common/font.c src/common/format.c src/common/init.c - src/common/io.c src/common/library.c src/common/parsing.c src/common/printing.c src/common/properties.c src/common/settings.c + src/detection/bluetooth/bluetooth.c src/detection/cpu/cpu.c src/detection/cpuUsage/cpuUsage.c - src/detection/datetime.c + src/detection/datetime/datetime.c src/detection/disk/disk.c src/detection/displayserver/displayserver.c src/detection/font/font.c @@ -246,7 +246,7 @@ set(LIBFASTFETCH_SRC src/detection/packages/packages.c src/detection/terminalfont/terminalfont.c src/detection/terminalshell/terminalshell.c - src/detection/vulkan.c + src/detection/vulkan/vulkan.c src/logo/builtin.c src/logo/image/im6.c src/logo/image/im7.c @@ -254,6 +254,7 @@ set(LIBFASTFETCH_SRC src/logo/logo.c src/modules/battery.c src/modules/bios.c + src/modules/bluetooth.c src/modules/board.c src/modules/brightness.c src/modules/break.c @@ -272,6 +273,7 @@ set(LIBFASTFETCH_SRC src/modules/gpu.c src/modules/host.c src/modules/icons.c + src/modules/gamepad.c src/modules/kernel.c src/modules/locale.c src/modules/localip.c @@ -287,6 +289,7 @@ set(LIBFASTFETCH_SRC src/modules/display.c src/modules/separator.c src/modules/shell.c + src/modules/sound.c src/modules/media.c src/modules/terminal.c src/modules/terminalfont.c @@ -304,10 +307,13 @@ set(LIBFASTFETCH_SRC src/util/FFstrbuf.c src/util/FFvaluestore.c src/util/platform/FFPlatform.c + src/util/stringUtils.c ) if(LINUX) list(APPEND LIBFASTFETCH_SRC + src/common/dbus.c + src/common/io/io_unix.c src/common/networking_linux.c src/common/processing_linux.c src/detection/battery/battery_linux.c @@ -318,6 +324,7 @@ if(LINUX) src/detection/cpu/cpu_linux.c src/detection/cpuUsage/cpuUsage_linux.c src/detection/cursor/cursor_linux.c + src/detection/bluetooth/bluetooth_linux.c src/detection/disk/disk_linux.c src/detection/displayserver/linux/displayserver_linux.c src/detection/displayserver/linux/wayland.c @@ -326,9 +333,10 @@ if(LINUX) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_linux.c - src/detection/gtk.c + src/detection/gtk_qt/gtk.c src/detection/host/host_linux.c src/detection/localip/localip_linux.c + src/detection/gamepad/gamepad_linux.c src/detection/media/media_linux.c src/detection/memory/memory_linux.c src/detection/opengl/opengl_linux.c @@ -336,7 +344,8 @@ if(LINUX) src/detection/packages/packages_linux.c src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_linux.c - src/detection/qt.c + src/detection/gtk_qt/qt.c + src/detection/sound/sound_linux.c src/detection/swap/swap_linux.c src/detection/temps/temps_linux.c src/detection/terminalfont/terminalfont_linux.c @@ -349,10 +358,12 @@ if(LINUX) ) elseif(ANDROID) list(APPEND LIBFASTFETCH_SRC + src/common/io/io_unix.c src/common/networking_linux.c src/common/processing_linux.c src/detection/battery/battery_android.c src/detection/bios/bios_nosupport.c + src/detection/bluetooth/bluetooth_nosupport.c src/detection/board/board_nosupport.c src/detection/brightness/brightness_nosupport.c src/detection/chassis/chassis_nosupport.c @@ -365,6 +376,7 @@ elseif(ANDROID) src/detection/gpu/gpu_nosupport.c src/detection/host/host_android.c src/detection/localip/localip_linux.c + src/detection/gamepad/gamepad_nosupport.c src/detection/media/media_nosupport.c src/detection/memory/memory_linux.c src/detection/opengl/opengl_linux.c @@ -372,6 +384,7 @@ elseif(ANDROID) src/detection/packages/packages_linux.c src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_linux.c + src/detection/sound/sound_nosupport.c src/detection/swap/swap_linux.c src/detection/temps/temps_linux.c src/detection/terminalfont/terminalfont_android.c @@ -384,11 +397,14 @@ elseif(ANDROID) ) elseif(BSD) list(APPEND LIBFASTFETCH_SRC + src/common/dbus.c + src/common/io/io_unix.c src/common/networking_linux.c src/common/processing_linux.c src/common/sysctl.c src/detection/battery/battery_bsd.c src/detection/bios/bios_bsd.c + src/detection/bluetooth/bluetooth_linux.c src/detection/board/board_nosupport.c src/detection/brightness/brightness_nosupport.c src/detection/chassis/chassis_nosupport.c @@ -403,9 +419,10 @@ elseif(BSD) src/detection/displayserver/linux/xlib.c src/detection/font/font_linux.c src/detection/gpu/gpu_linux.c - src/detection/gtk.c + src/detection/gtk_qt/gtk.c src/detection/host/host_bsd.c src/detection/localip/localip_linux.c + src/detection/gamepad/gamepad_nosupport.c src/detection/media/media_linux.c src/detection/memory/memory_bsd.c src/detection/opengl/opengl_linux.c @@ -413,7 +430,8 @@ elseif(BSD) src/detection/packages/packages_linux.c src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_bsd.c - src/detection/qt.c + src/detection/gtk_qt/qt.c + src/detection/sound/sound_linux.c src/detection/swap/swap_bsd.c src/detection/temps/temps_linux.c src/detection/terminalfont/terminalfont_linux.c @@ -426,11 +444,13 @@ elseif(BSD) ) elseif(APPLE) list(APPEND LIBFASTFETCH_SRC + src/common/io/io_unix.c src/common/networking_linux.c src/common/processing_linux.c src/common/sysctl.c src/detection/battery/battery_apple.c src/detection/bios/bios_apple.c + src/detection/bluetooth/bluetooth_apple.m src/detection/board/board_nosupport.c src/detection/brightness/brightness_apple.c src/detection/chassis/chassis_nosupport.c @@ -444,6 +464,7 @@ elseif(APPLE) src/detection/gpu/gpu_apple.c src/detection/host/host_apple.c src/detection/localip/localip_linux.c + src/detection/gamepad/gamepad_apple.c src/detection/media/media_apple.m src/detection/memory/memory_apple.c src/detection/opengl/opengl_apple.c @@ -451,6 +472,7 @@ elseif(APPLE) src/detection/packages/packages_apple.c src/detection/poweradapter/poweradapter_apple.c src/detection/processes/processes_bsd.c + src/detection/sound/sound_apple.c src/detection/swap/swap_apple.c src/detection/temps/temps_apple.c src/detection/terminalfont/terminalfont_apple.m @@ -465,10 +487,12 @@ elseif(APPLE) ) elseif(WIN32) list(APPEND LIBFASTFETCH_SRC + src/common/io/io_windows.c src/common/networking_windows.c src/common/processing_windows.c src/detection/battery/battery_windows.c src/detection/bios/bios_windows.c + src/detection/bluetooth/bluetooth_windows.c src/detection/board/board_windows.c src/detection/brightness/brightness_windows.cpp src/detection/chassis/chassis_nosupport.c @@ -481,6 +505,7 @@ elseif(WIN32) src/detection/gpu/gpu_windows.cpp src/detection/host/host_windows.c src/detection/localip/localip_windows.c + src/detection/gamepad/gamepad_windows.cpp src/detection/media/media_nosupport.c src/detection/memory/memory_windows.c src/detection/opengl/opengl_windows.c @@ -488,6 +513,7 @@ elseif(WIN32) src/detection/packages/packages_windows.c src/detection/poweradapter/poweradapter_nosupport.c src/detection/processes/processes_windows.cpp + src/detection/sound/sound_windows.cpp src/detection/swap/swap_windows.cpp src/detection/terminalfont/terminalfont_windows.c src/detection/terminalshell/terminalshell_windows.cpp @@ -496,6 +522,7 @@ elseif(WIN32) src/detection/wifi/wifi_windows.c src/detection/wmtheme/wmtheme_windows.c src/util/windows/getline.c + src/util/windows/com.cpp src/util/windows/registry.c src/util/windows/unicode.c src/util/windows/wmi.cpp @@ -646,6 +673,10 @@ ff_lib_enable(FREETYPE "freetype2" "FreeType2" ) +ff_lib_enable(PULSE + "libpulse" + "Pulse" +) if(ENABLE_THREADS) target_compile_definitions(libfastfetch PRIVATE FF_HAVE_THREADS) @@ -666,34 +697,34 @@ if(APPLE) PRIVATE "-framework OpenCL" PRIVATE "-framework Cocoa" PRIVATE "-framework CoreWLAN" + PRIVATE "-framework CoreAudio" PRIVATE "-framework CoreVideo" + PRIVATE "-framework IOBluetooth" PRIVATE "-weak_framework MediaRemote -F /System/Library/PrivateFrameworks" PRIVATE "-weak_framework DisplayServices -F /System/Library/PrivateFrameworks" ) elseif(WIN32) target_compile_definitions(libfastfetch PRIVATE -D_WIN32_WINNT=0x0601) target_link_libraries(libfastfetch + PRIVATE "bthprops" PRIVATE "dwmapi" PRIVATE "gdi32" PRIVATE "iphlpapi" PRIVATE "ole32" PRIVATE "oleaut32" PRIVATE "opengl32" - PRIVATE "wbemuuid" PRIVATE "ws2_32" PRIVATE "ntdll" PRIVATE "version" PRIVATE "setupapi" PRIVATE "dxgi" + PRIVATE "dinput8" PRIVATE "wtsapi32" PRIVATE "powrprof" ) if(USE_WIN_NTAPI) target_compile_definitions(libfastfetch PRIVATE FF_USE_WIN_NTAPI) endif() - if(USE_WIN_GPU_DXGI) - target_compile_definitions(libfastfetch PRIVATE FF_USE_WIN_GPU_DXGI) - endif() endif() target_include_directories(libfastfetch diff --git a/README.md b/README.md index c1d5dbb99..7de10993e 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ The following libraries are used if present at runtime: * [`libmagickcore` (ImageMagick)](https://www.imagemagick.org/): Images in terminal using sixel or kitty graphics protocol. * [`libchafa`](https://github.com/hpjansson/chafa): Image output as ascii art. * [`libZ`](https://www.zlib.net/): Faster image output when using kitty graphics protocol. -* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Needed for detecting current media player and song. +* [`libDBus`](https://www.freedesktop.org/wiki/Software/dbus): Bluetooth, Player & Media detection. * [`libEGL`](https://www.khronos.org/registry/EGL/), [`libGLX`](https://dri.freedesktop.org/wiki/GLX/), [`libOSMesa`](https://docs.mesa3d.org/osmesa.html): At least one of them is needed by the OpenGL module for gl context creation. @@ -54,7 +54,8 @@ The following libraries are used if present at runtime: * [`libsqlite3`](https://www.sqlite.org/index.html): Needed for pkg & rpm package count. * [`librpm`](http://rpm.org/): Slower fallback for rpm package count. Needed on openSUSE. * [`libcJSON`](https://github.com/DaveGamble/cJSON): Needed for Windows Terminal font ( WSL ). -* [`libnm`](https://networkmanager.dev/docs/libnm/latest/): Used for Wifi detection on Linux. +* [`libnm`](https://networkmanager.dev/docs/libnm/latest/): Used for Wifi detection. +* [`libpulse`](https://freedesktop.org/software/pulseaudio/doxygen/): Used for Sound detection. ### macOS @@ -88,7 +89,7 @@ All categories not listed here should work without needing a specific implementa ##### Available Modules ``` -Battery, Bios, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, GPU, Host, Icons, Kernel, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator OS, Shell, Swap, Terminal, Terminal Font, Theme, Time, Title, Uptime, Vulkan, Wifi, WM, WMTheme +Battery, Bios, Bluetooth, Board, Break, Brightness, Colors, Command, CPU, CPUUsage, Cursor, Custom, Date, DateTime, DE, Disk, Display, Font, Gamepad, GPU, Host, Icons, Kernel, Locale, LocalIP, Media, Memory, OpenCL, OpenGL, Packages, Player, Power Adapter, Processes, PublicIP, Separator, OS, Shell, Sound, Swap, Terminal, Terminal Font, Theme, Time, Title, Uptime, Vulkan, Wifi, WM, WMTheme ``` ##### Builtin logos @@ -113,7 +114,7 @@ Budgie, Cinnamon, Gnome, KDE Plasma, LXQt, Mate, XFCE4 ##### Terminal fonts ``` -Alacritty, Apple Terminal, ConEmu, Deepin Terminal, Gnome Terminal, iTerm2, Kitty, Konsole, LXTerminal, mintty, Termux, Tilix, TTY, Warp, WezTerm, Windows Terminal, XFCE4 Terminal +Alacritty, Apple Terminal, ConEmu, Deepin Terminal, Gnome Terminal, iTerm2, Kitty, Konsole, LXTerminal, mintty, Terminator, Termux, Tilix, TTY, Warp, WezTerm, Windows Terminal, XFCE4 Terminal ``` ## Building diff --git a/completions/bash b/completions/bash index 7c32c4cc3..5533d45a2 100644 --- a/completions/bash +++ b/completions/bash @@ -42,6 +42,7 @@ __fastfetch_complete_help() "vulkan-format" "opengl-format" "opencl-format" + "bluetooth-format" ) COMPREPLY=($(compgen -W "${__ff_helps[*]}" -- "$CURRENT_WORD")) } @@ -185,6 +186,7 @@ __fastfetch_completion() "--localip-show-ipv6" "--localip-show-loop" "--localip-name-prefix" + "--localip-compact-type" "--escape-bedrock" "--pipe" "--title-fqdn" @@ -198,6 +200,7 @@ __fastfetch_completion() "--gpu-hide-integrated" "--gpu-hide-discrete" "--disk-show-unknown" + "--bluetooth-show-disconnected" ) local FF_OPTIONS_STRING=( @@ -349,6 +352,9 @@ __fastfetch_completion() "--users-key" "--users-format" "--users-error" + "--bluetooth-key" + "--bluetooth-format" + "--bluetooth-error" ) local FF_OPTIONS_PATH=( @@ -374,6 +380,7 @@ __fastfetch_completion() "--lib-glx" "--lib-osmesa" "--lib-opencl" + "--lib-pulse" "--battery-dir" ) diff --git a/presets/all b/presets/all index 85be11eef..e8b10e197 100644 --- a/presets/all +++ b/presets/all @@ -1 +1 @@ ---structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Weather:Break:Colors +--structure Title:Separator:OS:Host:Bios:Board:Chassis:Kernel:Uptime:Processes:Packages:Shell:Display:Brightness:DE:WM:WMTheme:Theme:Icons:Font:Cursor:Terminal:TerminalFont:CPU:CPUUsage:GPU:Memory:Swap:Disk:Battery:PowerAdapter:Player:Media:PublicIP:LocalIP:Wifi:DateTime:Locale:Vulkan:OpenGL:OpenCL:Users:Bluetooth:Sound:Gamepad:Weather:Break:Colors diff --git a/presets/verbose b/presets/verbose index 57711c43d..5d8a675bb 100644 --- a/presets/verbose +++ b/presets/verbose @@ -5,7 +5,7 @@ --processes-format Count: {} --packages-format All: {}; pacman: {}; pacman branch: {}; dpkg: {}; rpm: {}; emerge: {}; eopkg: {}; xbps: {}; apk: {}; flatpak: {}; snap: {}; brew: {}; brew-cask: {}; port: {}; scoop: {}; choco: {} --shell-format Process name: {}; Process path: {}; Process exe: {}; Process version: {}; User path: {}; User exe: {}; User version: {} ---display-format Width: {}; Height: {}; Refresh rate: {} +--display-format Width: {}; Height: {}; Refresh rate: {}; ScaledWith: {}; ScaledHeight: {} --de-format Process name: {}; Pretty name: {}; Version: {} --wm-format Process name: {}; Pretty name: {}; Protocol: {} --wm-theme-format Name: {} @@ -17,7 +17,7 @@ --terminal-font-format Pretty: {}; Name: {}; Size: {}; Styles: {} --cpu-format Name: {}, Vendor: {}, CoresPhysical: {}, CoresLogical: {}, CoresOnline: {}, FrequencyMin: {}, FrequencyMax: {}, Temperature: {} --cpu-usage-format Percentage: {} ---gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {}; CoreCount: {} +--gpu-format Vendor: {}; Name: {}; Driver: {}; Temperature: {}; CoreCount: {}; Type: {} --memory-format Used: {}; Total: {}; Percentage: {} --disk-format SizeUsed: {}; SizeTotal: {}; SizePercentage: {}; FilesUsed: {}; FilesTotal: {}; FilesPercentage: {}; Removable: {}; Hidden: {}; Filesystem: {}; Name: {} --battery-format Manufactor: {}; Model: {}; Technology: {}; Capacity: {}; Status: {} @@ -28,3 +28,4 @@ --vulkan-format driver: {}; Api Version: {}; Conformance Version: {} --opengl-format version: {}; renderer: {}; vendor: {} --opencl-format version: {}; device: {}; vendor: {} +--bluetooth-format Name: {}; Address: {}; Type: {}; Battery: {} diff --git a/src/common/bar.c b/src/common/bar.c index 34b14aa7a..d4a8cf0f1 100644 --- a/src/common/bar.c +++ b/src/common/bar.c @@ -47,3 +47,53 @@ void ffAppendPercentBar(FFinstance* instance, FFstrbuf* buffer, uint8_t percent, else ffStrbufAppendS(buffer, " ]"); } + +// if (green < yellow) +// [0, green]: print green +// (green, yellow]: print yellow +// (yellow, 100]: print red +// +// if (green > yellow) +// [green, 100]: print green +// [yellow, green): print yellow +// [0, yellow): PRINT RED +void ffAppendPercentNum(FFinstance* instance, FFstrbuf* buffer, uint8_t percent, uint8_t green, uint8_t yellow, bool parentheses) +{ + assert(green <= 100 && yellow <= 100); + + bool colored = !!(instance->config.percentType & FF_PERCENTAGE_TYPE_NUM_COLOR_BIT); + + if (parentheses) + ffStrbufAppendC(buffer, '('); + + if (colored && !instance->config.pipe) + { + if(green < yellow) + { + if (percent <= green) + ffStrbufAppendS(buffer, "\033[32m"); + else if (percent <= yellow) + ffStrbufAppendS(buffer, "\033[93m"); + else + ffStrbufAppendS(buffer, "\033[91m"); + } + else + { + if (percent >= green) + ffStrbufAppendS(buffer, "\033[32m"); + else if (percent >= yellow) + ffStrbufAppendS(buffer, "\033[93m"); + else + ffStrbufAppendS(buffer, "\033[91m"); + } + } + ffStrbufAppendF(buffer, "%u%%", (unsigned) percent); + + if (colored && !instance->config.pipe) + { + ffStrbufAppendS(buffer, FASTFETCH_TEXT_MODIFIER_RESET); + } + + if (parentheses) + ffStrbufAppendC(buffer, ')'); +} diff --git a/src/common/bar.h b/src/common/bar.h index 575adc01d..f28cbe777 100644 --- a/src/common/bar.h +++ b/src/common/bar.h @@ -7,11 +7,13 @@ enum { - FF_PERCENTAGE_TYPE_NUM_BIT = 1, - FF_PERCENTAGE_TYPE_BAR_BIT = 2, - FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 4, + FF_PERCENTAGE_TYPE_NUM_BIT = 1 << 0, + FF_PERCENTAGE_TYPE_BAR_BIT = 1 << 1, + FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT = 1 << 2, + FF_PERCENTAGE_TYPE_NUM_COLOR_BIT = 1 << 3, }; void ffAppendPercentBar(FFinstance* instance, FFstrbuf* buffer, uint8_t percent, uint8_t green, uint8_t yellow, uint8_t red); +void ffAppendPercentNum(FFinstance* instance, FFstrbuf* buffer, uint8_t percent, uint8_t green, uint8_t yellow, bool parentheses); #endif diff --git a/src/common/dbus.c b/src/common/dbus.c new file mode 100644 index 000000000..b0f5c4ffe --- /dev/null +++ b/src/common/dbus.c @@ -0,0 +1,206 @@ +#include "dbus.h" + +#ifdef FF_HAVE_DBUS + +#include "common/thread.h" +#include "util/stringUtils.h" + +static bool loadLibSymbols(const FFinstance* instance, FFDBusLibrary* lib) +{ + FF_LIBRARY_LOAD(dbus, &instance->config.libDBus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4); + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_bus_get, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_new_method_call, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init_append, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_append_basic, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_arg_type, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_basic, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_recurse, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_has_next, false) + 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_flush, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_pending_call_block, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_pending_call_steal_reply, false) + FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_pending_call_unref, false) + dbus = NULL; // don't auto dlclose + return true; +} + +static const FFDBusLibrary* loadLib(const FFinstance* instance) +{ + static FFDBusLibrary lib; + static bool loaded = false; + static bool loadSuccess = false; + static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER; + + ffThreadMutexLock(&mutex); + + if(!loaded) + { + loaded = true; + loadSuccess = loadLibSymbols(instance, &lib); + } + + ffThreadMutexUnlock(&mutex); + return loadSuccess ? &lib : NULL; +} + +const char* ffDBusLoadData(const FFinstance* instance, DBusBusType busType, FFDBusData* data) +{ + data->lib = loadLib(instance); + if(data->lib == NULL) + return "Failed to load DBus library"; + + data->connection = data->lib->ffdbus_bus_get(busType, NULL); + if(data->connection == NULL) + return "Failed to connect to DBus"; + + return NULL; +} + +bool ffDBusGetValue(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result) +{ + int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); + + if(argType == DBUS_TYPE_STRING) + { + const char* value = NULL; + dbus->lib->ffdbus_message_iter_get_basic(iter, &value); + + if(!ffStrSet(value)) + return false; + + ffStrbufAppendS(result, value); + return true; + } + + if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) + return false; + + DBusMessageIter subIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); + + if(argType == DBUS_TYPE_VARIANT) + return ffDBusGetValue(dbus, &subIter, result); + + //At this point we have an array + + bool foundAValue = false; + + while(true) + { + if(ffDBusGetValue(dbus, &subIter, result)) + { + foundAValue = true; + ffStrbufAppendS(result, ", "); + } + + FF_DBUS_ITER_CONTINUE(dbus, &subIter); + } + + if(foundAValue) + ffStrbufSubstrBefore(result, result->length - 2); + + return foundAValue; +} + +bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) +{ + int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); + + if(argType == DBUS_TYPE_BOOLEAN) + { + dbus_bool_t value = 0; + dbus->lib->ffdbus_message_iter_get_basic(iter, &value); + *result = value != 0; + return true; + } + + if(argType != DBUS_TYPE_VARIANT) + return false; + + DBusMessageIter subIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); + return ffDBusGetBool(dbus, &subIter, result); +} + +bool ffDBusGetByte(FFDBusData* dbus, DBusMessageIter* iter, uint8_t* result) +{ + int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); + + if(argType == DBUS_TYPE_BYTE) + { + dbus->lib->ffdbus_message_iter_get_basic(iter, result); + return true; + } + + if(argType != DBUS_TYPE_VARIANT) + return false; + + DBusMessageIter subIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); + return ffDBusGetByte(dbus, &subIter, result); +} + +DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method) +{ + DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method); + if(message == NULL) + return NULL; + + DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, FF_DBUS_TIMEOUT_MILLISECONDS, NULL); + + dbus->lib->ffdbus_message_unref(message); + + return reply; +} + +DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property) +{ + DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get"); + if(message == NULL) + return NULL; + + DBusMessageIter requestIterator; + dbus->lib->ffdbus_message_iter_init_append(message, &requestIterator); + + if(!dbus->lib->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface)) + { + dbus->lib->ffdbus_message_unref(message); + return NULL; + } + + if(!dbus->lib->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property)) + { + dbus->lib->ffdbus_message_unref(message); + return NULL; + } + + DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, FF_DBUS_TIMEOUT_MILLISECONDS, NULL); + + dbus->lib->ffdbus_message_unref(message); + + return reply; +} + +void ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result) +{ + DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property); + if(reply == NULL) + return; + + DBusMessageIter rootIterator; + if(!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) + { + dbus->lib->ffdbus_message_unref(reply); + return; + } + + ffDBusGetValue(dbus, &rootIterator, result); + + dbus->lib->ffdbus_message_unref(reply); +} + +#endif //FF_HAVE_DBUS diff --git a/src/common/dbus.h b/src/common/dbus.h new file mode 100644 index 000000000..7f0fa2402 --- /dev/null +++ b/src/common/dbus.h @@ -0,0 +1,57 @@ +#pragma once + +#ifndef FF_INCLUDED_common_dbus +#define FF_INCLUDED_common_dbus + +#ifdef FF_HAVE_DBUS +#include + +#include "util/FFstrbuf.h" +#include "common/library.h" + +#define FF_DBUS_TIMEOUT_MILLISECONDS 35 + +#define FF_DBUS_ITER_CONTINUE(dbus, iterator) \ + { \ + if(!(dbus)->lib->ffdbus_message_iter_has_next(iterator)) \ + break; \ + (dbus)->lib->ffdbus_message_iter_next(iterator); \ + continue; \ + } + +typedef struct FFDBusLibrary +{ + FF_LIBRARY_SYMBOL(dbus_bus_get) + FF_LIBRARY_SYMBOL(dbus_message_new_method_call) + FF_LIBRARY_SYMBOL(dbus_message_iter_init) + FF_LIBRARY_SYMBOL(dbus_message_iter_init_append) + FF_LIBRARY_SYMBOL(dbus_message_iter_append_basic) + FF_LIBRARY_SYMBOL(dbus_message_iter_get_arg_type) + FF_LIBRARY_SYMBOL(dbus_message_iter_get_basic) + FF_LIBRARY_SYMBOL(dbus_message_iter_recurse) + FF_LIBRARY_SYMBOL(dbus_message_iter_has_next) + 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_flush) + FF_LIBRARY_SYMBOL(dbus_pending_call_block) + FF_LIBRARY_SYMBOL(dbus_pending_call_steal_reply) + FF_LIBRARY_SYMBOL(dbus_pending_call_unref) +} FFDBusLibrary; + +typedef struct FFDBusData +{ + const FFDBusLibrary* lib; + DBusConnection* connection; +} FFDBusData; + +const char* ffDBusLoadData(const FFinstance* instance, DBusBusType busType, FFDBusData* data); //Returns an error message or NULL on success +bool ffDBusGetValue(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result); +bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result); +bool ffDBusGetByte(FFDBusData* dbus, DBusMessageIter* iter, uint8_t* result); +DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method); +DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property); +void ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result); + +#endif // FF_HAVE_DBUS +#endif // FF_INCLUDED_common_dbus diff --git a/src/common/format.c b/src/common/format.c index 1a4a688c5..7394822f8 100644 --- a/src/common/format.c +++ b/src/common/format.c @@ -2,6 +2,7 @@ #include "common/format.h" #include "common/parsing.h" #include "util/textModifier.h" +#include "util/stringUtils.h" #include diff --git a/src/common/init.c b/src/common/init.c index e4f106e94..90970089a 100644 --- a/src/common/init.c +++ b/src/common/init.c @@ -1,8 +1,6 @@ #include "fastfetch.h" #include "common/parsing.h" #include "common/thread.h" -#include "detection/qt.h" -#include "detection/gtk.h" #include "detection/displayserver/displayserver.h" #include "util/textModifier.h" @@ -115,6 +113,9 @@ static void defaultConfig(FFinstance* instance) initModuleArg(&instance->config.openGL); initModuleArg(&instance->config.openCL); initModuleArg(&instance->config.users); + initModuleArg(&instance->config.bluetooth); + initModuleArg(&instance->config.sound); + initModuleArg(&instance->config.gamepad); ffStrbufInitA(&instance->config.libPCI, 0); ffStrbufInitA(&instance->config.libVulkan, 0); @@ -138,6 +139,7 @@ static void defaultConfig(FFinstance* instance) ffStrbufInitA(&instance->config.libOpenCL, 0); ffStrbufInitA(&instance->config.libcJSON, 0); ffStrbufInitA(&instance->config.libfreetype, 0); + ffStrbufInit(&instance->config.libPulse); ffStrbufInit(&instance->config.libwlanapi); ffStrbufInit(&instance->config.libnm); @@ -159,6 +161,10 @@ static void defaultConfig(FFinstance* instance) instance->config.diskShowUnknown = false; instance->config.diskShowSubvolumes = false; + instance->config.bluetoothShowDisconnected = false; + + instance->config.soundType = FF_SOUND_TYPE_MAIN; + ffStrbufInitA(&instance->config.batteryDir, 0); ffStrbufInitA(&instance->config.separatorString, 0); @@ -166,7 +172,9 @@ static void defaultConfig(FFinstance* instance) instance->config.localIpShowIpV4 = true; instance->config.localIpShowIpV6 = false; instance->config.localIpShowLoop = false; + instance->config.localIpV6First = false; ffStrbufInit(&instance->config.localIpNamePrefix); + instance->config.localIpCompactType = FF_LOCALIP_COMPACT_TYPE_NONE; instance->config.publicIpTimeout = 0; ffStrbufInit(&instance->config.publicIpUrl); @@ -210,6 +218,8 @@ FF_THREAD_ENTRY_DECL_WRAPPER(ffConnectDisplayServer, FFinstance*) #if !(defined(__APPLE__) || defined(_WIN32)) +#include "detection/gtk_qt/gtk_qt.h" + #define FF_DETECT_QT_GTK 1 FF_THREAD_ENTRY_DECL_WRAPPER(ffDetectQt, FFinstance*) @@ -377,6 +387,9 @@ static void destroyConfig(FFinstance* instance) destroyModuleArg(&instance->config.openGL); destroyModuleArg(&instance->config.openCL); destroyModuleArg(&instance->config.users); + destroyModuleArg(&instance->config.bluetooth); + destroyModuleArg(&instance->config.sound); + destroyModuleArg(&instance->config.gamepad); ffStrbufDestroy(&instance->config.libPCI); ffStrbufDestroy(&instance->config.libVulkan); @@ -400,6 +413,7 @@ static void destroyConfig(FFinstance* instance) ffStrbufDestroy(&instance->config.libOpenCL); ffStrbufDestroy(&instance->config.libcJSON); ffStrbufDestroy(&instance->config.libfreetype); + ffStrbufDestroy(&instance->config.libPulse); ffStrbufDestroy(&instance->config.libwlanapi); ffStrbufDestroy(&instance->config.libnm); @@ -505,6 +519,9 @@ void ffListFeatures() #ifdef FF_HAVE_FREETYPE "freetype\n" #endif + #ifdef FF_HAVE_PULSE + "libpulse\n" + #endif #ifdef FF_HAVE_LIBNM "libnm\n" #endif diff --git a/src/common/io.h b/src/common/io.h deleted file mode 100644 index b5446f455..000000000 --- a/src/common/io.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#ifndef FF_INCLUDED_common_io -#define FF_INCLUDED_common_io - -#include "fastfetch.h" - -#include //mode_t, fstat, stat - -bool ffWriteFDBuffer(int fd, const FFstrbuf* content); -bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data); -bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer); - -bool ffAppendFDBuffer(int fd, FFstrbuf* buffer); -ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data); -bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer); -bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer); - -#ifdef _WIN32 -bool ffAppendHandleBuffer(HANDLE handle, FFstrbuf* buffer); -#endif - -bool ffFileExists(const char* fileName, mode_t mode); - -// Not thread safe! -void ffSuppressIO(bool suppress); - -FF_C_SCANF(2, 3) void ffGetTerminalResponse(const char* request, const char* format, ...); - -#endif diff --git a/src/common/io/io.h b/src/common/io/io.h new file mode 100644 index 000000000..ca800dbe6 --- /dev/null +++ b/src/common/io/io.h @@ -0,0 +1,104 @@ +#pragma once + +#ifndef FF_INCLUDED_common_io_io +#define FF_INCLUDED_common_io_io + +#include "util/FFstrbuf.h" + +#ifdef _WIN32 + #include + #include + typedef HANDLE FFNativeFD; +#else + #include + typedef int FFNativeFD; +#endif + +static inline FFNativeFD FFUnixFD2NativeFD(int unixfd) +{ + #ifndef _WIN32 + return unixfd; + #else + return (FFNativeFD) _get_osfhandle(unixfd); + #endif +} + +static inline bool ffWriteFDData(FFNativeFD fd, size_t dataSize, const void* data) +{ + #ifndef _WIN32 + return write(fd, data, dataSize) != -1; + #else + DWORD written; + return WriteFile(fd, data, (DWORD) dataSize, &written, NULL) && written == dataSize; + #endif +} + +static inline bool ffWriteFDBuffer(FFNativeFD fd, const FFstrbuf* content) +{ + return ffWriteFDData(fd, content->length, content->chars); +} + +bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data); + +static inline bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer) +{ + return ffWriteFileData(fileName, buffer->length, buffer->chars); +} + +static inline ssize_t ffReadFDData(FFNativeFD fd, size_t dataSize, void* data) +{ + #ifndef _WIN32 + return read(fd, data, dataSize); + #else + DWORD readed; + if(!ReadFile(fd, data, (DWORD)dataSize, &readed, NULL)) + return -1; + + return (ssize_t)readed; + #endif +} + +ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data); + +bool ffAppendFDBuffer(FFNativeFD fd, FFstrbuf* buffer); +bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer); + +static inline bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) +{ + ffStrbufClear(buffer); + return ffAppendFileBuffer(fileName, buffer); +} + +//Bit flags, combine with | +typedef enum FFPathType +{ + FF_PATHTYPE_REGULAR = 1, + FF_PATHTYPE_LINK = 2, + FF_PATHTYPE_DIRECTORY = 4 +} FFPathType; + +#define FF_PATHTYPE_FILE (FF_PATHTYPE_REGULAR | FF_PATHTYPE_LINK) +#define FF_PATHTYPE_ANY (FF_PATHTYPE_FILE | FF_PATHTYPE_DIRECTORY) + +bool ffPathExists(const char* path, FFPathType pathType); + +#ifndef _WIN32 + FF_C_SCANF(2, 3) + void ffGetTerminalResponse(const char* request, const char* format, ...); +#endif + +// Not thread safe! +bool ffSuppressIO(bool suppress); + +static inline void ffUnsuppressIO(bool* suppressed) +{ + if (!*suppressed) return; + ffSuppressIO(false); + *suppressed = false; +} + +#define FF_SUPPRESS_IO() bool __attribute__((__cleanup__(ffUnsuppressIO), __unused__)) io_suppressed__ = ffSuppressIO(true) + +void ffListFilesRecursively(const char* path); + +#endif // FF_INCLUDED_common_io_io diff --git a/src/common/io.c b/src/common/io/io_unix.c similarity index 54% rename from src/common/io.c rename to src/common/io/io_unix.c index 1c2fb918b..12afb7bc2 100644 --- a/src/common/io.c +++ b/src/common/io/io_unix.c @@ -1,15 +1,10 @@ -#include "fastfetch.h" -#include "common/io.h" +#include "io.h" -#include #include - -#ifdef _WIN32 - #include -#else - #include - #include -#endif +#include +#include +#include +#include static void createSubfolders(const char* fileName) { @@ -20,41 +15,15 @@ static void createSubfolders(const char* fileName) { ffStrbufAppendC(&path, *fileName); if(*fileName == '/') - { - mkdir(path.chars - #ifndef WIN32 - , S_IRWXU | S_IRGRP | S_IROTH - #endif - ); - } + mkdir(path.chars, S_IRWXU | S_IRGRP | S_IROTH); ++fileName; } ffStrbufDestroy(&path); } -bool ffWriteFDBuffer(int fd, const FFstrbuf* content) -{ - return write(fd, content->chars, content->length) != -1; -} - bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) { - #ifdef _WIN32 - HANDLE handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if(handle == INVALID_HANDLE_VALUE) - { - createSubfolders(fileName); - handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - if(handle == INVALID_HANDLE_VALUE) - return false; - } - - DWORD written; - bool ret = !!WriteFile(handle, data, (DWORD)dataSize, &written, NULL); - - CloseHandle(handle); - #else int openFlagsModes = O_WRONLY | O_CREAT | O_TRUNC; int openFlagsRights = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; @@ -70,52 +39,10 @@ bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) bool ret = write(fd, data, dataSize) != -1; close(fd); - #endif return ret; } -bool ffWriteFileBuffer(const char* fileName, const FFstrbuf* buffer) -{ - return ffWriteFileData(fileName, buffer->length, buffer->chars); -} - -#ifdef _WIN32 - -bool ffAppendHandleBuffer(HANDLE handle, FFstrbuf* buffer) -{ - DWORD readed = 0; - - LARGE_INTEGER fileSize; - if(!GetFileSizeEx(handle, &fileSize)) - fileSize.QuadPart = 0; - - ffStrbufEnsureFree(buffer, fileSize.QuadPart > 0 ? (uint32_t)fileSize.QuadPart : 31); - uint32_t free = ffStrbufGetFree(buffer); - - bool success; - while( - (success = !!ReadFile(handle, buffer->chars + buffer->length, free, &readed, NULL)) && - (uint32_t) readed == free - ) { - buffer->length += (uint32_t) readed; - ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte. - free = ffStrbufGetFree(buffer); - } - - if(readed > 0) - buffer->length += (uint32_t) readed; - - buffer->chars[buffer->length] = '\0'; - - ffStrbufTrimRight(buffer, '\n'); - ffStrbufTrimRight(buffer, ' '); - - return success; -} - -#endif - bool ffAppendFDBuffer(int fd, FFstrbuf* buffer) { ssize_t readed = 0; @@ -150,40 +77,19 @@ bool ffAppendFDBuffer(int fd, FFstrbuf* buffer) ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data) { - #ifdef _WIN32 - HANDLE handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if(handle == INVALID_HANDLE_VALUE) - return false; - - DWORD readed; - if(!ReadFile(handle, data, (DWORD)dataSize, &readed, NULL)) - return -1; - - return (ssize_t)readed; - #else int fd = open(fileName, O_RDONLY); if(fd == -1) return -1; - ssize_t readed = read(fd, data, dataSize); + ssize_t readed = ffReadFDData(fd, dataSize, data); close(fd); return readed; - #endif } bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) { - #ifdef _WIN32 - HANDLE handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if(handle == INVALID_HANDLE_VALUE) - return false; - - bool ret = ffAppendHandleBuffer(handle, buffer); - - CloseHandle(handle); - #else int fd = open(fileName, O_RDONLY); if(fd == -1) return false; @@ -191,55 +97,32 @@ bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) bool ret = ffAppendFDBuffer(fd, buffer); close(fd); - #endif return ret; } -bool ffReadFileBuffer(const char* fileName, FFstrbuf* buffer) -{ - ffStrbufClear(buffer); - return ffAppendFileBuffer(fileName, buffer); -} - -// Not thread safe! -void ffSuppressIO(bool suppress) -{ - static bool init = false; - static int origOut = -1; - static int origErr = -1; - static int nullFile = -1; - - if(!init) - { - if(!suppress) - return; - - origOut = dup(STDOUT_FILENO); - origErr = dup(STDERR_FILENO); - nullFile = open("/dev/null", O_WRONLY); - init = true; - } - - if(nullFile == -1) - return; - - fflush(stdout); - fflush(stderr); - - dup2(suppress ? nullFile : origOut, STDOUT_FILENO); - dup2(suppress ? nullFile : origErr, STDERR_FILENO); -} - -bool ffFileExists(const char* fileName, mode_t mode) +bool ffPathExists(const char* path, FFPathType type) { struct stat fileStat; - return stat(fileName, &fileStat) == 0 && ((fileStat.st_mode & S_IFMT) == mode); + if(stat(path, &fileStat) != 0) + return false; + + int mode = fileStat.st_mode & S_IFMT; + + if(type & FF_PATHTYPE_REGULAR && mode == S_IFREG) + return true; + + if(type & FF_PATHTYPE_DIRECTORY && mode == S_IFDIR) + return true; + + if(type & FF_PATHTYPE_LINK && mode == S_IFLNK) + return true; + + return false; } void ffGetTerminalResponse(const char* request, const char* format, ...) { - #ifndef WIN32 struct termios oldTerm, newTerm; if(tcgetattr(STDIN_FILENO, &oldTerm) == -1) return; @@ -278,8 +161,78 @@ void ffGetTerminalResponse(const char* request, const char* format, ...) va_start(args, format); vsscanf(buffer, format, args); va_end(args); - #else - //Unimplemented - FF_UNUSED(request, format); - #endif +} + +bool ffSuppressIO(bool suppress) +{ + static bool init = false; + static int origOut = -1; + static int origErr = -1; + static int nullFile = -1; + + if(!init) + { + if(!suppress) + return true; + + origOut = dup(STDOUT_FILENO); + origErr = dup(STDERR_FILENO); + nullFile = open("/dev/null", O_WRONLY); + init = true; + } + + if(nullFile == -1) + return false; + + fflush(stdout); + fflush(stderr); + + dup2(suppress ? nullFile : origOut, STDOUT_FILENO); + dup2(suppress ? nullFile : origErr, STDERR_FILENO); + return true; +} + +void listFilesRecursively(FFstrbuf* folder, uint8_t indentation, const char* folderName) +{ + DIR* dir = opendir(folder->chars); + if(dir == NULL) + return; + + uint32_t folderLength = folder->length; + + if(folderName != NULL) + printf("%s/\n", folderName); + + struct dirent* entry; + + while((entry = readdir(dir)) != NULL) + { + if(entry->d_type == DT_DIR) + { + if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + ffStrbufAppendS(folder, entry->d_name); + ffStrbufAppendC(folder, '/'); + listFilesRecursively(folder, (uint8_t) (indentation + 1), entry->d_name); + ffStrbufSubstrBefore(folder, folderLength); + continue; + } + + for(uint8_t i = 0; i < indentation; i++) + fputs(" | ", stdout); + + puts(entry->d_name); + } + + closedir(dir); +} + +void ffListFilesRecursively(const char* path) +{ + FFstrbuf folder; + ffStrbufInitS(&folder, path); + ffStrbufEnsureEndsWithC(&folder, '/'); + listFilesRecursively(&folder, 0, NULL); + ffStrbufDestroy(&folder); } diff --git a/src/common/io/io_windows.c b/src/common/io/io_windows.c new file mode 100644 index 000000000..152c7c9a4 --- /dev/null +++ b/src/common/io/io_windows.c @@ -0,0 +1,163 @@ +#include "io.h" + +static void createSubfolders(const char* fileName) +{ + FFstrbuf path; + ffStrbufInit(&path); + + while(*fileName != '\0') + { + ffStrbufAppendC(&path, *fileName); + if(*fileName == '/') + CreateDirectoryA(path.chars, NULL); + ++fileName; + } + + ffStrbufDestroy(&path); +} + +bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data) +{ + HANDLE handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(handle == INVALID_HANDLE_VALUE) + { + createSubfolders(fileName); + handle = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if(handle == INVALID_HANDLE_VALUE) + return false; + } + + DWORD written; + bool ret = !!WriteFile(handle, data, (DWORD)dataSize, &written, NULL); + + CloseHandle(handle); + + return ret; +} + +bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer) +{ + DWORD readed = 0; + + LARGE_INTEGER fileSize; + if(!GetFileSizeEx(handle, &fileSize)) + fileSize.QuadPart = 0; + + ffStrbufEnsureFree(buffer, fileSize.QuadPart > 0 ? (uint32_t)fileSize.QuadPart : 31); + uint32_t free = ffStrbufGetFree(buffer); + + bool success; + while( + (success = !!ReadFile(handle, buffer->chars + buffer->length, free, &readed, NULL)) && + (uint32_t) readed == free + ) { + buffer->length += (uint32_t) readed; + ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte. + free = ffStrbufGetFree(buffer); + } + + if(readed > 0) + buffer->length += (uint32_t) readed; + + buffer->chars[buffer->length] = '\0'; + + ffStrbufTrimRight(buffer, '\n'); + ffStrbufTrimRight(buffer, ' '); + + return success; +} + +ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data) +{ + HANDLE handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(handle == INVALID_HANDLE_VALUE) + return -1; + + ssize_t readed = ffReadFDData(handle, dataSize, data); + + CloseHandle(handle); + + return readed; +} + +bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer) +{ + HANDLE handle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if(handle == INVALID_HANDLE_VALUE) + return false; + + bool ret = ffAppendFDBuffer(handle, buffer); + + CloseHandle(handle); + + return ret; +} + +bool ffPathExists(const char* path, FFPathType type) +{ + DWORD attr = GetFileAttributesA(path); + if(attr == INVALID_FILE_ATTRIBUTES) + return false; + + if(type & FF_PATHTYPE_REGULAR && !(attr & FILE_ATTRIBUTE_DIRECTORY)) + return true; + + if(type & FF_PATHTYPE_DIRECTORY && (attr & FILE_ATTRIBUTE_DIRECTORY)) + return true; + + if(type & FF_PATHTYPE_LINK && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) + return true; + + return false; +} + +bool ffSuppressIO(bool suppress) +{ + (void) suppress; //Not implemented. + return false; +} + +void listFilesRecursively(FFstrbuf* folder, uint8_t indentation, const char* folderName) +{ + uint32_t folderLength = folder->length; + + if(folderName != NULL) + printf("%s/\n", folderName); + + ffStrbufAppendC(folder, '*'); + WIN32_FIND_DATAA entry; + HANDLE hFind = FindFirstFileA(folder->chars, &entry); + if(hFind == INVALID_HANDLE_VALUE) + return; + + do + { + if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if(strcmp(entry.cFileName, ".") == 0 || strcmp(entry.cFileName, "..") == 0) + continue; + + ffStrbufSubstrBefore(folder, folderLength); + ffStrbufAppendS(folder, entry.cFileName); + ffStrbufAppendC(folder, '/'); + listFilesRecursively(folder, (uint8_t) (indentation + 1), entry.cFileName); + ffStrbufSubstrBefore(folder, folderLength); + continue; + } + + for(uint8_t i = 0; i < indentation; i++) + fputs(" | ", stdout); + + puts(entry.cFileName); + } while (FindNextFileA(hFind, &entry)); + FindClose(hFind); +} + +void ffListFilesRecursively(const char* path) +{ + FFstrbuf folder; + ffStrbufInitS(&folder, path); + ffStrbufEnsureEndsWithC(&folder, '/'); + listFilesRecursively(&folder, 0, NULL); + ffStrbufDestroy(&folder); +} diff --git a/src/common/library.h b/src/common/library.h index c23aa7b53..a0de3d621 100644 --- a/src/common/library.h +++ b/src/common/library.h @@ -6,7 +6,7 @@ #include "fastfetch.h" #include "util/FFcheckmacros.h" -#if defined(_WIN32) //We don't force MSYS using LoadLibrary because dlopen also searches $LD_LIBRARY_PATH +#if defined(_WIN32) #include #define FF_DLOPEN_FLAGS 0 FF_C_NODISCARD static inline void* dlopen(const char* path, int mode) { FF_UNUSED(mode); return LoadLibraryA(path); } @@ -24,21 +24,30 @@ #define FF_LIBRARY_EXTENSION ".so" #endif +static inline void ffLibraryUnload(void** handle) +{ + assert(handle); + if (*handle) + dlclose(*handle); +} + #define FF_LIBRARY_SYMBOL(symbolName) \ __typeof__(&symbolName) ff ## symbolName; #define FF_LIBRARY_LOAD(libraryObjectName, userLibraryName, returnValue, ...) \ - void* libraryObjectName = ffLibraryLoad(userLibraryName, __VA_ARGS__, NULL);\ + void* __attribute__((__cleanup__(ffLibraryUnload))) libraryObjectName = ffLibraryLoad(userLibraryName, __VA_ARGS__, NULL);\ if(libraryObjectName == NULL) \ return returnValue; #define FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, symbolMapping, symbolName, returnValue) \ symbolMapping = dlsym(library, #symbolName); \ if(symbolMapping == NULL) \ - { \ - dlclose(library); \ - return returnValue; \ - } + return returnValue; + +#define FF_LIBRARY_LOAD_SYMBOL_ADDRESS2(library, symbolMapping, symbolName, alternateName, returnValue) \ + symbolMapping = dlsym(library, #symbolName); \ + if(symbolMapping == NULL && !(symbolMapping = dlsym(library, #alternateName))) \ + return returnValue; #define FF_LIBRARY_LOAD_SYMBOL(library, symbolName, returnValue) \ __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, returnValue); @@ -49,12 +58,18 @@ #define FF_LIBRARY_LOAD_SYMBOL_MESSAGE(library, symbolName) \ __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, ff ## symbolName, symbolName, "dlsym " #symbolName " failed"); +#define FF_LIBRARY_LOAD_SYMBOL_MESSAGE2(library, symbolName, alternateName) \ + __typeof__(&symbolName) FF_LIBRARY_LOAD_SYMBOL_ADDRESS2(library, ff ## symbolName, symbolName, alternateName, "dlsym " #symbolName " failed"); + #define FF_LIBRARY_LOAD_SYMBOL_VAR(library, varName, symbolName, returnValue) \ FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, varName.ff ## symbolName, symbolName, returnValue); #define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(library, varName, symbolName) \ FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, varName.ff ## symbolName, symbolName, "dlsym " #symbolName " failed"); +#define FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(library, varName, symbolName, alternateName) \ + FF_LIBRARY_LOAD_SYMBOL_ADDRESS2(library, varName.ff ## symbolName, symbolName, alternateName, "dlsym " #symbolName " failed"); + #define FF_LIBRARY_LOAD_SYMBOL_PTR(library, varName, symbolName, returnValue) \ FF_LIBRARY_LOAD_SYMBOL_ADDRESS(library, varName->ff ## symbolName, symbolName, returnValue); diff --git a/src/common/parsing.c b/src/common/parsing.c index 95bba4720..5761206d3 100644 --- a/src/common/parsing.c +++ b/src/common/parsing.c @@ -1,8 +1,14 @@ #include "fastfetch.h" #include "common/parsing.h" + #include #include +#ifdef _WIN32 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wformat" +#endif + void ffParseSemver(FFstrbuf* buffer, const FFstrbuf* major, const FFstrbuf* minor, const FFstrbuf* patch) { if(major->length > 0) @@ -164,3 +170,7 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co ffStrbufAppendS(buffer, " [GTK4]"); } } + +#ifdef _WIN32 + #pragma GCC diagnostic pop +#endif diff --git a/src/common/processing_linux.c b/src/common/processing_linux.c index a628aeb3d..74502ef52 100644 --- a/src/common/processing_linux.c +++ b/src/common/processing_linux.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/processing.h" -#include "common/io.h" +#include "common/io/io.h" #include #include diff --git a/src/common/settings.c b/src/common/settings.c index 38cbd4b36..280557358 100644 --- a/src/common/settings.c +++ b/src/common/settings.c @@ -2,7 +2,7 @@ #include "common/settings.h" #include "common/library.h" #include "common/thread.h" -#include "common/io.h" +#include "common/io/io.h" #include @@ -309,7 +309,7 @@ static const SQLiteData* getSQLiteData(const FFinstance* instance) int ffSettingsGetSQLite3Int(const FFinstance* instance, const char* dbPath, const char* query) { - if(!ffFileExists(dbPath, S_IFREG)) + if(!ffPathExists(dbPath, FF_PATHTYPE_FILE)) return 0; const SQLiteData* data = getSQLiteData(instance); diff --git a/src/data/config_user.txt b/src/data/config_user.txt index 0e987509e..62aef8ad1 100644 --- a/src/data/config_user.txt +++ b/src/data/config_user.txt @@ -247,10 +247,22 @@ # Default is "/:/home" ("C:\\;D:\\ ..." on Windows). #--disk-folders /:/home +# Bluetooth show disconnected option +# Sets if disconnected bluetooth devices should be printed +# Must be either true or false +# Default is false. +#--bluetooth-show-disconnected false + +# Sound show all option +# Sets if all sound devices should be printed +# Must be either main, active or all. Default is main +# Default is main. +#--sound-type main + # Percentage output type option # Applies to all modules that prints percentage values. Currently memory, swap, disk, battery and CPU usage are supported. # Only works with default format ( without --module-format option ). -# 0: prints none; 1: prints percent number only; 2: prints bar only; 3: prints both percent number and bar; 6: prints bar and hide other texts +# 0: prints none; 1: prints percent number only; 2: prints bar only; 3: prints both percent number and bar; 6: prints bar and hide other texts; 9: prints colored number #--percent-type 1 # Key options: @@ -295,6 +307,9 @@ #--opengl-key OpenGL #--opencl-key OpenCL #--users-key Users +#--bluetooth-key Bluetooth +#--sound-key Sound +#--gamepad-key Gamepad # Format options: # Sets the format string for module values. @@ -339,6 +354,9 @@ #--opengl-format #--opencl-format #--users-format +#--bluetooth-format +#--sound-format +#--gamepad-format # Error options: # Sets the format string to use if an error occured @@ -383,6 +401,9 @@ #--opengl-error #--opencl-error #--users-error +#--bluetooth-error +#--sound-error +#--gamepad-error # Library options: # Sets an user specific path to a library to load. @@ -408,4 +429,6 @@ #--lib-osmesa /usr/lib/libOSMesa.so #--lib-opencl /usr/lib/libOpenCL.so #--lib-cjson /usr/lib/libcjson.so +#--lib-cjson /usr/lib/libasound.so #--lib-freetype /data/data/com.termux/files/usr/lib +#--lib-pulse /usr/lib/libpulse.so diff --git a/src/data/help.txt b/src/data/help.txt index b8a546c9c..789bfb390 100644 --- a/src/data/help.txt +++ b/src/data/help.txt @@ -98,38 +98,44 @@ Library options: Set the path of a library to load --lib-osmesa --lib-opencl --lib-cjson + --lib-pulse + --lib-freetype Module specific options: - --title-fqdn : Set if the title should use fully qualified domain name. Default is false - --separator-string : Set the string printed by the separator module - --os-file : Set the path to the file containing OS information - --shell-version : Set if shell version should be detected and printed - --terminal-version : Set if terminal version should be detected and printed - --disk-folders : A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows) - --disk-show-removable : Set if removable volume should be printed. Default is true - --disk-show-hidden : Set if hidden volumes should be printed. Default is false - --disk-show-subvolumes : Set if subvolumes should be printed. Default is false - --disk-show-unknown : Set if unknown (unable to detect sizes) volumes should be printed. Default is false - --battery-dir : The directory where the battery folders are. Standard: /sys/class/power_supply/ - --cpu-temp : Detect and display CPU temperature if supported. Default is false - --gpu-temp : Detect and display GPU temperature if supported. Default is false - --gpu-hide-integrated : Hide integrated GPU if supported. Default is false - --gpu-hide-discrete : Hide discrete GPU if supported. Default is false - --battery-temp : Detect and display Battery temperature if supported. Default is false - --localip-show-ipv4 : Show IPv4 addresses in local ip module. Default is true - --localip-show-ipv6 : Show IPv6 addresses in local ip module. Default is false - --localip-show-loop : Show loop back addresses (127.0.0.1) in local ip module. Default is false - --localip-name-prefix : Show IPs with given name prefix only. Default is empty - --public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0) - --public-ip-url: The URL of public IP detection server to be used. - --weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0) - --weather-output-format: The output weather format to be used. It must be URI encoded. - --player-name: The name of the player to use - --gl : Set the OpenGL context creation library to use. Must be auto, egl, glx or osmesa. Default is auto - --percent-type : Set the percentage output type. 1 for percentage number, 2 for bar, 3 for both, 6 for bar only. Default is 1 - --command-shell : Set the shell program to execute the command text. Default is cmd for Windows, csh for FreeBSD, bash for others - --command-key : Set the module key to display, can be specified mulitple times - --command-text : Set the command text to be executed, can be specified mulitple times + --title-fqdn : Set if the title should use fully qualified domain name. Default is false + --separator-string : Set the string printed by the separator module + --os-file : Set the path to the file containing OS information + --shell-version : Set if shell version should be detected and printed + --terminal-version : Set if terminal version should be detected and printed + --disk-folders : A colon (semicolon on Windows) separated list of folder paths for the disk output. Default is "/:/home" ("C:\\;D:\\ ..." on Windows) + --disk-show-removable : Set if removable volume should be printed. Default is true + --disk-show-hidden : Set if hidden volumes should be printed. Default is false + --disk-show-subvolumes : Set if subvolumes should be printed. Default is false + --disk-show-unknown : Set if unknown (unable to detect sizes) volumes should be printed. Default is false + --bluetooth-show-disconnected: : Set if disconnected bluetooth devices should be printed. Default is false + --sound-type: : Set what type of sound devices should be printed. Should be either main, active or all. Default is main + --battery-dir : The directory where the battery folders are. Standard: /sys/class/power_supply/ + --cpu-temp : Detect and display CPU temperature if supported. Default is false + --gpu-temp : Detect and display GPU temperature if supported. Default is false + --gpu-hide-integrated : Hide integrated GPU if supported. Default is false + --gpu-hide-discrete : Hide discrete GPU if supported. Default is false + --battery-temp : Detect and display Battery temperature if supported. Default is false + --localip-show-ipv4 : Show IPv4 addresses in local ip module. Default is true + --localip-show-ipv6 : Show IPv6 addresses in local ip module. Default is false + --localip-show-loop : Show loop back addresses (127.0.0.1) in local ip module. Default is false + --localip-name-prefix : Show IPs with given name prefix only. Default is empty + --localip-compact-type : Show IPs in one line. Should be either none, oneline, multiline. Default is none + --localip-v6first : Set if ipv6 should be printed first. Default is false + --public-ip-timeout: Time in milliseconds to wait for the public ip server to respond. Default is disabled (0) + --public-ip-url: The URL of public IP detection server to be used. + --weather-timeout: Time in milliseconds to wait for the weather server to respond. Default is disabled (0) + --weather-output-format: The output weather format to be used. It must be URI encoded. + --player-name: The name of the player to use + --gl : Set the OpenGL context creation library to use. Must be auto, egl, glx or osmesa. Default is auto + --percent-type : Set the percentage output type. 1 for percentage number, 2 for bar, 3 for both, 6 for bar only, 9 for colored number. Default is 1 + --command-shell : Set the shell program to execute the command text. Default is cmd for Windows, csh for FreeBSD, bash for others + --command-key : Set the module key to display, can be specified mulitple times + --command-text : Set the command text to be executed, can be specified mulitple times Parsing is not case sensitive. E.g. "--lib-PCI" is equal to "--Lib-Pci" If a value starts with a ?, it is optional. "true" will be used if not set. diff --git a/src/data/modules.txt b/src/data/modules.txt index 586c2de1d..e83353ec9 100644 --- a/src/data/modules.txt +++ b/src/data/modules.txt @@ -1,5 +1,6 @@ Battery Bios +Bluetooth Board Break Chassis diff --git a/src/detection/battery/battery_android.c b/src/detection/battery/battery_android.c index 0c4772c3e..fe081e85b 100644 --- a/src/detection/battery/battery_android.c +++ b/src/detection/battery/battery_android.c @@ -4,16 +4,22 @@ #include "common/processing.h" #include "common/properties.h" +#define FF_TERMUX_API_PATH FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api" +#define FF_TERMUX_API_PARAM "BatteryStatus" + const char* ffDetectBatteryImpl(FF_MAYBE_UNUSED FFinstance* instance, FFlist* results) { FF_STRBUF_AUTO_DESTROY buffer; ffStrbufInit(&buffer); if(ffProcessAppendStdOut(&buffer, (char* const[]){ - FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api", - "BatteryStatus" + FF_TERMUX_API_PATH, + FF_TERMUX_API_PARAM })) - return "Starting `" FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api" " BatteryStatus` failed"; + return "Starting `" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` failed"; + + if(buffer.length == 0) + return "`" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` prints empty"; BatteryResult* battery = ffListAdd(results); battery->temperature = FF_BATTERY_TEMP_UNSET; @@ -28,6 +34,17 @@ const char* ffDetectBatteryImpl(FF_MAYBE_UNUSED FFinstance* instance, FFlist* re ffStrbufClear(&battery->status); } + if(instance->config.batteryTemp) + { + if(ffParsePropLines(buffer.chars, "\"temperature\": ", &battery->status)) + { + ffStrbufTrimRight(&battery->status, ','); + ffStrbufTrim(&battery->status, '"'); + battery->temperature = ffStrbufToDouble(&battery->status); + ffStrbufClear(&battery->status); + } + } + if(ffParsePropLines(buffer.chars, "\"status\": ", &battery->status)) { ffStrbufTrimRight(&battery->status, ','); diff --git a/src/detection/battery/battery_linux.c b/src/detection/battery/battery_linux.c index 756dd9c8a..b78a6cf7f 100644 --- a/src/detection/battery/battery_linux.c +++ b/src/detection/battery/battery_linux.c @@ -1,5 +1,5 @@ #include "fastfetch.h" -#include "common/io.h" +#include "common/io/io.h" #include "battery.h" #include diff --git a/src/detection/battery/battery_windows.c b/src/detection/battery/battery_windows.c index ca8c60991..ce1838613 100644 --- a/src/detection/battery/battery_windows.c +++ b/src/detection/battery/battery_windows.c @@ -8,6 +8,19 @@ #include #include +#ifdef FF_USE_WIN_NTAPI + NTSYSCALLAPI + NTSTATUS + NTAPI + NtPowerInformation( + IN POWER_INFORMATION_LEVEL InformationLevel, + IN PVOID InputBuffer OPTIONAL, + IN ULONG InputBufferLength, + OUT PVOID OutputBuffer OPTIONAL, + IN ULONG OutputBufferLength); + #define CallNtPowerInformation NtPowerInformation +#endif + static inline void wrapCloseHandle(HANDLE* handle) { if(*handle) diff --git a/src/detection/bios/bios_linux.c b/src/detection/bios/bios_linux.c index 10bbab589..ce23edf89 100644 --- a/src/detection/bios/bios_linux.c +++ b/src/detection/bios/bios_linux.c @@ -1,5 +1,5 @@ #include "bios.h" -#include "common/io.h" +#include "common/io/io.h" #include diff --git a/src/detection/bluetooth/bluetooth.c b/src/detection/bluetooth/bluetooth.c new file mode 100644 index 000000000..f254fe535 --- /dev/null +++ b/src/detection/bluetooth/bluetooth.c @@ -0,0 +1,15 @@ +#include "bluetooth.h" + +#include "../internal.h" + +void ffDetectBluetoothImpl(const FFinstance* instance, FFBluetoothResult* bluetooth); + +const FFBluetoothResult* ffDetectBluetooth(const FFinstance* instance) +{ + FF_DETECTION_INTERNAL_GUARD(FFBluetoothResult, + ffStrbufInit(&result.error); + ffListInit(&result.devices, sizeof(FFBluetoothDevice)); + + ffDetectBluetoothImpl(instance, &result); + ) +} diff --git a/src/detection/bluetooth/bluetooth.h b/src/detection/bluetooth/bluetooth.h new file mode 100644 index 000000000..ccd6ecd22 --- /dev/null +++ b/src/detection/bluetooth/bluetooth.h @@ -0,0 +1,25 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_bluetooth_bluetooth +#define FF_INCLUDED_detection_bluetooth_bluetooth + +#include "fastfetch.h" + +typedef struct FFBluetoothDevice +{ + FFstrbuf name; + FFstrbuf address; + FFstrbuf type; + uint8_t battery; // 0-100% + bool connected; +} FFBluetoothDevice; + +typedef struct FFBluetoothResult +{ + FFstrbuf error; + FFlist devices; // List of FFBluetoothDevice +} FFBluetoothResult; + +const FFBluetoothResult* ffDetectBluetooth(const FFinstance* instance); + +#endif diff --git a/src/detection/bluetooth/bluetooth_apple.m b/src/detection/bluetooth/bluetooth_apple.m new file mode 100644 index 000000000..8affb9074 --- /dev/null +++ b/src/detection/bluetooth/bluetooth_apple.m @@ -0,0 +1,93 @@ +#include "bluetooth.h" + +#import + +void ffDetectBluetoothImpl(FF_MAYBE_UNUSED const FFinstance* instance, FFBluetoothResult* bluetooth) +{ + NSArray* ioDevices = IOBluetoothDevice.pairedDevices; + if(!ioDevices) + { + ffStrbufAppendS(&bluetooth->error, "IOBluetoothDevice.pairedDevices failed"); + return; + } + + for(IOBluetoothDevice* ioDevice in ioDevices) + { + FFBluetoothDevice* device = ffListAdd(&bluetooth->devices); + ffStrbufInitS(&device->name, ioDevice.name.UTF8String); + ffStrbufInitS(&device->address, ioDevice.addressString.UTF8String); + ffStrbufInit(&device->type); + device->battery = 0; + device->connected = !!ioDevice.isConnected; + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorLimitedDiscoverableMode) + ffStrbufAppendS(&device->type, "Limited Discoverable Mode, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorReserved1) + ffStrbufAppendS(&device->type, "LE audio, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorReserved2) + ffStrbufAppendS(&device->type, "Reserved for future use, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorPositioning) + ffStrbufAppendS(&device->type, "Positioning, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorNetworking) + ffStrbufAppendS(&device->type, "Networking, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorRendering) + ffStrbufAppendS(&device->type, "Rendering, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorCapturing) + ffStrbufAppendS(&device->type, "Capturing, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorObjectTransfer) + ffStrbufAppendS(&device->type, "Object Transfer, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorAudio) + ffStrbufAppendS(&device->type, "Audio, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorTelephony) + ffStrbufAppendS(&device->type, "Telephony, "); + if(ioDevice.serviceClassMajor & kBluetoothServiceClassMajorInformation) + ffStrbufAppendS(&device->type, "Information, "); + + if(device->type.length == 0) + { + switch(ioDevice.deviceClassMajor) + { + case kBluetoothDeviceClassMajorMiscellaneous: + ffStrbufAppendS(&device->type, "Miscellaneous"); + break; + case kBluetoothDeviceClassMajorComputer: + ffStrbufAppendS(&device->type, "Computer"); + break; + case kBluetoothDeviceClassMajorPhone: + ffStrbufAppendS(&device->type, "Phone"); + break; + case kBluetoothDeviceClassMajorLANAccessPoint: + ffStrbufAppendS(&device->type, "LAN/Network Access point"); + break; + case kBluetoothDeviceClassMajorAudio: + ffStrbufAppendS(&device->type, "Audio/Video"); + break; + case kBluetoothDeviceClassMajorPeripheral: + ffStrbufAppendS(&device->type, "Peripheral"); + break; + case kBluetoothDeviceClassMajorImaging: + ffStrbufAppendS(&device->type, "Imaging"); + break; + case kBluetoothDeviceClassMajorWearable: + ffStrbufAppendS(&device->type, "Wearable"); + break; + case kBluetoothDeviceClassMajorToy: + ffStrbufAppendS(&device->type, "Toy"); + break; + case kBluetoothDeviceClassMajorHealth: + ffStrbufAppendS(&device->type, "Health"); + break; + case kBluetoothDeviceClassMajorUnclassified: + ffStrbufAppendS(&device->type, "Uncategorized"); + break; + default: + ffStrbufAppendS(&device->type, "Unknown"); + break; + } + } + else + { + ffStrbufTrimRight(&device->type, ' '); + ffStrbufTrimRight(&device->type, ','); + } + } +} diff --git a/src/detection/bluetooth/bluetooth_linux.c b/src/detection/bluetooth/bluetooth_linux.c new file mode 100644 index 000000000..bcfca6e7d --- /dev/null +++ b/src/detection/bluetooth/bluetooth_linux.c @@ -0,0 +1,203 @@ +#include "bluetooth.h" + +#ifdef FF_HAVE_DBUS +#include "common/dbus.h" + +/* Example dbus reply, striped to only the relevant parts: +array [ //root + dict entry( //object + object path "/org/bluez/hci0/dev_03_21_8B_91_16_4D" + array [ + dict entry( //property + string "org.bluez.Device1" + array [ + dict entry( //value + string "Address" + variant string "03:21:8B:91:16:4D" + ) + dict entry( //value + string "Name" + variant string "JBL TUNE160BT" + ) + dict entry( //value + string "Icon" + variant string "audio-headset" + ) + dict entry( //value + string "Connected" + variant boolean true + ) + ] + ) + dict entry( //property + string "org.bluez.Battery1" + array [ + dict entry( //value + string "Percentage" + variant byte 100 + ) + ] + ) + ] + ) +] +*/ + +static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothDevice* device) +{ + if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) + return; + + DBusMessageIter dictIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); + + if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) + return; + + const char* deviceProperty; + dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty); + + dbus->lib->ffdbus_message_iter_next(&dictIter); + + if(strcmp(deviceProperty, "Address") == 0) + ffDBusGetValue(dbus, &dictIter, &device->address); + else if(strcmp(deviceProperty, "Name") == 0) + ffDBusGetValue(dbus, &dictIter, &device->name); + else if(strcmp(deviceProperty, "Icon") == 0) + ffDBusGetValue(dbus, &dictIter, &device->type); + else if(strcmp(deviceProperty, "Percentage") == 0) + ffDBusGetByte(dbus, &dictIter, &device->battery); + else if(strcmp(deviceProperty, "Connected") == 0) + ffDBusGetBool(dbus, &dictIter, &device->connected); +} + +static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothDevice* device) +{ + if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) + return; + + DBusMessageIter dictIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); + + if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING) + return; + + const char* propertyType; + dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &propertyType); + + if(strstr(propertyType, "Device") == NULL && strstr(propertyType, "Battery") == NULL) + return; //We don't care about other properties + + dbus->lib->ffdbus_message_iter_next(&dictIter); + + if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) + return; + + DBusMessageIter arrayIter; + dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter); + + while(true) + { + detectBluetoothValue(dbus, &arrayIter, device); + FF_DBUS_ITER_CONTINUE(dbus, &arrayIter); + } +} + +static void detectBluetoothObject(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter) +{ + if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY) + return; + + DBusMessageIter dictIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter); + + if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH) + return; + + const char* objectPath; + dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath); + + //We don't want adapter objects + if(strstr(objectPath, "dev_") == NULL) + return; + + dbus->lib->ffdbus_message_iter_next(&dictIter); + + if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY) + return; + + DBusMessageIter arrayIter; + dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter); + + FFBluetoothDevice* device = ffListAdd(&bluetooth->devices); + ffStrbufInit(&device->name); + ffStrbufInit(&device->address); + ffStrbufInit(&device->type); + device->battery = 0; + device->connected = false; + + while(true) + { + detectBluetoothProperty(dbus, &arrayIter, device); + FF_DBUS_ITER_CONTINUE(dbus, &arrayIter); + } + + if(device->name.length == 0) + { + ffStrbufDestroy(&device->name); + ffStrbufDestroy(&device->address); + ffStrbufDestroy(&device->type); + --bluetooth->devices.length; + } +} + +static void detectBluetoothRoot(FFBluetoothResult* bluetooth, FFDBusData* dbus, DBusMessageIter* iter) +{ + if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) + return; + + DBusMessageIter arrayIter; + dbus->lib->ffdbus_message_iter_recurse(iter, &arrayIter); + + while(true) + { + detectBluetoothObject(bluetooth, dbus, &arrayIter); + FF_DBUS_ITER_CONTINUE(dbus, &arrayIter); + } +} + +static const char* detectBluetooth(const FFinstance* instance, FFBluetoothResult* bluetooth) +{ + FFDBusData dbus; + const char* error = ffDBusLoadData(instance, DBUS_BUS_SYSTEM, &dbus); + if(error) + return error; + + DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); + if(!managedObjects) + return "Failed to call GetManagedObjects"; + + DBusMessageIter rootIter; + if(!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter)) + { + dbus.lib->ffdbus_message_unref(managedObjects); + return "Failed to get root iterator of GetManagedObjects"; + } + + detectBluetoothRoot(bluetooth, &dbus, &rootIter); + + dbus.lib->ffdbus_message_unref(managedObjects); + return NULL; +} + +#endif + +void ffDetectBluetoothImpl(const FFinstance* instance, FFBluetoothResult* bluetooth) +{ + #ifdef FF_HAVE_DBUS + ffStrbufAppendS(&bluetooth->error, detectBluetooth(instance, bluetooth)); + #else + FF_UNUSED(instance); + ffStrbufAppendS(&bluetooth->error, "Fastfetch was compiled without DBus support"); + #endif +} diff --git a/src/detection/bluetooth/bluetooth_nosupport.c b/src/detection/bluetooth/bluetooth_nosupport.c new file mode 100644 index 000000000..f8cafe045 --- /dev/null +++ b/src/detection/bluetooth/bluetooth_nosupport.c @@ -0,0 +1,6 @@ +#include "bluetooth.h" + +void ffDetectBluetoothImpl(FF_MAYBE_UNUSED const FFinstance* instance, FFBluetoothResult* bluetooth) +{ + ffStrbufAppendS(&bluetooth->error, "Bluetooth not supported on this platform"); +} diff --git a/src/detection/bluetooth/bluetooth_windows.c b/src/detection/bluetooth/bluetooth_windows.c new file mode 100644 index 000000000..e713302b4 --- /dev/null +++ b/src/detection/bluetooth/bluetooth_windows.c @@ -0,0 +1,114 @@ +#include "bluetooth.h" +#include "util/windows/unicode.h" + +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-sign" + +void ffDetectBluetoothImpl(FF_MAYBE_UNUSED const FFinstance* instance, FFBluetoothResult* bluetooth) +{ + BLUETOOTH_DEVICE_SEARCH_PARAMS btsp = { + .fReturnConnected = TRUE, + .fReturnRemembered = TRUE, + .fReturnAuthenticated = TRUE, + .fReturnUnknown = TRUE, + .dwSize = sizeof(btsp) + }; + + BLUETOOTH_DEVICE_INFO btdi = { + .dwSize = sizeof(btdi) + }; + HBLUETOOTH_DEVICE_FIND hFind = BluetoothFindFirstDevice(&btsp, &btdi); + if(!hFind) + ffStrbufAppendS(&bluetooth->error, "BluetoothFindFirstDevice() failed or no devices found"); + + do { + FFBluetoothDevice* device = ffListAdd(&bluetooth->devices); + ffStrbufInit(&device->name); + ffStrbufInit(&device->address); + ffStrbufInit(&device->type); + device->battery = 0; + device->connected = !!btdi.fConnected; + + ffStrbufSetWS(&device->name, btdi.szName); + for (uint32_t i = 0; i < sizeof(btdi.Address.rgBytes) / sizeof(btdi.Address.rgBytes); ++i) + ffStrbufAppendF(&device->address, "%X:", btdi.Address.rgBytes[i]); + ffStrbufTrimRight(&device->name, ':'); + //https://btprodspecificationrefs.blob.core.windows.net/assigned-numbers/Assigned%20Number%20Types/Assigned%20Numbers.pdf + + if(BitTest(&btdi.ulClassofDevice, 13)) + ffStrbufAppendS(&device->type, "Limited Discoverable Mode, "); + if(BitTest(&btdi.ulClassofDevice, 14)) + ffStrbufAppendS(&device->type, "LE audio, "); + if(BitTest(&btdi.ulClassofDevice, 15)) + ffStrbufAppendS(&device->type, "Reserved for future use, "); + if(BitTest(&btdi.ulClassofDevice, 16)) + ffStrbufAppendS(&device->type, "Positioning, "); + if(BitTest(&btdi.ulClassofDevice, 17)) + ffStrbufAppendS(&device->type, "Networking, "); + if(BitTest(&btdi.ulClassofDevice, 18)) + ffStrbufAppendS(&device->type, "Rendering, "); + if(BitTest(&btdi.ulClassofDevice, 19)) + ffStrbufAppendS(&device->type, "Capturing, "); + if(BitTest(&btdi.ulClassofDevice, 20)) + ffStrbufAppendS(&device->type, "Object Transfer, "); + if(BitTest(&btdi.ulClassofDevice, 21)) + ffStrbufAppendS(&device->type, "Audio, "); + if(BitTest(&btdi.ulClassofDevice, 22)) + ffStrbufAppendS(&device->type, "Telephony, "); + if(BitTest(&btdi.ulClassofDevice, 23)) + ffStrbufAppendS(&device->type, "Information, "); + + if(device->type.length == 0) + { + uint32_t majorDeviceClasses = (btdi.ulClassofDevice >> 8) & ~(UINT32_MAX << 5); + switch(majorDeviceClasses) + { + case 0b00000: + ffStrbufAppendS(&device->type, "Miscellaneous"); + break; + case 0b00001: + ffStrbufAppendS(&device->type, "Computer"); + break; + case 0b00010: + ffStrbufAppendS(&device->type, "Phone"); + break; + case 0b00011: + ffStrbufAppendS(&device->type, "LAN/Network Access point"); + break; + case 0b00100: + ffStrbufAppendS(&device->type, "Audio/Video"); + break; + case 0b00101: + ffStrbufAppendS(&device->type, "Peripheral"); + break; + case 0b00110: + ffStrbufAppendS(&device->type, "Imaging"); + break; + case 0b00111: + ffStrbufAppendS(&device->type, "Wearable"); + break; + case 0b01000: + ffStrbufAppendS(&device->type, "Toy"); + break; + case 0b01001: + ffStrbufAppendS(&device->type, "Health"); + break; + case 0b11111: + ffStrbufAppendS(&device->type, "Uncategorized"); + break; + default: + ffStrbufAppendS(&device->type, "Unknown"); + break; + } + } + else + { + ffStrbufTrimRight(&device->type, ' '); + ffStrbufTrimRight(&device->type, ','); + } + } while (BluetoothFindNextDevice(hFind, &btdi)); +} + +#pragma GCC diagnostic pop diff --git a/src/detection/board/board_linux.c b/src/detection/board/board_linux.c index 8e92eec4e..8f5bcd2ff 100644 --- a/src/detection/board/board_linux.c +++ b/src/detection/board/board_linux.c @@ -1,5 +1,5 @@ #include "board.h" -#include "common/io.h" +#include "common/io/io.h" #include diff --git a/src/detection/brightness/brightness_linux.c b/src/detection/brightness/brightness_linux.c index 0f2a9d5fd..97f3ea4f9 100644 --- a/src/detection/brightness/brightness_linux.c +++ b/src/detection/brightness/brightness_linux.c @@ -1,5 +1,5 @@ #include "brightness.h" -#include "common/io.h" +#include "common/io/io.h" #include diff --git a/src/detection/chassis/chassis_linux.c b/src/detection/chassis/chassis_linux.c index 192747e7d..0898fa4b8 100644 --- a/src/detection/chassis/chassis_linux.c +++ b/src/detection/chassis/chassis_linux.c @@ -1,5 +1,5 @@ #include "chassis.h" -#include "common/io.h" +#include "common/io/io.h" #include diff --git a/src/detection/cpu/cpu_linux.c b/src/detection/cpu/cpu_linux.c index 73ce6eaca..202317033 100644 --- a/src/detection/cpu/cpu_linux.c +++ b/src/detection/cpu/cpu_linux.c @@ -1,5 +1,5 @@ #include "cpu.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/properties.h" #include "detection/temps/temps_linux.h" @@ -131,7 +131,7 @@ void ffDetectCPUImpl(const FFinstance* instance, FFCPUResult* cpu) cpu->coresOnline = (uint16_t) get_nprocs(); #define BP "/sys/devices/system/cpu/cpufreq/policy0/" - if(ffFileExists(BP, S_IFDIR)) + if(ffPathExists(BP, FF_PATHTYPE_DIRECTORY)) { cpu->frequencyMin = getFrequency(BP"cpuinfo_min_freq", BP"scaling_min_freq"); cpu->frequencyMax = getFrequency(BP"cpuinfo_max_freq", BP"scaling_max_freq"); diff --git a/src/detection/cpuUsage/cpuUsage_apple.c b/src/detection/cpuUsage/cpuUsage_apple.c index 38a6b4865..d3b533f48 100644 --- a/src/detection/cpuUsage/cpuUsage_apple.c +++ b/src/detection/cpuUsage/cpuUsage_apple.c @@ -6,23 +6,18 @@ const char* ffGetCpuUsageInfo(uint64_t* inUseAll, uint64_t* totalAll) { - natural_t numCPUs = 0U; - processor_info_array_t cpuInfo; - mach_msg_type_number_t numCpuInfo; + host_cpu_load_info_data_t cpustats; + mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; + *inUseAll = *totalAll = 0; - if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUs, &cpuInfo, &numCpuInfo) != KERN_SUCCESS) - return "host_processor_info() failed"; - if (numCPUs * CPU_STATE_MAX != numCpuInfo) - return "Unexpected host_processor_info() result"; + if (host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t)(&cpustats), &count) != KERN_SUCCESS) + return "host_statistics() failed"; + + *inUseAll = cpustats.cpu_ticks[CPU_STATE_USER] + + cpustats.cpu_ticks[CPU_STATE_SYSTEM] + + cpustats.cpu_ticks[CPU_STATE_NICE]; + *totalAll = *inUseAll + cpustats.cpu_ticks[CPU_STATE_IDLE]; - for (natural_t i = 0U; i < numCPUs; ++i) { - integer_t inUse = cpuInfo[CPU_STATE_MAX * i + CPU_STATE_USER] - + cpuInfo[CPU_STATE_MAX * i + CPU_STATE_SYSTEM] - + cpuInfo[CPU_STATE_MAX * i + CPU_STATE_NICE]; - integer_t total = inUse + cpuInfo[CPU_STATE_MAX * i + CPU_STATE_IDLE]; - *inUseAll += (uint64_t)inUse; - *totalAll += (uint64_t)total; - } return NULL; } diff --git a/src/detection/cursor/cursor_linux.c b/src/detection/cursor/cursor_linux.c index 63507e803..3ca696091 100644 --- a/src/detection/cursor/cursor_linux.c +++ b/src/detection/cursor/cursor_linux.c @@ -3,8 +3,9 @@ #include "common/properties.h" #include "common/parsing.h" #include "common/settings.h" -#include "detection/gtk.h" +#include "detection/gtk_qt/gtk_qt.h" #include "detection/displayserver/displayserver.h" +#include "util/stringUtils.h" #include @@ -72,13 +73,13 @@ void ffDetectCursor(const FFinstance* instance, FFCursorResult* result) { const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); - if(ffStrbufCompS(&wmde->wmPrettyName, "WSLg") == 0) + if(ffStrbufCompS(&wmde->wmPrettyName, FF_WM_PRETTY_WSLG) == 0) ffStrbufAppendS(&result->error, "WSLg uses native windows cursor"); - else if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0) + else if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) ffStrbufAppendS(&result->error, "Cursor isn't supported in TTY"); - else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "KDE Plasma") == 0) + else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA) == 0) detectCursorFromConfigFile(instance, "kcminputrc", "cursorTheme =", "Breeze", "cursorSize =", "24", result); - else if(ffStrbufStartsWithIgnCaseS(&wmde->dePrettyName, "LXQt")) + else if(ffStrbufStartsWithIgnCaseS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT)) detectCursorFromConfigFile(instance, "lxqt/session.conf", "cursor_theme =", "Adwaita", "cursor_size =", "24", result); else if( !detectCursorGTK(instance, result) && diff --git a/src/detection/datetime.c b/src/detection/datetime/datetime.c similarity index 98% rename from src/detection/datetime.c rename to src/detection/datetime/datetime.c index 20b8ec367..317fdcf85 100644 --- a/src/detection/datetime.c +++ b/src/detection/datetime/datetime.c @@ -1,5 +1,5 @@ #include "fastfetch.h" -#include "detection/datetime.h" +#include "detection/datetime/datetime.h" #include "common/thread.h" #include diff --git a/src/detection/datetime.h b/src/detection/datetime/datetime.h similarity index 89% rename from src/detection/datetime.h rename to src/detection/datetime/datetime.h index 7f6956e61..418f14fb2 100644 --- a/src/detection/datetime.h +++ b/src/detection/datetime/datetime.h @@ -1,7 +1,7 @@ #pragma once -#ifndef FF_INCLUDED_detection_datetime -#define FF_INCLUDED_detection_datetime +#ifndef FF_INCLUDED_detection_datetime_datetime +#define FF_INCLUDED_detection_datetime_datetime #include "fastfetch.h" diff --git a/src/detection/disk/disk_linux.c b/src/detection/disk/disk_linux.c index ec7a26abf..7e6a1bc0b 100644 --- a/src/detection/disk/disk_linux.c +++ b/src/detection/disk/disk_linux.c @@ -1,5 +1,7 @@ #include "disk.h" +#include "util/stringUtils.h" + #include #include #include @@ -13,24 +15,35 @@ #define readdir readdir64 #endif -static bool isPhysicalDevice(const char* device) +static bool isPhysicalDevice(FFstrbuf* device) { + struct stat deviceStat; + if(stat(device->chars, &deviceStat) != 0) + return false; + + //Ignore all devices that are not block devices + if(!S_ISBLK(deviceStat.st_mode)) + return false; + + //Ignore all devices that are not physical devices + + //DrvFs is a filesystem plugin to WSL that was designed to support interop between WSL and the Windows filesystem. - if(strcmp(device, "drvfs") == 0) + if(ffStrbufEqualS(device, "drvfs")) + return true; + + //ZFS root pool. The format is rpool/// + if(ffStrbufStartsWithS(device, "rpool/")) return true; //Pseudo filesystems don't have a device in /dev - const char* devPrefix = "/dev/"; - if(strncmp(device, devPrefix, strlen(devPrefix)) != 0) + if(!ffStrbufStartsWithS(device, "/dev/")) return false; - //Skip /dev/ prefix - device += strlen(devPrefix); - if( - strncmp(device, "loop", 4) == 0 || //Ignore loop devices - strncmp(device, "ram", 3) == 0 || //Ignore ram devices - strncmp(device, "fd", 2) == 0 //Ignore fd devices + ffStrbufStartsWithS(device, "/dev/loop") || //Ignore loop devices + ffStrbufStartsWithS(device, "/dev/ram") || //Ignore ram devices + ffStrbufStartsWithS(device, "/dev/fd") //Ignore fd devices ) return false; return true; @@ -141,6 +154,7 @@ static bool isSubvolume(const FFlist* devices) { const FFstrbuf* currentDevie = ffListGet(devices, devices->length - 1); + //Filter all disks which device was already found. This catches BTRFS subvolumes. for(uint32_t i = 0; i < devices->length - 1; i++) { const FFstrbuf* otherDevice = ffListGet(devices, i); @@ -149,6 +163,11 @@ static bool isSubvolume(const FFlist* devices) return true; } + //ZFS subvolumes: rpool///. + //Test if the third slash is present. + if(strncmp(currentDevie->chars, "rpool/", 6) == 0 && ffStrHasNChars(currentDevie->chars, '/', 3)) + return true; + return false; } @@ -196,12 +215,6 @@ void ffDetectDisksImpl(FFDiskResult* disks) while(getline(&line, &len, mountsFile) != EOF) { - if(!isPhysicalDevice(line)) - continue; - - //We have a valid device, add it to the list - FFDisk* disk = ffListAdd(&disks->disks); - //Format of the file: " ..." (Same as fstab) char* currentPos = line; @@ -210,6 +223,16 @@ void ffDetectDisksImpl(FFDiskResult* disks) ffStrbufInit(device); appendNextEntry(device, ¤tPos); + if(!isPhysicalDevice(device)) + { + ffStrbufDestroy(device); + devices.length--; + continue; + } + + //We have a valid device, add it to the list + FFDisk* disk = ffListAdd(&disks->disks); + //detect mountpoint ffStrbufInit(&disk->mountpoint); appendNextEntry(&disk->mountpoint, ¤tPos); diff --git a/src/detection/displayserver/displayserver.h b/src/detection/displayserver/displayserver.h index 17fef3ba5..271a35085 100644 --- a/src/detection/displayserver/displayserver.h +++ b/src/detection/displayserver/displayserver.h @@ -5,6 +5,35 @@ #include "fastfetch.h" +#define FF_DE_PRETTY_PLASMA "KDE Plasma" +#define FF_DE_PRETTY_GNOME "Gnome" +#define FF_DE_PRETTY_XFCE4 "Xfce4" +#define FF_DE_PRETTY_CINNAMON "Cinnamon" +#define FF_DE_PRETTY_MATE "Mate" +#define FF_DE_PRETTY_LXDE "LXDE" +#define FF_DE_PRETTY_LXQT "LXQT" +#define FF_DE_PRETTY_BUDGIE "Budgie" +#define FF_DE_PRETTY_UNITY "Unity" + +#define FF_WM_PRETTY_KWIN "KWin" +#define FF_WM_PRETTY_MUTTER "Mutter" +#define FF_WM_PRETTY_MUFFIN "Muffin" +#define FF_WM_PRETTY_MARCO "Marco" +#define FF_WM_PRETTY_XFWM4 "Xfwm4" +#define FF_WM_PRETTY_OPENBOX "Openbox" +#define FF_WM_PRETTY_I3 "i3" +#define FF_WM_PRETTY_WAYFIRE "Wayfire" +#define FF_WM_PRETTY_SWAY "Sway" +#define FF_WM_PRETTY_BSPWM "bspwm" +#define FF_WM_PRETTY_DWM "dwm" +#define FF_WM_PRETTY_WESTON "Weston" +#define FF_WM_PRETTY_XMONAD "XMonad" +#define FF_WM_PRETTY_WSLG "WSLg" + +#define FF_WM_PROTOCOL_TTY "TTY" +#define FF_WM_PROTOCOL_X11 "X11" +#define FF_WM_PROTOCOL_WAYLAND "Wayland" + typedef struct FFDisplayResult { uint32_t width; diff --git a/src/detection/displayserver/linux/displayserver_linux.h b/src/detection/displayserver/linux/displayserver_linux.h index 9c7588058..aee7c25ff 100644 --- a/src/detection/displayserver/linux/displayserver_linux.h +++ b/src/detection/displayserver/linux/displayserver_linux.h @@ -5,10 +5,6 @@ #include "detection/displayserver/displayserver.h" -#define FF_DISPLAYSERVER_PROTOCOL_WAYLAND "Wayland" -#define FF_DISPLAYSERVER_PROTOCOL_X11 "X11" -#define FF_DISPLAYSERVER_PROTOCOL_TTY "TTY" - void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* result); void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* result); diff --git a/src/detection/displayserver/linux/wayland.c b/src/detection/displayserver/linux/wayland.c index 27a5c09d3..fce97c8f2 100644 --- a/src/detection/displayserver/linux/wayland.c +++ b/src/detection/displayserver/linux/wayland.c @@ -5,20 +5,30 @@ #ifdef FF_HAVE_WAYLAND #include "common/library.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/thread.h" #include #include typedef struct WaylandData { - FFlist* results; + FFDisplayServerResult* result; FF_LIBRARY_SYMBOL(wl_proxy_marshal_constructor_versioned) FF_LIBRARY_SYMBOL(wl_proxy_add_listener) FF_LIBRARY_SYMBOL(wl_proxy_destroy) + FF_LIBRARY_SYMBOL(wl_display_roundtrip) + struct wl_display* display; const struct wl_interface* ffwl_output_interface; } WaylandData; +typedef struct WaylandDisplay +{ + int32_t width; + int32_t height; + int32_t refreshRate; + int32_t scale; +} WaylandDisplay; + #ifndef __FreeBSD__ static void waylandDetectWM(int fd, FFDisplayServerResult* result) { @@ -49,25 +59,76 @@ static void stubListener(void* data, ...) static void waylandOutputModeListener(void* data, struct wl_output* output, uint32_t flags, int32_t width, int32_t height, int32_t refreshRate) { - WaylandData* wldata = data; + FF_UNUSED(output); - wldata->ffwl_proxy_destroy((struct wl_proxy*) output); + if(!(flags & WL_OUTPUT_MODE_CURRENT)) + return; - if(!(flags & WL_OUTPUT_MODE_CURRENT) || width <= 0 || height <= 0) + WaylandDisplay* display = data; + display->width = width; + display->height = height; + display->refreshRate = refreshRate; +} + +#if WAYLAND_VERSION_MINOR >= 2 +static void waylandOutputScaleListener(void* data, struct wl_output* output, int32_t scale) +{ + FF_UNUSED(output); + + WaylandDisplay* display = data; + display->scale = scale; +} +#endif + +static void waylandOutputHandler(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version) +{ + struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL); + if(output == NULL) + return; + + WaylandDisplay display = { + .width = 0, + .height = 0, + .refreshRate = 0, + .scale = 1, + }; + + struct wl_output_listener outputListener = { + .mode = waylandOutputModeListener, + .geometry = (void*) stubListener, + + //https://lists.freedesktop.org/archives/wayland-devel/2013-July/010278.html + #if WAYLAND_VERSION_MINOR >= 2 + .done = (void*) stubListener, + .scale = waylandOutputScaleListener, + #endif + + //https://lists.freedesktop.org/archives/wayland-devel/2021-December/042064.html + #if WAYLAND_VERSION_MINOR >= 20 + .name = (void*) stubListener, + .description = (void*) stubListener, + #endif + }; + + wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, &display); + wldata->ffwl_display_roundtrip(wldata->display); + wldata->ffwl_proxy_destroy(output); + + if(display.width <= 0 || display.height <= 0) return; static FFThreadMutex mutex = FF_THREAD_MUTEX_INITIALIZER; ffThreadMutexLock(&mutex); - FFDisplayResult* result = ffListAdd(wldata->results); + ffdsAppendDisplay(wldata->result, + (uint32_t) display.width, + (uint32_t) display.height, + ffdsParseRefreshRate(display.refreshRate / 1000), + (uint32_t) (display.width / display.scale), + (uint32_t) (display.height / display.scale) + ); ffThreadMutexUnlock(&mutex); - - result->width = (uint32_t) width; - result->height = (uint32_t) height; - result->refreshRate = ffdsParseRefreshRate(refreshRate / 1000); - result->scaledWidth = 0; - result->scaledHeight = 0; } static void waylandGlobalAddListener(void* data, struct wl_registry* registry, uint32_t name, const char* interface, uint32_t version) @@ -75,31 +136,7 @@ static void waylandGlobalAddListener(void* data, struct wl_registry* registry, u WaylandData* wldata = data; if(strcmp(interface, wldata->ffwl_output_interface->name) == 0) - { - struct wl_proxy* output = wldata->ffwl_proxy_marshal_constructor_versioned((struct wl_proxy*) registry, WL_REGISTRY_BIND, wldata->ffwl_output_interface, version, name, wldata->ffwl_output_interface->name, version, NULL); - if(output == NULL) - return; - - //Needs to be static, because the scope of the function will already be lost when calling the listener - static struct wl_output_listener outputListener = { - .mode = waylandOutputModeListener, - .geometry = (void*) stubListener, - - //https://lists.freedesktop.org/archives/wayland-devel/2013-July/010278.html - #if WAYLAND_VERSION_MINOR >= 2 - .done = (void*) stubListener, - .scale = (void*) stubListener, - #endif - - //https://lists.freedesktop.org/archives/wayland-devel/2021-December/042064.html - #if WAYLAND_VERSION_MINOR >= 20 - .name = (void*) stubListener, - .description = (void*) stubListener, - #endif - }; - - wldata->ffwl_proxy_add_listener(output, (void(**)(void)) &outputListener, data); - } + waylandOutputHandler(wldata, registry, name, version); } bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result) @@ -109,7 +146,6 @@ bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result) FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_connect, false) FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_get_fd, false) FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_dispatch, false) - FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_roundtrip, false) FF_LIBRARY_LOAD_SYMBOL(wayland, wl_proxy_marshal_constructor, false) FF_LIBRARY_LOAD_SYMBOL(wayland, wl_display_disconnect, false) FF_LIBRARY_LOAD_SYMBOL(wayland, wl_registry_interface, false) @@ -119,26 +155,23 @@ bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result) FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_marshal_constructor_versioned, false) FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_add_listener, false) FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_proxy_destroy, false) + FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_display_roundtrip, false) FF_LIBRARY_LOAD_SYMBOL_VAR(wayland, data, wl_output_interface, false) - struct wl_display* display = ffwl_display_connect(NULL); - if(display == NULL) - { - dlclose(wayland); + data.display = ffwl_display_connect(NULL); + if(data.display == NULL) return false; - } - waylandDetectWM(ffwl_display_get_fd(display), result); + waylandDetectWM(ffwl_display_get_fd(data.display), result); - struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL); + struct wl_proxy* registry = ffwl_proxy_marshal_constructor((struct wl_proxy*) data.display, WL_DISPLAY_GET_REGISTRY, ffwl_registry_interface, NULL); if(registry == NULL) { - ffwl_display_disconnect(display); - dlclose(wayland); + ffwl_display_disconnect(data.display); return false; } - data.results = &result->displays; + data.result = result; struct wl_registry_listener registry_listener = { .global = waylandGlobalAddListener, @@ -146,17 +179,16 @@ bool detectWayland(const FFinstance* instance, FFDisplayServerResult* result) }; data.ffwl_proxy_add_listener(registry, (void(**)(void)) ®istry_listener, &data); - ffwl_display_dispatch(display); - ffwl_display_roundtrip(display); + ffwl_display_dispatch(data.display); + data.ffwl_display_roundtrip(data.display); data.ffwl_proxy_destroy(registry); - ffwl_display_disconnect(display); - dlclose(wayland); + ffwl_display_disconnect(data.display); //We successfully connected to wayland and detected the display. //So we can set set the session type to wayland. //This is used as an indicator that we are running wayland by the x11 backends. - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND); return true; } #endif @@ -187,5 +219,5 @@ void ffdsConnectWayland(const FFinstance* instance, FFDisplayServerResult* resul //We are probably running a wayland compositor at this point, //but fastfetch was compiled without the required library, or loading the library failed. - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND); } diff --git a/src/detection/displayserver/linux/wmde.c b/src/detection/displayserver/linux/wmde.c index 4d9d79b6a..3c40b2e11 100644 --- a/src/detection/displayserver/linux/wmde.c +++ b/src/detection/displayserver/linux/wmde.c @@ -1,8 +1,9 @@ #include "displayserver_linux.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/properties.h" #include "common/parsing.h" #include "common/processing.h" +#include "util/stringUtils.h" #include #include @@ -48,7 +49,7 @@ static const char* parseEnv() if( getenv("WAYLAND_DISPLAY") != NULL && - ffFileExists("/mnt/wslg/", S_IFDIR) + ffPathExists("/mnt/wslg/", FF_PATHTYPE_DIRECTORY) ) return "WSLg"; return NULL; @@ -65,31 +66,34 @@ static void applyPrettyNameIfWM(FFDisplayServerResult* result, const char* proce strcasecmp(processName, "kwin_x11") == 0 || strcasecmp(processName, "kwin_x11_wrapper") == 0 || strcasecmp(processName, "kwin") == 0 - ) ffStrbufSetS(&result->wmPrettyName, "KWin"); + ) ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_KWIN); else if( strcasecmp(processName, "gnome-shell") == 0 || strcasecmp(processName, "gnome shell") == 0 || strcasecmp(processName, "gnome-session-binary") == 0 || strcasecmp(processName, "Mutter") == 0 - ) ffStrbufSetS(&result->wmPrettyName, "Mutter"); + ) ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_MUTTER); else if( strcasecmp(processName, "cinnamon-session") == 0 || - strcasecmp(processName, "Muffin") == 0 - ) ffStrbufSetS(&result->wmPrettyName, "Muffin"); + strcasecmp(processName, "Muffin") == 0 || + strcasecmp(processName, "Mutter (Muffin)") == 0 + ) ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_MUFFIN); else if(strcasecmp(processName, "sway") == 0) - ffStrbufSetS(&result->wmPrettyName, "Sway"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_SWAY); else if(strcasecmp(processName, "weston") == 0) - ffStrbufSetS(&result->wmPrettyName, "Weston"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_WESTON); else if(strcasecmp(processName, "wayfire") == 0) - ffStrbufSetS(&result->wmPrettyName, "Wayfire"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_WAYFIRE); else if(strcasecmp(processName, "openbox") == 0) - ffStrbufSetS(&result->wmPrettyName, "Openbox"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_OPENBOX); else if(strcasecmp(processName, "xfwm4") == 0) - ffStrbufSetS(&result->wmPrettyName, "Xfwm4"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_XFWM4); else if(strcasecmp(processName, "Marco") == 0) - ffStrbufSetS(&result->wmPrettyName, "Marco"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_MARCO); else if(strcasecmp(processName, "xmonad") == 0) - ffStrbufSetS(&result->wmPrettyName, "XMonad"); + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_XMONAD); + else if(strcasecmp(processName, "WSLg") == 0) + ffStrbufSetS(&result->wmPrettyName, FF_WM_PRETTY_WSLG); else if( // WMs where the pretty name matches the process name strcasecmp(processName, "dwm") == 0 || strcasecmp(processName, "bspwm") == 0 || @@ -119,7 +123,7 @@ static void applyBetterWM(FFDisplayServerResult* result, const char* processName static void getKDE(const FFinstance* instance, FFDisplayServerResult* result) { ffStrbufSetS(&result->deProcessName, "plasmashell"); - ffStrbufSetS(&result->dePrettyName, "KDE Plasma"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_PLASMA); ffParsePropFileData(instance, "xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", &result->deVersion); if(result->deVersion.length == 0) @@ -135,21 +139,21 @@ static void getKDE(const FFinstance* instance, FFDisplayServerResult* result) static void getGnome(const FFinstance* instance, FFDisplayServerResult* result) { ffStrbufSetS(&result->deProcessName, "gnome-shell"); - ffStrbufSetS(&result->dePrettyName, "GNOME"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_GNOME); ffParsePropFileData(instance, "gnome-shell/org.gnome.Extensions", "version :", &result->deVersion); } static void getCinnamon(const FFinstance* instance, FFDisplayServerResult* result) { ffStrbufSetS(&result->deProcessName, "cinnamon"); - ffStrbufSetS(&result->dePrettyName, "Cinnamon"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_CINNAMON); ffParsePropFileData(instance, "applications/cinnamon.desktop", "X-GNOME-Bugzilla-Version =", &result->deVersion); } static void getMate(const FFinstance* instance, FFDisplayServerResult* result) { ffStrbufSetS(&result->deProcessName, "mate-session"); - ffStrbufSetS(&result->dePrettyName, "MATE"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_MATE); FFstrbuf major; ffStrbufInit(&major); @@ -188,7 +192,7 @@ static void getMate(const FFinstance* instance, FFDisplayServerResult* result) static void getXFCE4(const FFinstance* instance, FFDisplayServerResult* result) { ffStrbufSetS(&result->deProcessName, "xfce4-session"); - ffStrbufSetS(&result->dePrettyName, "Xfce4"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_XFCE4); ffParsePropFileData(instance, "gtk-doc/html/libxfce4ui/index.html", "

Version", &result->deVersion); if(result->deVersion.length == 0 && instance->config.allowSlowOperations) @@ -209,7 +213,7 @@ static void getXFCE4(const FFinstance* instance, FFDisplayServerResult* result) static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result) { ffStrbufSetS(&result->deProcessName, "lxqt-session"); - ffStrbufSetS(&result->dePrettyName, "LXQt"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_LXQT); ffParsePropFileData(instance, "gconfig/lxqt.pc", "Version:", &result->deVersion); if(result->deVersion.length == 0) @@ -241,8 +245,8 @@ static void getLXQt(const FFinstance* instance, FFDisplayServerResult* result) static void getBudgie(const FFinstance* instance, FFDisplayServerResult* result) { - ffStrbufSetS(&result->dePrettyName, "Budgie"); ffStrbufSetS(&result->deProcessName, "budgie-desktop"); + ffStrbufSetS(&result->dePrettyName, FF_DE_PRETTY_BUDGIE); ffParsePropFileData(instance, "budgie/budgie-version.xml", "", &result->deVersion); } @@ -307,9 +311,9 @@ static void getWMProtocolNameFromEnv(FFDisplayServerResult* result) if(ffStrSet(env)) { if(strcasecmp(env, "x11") == 0) - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); else if(strcasecmp(env, "tty") == 0) - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_TTY); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY); else ffStrbufSetS(&result->wmProtocolName, env); @@ -319,14 +323,14 @@ static void getWMProtocolNameFromEnv(FFDisplayServerResult* result) env = getenv("DISPLAY"); if(ffStrSet(env)) { - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); return; } env = getenv("TERM"); - if(ffStrSet(env)) + if(ffStrSet(env) && strcasecmp(env, "linux") == 0) { - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_TTY); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY); return; } } @@ -408,7 +412,7 @@ void ffdsDetectWMDE(const FFinstance* instance, FFDisplayServerResult* result) //We don't want to detect anything in TTY //This can't happen if a connection succeeded, so we don't need to clear wmProcessName - if(ffStrbufIgnCaseCompS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_TTY) == 0) + if(ffStrbufIgnCaseCompS(&result->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) return; const char* env = parseEnv(); diff --git a/src/detection/displayserver/linux/xcb.c b/src/detection/displayserver/linux/xcb.c index 99a960894..c31803286 100644 --- a/src/detection/displayserver/linux/xcb.c +++ b/src/detection/displayserver/linux/xcb.c @@ -62,7 +62,7 @@ static void* xcbGetProperty(XcbPropertyData* data, xcb_connection_t* connection, static void xcbDetectWMfromEWMH(XcbPropertyData* data, xcb_connection_t* connection, xcb_window_t rootWindow, FFDisplayServerResult* result) { - if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND) == 0) + if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0) return; xcb_window_t* wmWindow = (xcb_window_t*) xcbGetProperty(data, connection, rootWindow, "_NET_SUPPORTING_WM_CHECK"); @@ -103,10 +103,7 @@ void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result) xcb_connection_t* connection = ffxcb_connect(NULL, NULL); if(connection == NULL) - { - dlclose(xcb); return; - } xcb_screen_iterator_t iterator = ffxcb_setup_roots_iterator(ffxcb_get_setup(connection)); @@ -120,18 +117,17 @@ void ffdsConnectXcb(const FFinstance* instance, FFDisplayServerResult* result) (uint32_t) iterator.data->width_in_pixels, (uint32_t) iterator.data->height_in_pixels, 0, - 0, - 0 + (uint32_t) iterator.data->width_in_pixels, + (uint32_t) iterator.data->height_in_pixels ); ffxcb_screen_next(&iterator); } ffxcb_disconnect(connection); - dlclose(xcb); //If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland. if(result->wmProtocolName.length == 0) - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); } #else @@ -187,8 +183,8 @@ static bool xcbRandrHandleModeInfo(XcbRandrData* data, xcb_randr_mode_info_t* mo (uint32_t) modeInfo->width, (uint32_t) modeInfo->height, refreshRate == 0 ? data->defaultRefreshRate : refreshRate, - 0, - 0 + (uint32_t) modeInfo->width, + (uint32_t) modeInfo->height ); } @@ -224,8 +220,8 @@ static bool xcbRandrHandleCrtc(XcbRandrData* data, xcb_randr_crtc_t crtc) (uint32_t) crtcInfoReply->width, (uint32_t) crtcInfoReply->height, data->defaultRefreshRate, - 0, - 0 + (uint32_t) crtcInfoReply->width, + (uint32_t) crtcInfoReply->height ); free(crtcInfoReply); @@ -269,8 +265,8 @@ static bool xcbRandrHandleMonitor(XcbRandrData* data, xcb_randr_monitor_info_t* (uint32_t) monitor->width, (uint32_t) monitor->height, data->defaultRefreshRate, - 0, - 0 + (uint32_t) monitor->width, + (uint32_t) monitor->height ); } @@ -329,8 +325,8 @@ static void xcbRandrHandleScreen(XcbRandrData* data, xcb_screen_t* screen) (uint32_t) screen->width_in_pixels, (uint32_t) screen->height_in_pixels, data->defaultRefreshRate, - 0, - 0 + (uint32_t) screen->width_in_pixels, + (uint32_t) screen->height_in_pixels ); } @@ -368,10 +364,7 @@ void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* resu data.connection = ffxcb_connect(NULL, NULL); if(data.connection == NULL) - { - dlclose(xcbRandr); return; - } data.result = result; @@ -387,11 +380,10 @@ void ffdsConnectXcbRandr(const FFinstance* instance, FFDisplayServerResult* resu } ffxcb_disconnect(data.connection); - dlclose(xcbRandr); //If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland. if(result->wmProtocolName.length == 0) - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); } #else diff --git a/src/detection/displayserver/linux/xlib.c b/src/detection/displayserver/linux/xlib.c index 12f87587c..241db5e87 100644 --- a/src/detection/displayserver/linux/xlib.c +++ b/src/detection/displayserver/linux/xlib.c @@ -3,6 +3,7 @@ #ifdef FF_HAVE_X11 #include "common/library.h" #include "common/parsing.h" +#include "util/stringUtils.h" #include typedef struct X11PropertyData @@ -39,7 +40,7 @@ static unsigned char* x11GetProperty(X11PropertyData* data, Display* display, Wi static void x11DetectWMFromEWMH(X11PropertyData* data, Display* display, FFDisplayServerResult* result) { - if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_WAYLAND) == 0) + if(result->wmProcessName.length > 0 || ffStrbufCompS(&result->wmProtocolName, FF_WM_PROTOCOL_WAYLAND) == 0) return; Window* wmWindow = (Window*) x11GetProperty(data, display, DefaultRootWindow(display), "_NET_SUPPORTING_WM_CHECK"); @@ -68,10 +69,7 @@ void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result) Display* display = ffXOpenDisplay(x11); if(display == NULL) - { - dlclose(x11); return; - } if(propertyDataInitialized && ScreenCount(display) > 0) x11DetectWMFromEWMH(&propertyData, display, result); @@ -81,20 +79,19 @@ void ffdsConnectXlib(const FFinstance* instance, FFDisplayServerResult* result) Screen* screen = ScreenOfDisplay(display, i); ffdsAppendDisplay( result, - (uint32_t) screen->width, - (uint32_t) screen->height, + (uint32_t) WidthOfScreen(screen), + (uint32_t) HeightOfScreen(screen), 0, - 0, - 0 + (uint32_t) WidthOfScreen(screen), + (uint32_t) HeightOfScreen(screen) ); } ffXCloseDisplay(display); - dlclose(x11); //If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland. if(result->wmProtocolName.length == 0) - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); } #else @@ -145,8 +142,8 @@ static bool xrandrHandleModeInfo(XrandrData* data, XRRModeInfo* modeInfo) (uint32_t) modeInfo->width, (uint32_t) modeInfo->height, refreshRate == 0 ? data->defaultRefreshRate : refreshRate, - 0, - 0 + (uint32_t) modeInfo->width, + (uint32_t) modeInfo->height ); } @@ -176,8 +173,8 @@ static bool xrandrHandleCrtc(XrandrData* data, RRCrtc crtc) (uint32_t) crtcInfo->width, (uint32_t) crtcInfo->height, data->defaultRefreshRate, - 0, - 0 + (uint32_t) crtcInfo->width, + (uint32_t) crtcInfo->height ); data->ffXRRFreeCrtcInfo(crtcInfo); @@ -212,8 +209,8 @@ static bool xrandrHandleMonitor(XrandrData* data, XRRMonitorInfo* monitorInfo) (uint32_t) monitorInfo->width, (uint32_t) monitorInfo->height, data->defaultRefreshRate, - 0, - 0 + (uint32_t) monitorInfo->width, + (uint32_t) monitorInfo->height ); } @@ -266,8 +263,8 @@ static void xrandrHandleScreen(XrandrData* data, Screen* screen) (uint32_t) WidthOfScreen(screen), (uint32_t) HeightOfScreen(screen), data->defaultRefreshRate, - 0, - 0 + (uint32_t) WidthOfScreen(screen), + (uint32_t) HeightOfScreen(screen) ); } @@ -297,10 +294,7 @@ void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result data.display = ffXOpenDisplay(NULL); if(data.display == NULL) - { - dlclose(xrandr); return; - } if(propertyDataInitialized && ScreenCount(data.display) > 0) x11DetectWMFromEWMH(&propertyData, data.display, result); @@ -311,11 +305,10 @@ void ffdsConnectXrandr(const FFinstance* instance, FFDisplayServerResult* result xrandrHandleScreen(&data, ScreenOfDisplay(data.display, i)); ffXCloseDisplay(data.display); - dlclose(xrandr); //If wayland hasn't set this, connection failed for it. So we are running only a X Server, not XWayland. if(result->wmProtocolName.length == 0) - ffStrbufSetS(&result->wmProtocolName, FF_DISPLAYSERVER_PROTOCOL_X11); + ffStrbufSetS(&result->wmProtocolName, FF_WM_PROTOCOL_X11); } #else diff --git a/src/detection/font/font_apple.m b/src/detection/font/font_apple.m index 773c7705b..6f26803b0 100644 --- a/src/detection/font/font_apple.m +++ b/src/detection/font/font_apple.m @@ -1,5 +1,5 @@ #include "common/font.h" -#include "common/io.h" +#include "common/io/io.h" #include "font.h" #import diff --git a/src/detection/font/font_linux.c b/src/detection/font/font_linux.c index 62c66445b..ae2f03331 100644 --- a/src/detection/font/font_linux.c +++ b/src/detection/font/font_linux.c @@ -1,6 +1,5 @@ -#include "detection/qt.h" -#include "detection/gtk.h" #include "common/font.h" +#include "detection/gtk_qt/gtk_qt.h" #include "font.h" void ffDetectFontImpl(const FFinstance* instance, FFFontResult* result) diff --git a/src/detection/gamepad/gamepad.h b/src/detection/gamepad/gamepad.h new file mode 100644 index 000000000..1def1b430 --- /dev/null +++ b/src/detection/gamepad/gamepad.h @@ -0,0 +1,16 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_gamepad_gamepad +#define FF_INCLUDED_detection_gamepad_gamepad + +#include "fastfetch.h" + +typedef struct FFGamepadDevice +{ + FFstrbuf identifier; + FFstrbuf name; +} FFGamepadDevice; + +const char* ffDetectGamepad(const FFinstance* instance, FFlist* devices /* List of FFGamepadDevice */); + +#endif diff --git a/src/detection/gamepad/gamepad_apple.c b/src/detection/gamepad/gamepad_apple.c new file mode 100644 index 000000000..154f1c587 --- /dev/null +++ b/src/detection/gamepad/gamepad_apple.c @@ -0,0 +1,41 @@ +#include "gamepad.h" +#include "util/apple/cf_helpers.h" + +#include +#include + +static void enumSet(const void* value, void *context) +{ + CFStringRef product = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDProductKey)); + CFStringRef serialNumber = IOHIDDeviceGetProperty((IOHIDDeviceRef) value, CFSTR(kIOHIDSerialNumberKey)); + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd((FFlist*) context); + ffStrbufInit(&device->identifier); + ffCfStrGetString(serialNumber, &device->identifier); + ffStrbufInit(&device->name); + ffCfStrGetString(product, &device->name); +} + +const char* ffDetectGamepad(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* devices /* List of FFGamepadDevice */) +{ + IOHIDManagerRef FF_CFTYPE_AUTO_RELEASE manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); + if (IOHIDManagerOpen(manager, kIOHIDOptionsTypeNone) != kIOReturnSuccess) + return "IOHIDManagerOpen() failed"; + + CFNumberRef FF_CFTYPE_AUTO_RELEASE genericDesktop = ffCfCreateInt(kHIDPage_GenericDesktop); + CFNumberRef FF_CFTYPE_AUTO_RELEASE gamePad = ffCfCreateInt(kHIDUsage_GD_GamePad); + CFDictionaryRef FF_CFTYPE_AUTO_RELEASE matching = CFDictionaryCreate(kCFAllocatorDefault, (const void **)(CFStringRef[]){ + CFSTR(kIOHIDDeviceUsagePageKey), + CFSTR(kIOHIDDeviceUsageKey) + }, (const void **)(CFNumberRef[]){ + genericDesktop, + gamePad + }, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + IOHIDManagerSetDeviceMatching(manager, matching); + + CFSetRef FF_CFTYPE_AUTO_RELEASE set = IOHIDManagerCopyDevices(manager); + if (set) + CFSetApplyFunction(set, &enumSet, devices); + IOHIDManagerClose(manager, 0); + + return NULL; +} diff --git a/src/detection/gamepad/gamepad_linux.c b/src/detection/gamepad/gamepad_linux.c new file mode 100644 index 000000000..ce61a5711 --- /dev/null +++ b/src/detection/gamepad/gamepad_linux.c @@ -0,0 +1,42 @@ +#include "gamepad.h" +#include "common/io/io.h" + +#include +#include + +const char* ffDetectGamepad(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* devices /* List of FFGamepadDevice */) +{ + DIR* dirp = opendir("/sys/class/input/"); + if(dirp == NULL) + return "opendir(\"/sys/class/input/\") == NULL"; + + FF_STRBUF_AUTO_DESTROY path; + ffStrbufInitS(&path, "/sys/class/input/"); + uint32_t baseLen = path.length; + + struct dirent* entry; + while((entry = readdir(dirp)) != NULL) + { + if(strncmp(entry->d_name, "js", 2) != 0) + continue; + if(!isdigit(entry->d_name[2])) + continue; + + ffStrbufAppendS(&path, entry->d_name); + ffStrbufAppendS(&path, "/device/name"); + + if (ffPathExists(path.chars, FF_PATHTYPE_FILE)) + { + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); + ffStrbufInitS(&device->identifier, entry->d_name); + ffStrbufInit(&device->name); + ffAppendFileBuffer(path.chars, &device->name); + } + + ffStrbufSubstrBefore(&path, baseLen); + } + + closedir(dirp); + + return NULL; +} diff --git a/src/detection/gamepad/gamepad_nosupport.c b/src/detection/gamepad/gamepad_nosupport.c new file mode 100644 index 000000000..d921d3552 --- /dev/null +++ b/src/detection/gamepad/gamepad_nosupport.c @@ -0,0 +1,6 @@ +#include "gamepad.h" + +const char* ffDetectGamepad(FF_MAYBE_UNUSED const FFinstance* instance, FF_MAYBE_UNUSED FFlist* devices /* List of FFGamepadDevice */) +{ + return "Not supported on this platform"; +} diff --git a/src/detection/gamepad/gamepad_windows.cpp b/src/detection/gamepad/gamepad_windows.cpp new file mode 100644 index 000000000..3d9345423 --- /dev/null +++ b/src/detection/gamepad/gamepad_windows.cpp @@ -0,0 +1,32 @@ +extern "C" { + #include "gamepad.h" +} + +#include +#define DIRECTINPUT_VERSION 0x0800 +#include + +CALLBACK BOOL DIEnumDevicesCallback(LPCDIDEVICEINSTANCEA lpddi, LPVOID pvRef) +{ + FFlist* devices = (FFlist*) pvRef; + + FFGamepadDevice* device = (FFGamepadDevice*) ffListAdd(devices); + ffStrbufInitF(&device->identifier, "{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}", + lpddi->guidInstance.Data1, lpddi->guidInstance.Data2, lpddi->guidInstance.Data3, + lpddi->guidInstance.Data4[0], lpddi->guidInstance.Data4[1], lpddi->guidInstance.Data4[2], lpddi->guidInstance.Data4[3], + lpddi->guidInstance.Data4[4], lpddi->guidInstance.Data4[5], lpddi->guidInstance.Data4[6], lpddi->guidInstance.Data4[7]); + ffStrbufInitS(&device->name, lpddi->tszInstanceName); + + return DIENUM_CONTINUE; +} + +extern "C" +const char* ffDetectGamepad(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* devices /* List of FFGamepadDevice */) +{ + IDirectInput8A* dinput; + if (!SUCCEEDED(DirectInput8Create(GetModuleHandleW(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8A, (void**)&dinput, NULL))) + return "DirectInput8Create() failed"; + dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, devices, DIEDFL_ATTACHEDONLY); + dinput->Release(); + return NULL; +} diff --git a/src/detection/gpu/gpu.c b/src/detection/gpu/gpu.c index 420b6a124..61951e32d 100644 --- a/src/detection/gpu/gpu.c +++ b/src/detection/gpu/gpu.c @@ -1,16 +1,42 @@ #include "gpu.h" #include "detection/internal.h" -#include "detection/vulkan.h" +#include "detection/vulkan/vulkan.h" -void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance); +const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance); + +const char* FF_GPU_VENDOR_NAME_APPLE = "Apple"; +const char* FF_GPU_VENDOR_NAME_AMD = "AMD"; +const char* FF_GPU_VENDOR_NAME_INTEL = "Intel"; +const char* FF_GPU_VENDOR_NAME_NVIDIA = "NVIDIA"; + +static inline bool arrayContains(const unsigned arr[], unsigned vendorId, unsigned length) +{ + for (unsigned i = 0; i < length; ++i) + { + if (arr[i] == vendorId) + return true; + } + return false; +} + +const char* ffGetGPUVendorString(unsigned vendorId) +{ + if(vendorId == 0x106b) + return FF_GPU_VENDOR_NAME_APPLE; + if(arrayContains((const unsigned[]) {0x1002, 0x1022}, vendorId, 2)) + return FF_GPU_VENDOR_NAME_AMD; + else if(arrayContains((const unsigned[]) {0x03e7, 0x8086, 0x8087}, vendorId, 3)) + return FF_GPU_VENDOR_NAME_INTEL; + else if(arrayContains((const unsigned[]) {0x0955, 0x10de, 0x12d2}, vendorId, 3)) + return FF_GPU_VENDOR_NAME_NVIDIA; + return NULL; +} const FFlist* ffDetectGPU(const FFinstance* instance) { FF_DETECTION_INTERNAL_GUARD(FFlist, ffListInit(&result, sizeof(FFGPUResult)); - ffDetectGPUImpl(&result, instance); - - if(result.length == 0) + if(ffDetectGPUImpl(&result, instance) != NULL) { const FFVulkanResult* vulkan = ffDetectVulkan(instance); result = vulkan->gpus; diff --git a/src/detection/gpu/gpu.h b/src/detection/gpu/gpu.h index e14feb9d8..13983a8a4 100644 --- a/src/detection/gpu/gpu.h +++ b/src/detection/gpu/gpu.h @@ -7,29 +7,41 @@ #define FF_GPU_TEMP_UNSET (0/0.0) #define FF_GPU_CORE_COUNT_UNSET -1 +#define FF_GPU_VMEM_SIZE_UNSET ((uint64_t)-1) -#define FF_GPU_VENDOR_NAME_APPLE "Apple" -#define FF_GPU_VENDOR_NAME_AMD "AMD" -#define FF_GPU_VENDOR_NAME_INTEL "Intel" -#define FF_GPU_VENDOR_NAME_NVIDIA "NVIDIA" +extern const char* FF_GPU_VENDOR_NAME_APPLE; +extern const char* FF_GPU_VENDOR_NAME_AMD; +extern const char* FF_GPU_VENDOR_NAME_INTEL; +extern const char* FF_GPU_VENDOR_NAME_NVIDIA; typedef enum FFGpuType { + FF_GPU_TYPE_UNKNOWN, FF_GPU_TYPE_INTEGRATED, FF_GPU_TYPE_DISCRETE, - FF_GPU_TYPE_UNKNOWN } FFGpuType; +typedef struct FFGPUMemory +{ + uint64_t total; + uint64_t used; +} FFGPUMemory; + typedef struct FFGPUResult { + uint64_t id; FFGpuType type; FFstrbuf vendor; FFstrbuf name; FFstrbuf driver; double temperature; int coreCount; + FFGPUMemory dedicated; + FFGPUMemory shared; } FFGPUResult; const FFlist* ffDetectGPU(const FFinstance* instance); +const char* ffGetGPUVendorString(unsigned vendorId); + #endif diff --git a/src/detection/gpu/gpu_apple.c b/src/detection/gpu/gpu_apple.c index 413e65746..fa514732e 100644 --- a/src/detection/gpu/gpu_apple.c +++ b/src/detection/gpu/gpu_apple.c @@ -60,32 +60,20 @@ const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) FFGPUResult* gpu = ffListAdd(gpus); + gpu->id = 0; + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; gpu->type = FF_GPU_TYPE_UNKNOWN; ffStrbufInit(&gpu->vendor); int vendorId; if(!ffCfDictGetInt(properties, CFSTR("vendor-id"), &vendorId)) { - if(vendorId == 0x106b) - { - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE); + const char* vendorStr = ffGetGPUVendorString((unsigned) vendorId); + ffStrbufAppendS(&gpu->vendor, vendorStr); + if (vendorStr == FF_GPU_VENDOR_NAME_APPLE || vendorStr == FF_GPU_VENDOR_NAME_INTEL) gpu->type = FF_GPU_TYPE_INTEGRATED; - } - else if(wmemchr((const wchar_t[]) {0x1002, 0x1022}, (wchar_t)vendorId, 2)) - { - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); - gpu->type = FF_GPU_TYPE_DISCRETE; // Apple never used AMD CPUs - } - else if(wmemchr((const wchar_t[]) {0x03e7, 0x8086, 0x8087}, (wchar_t)vendorId, 3)) - { - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); - gpu->type = FF_GPU_TYPE_INTEGRATED; - } - else if(wmemchr((const wchar_t[]) {0x0955, 0x10de, 0x12d2}, (wchar_t)vendorId, 3)) - { - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); + else if (vendorStr == FF_GPU_VENDOR_NAME_NVIDIA || vendorStr == FF_GPU_VENDOR_NAME_AMD) gpu->type = FF_GPU_TYPE_DISCRETE; - } } ffStrbufInit(&gpu->driver); diff --git a/src/detection/gpu/gpu_linux.c b/src/detection/gpu/gpu_linux.c index d34807df9..999856cdc 100644 --- a/src/detection/gpu/gpu_linux.c +++ b/src/detection/gpu/gpu_linux.c @@ -1,11 +1,12 @@ -#include "gpu.h" -#include "detection/vulkan.h" +#include "detection/gpu/gpu.h" +#include "detection/vulkan/vulkan.h" #ifdef FF_HAVE_LIBPCI #include "common/library.h" #include "common/properties.h" #include "common/parsing.h" #include "detection/temps/temps_linux.h" +#include "util/stringUtils.h" #include #include #include @@ -23,25 +24,9 @@ typedef struct PCIData #endif } PCIData; -static bool pciIDsContains(u16 searched, const u16* ids) -{ - while(*ids != 0) - { - if(*ids == searched) - return true; - ids++; - } - return false; -} - static void pciDetectVendorName(FFGPUResult* gpu, PCIData* pci, struct pci_dev* device) { - if(pciIDsContains(device->vendor_id, (const u16[]) {0x1002, 0x1022, 0})) - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); - else if(pciIDsContains(device->vendor_id, (const u16[]) {0x03e7, 0x8086, 0x8087, 0})) - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); - else if(pciIDsContains(device->vendor_id, (const u16[]) {0x0955, 0x10de, 0x12d2, 0})) - ffStrbufAppendS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); + ffStrbufAppendS(&gpu->vendor, ffGetGPUVendorString(device->vendor_id)); if(gpu->vendor.length > 0) return; @@ -214,6 +199,9 @@ static void pciHandleDevice(const FFinstance* instance, FFlist* results, PCIData FFGPUResult* gpu = ffListAdd(results); + gpu->id = 0; + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; + ffStrbufInit(&gpu->vendor); pciDetectVendorName(gpu, pci, device); @@ -263,17 +251,17 @@ static const char* pciDetectGPUs(const FFinstance* instance, FFlist* gpus) } ffpci_cleanup(pci.access); - dlclose(libpci); return NULL; } #endif -void ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) +const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) { #ifdef FF_HAVE_LIBPCI - pciDetectGPUs(instance, gpus); + return pciDetectGPUs(instance, gpus); #else FF_UNUSED(gpus, instance); + return "fastfetch is built without libpci support"; #endif } diff --git a/src/detection/gpu/gpu_windows.cpp b/src/detection/gpu/gpu_windows.cpp index 07b711205..0ff1ad43c 100644 --- a/src/detection/gpu/gpu_windows.cpp +++ b/src/detection/gpu/gpu_windows.cpp @@ -1,12 +1,89 @@ extern "C" { #include "gpu.h" #include "util/windows/unicode.h" +#include "util/windows/registry.h" } - -#ifdef FF_USE_WIN_GPU_DXGI +#include "util/windows/wmi.hpp" #include #include +#include + +static const char* detectWithRegistry(FFlist* gpus) +{ + // Ref: https://github.com/lptstr/winfetch/pull/155 + + FF_HKEY_AUTO_DESTROY hKey = NULL; + if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\DirectX", &hKey, nullptr)) + return "Open \"HKLM\\SOFTWARE\\Microsoft\\DirectX\" failed"; + + uint64_t lastSeen; + if(!ffRegReadUint64(hKey, L"LastSeen", &lastSeen, nullptr)) + return "Read \"HKLM\\SOFTWARE\\Microsoft\\DirectX\\LastSeen\" failed"; + + DWORD index = 0; + wchar_t subKeyName[64]; + while(true) + { + DWORD subKeySize = sizeof(subKeyName) / sizeof(*subKeyName); + if(RegEnumKeyExW(hKey, index++, subKeyName, &subKeySize, nullptr, nullptr, nullptr, nullptr) != ERROR_SUCCESS) + break; + + FF_HKEY_AUTO_DESTROY hSubKey = NULL; + if(!ffRegOpenKeyForRead(hKey, subKeyName, &hSubKey, nullptr)) + continue; + + uint64_t adapterLastSeen; + if(!ffRegReadUint64(hSubKey, L"LastSeen", &adapterLastSeen, nullptr) || lastSeen != adapterLastSeen) + continue; + + uint32_t softwareAdapter; + if(!ffRegReadUint(hSubKey, L"SoftwareAdapter", &softwareAdapter, nullptr) || softwareAdapter) + continue; + + FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); + ffStrbufInit(&gpu->vendor); + ffStrbufInit(&gpu->name); + ffStrbufInit(&gpu->driver); + gpu->temperature = FF_GPU_TEMP_UNSET; + gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; + gpu->type = FF_GPU_TYPE_UNKNOWN; + gpu->id = 0; + gpu->dedicated.total = gpu->dedicated.used = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; + + ffRegReadUint64(hSubKey, L"AdapterLuid", &gpu->id, nullptr); + + ffRegReadStrbuf(hSubKey, L"Description", &gpu->name, nullptr); + + uint32_t vendorId; + if(ffRegReadUint(hSubKey, L"VendorId", &vendorId, nullptr)) + ffStrbufAppendS(&gpu->vendor, ffGetGPUVendorString(vendorId)); + + uint64_t dedicatedVideoMemory = 0; + if(ffRegReadUint64(hSubKey, L"DedicatedVideoMemory", &dedicatedVideoMemory, nullptr)) + gpu->type = dedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED; + + uint64_t dedicatedSystemMemory, sharedSystemMemory; + if(ffRegReadUint64(hSubKey, L"DedicatedSystemMemory", &dedicatedSystemMemory, nullptr) && + ffRegReadUint64(hSubKey, L"SharedSystemMemory", &sharedSystemMemory, nullptr)) + { + gpu->dedicated.total = dedicatedVideoMemory + dedicatedSystemMemory; + gpu->shared.total = sharedSystemMemory; + } + + uint64_t driverVersion; + if(ffRegReadUint64(hSubKey, L"DriverVersion", &driverVersion, nullptr)) + { + ffStrbufSetF(&gpu->driver, "%" PRIu64 ".%" PRIu64 ".%" PRIu64 ".%" PRIu64, + (driverVersion >> 48) & 0xFFFF, + (driverVersion >> 32) & 0xFFFF, + (driverVersion >> 16) & 0xFFFF, + (driverVersion >> 0) & 0xFFFF); + } + } + + return nullptr; +} static const char* detectWithDxgi(FFlist* gpus) { @@ -25,15 +102,12 @@ static const char* detectWithDxgi(FFlist* gpus) continue; FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); + gpu->dedicated.total = gpu->dedicated.total = gpu->shared.total = gpu->shared.used = FF_GPU_VMEM_SIZE_UNSET; - if(wmemchr((const wchar_t[]) {0x1002, 0x1022}, (wchar_t)desc.VendorId, 2)) - ffStrbufInitS(&gpu->vendor, FF_GPU_VENDOR_NAME_AMD); - else if(wmemchr((const wchar_t[]) {0x03e7, 0x8086, 0x8087}, (wchar_t)desc.VendorId, 3)) - ffStrbufInitS(&gpu->vendor, FF_GPU_VENDOR_NAME_INTEL); - else if(wmemchr((const wchar_t[]) {0x0955, 0x10de, 0x12d2}, (wchar_t)desc.VendorId, 3)) - ffStrbufInitS(&gpu->vendor, FF_GPU_VENDOR_NAME_NVIDIA); - else - ffStrbufInit(&gpu->vendor); + ffStrbufInit(&gpu->vendor); + ffStrbufAppendS(&gpu->vendor, ffGetGPUVendorString(desc.VendorId)); + + gpu->id = (uint64_t&)desc.AdapterLuid; ffStrbufInit(&gpu->name); ffStrbufSetWS(&gpu->name, desc.Description); @@ -41,6 +115,8 @@ static const char* detectWithDxgi(FFlist* gpus) ffStrbufInit(&gpu->driver); gpu->type = desc.DedicatedVideoMemory >= 1024 * 1024 * 1024 ? FF_GPU_TYPE_DISCRETE : FF_GPU_TYPE_INTEGRATED; + gpu->dedicated.total = desc.DedicatedVideoMemory + desc.DedicatedSystemMemory; + gpu->shared.total = desc.SharedSystemMemory; adapter->Release(); @@ -50,56 +126,47 @@ static const char* detectWithDxgi(FFlist* gpus) pFactory->Release(); - return NULL; + return nullptr; } -#else - -#include "util/windows/wmi.hpp" - -static const char* detectWithWmi(FFlist* gpus) +static const char* detectMemoryUsage(FFlist* gpus) { - FFWmiQuery query(L"SELECT Name, AdapterCompatibility, DriverVersion FROM Win32_VideoController", nullptr); + FFWmiQuery query(L"SELECT Name, DedicatedUsage, SharedUsage FROM Win32_PerfRawData_GPUPerformanceCounters_GPUAdapterMemory", nullptr); if(!query) return "Query WMI service failed"; + FF_STRBUF_AUTO_DESTROY name; + ffStrbufInit(&name); + while(FFWmiRecord record = query.next()) { - FFGPUResult* gpu = (FFGPUResult*)ffListAdd(gpus); + record.getString(L"Name", &name); // luid_0x00000000_0x000146E8_phys_0 + assert(name.length == strlen("luid_0x00000000_0x000146E8_phys_0")); + ffStrbufSubstrBefore(&name, strlen("luid_0x00000000_0x000146E8")); // luid_0x00000000_0x000146E8 + ffStrbufSubstrAfter(&name, strlen("luid_0x00000000_0x") - 1); // 000146E8 + uint64_t luid = strtoull(name.chars, nullptr, 16); - gpu->type = FF_GPU_TYPE_UNKNOWN; - - ffStrbufInit(&gpu->vendor); - record.getString(L"AdapterCompatibility", &gpu->vendor); - if(ffStrbufStartsWithS(&gpu->vendor, "Intel ")) + FF_LIST_FOR_EACH(FFGPUResult, gpu, *gpus) { - //Intel returns "Intel Corporation", not sure about AMD - ffStrbufSetS(&gpu->vendor, "Intel"); + if (gpu->id != luid) continue; + record.getUnsigned(L"DedicatedUsage", &gpu->dedicated.used); + record.getUnsigned(L"SharedUsage", &gpu->shared.used); + break; } - - ffStrbufInit(&gpu->name); - record.getString(L"Name", &gpu->name); - - ffStrbufInit(&gpu->driver); - record.getString(L"DriverVersion", &gpu->driver); - - gpu->temperature = FF_GPU_TEMP_UNSET; - gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; } return nullptr; } -#endif - extern "C" -const char* ffDetectGPUImpl(FFlist* gpus, const FFinstance* instance) +const char* ffDetectGPUImpl(FFlist* gpus, FF_MAYBE_UNUSED const FFinstance* instance) { - FF_UNUSED(instance); + const char* error = detectWithRegistry(gpus); + if (error) + error = detectWithDxgi(gpus); - #ifdef FF_USE_WIN_GPU_DXGI - return detectWithDxgi(gpus); - #else - return detectWithWmi(gpus); - #endif + if (!error && gpus->length > 0 && instance->config.allowSlowOperations) + detectMemoryUsage(gpus); + + return error; } diff --git a/src/detection/gtk.c b/src/detection/gtk_qt/gtk.c similarity index 94% rename from src/detection/gtk.c rename to src/detection/gtk_qt/gtk.c index 1db344edd..e06a63542 100644 --- a/src/detection/gtk.c +++ b/src/detection/gtk_qt/gtk.c @@ -1,5 +1,5 @@ #include "fastfetch.h" -#include "detection/gtk.h" +#include "detection/gtk_qt/gtk_qt.h" #include "common/properties.h" #include "common/thread.h" #include "common/settings.h" @@ -56,7 +56,7 @@ static void detectGTKFromSettings(const FFinstance* instance, FFGTKResult* resul const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); - if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Xfce") == 0 || ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Xfce4") == 0) + if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_XFCE4) == 0) { themeName = ffSettingsGetXFConf(instance, "xsettings", "/Net/ThemeName", FF_VARIANT_TYPE_STRING).strValue; iconsName = ffSettingsGetXFConf(instance, "xsettings", "/Net/IconThemeName", FF_VARIANT_TYPE_STRING).strValue; @@ -64,7 +64,7 @@ static void detectGTKFromSettings(const FFinstance* instance, FFGTKResult* resul cursorTheme = ffSettingsGetXFConf(instance, "xsettings", "/Gtk/CursorThemeName", FF_VARIANT_TYPE_STRING).strValue; cursorSize = ffSettingsGetXFConf(instance, "xsettings", "/Gtk/CursorThemeSize", FF_VARIANT_TYPE_INT).intValue; } - else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Cinnamon") == 0) + else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_CINNAMON) == 0) { themeName = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/gtk-theme", "org.cinnamon.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; iconsName = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/icon-theme", "org.cinnamon.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; @@ -72,7 +72,7 @@ static void detectGTKFromSettings(const FFinstance* instance, FFGTKResult* resul cursorTheme = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/cursor-theme", "org.cinnamon.desktop.interface", NULL, "cursor-theme", FF_VARIANT_TYPE_STRING).strValue; cursorSize = ffSettingsGet(instance, "/org/cinnamon/desktop/interface/cursor-size", "org.cinnamon.desktop.interface", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; } - else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Mate") == 0) + else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_MATE) == 0) { themeName = ffSettingsGet(instance, "/org/mate/interface/gtk-theme", "org.mate.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; iconsName = ffSettingsGet(instance, "/org/mate/interface/icon-theme", "org.mate.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; @@ -81,9 +81,9 @@ static void detectGTKFromSettings(const FFinstance* instance, FFGTKResult* resul cursorSize = ffSettingsGet(instance, "/org/mate/peripherals-mouse/cursor-size", "org.mate.peripherals-mouse", NULL, "cursor-size", FF_VARIANT_TYPE_INT).intValue; } else if( - ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Gnome") == 0 || - ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Unity") == 0 || - ffStrbufIgnCaseCompS(&wmde->dePrettyName, "Budgie") == 0 + ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_GNOME) == 0 || + ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_UNITY) == 0 || + ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_BUDGIE) == 0 ) { themeName = ffSettingsGet(instance, "/org/gnome/desktop/interface/gtk-theme", "org.gnome.desktop.interface", NULL, "gtk-theme", FF_VARIANT_TYPE_STRING).strValue; iconsName = ffSettingsGet(instance, "/org/gnome/desktop/interface/icon-theme", "org.gnome.desktop.interface", NULL, "icon-theme", FF_VARIANT_TYPE_STRING).strValue; diff --git a/src/detection/gtk.h b/src/detection/gtk_qt/gtk_qt.h similarity index 57% rename from src/detection/gtk.h rename to src/detection/gtk_qt/gtk_qt.h index 683984351..fb3c44c4b 100644 --- a/src/detection/gtk.h +++ b/src/detection/gtk_qt/gtk_qt.h @@ -1,7 +1,7 @@ #pragma once -#ifndef FF_INCLUDED_detection_gtk -#define FF_INCLUDED_detection_gtk +#ifndef FF_INCLUDED_detection_gtkqt_gtkqt +#define FF_INCLUDED_detection_gtkqt_gtkqt #include "fastfetch.h" @@ -14,8 +14,17 @@ typedef struct FFGTKResult FFstrbuf cursorSize; } FFGTKResult; +typedef struct FFQtResult +{ + FFstrbuf widgetStyle; + FFstrbuf colorScheme; + FFstrbuf icons; + FFstrbuf font; +} FFQtResult; + const FFGTKResult* ffDetectGTK2(const FFinstance* instance); const FFGTKResult* ffDetectGTK4(const FFinstance* instance); const FFGTKResult* ffDetectGTK3(const FFinstance* instance); +const FFQtResult* ffDetectQt(const FFinstance* instance); #endif diff --git a/src/detection/qt.c b/src/detection/gtk_qt/qt.c similarity index 95% rename from src/detection/qt.c rename to src/detection/gtk_qt/qt.c index 5ac1d943e..74b54a1df 100644 --- a/src/detection/qt.c +++ b/src/detection/gtk_qt/qt.c @@ -1,7 +1,7 @@ #include "fastfetch.h" -#include "detection/qt.h" #include "common/properties.h" #include "common/thread.h" +#include "detection/gtk_qt/gtk_qt.h" #include "detection/displayserver/displayserver.h" #include @@ -152,9 +152,9 @@ const FFQtResult* ffDetectQt(const FFinstance* instance) const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); - if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "KDE Plasma") == 0) + if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_PLASMA) == 0) detectPlasma(instance, &result); - else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, "LXQt") == 0) + else if(ffStrbufIgnCaseCompS(&wmde->dePrettyName, FF_DE_PRETTY_LXQT) == 0) detectLXQt(instance, &result); ffThreadMutexUnlock(&mutex); diff --git a/src/detection/host/host_apple.c b/src/detection/host/host_apple.c index d768d83e4..4f739276b 100644 --- a/src/detection/host/host_apple.c +++ b/src/detection/host/host_apple.c @@ -8,7 +8,13 @@ static inline bool strEqual(const char* a, const char* b) static const char* getProductName(const FFstrbuf* hwModel) { - //https://github.com/hykilpikonna/hyfetch/blob/master/neofetch#L1386 + // Macbook Pro: https://support.apple.com/en-us/HT201300 + // Macbook Air: https://support.apple.com/en-us/HT201862 + // Mac mini: https://support.apple.com/en-us/HT201894 + // iMac: https://support.apple.com/en-us/HT201634 + // Mac Pro: https://support.apple.com/en-us/HT202888 + // Mac Studio: https://support.apple.com/en-us/HT213073 + if(ffStrbufStartsWithS(hwModel, "MacBookPro")) { const char* version = hwModel->chars + strlen("MacBookPro"); @@ -106,20 +112,26 @@ static const char* getProductName(const FFstrbuf* hwModel) else if(ffStrbufStartsWithS(hwModel, "Mac")) { const char* version = hwModel->chars + strlen("Mac"); + if(strEqual(version, "14,6") || + strEqual(version, "14,10")) return "MacBook Pro (16-inch, 2023)"; + if(strEqual(version, "14,5") || + strEqual(version, "14,9")) return "MacBook Pro (14-inch, 2023)"; + if(strEqual(version, "14,3")) return "Mac mini (M2, 2023, Two Thunderbolt 4 ports)"; + if(strEqual(version, "14,12")) return "Mac mini (M2, 2023, Four Thunderbolt 4 ports)"; if(strEqual(version, "14,7")) return "MacBook Pro (13-inch, M2, 2022)"; if(strEqual(version, "14,2")) return "MacBook Air (M2, 2022)"; - if(strEqual(version, "13,1")) return "Mac Studio (2022, Two USB-C front ports)"; - if(strEqual(version, "13,2")) return "Mac Studio (2022, Two Thunderbolt 4 front ports)"; + if(strEqual(version, "13,1")) return "Mac Studio (M1 Max, 2022, Two USB-C front ports)"; + if(strEqual(version, "13,2")) return "Mac Studio (M1 Ultra, 2022, Two Thunderbolt 4 front ports)"; } else if(ffStrbufStartsWithS(hwModel, "iMac")) { const char* version = hwModel->chars + strlen("iMac"); - if(strEqual(version, "21,1") || - strEqual(version, "21,2")) return "iMac (24-inch, M1, 2021)"; + if(strEqual(version, "21,1")) return "iMac (24-inch, M1, 2021, Two Thunderbolt / USB 4 ports, Two USB 3 ports)"; + if(strEqual(version, "21,2")) return "iMac (24-inch, M1, 2021, Two Thunderbolt / USB 4 ports)"; if(strEqual(version, "20,1") || strEqual(version, "20,2")) return "iMac (Retina 5K, 27-inch, 2020)"; - if(strEqual(version, "19,1") || - strEqual(version, "19,2")) return "iMac (Retina 4K, 21.5-inch, 2019)"; + if(strEqual(version, "19,1")) return "iMac (Retina 5K, 27-inch, 2019)"; + if(strEqual(version, "19,2")) return "iMac (Retina 4K, 21.5-inch, 2019)"; if(strEqual(version, "Pro1,1")) return "iMac Pro (2017)"; if(strEqual(version, "18,3")) return "iMac (Retina 5K, 27-inch, 2017)"; if(strEqual(version, "18,2")) return "iMac (Retina 4K, 21.5-inch, 2017)"; diff --git a/src/detection/host/host_linux.c b/src/detection/host/host_linux.c index e4e7dfef1..04ae3aa27 100644 --- a/src/detection/host/host_linux.c +++ b/src/detection/host/host_linux.c @@ -1,5 +1,5 @@ #include "host.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/processing.h" #include diff --git a/src/detection/locale/locale.c b/src/detection/locale/locale.c index 7b9e085cf..e2f27a214 100644 --- a/src/detection/locale/locale.c +++ b/src/detection/locale/locale.c @@ -5,7 +5,7 @@ #include #include -__attribute__((__unused__)) +FF_MAYBE_UNUSED static void getLocaleFromEnv(FFstrbuf* locale) { ffStrbufAppendS(locale, getenv("LANG")); diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index e23a32fe8..4125542b4 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -77,7 +77,7 @@ const char* ffDetectLocalIps(const FFinstance* instance, FFlist* results) SOCKADDR_IN6* ipv6 = (SOCKADDR_IN6*) ifa->Address.lpSockaddr; char addressBuffer[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, &ipv6->sin6_addr, addressBuffer, INET6_ADDRSTRLEN); - addNewIp(results, name, addressBuffer, false); + addNewIp(results, name, addressBuffer, true); } } } diff --git a/src/detection/media/media_linux.c b/src/detection/media/media_linux.c index f8d410593..d41ce1e4f 100644 --- a/src/detection/media/media_linux.c +++ b/src/detection/media/media_linux.c @@ -8,208 +8,75 @@ #define FF_DBUS_TIMEOUT_MILLISECONDS 35 #ifdef FF_HAVE_DBUS +#include "common/dbus.h" #include "common/library.h" #include "common/parsing.h" -#include -#define FF_DBUS_ITER_CONTINUE(iterator) \ - { \ - if(!data->ffdbus_message_iter_has_next(&iterator)) \ - break; \ - data->ffdbus_message_iter_next(&iterator); \ - continue; \ - } - -typedef struct DBusData +static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResult* result) { - FF_LIBRARY_SYMBOL(dbus_message_new_method_call) - FF_LIBRARY_SYMBOL(dbus_message_iter_init) - FF_LIBRARY_SYMBOL(dbus_message_iter_init_append) - FF_LIBRARY_SYMBOL(dbus_message_iter_append_basic) - FF_LIBRARY_SYMBOL(dbus_message_iter_get_arg_type) - FF_LIBRARY_SYMBOL(dbus_message_iter_get_basic) - FF_LIBRARY_SYMBOL(dbus_message_iter_recurse) - FF_LIBRARY_SYMBOL(dbus_message_iter_has_next) - FF_LIBRARY_SYMBOL(dbus_message_iter_next) - FF_LIBRARY_SYMBOL(dbus_message_unref) - FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply) - FF_LIBRARY_SYMBOL(dbus_connection_flush) - FF_LIBRARY_SYMBOL(dbus_pending_call_block) - FF_LIBRARY_SYMBOL(dbus_pending_call_steal_reply) - FF_LIBRARY_SYMBOL(dbus_pending_call_unref) - - DBusConnection *connection; -} DBusData; - -static bool getValue(DBusMessageIter* iter, FFstrbuf* result, DBusData* data) -{ - int argType = data->ffdbus_message_iter_get_arg_type(iter); - - if(argType == DBUS_TYPE_STRING) - { - const char* value = NULL; - data->ffdbus_message_iter_get_basic(iter, &value); - - if(!ffStrSet(value)) - return false; - - ffStrbufAppendS(result, value); - return true; - } - - if(argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) - return false; - - DBusMessageIter subIter; - data->ffdbus_message_iter_recurse(iter, &subIter); - - if(argType == DBUS_TYPE_VARIANT) - return getValue(&subIter, result, data); - - //At this point we have an array - - bool foundAValue = false; - - while(true) - { - if(getValue(&subIter, result, data)) - { - foundAValue = true; - ffStrbufAppendS(result, ", "); - } - - FF_DBUS_ITER_CONTINUE(subIter); - } - - if(foundAValue) - ffStrbufSubstrBefore(result, result->length - 2); - - return foundAValue; -} - -static DBusMessage* getReply(DBusMessage* request, DBusData* data) -{ - DBusPendingCall* pendingCall = NULL; - dbus_bool_t succesfull = data->ffdbus_connection_send_with_reply(data->connection, request, &pendingCall, FF_DBUS_TIMEOUT_MILLISECONDS); - data->ffdbus_message_unref(request); - if(!succesfull || pendingCall == NULL) - return NULL; - - data->ffdbus_connection_flush(data->connection); - data->ffdbus_pending_call_block(pendingCall); - - DBusMessage* reply = data->ffdbus_pending_call_steal_reply(pendingCall); - data->ffdbus_pending_call_unref(pendingCall); - return reply; -} - -static DBusMessage* getProperty(const char* busName, const char* objectPath, const char* interface, const char* property, DBusData* data) -{ - DBusMessage* message = data->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get"); - if(message == NULL) - return NULL; - - DBusMessageIter requestIterator; - data->ffdbus_message_iter_init_append(message, &requestIterator); - - if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &interface)) - { - data->ffdbus_message_unref(message); - return NULL; - } - - if(!data->ffdbus_message_iter_append_basic(&requestIterator, DBUS_TYPE_STRING, &property)) - { - data->ffdbus_message_unref(message); - return NULL; - } - - return getReply(message, data); -} - -static void getPropertyString(const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result, DBusData* data) -{ - DBusMessage* reply = getProperty(busName, objectPath, interface, property, data); - if(reply == NULL) - return; - - DBusMessageIter rootIterator; - if(!data->ffdbus_message_iter_init(reply, &rootIterator)) - { - data->ffdbus_message_unref(reply); - return; - } - - getValue(&rootIterator, result, data); - - data->ffdbus_message_unref(reply); -} - -static bool getBusProperties(const char* busName, FFMediaResult* result, DBusData* data) -{ - DBusMessage* reply = getProperty(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata", data); + DBusMessage* reply = ffDBusGetProperty(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Metadata"); if(reply == NULL) return false; DBusMessageIter rootIterator; - if(!data->ffdbus_message_iter_init(reply, &rootIterator)) + if(!data->lib->ffdbus_message_iter_init(reply, &rootIterator)) { - data->ffdbus_message_unref(reply); + data->lib->ffdbus_message_unref(reply); return false; } - if(data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT) + if(data->lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT) { - data->ffdbus_message_unref(reply); + data->lib->ffdbus_message_unref(reply); return false; } DBusMessageIter variantIterator; - data->ffdbus_message_iter_recurse(&rootIterator, &variantIterator); - if(data->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY) + data->lib->ffdbus_message_iter_recurse(&rootIterator, &variantIterator); + if(data->lib->ffdbus_message_iter_get_arg_type(&variantIterator) != DBUS_TYPE_ARRAY) { - data->ffdbus_message_unref(reply); + data->lib->ffdbus_message_unref(reply); return false; } DBusMessageIter arrayIterator; - data->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator); + data->lib->ffdbus_message_iter_recurse(&variantIterator, &arrayIterator); while(true) { - if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) - FF_DBUS_ITER_CONTINUE(arrayIterator) + if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_DICT_ENTRY) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) DBusMessageIter dictIterator; - data->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator); + data->lib->ffdbus_message_iter_recurse(&arrayIterator, &dictIterator); - if(data->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_STRING) - FF_DBUS_ITER_CONTINUE(arrayIterator) + if(data->lib->ffdbus_message_iter_get_arg_type(&dictIterator) != DBUS_TYPE_STRING) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) - if(!data->ffdbus_message_iter_has_next(&dictIterator)) - FF_DBUS_ITER_CONTINUE(arrayIterator) + if(!data->lib->ffdbus_message_iter_has_next(&dictIterator)) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) const char* key; - data->ffdbus_message_iter_get_basic(&dictIterator, &key); + data->lib->ffdbus_message_iter_get_basic(&dictIterator, &key); - data->ffdbus_message_iter_next(&dictIterator); + data->lib->ffdbus_message_iter_next(&dictIterator); if(strcmp(key, "xesam:title") == 0) - getValue(&dictIterator, &result->song, data); + ffDBusGetValue(data, &dictIterator, &result->song); else if(strcmp(key, "xesam:album") == 0) - getValue(&dictIterator, &result->album, data); + ffDBusGetValue(data, &dictIterator, &result->album); else if(strcmp(key, "xesam:artist") == 0) - getValue(&dictIterator, &result->artist, data); + ffDBusGetValue(data, &dictIterator, &result->artist); else if(strcmp(key, "xesam:url") == 0) - getValue(&dictIterator, &result->url, data); + ffDBusGetValue(data, &dictIterator, &result->url); if(result->song.length > 0 && result->artist.length > 0 && result->album.length > 0 && result->url.length > 0) break; - FF_DBUS_ITER_CONTINUE(arrayIterator) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) } - data->ffdbus_message_unref(reply); + data->lib->ffdbus_message_unref(reply); if(result->song.length == 0) { @@ -223,20 +90,20 @@ static bool getBusProperties(const char* busName, FFMediaResult* result, DBusDat ffStrbufAppendS(&result->busNameShort, busName + sizeof(FF_DBUS_MPRIS_PREFIX) - 1); //We found a song, get the player name - getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player, data); + ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "Identity", &result->player); if(result->player.length == 0) - getPropertyString(busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player, data); + ffDBusGetPropertyString(data, busName, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2", "DesktopEntry", &result->player); if(result->player.length == 0) ffStrbufAppend(&result->player, &result->busNameShort); return true; } -static void getCustomBus(const FFinstance* instance, FFMediaResult* result, DBusData* data) +static void getCustomBus(FFDBusData* data, const FFinstance* instance, FFMediaResult* result) { if(ffStrbufStartsWithS(&instance->config.playerName, FF_DBUS_MPRIS_PREFIX)) { - getBusProperties(instance->config.playerName.chars, result, data); + getBusProperties(data, instance->config.playerName.chars, result); return; } @@ -244,88 +111,61 @@ static void getCustomBus(const FFinstance* instance, FFMediaResult* result, DBus ffStrbufInit(&busName); ffStrbufAppendS(&busName, FF_DBUS_MPRIS_PREFIX); ffStrbufAppend(&busName, &instance->config.playerName); - getBusProperties(busName.chars, result, data); + getBusProperties(data, busName.chars, result); ffStrbufDestroy(&busName); } -static void getBestBus(FFMediaResult* result, DBusData* data) +static void getBestBus(FFDBusData* data, FFMediaResult* result) { if( - getBusProperties(FF_DBUS_MPRIS_PREFIX"spotify", result, data) || - getBusProperties(FF_DBUS_MPRIS_PREFIX"vlc", result, data) || - getBusProperties(FF_DBUS_MPRIS_PREFIX"plasma-browser-integration", result, data) + getBusProperties(data, FF_DBUS_MPRIS_PREFIX"spotify", result) || + getBusProperties(data, FF_DBUS_MPRIS_PREFIX"vlc", result) || + getBusProperties(data, FF_DBUS_MPRIS_PREFIX"plasma-browser-integration", result) ) return; - DBusMessage* message = data->ffdbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames"); - if(message == NULL) - return; - - DBusMessage* reply = getReply(message, data); + DBusMessage* reply = ffDBusGetMethodReply(data, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames"); if(reply == NULL) return; DBusMessageIter rootIterator; - if(!data->ffdbus_message_iter_init(reply, &rootIterator) || data->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY) + if(!data->lib->ffdbus_message_iter_init(reply, &rootIterator) || data->lib->ffdbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY) return; DBusMessageIter arrayIterator; - data->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator); + data->lib->ffdbus_message_iter_recurse(&rootIterator, &arrayIterator); while(true) { - if(data->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING) - FF_DBUS_ITER_CONTINUE(arrayIterator) + if(data->lib->ffdbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) const char* busName; - data->ffdbus_message_iter_get_basic(&arrayIterator, &busName); + data->lib->ffdbus_message_iter_get_basic(&arrayIterator, &busName); if(strncmp(busName, FF_DBUS_MPRIS_PREFIX, sizeof(FF_DBUS_MPRIS_PREFIX) - 1) != 0) - FF_DBUS_ITER_CONTINUE(arrayIterator) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) - if(getBusProperties(busName, result, data)) + if(getBusProperties(data, busName, result)) break; - FF_DBUS_ITER_CONTINUE(arrayIterator) + FF_DBUS_ITER_CONTINUE(data, &arrayIterator) } - data->ffdbus_message_unref(reply); + data->lib->ffdbus_message_unref(reply); } static const char* getMedia(const FFinstance* instance, FFMediaResult* result) { - DBusData data; - - FF_LIBRARY_LOAD(dbus, &instance->config.libDBus, "dlopen dbus failed", "libdbus-1" FF_LIBRARY_EXTENSION, 4); - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(dbus, dbus_bus_get) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_new_method_call) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_init) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_init_append) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_append_basic) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_get_arg_type) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_get_basic) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_recurse) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_has_next) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_iter_next) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_message_unref) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_connection_send_with_reply) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_connection_flush) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_pending_call_block) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_pending_call_steal_reply) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(dbus, data, dbus_pending_call_unref) - - data.connection = ffdbus_bus_get(DBUS_BUS_SESSION, NULL); - if(data.connection == NULL) - { - dlclose(dbus); - return "Failed to connect to session dbus"; - } + FFDBusData data; + const char* error = ffDBusLoadData(instance, DBUS_BUS_SESSION, &data); + if(error != NULL) + return error; if(instance->config.playerName.length > 0) - getCustomBus(instance, result, &data); + getCustomBus(&data, instance, result); else - getBestBus(result, &data); + getBestBus(&data, result); - dlclose(dbus); return NULL; } diff --git a/src/detection/memory/memory_apple.c b/src/detection/memory/memory_apple.c index f86f52cd4..37b7addb7 100644 --- a/src/detection/memory/memory_apple.c +++ b/src/detection/memory/memory_apple.c @@ -1,30 +1,31 @@ #include "memory.h" -#include "common/sysctl.h" #include #include +#include void ffDetectMemory(FFMemoryStorage* ram) { - ram->bytesTotal = (uint64_t) ffSysctlGetInt64("hw.memsize", 0); - if(ram->bytesTotal == 0) + size_t length = sizeof(ram->bytesTotal); + if (sysctl((int[]){ CTL_HW, HW_MEMSIZE }, 2, &ram->bytesTotal, &length, NULL, 0)) { ffStrbufAppendS(&ram->error, "Failed to read hw.memsize"); return; } - uint32_t pagesize = (uint32_t) ffSysctlGetInt("hw.pagesize", 0); - if(pagesize == 0) + uint32_t pagesize; + length = sizeof(pagesize); + if (sysctl((int[]){ CTL_HW, HW_PAGESIZE }, 2, &pagesize, &length, NULL, 0)) { ffStrbufAppendS(&ram->error, "Failed to read hw.pagesize"); return; } - mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - vm_statistics_data_t vmstat; - if(host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) (&vmstat), &count) != KERN_SUCCESS) + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + vm_statistics64_data_t vmstat; + if(host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) (&vmstat), &count) != KERN_SUCCESS) { - ffStrbufAppendS(&ram->error, "Failed to read vm statistics"); + ffStrbufAppendS(&ram->error, "Failed to read host_statistics64"); return; } diff --git a/src/detection/memory/memory_windows.c b/src/detection/memory/memory_windows.c index ef3153843..d639c2a73 100644 --- a/src/detection/memory/memory_windows.c +++ b/src/detection/memory/memory_windows.c @@ -5,7 +5,11 @@ void ffDetectMemory(FFMemoryStorage* ram) MEMORYSTATUSEX statex = { .dwLength = sizeof(statex), }; - GlobalMemoryStatusEx(&statex); + if (!GlobalMemoryStatusEx(&statex)) + { + ffStrbufAppendS(&ram->error, "GlobalMemoryStatusEx() failed"); + return; + } ram->bytesTotal = statex.ullTotalPhys; ram->bytesUsed = statex.ullTotalPhys - statex.ullAvailPhys; } diff --git a/src/detection/opengl/opengl_linux.c b/src/detection/opengl/opengl_linux.c index d95062ad5..a959578f8 100644 --- a/src/detection/opengl/opengl_linux.c +++ b/src/detection/opengl/opengl_linux.c @@ -133,9 +133,7 @@ static const char* eglPrint(FFinstance* instance, FFOpenGLResult* result) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglDestroySurface); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(egl, eglData, eglTerminate); - const char* error = eglHandleData(result, &eglData); - dlclose(egl); - return error; + return eglHandleData(result, &eglData); } #endif //FF_HAVE_EGL @@ -252,9 +250,7 @@ static const char* glxPrint(FFinstance* instance, FFOpenGLResult* result) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XCloseDisplay); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(glx, data, XFree); - const char* error = glxHandleData(result, &data); - dlclose(glx); - return error; + return glxHandleData(result, &data); } #endif //FF_HAVE_GLX @@ -310,9 +306,7 @@ static const char* osMesaPrint(FFinstance* instance, FFOpenGLResult* result) FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaMakeCurrent); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(osmesa, data, OSMesaDestroyContext); - const char* error = osMesaHandleData(result, &data); - dlclose(osmesa); - return error; + return osMesaHandleData(result, &data); } #endif //FF_HAVE_OSMESA diff --git a/src/detection/os/os_linux.c b/src/detection/os/os_linux.c index 45a0f5cec..063e8455b 100644 --- a/src/detection/os/os_linux.c +++ b/src/detection/os/os_linux.c @@ -1,6 +1,7 @@ #include "os.h" #include "common/properties.h" #include "common/parsing.h" +#include "util/stringUtils.h" #include #include diff --git a/src/detection/os/os_windows.cpp b/src/detection/os/os_windows.cpp index 7b4c6ea2f..aa25e90ae 100644 --- a/src/detection/os/os_windows.cpp +++ b/src/detection/os/os_windows.cpp @@ -31,7 +31,7 @@ static const char* getOsNameByWinbrand(FFstrbuf* osName) //https://dennisbabkin.com/blog/?t=how-to-tell-the-real-version-of-windows-your-app-is-running-on#ver_string if(HMODULE __attribute__((__cleanup__(wrapFreeLibrary))) hWinbrand = LoadLibraryW(L"winbrand.dll")) { - auto BrandingFormatString = (PWSTR(WINAPI*)(PCWSTR))GetProcAddress(hWinbrand, "BrandingFormatString"); + auto BrandingFormatString = (PWSTR(WINAPI*)(PCWSTR))(void*)GetProcAddress(hWinbrand, "BrandingFormatString"); if(!BrandingFormatString) return "GetProcAddress(BrandingFormatString) failed"; diff --git a/src/detection/packages/packages_apple.c b/src/detection/packages/packages_apple.c index b8bc8a682..eaaf5f2fa 100644 --- a/src/detection/packages/packages_apple.c +++ b/src/detection/packages/packages_apple.c @@ -1,5 +1,6 @@ #include "packages.h" #include "common/parsing.h" +#include "util/stringUtils.h" #include diff --git a/src/detection/packages/packages_linux.c b/src/detection/packages/packages_linux.c index ace7d637e..11162b138 100644 --- a/src/detection/packages/packages_linux.c +++ b/src/detection/packages/packages_linux.c @@ -1,5 +1,5 @@ #include "packages.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/parsing.h" #include "common/processing.h" #include "common/properties.h" @@ -88,7 +88,7 @@ static uint32_t countFilesRecursiveImpl(FFstrbuf* baseDirPath, const char* filen ffStrbufAppendC(baseDirPath, '/'); ffStrbufAppendS(baseDirPath, filename); - bool exists = ffFileExists(baseDirPath->chars, S_IFREG); + bool exists = ffPathExists(baseDirPath->chars, FF_PATHTYPE_FILE); ffStrbufSubstrBefore(baseDirPath, baseDirPathLength); if(exists) return 1; @@ -129,7 +129,7 @@ static uint32_t countFilesRecursive(FFstrbuf* baseDir, const char* dirname, cons static uint32_t getNixPackagesImpl(char* path) { //Nix detection is kinda slow, so we only do it if the dir exists - if(!ffFileExists(path, S_IFDIR)) + if(!ffPathExists(path, FF_PATHTYPE_DIRECTORY)) return 0; FFstrbuf output; @@ -229,23 +229,16 @@ static uint32_t getRpmFromLibrpm(const FFinstance* instance) ffrpmlogSetMask(RPMLOG_MASK(RPMLOG_EMERG)); if(ffrpmReadConfigFiles(NULL, NULL) != 0) - { - dlclose(rpm); return 0; - } rpmts ts = ffrpmtsCreate(); if(ts == NULL) - { - dlclose(rpm); return 0; - } rpmdbMatchIterator mi = ffrpmtsInitIterator(ts, RPMDBI_LABEL, NULL, 0); if(mi == NULL) { ffrpmtsFree(ts); - dlclose(rpm); return 0; } @@ -253,7 +246,6 @@ static uint32_t getRpmFromLibrpm(const FFinstance* instance) ffrpmdbFreeIterator(mi); ffrpmtsFree(ts); - dlclose(rpm); return count > 0 ? (uint32_t) count : 0; } diff --git a/src/detection/packages/packages_windows.c b/src/detection/packages/packages_windows.c index afd016c6d..086a10ea1 100644 --- a/src/detection/packages/packages_windows.c +++ b/src/detection/packages/packages_windows.c @@ -1,11 +1,13 @@ #include "packages.h" +#include "util/stringUtils.h" #include #include -static uint32_t getNumElements(const char* searchPath /* including `\*` suffix */, DWORD type) +static uint32_t getNumElements(const char* searchPath /* including `\*` suffix */, DWORD type, const char* ignore) { uint32_t counter = 0; + bool flag = ignore == NULL; WIN32_FIND_DATAA wfd; HANDLE hFind = FindFirstFileA(searchPath, &wfd); @@ -13,8 +15,13 @@ static uint32_t getNumElements(const char* searchPath /* including `\*` suffix * { do // Managed to locate and create an handle to that folder. { - if(wfd.dwFileAttributes & type) - counter++; + if(!(wfd.dwFileAttributes & type)) continue; + if(!flag && strcasecmp(ignore, wfd.cFileName) == 0) + { + flag = true; + continue; + } + counter++; } while (FindNextFileA(hFind, &wfd)); FindClose(hFind); @@ -27,12 +34,21 @@ static uint32_t getNumElements(const char* searchPath /* including `\*` suffix * static void detectScoop(const FFinstance* instance, FFPackagesResult* result) { - char scoopPath[MAX_PATH + 3]; - strcpy(scoopPath, instance->state.platform.homeDir.chars); - strncat(scoopPath, "/scoop/apps/*", sizeof(scoopPath) - 1 - strlen(scoopPath)); - result->scoop = getNumElements(scoopPath, FILE_ATTRIBUTE_DIRECTORY); - if(result->scoop > 0) - result->scoop--; // scoop + FF_STRBUF_AUTO_DESTROY scoopPath; + ffStrbufInitA(&scoopPath, MAX_PATH + 3); + + const char* scoopEnv = getenv("SCOOP"); + if(ffStrSet(scoopEnv)) + { + ffStrbufAppendS(&scoopPath, scoopEnv); + ffStrbufAppendS(&scoopPath, "/apps/*"); + } + else + { + ffStrbufAppendS(&scoopPath, instance->state.platform.homeDir.chars); + ffStrbufAppendS(&scoopPath, "/scoop/apps/*"); + } + result->scoop = getNumElements(scoopPath.chars, FILE_ATTRIBUTE_DIRECTORY, "scoop"); } static void detectChoco(FF_MAYBE_UNUSED const FFinstance* instance, FFPackagesResult* result) @@ -44,9 +60,7 @@ static void detectChoco(FF_MAYBE_UNUSED const FFinstance* instance, FFPackagesRe char chocoPath[MAX_PATH + 3]; strcpy(chocoPath, chocoInstall); strncat(chocoPath, "/lib/*", sizeof(chocoPath) - 1 - strlen(chocoPath)); - result->choco = getNumElements(chocoPath, FILE_ATTRIBUTE_DIRECTORY); - if(result->choco > 0) - result->choco--; // choco + result->choco = getNumElements(chocoPath, FILE_ATTRIBUTE_DIRECTORY, "choco"); } static void detectPacman(FF_MAYBE_UNUSED const FFinstance* instance, FFPackagesResult* result) @@ -59,7 +73,7 @@ static void detectPacman(FF_MAYBE_UNUSED const FFinstance* instance, FFPackagesR char pacmanPath[MAX_PATH + 3]; strcpy(pacmanPath, msystemPrefix); strncat(pacmanPath, "/../var/lib/pacman/local/*", sizeof(pacmanPath) - 1 - strlen(pacmanPath)); - result->pacman = getNumElements(pacmanPath, FILE_ATTRIBUTE_DIRECTORY); + result->pacman = getNumElements(pacmanPath, FILE_ATTRIBUTE_DIRECTORY, NULL); } void ffDetectPackagesImpl(const FFinstance* instance, FFPackagesResult* result) diff --git a/src/detection/qt.h b/src/detection/qt.h deleted file mode 100644 index a23b29db6..000000000 --- a/src/detection/qt.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#ifndef FF_INCLUDED_detection_qt -#define FF_INCLUDED_detection_qt - -#include "fastfetch.h" - -typedef struct FFQtResult -{ - FFstrbuf widgetStyle; - FFstrbuf colorScheme; - FFstrbuf icons; - FFstrbuf font; -} FFQtResult; - -const FFQtResult* ffDetectQt(const FFinstance* instance); - -#endif diff --git a/src/detection/sound/sound.h b/src/detection/sound/sound.h new file mode 100644 index 000000000..9a89ab694 --- /dev/null +++ b/src/detection/sound/sound.h @@ -0,0 +1,19 @@ +#pragma once + +#ifndef FF_INCLUDED_detection_sound_sound +#define FF_INCLUDED_detection_sound_sound + +#include "fastfetch.h" + +typedef struct FFSoundDevice +{ + FFstrbuf identifier; + FFstrbuf name; + uint8_t volume; // 0-100% + bool main; + bool active; +} FFSoundDevice; + +const char* ffDetectSound(const FFinstance* instance, FFlist* devices /* List of FFSoundDevice */); + +#endif diff --git a/src/detection/sound/sound_apple.c b/src/detection/sound/sound_apple.c new file mode 100644 index 000000000..a9ec04703 --- /dev/null +++ b/src/detection/sound/sound_apple.c @@ -0,0 +1,81 @@ +#include "sound.h" +#include "util/apple/cf_helpers.h" + +#include + +const char* ffDetectSound(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* devices /* List of FFSoundDevice */) +{ + AudioDeviceID mainDeviceId; + UInt32 dataSize = sizeof(mainDeviceId); + if(AudioObjectGetPropertyData(kAudioObjectSystemObject, &(AudioObjectPropertyAddress){ + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain + }, 0, NULL, &dataSize, &mainDeviceId) != kAudioHardwareNoError) + return "AudioObjectGetPropertyData(kAudioHardwarePropertyDefaultOutputDevice) failed"; + + AudioObjectID deviceIds[32] = {}; + dataSize = sizeof(deviceIds); + if(AudioObjectGetPropertyData(kAudioObjectSystemObject, &(AudioObjectPropertyAddress){ + kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain + }, 0, NULL, &dataSize, &deviceIds) != kAudioHardwareNoError) + return "AudioObjectGetPropertyData(kAudioHardwarePropertyDevices) failed"; + + for(uint32_t index = 0, length = dataSize / sizeof(*deviceIds); index < length; ++index) + { + AudioDeviceID deviceId = deviceIds[index]; + + uint32_t muted; + dataSize = sizeof(muted); + if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){ + kAudioDevicePropertyMute, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain + }, 0, NULL, &dataSize, &muted) != kAudioHardwareNoError) + continue; + + FFSoundDevice* device = (FFSoundDevice*) ffListAdd(devices); + device->main = deviceId == mainDeviceId; + device->active = false; + device->volume = 0; + ffStrbufInitF(&device->identifier, "%u", (unsigned) deviceId); + ffStrbufInit(&device->name); + + uint32_t active; + dataSize = sizeof(active); + if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){ + kAudioDevicePropertyDeviceIsAlive, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain + }, 0, NULL, &dataSize, &active) == kAudioHardwareNoError) + device->active = !!active; + + if (!muted) + { + float volume; + dataSize = sizeof(volume); + if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){ + kAudioDevicePropertyVolumeScalar, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain + }, 0, NULL, &dataSize, &volume) == kAudioHardwareNoError) + device->volume = (uint8_t) (volume * 100 + 0.5); + } + + CFStringRef name; + dataSize = sizeof(name); + if(AudioObjectGetPropertyData(deviceId, &(AudioObjectPropertyAddress){ + kAudioObjectPropertyName, + kAudioObjectPropertyScopeOutput, + kAudioObjectPropertyElementMain + }, 0, NULL, &dataSize, &name) == kAudioHardwareNoError) + { + ffCfStrGetString(name, &device->name); + CFRelease(name); + } + } + + return NULL; +} diff --git a/src/detection/sound/sound_linux.c b/src/detection/sound/sound_linux.c new file mode 100644 index 000000000..bb0b9d409 --- /dev/null +++ b/src/detection/sound/sound_linux.c @@ -0,0 +1,130 @@ +#include "sound.h" + +#ifdef FF_HAVE_PULSE +#include +#include + +static void paSinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata) +{ + FF_UNUSED(c); + + if(eol > 0 || !i) + return; + + FFSoundDevice* device = ffListAdd(userdata); + ffStrbufInitS(&device->identifier, i->name); + ffStrbufInitS(&device->name, i->description); + device->volume = i->mute ? 0 : (uint8_t) (i->volume.values[0] * 100 / PA_VOLUME_NORM); + device->active = i->active_port && i->active_port->available != PA_PORT_AVAILABLE_NO; + device->main = false; +} + +static void paServerInfoCallback(pa_context *c, const pa_server_info *i, void *userdata) +{ + FF_UNUSED(c); + + if(!i) + return; + + FF_LIST_FOR_EACH(FFSoundDevice, device, *(FFlist*)userdata) + { + if(ffStrbufEqualS(&device->identifier, i->default_sink_name)) + { + device->main = true; + break; + } + } +} + +static const char* detectSound(const FFinstance* instance, FFlist* devices) +{ + FF_LIBRARY_LOAD(pulse, &instance->config.libPulse, "Failed to load libpulse" FF_LIBRARY_EXTENSION, "libpulse" FF_LIBRARY_EXTENSION, 0) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_mainloop_new) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_mainloop_get_api) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_mainloop_iterate) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_mainloop_free) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_new) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_connect) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_get_state) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_get_sink_info_list) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_get_server_info) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_context_unref) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_operation_get_state) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE(pulse, pa_operation_unref) + + pa_mainloop* mainloop = ffpa_mainloop_new(); + if(!mainloop) + return "Failed to create pulseaudio mainloop"; + + pa_mainloop_api* mainloopApi = ffpa_mainloop_get_api(mainloop); + if(!mainloopApi) + { + ffpa_mainloop_free(mainloop); + return "Failed to get pulseaudio mainloop api"; + } + + pa_context* context = ffpa_context_new(mainloopApi, "fastfetch"); + if(!context) + { + ffpa_mainloop_free(mainloop); + return "Failed to create pulseaudio context"; + } + + if(ffpa_context_connect(context, NULL, PA_CONTEXT_NOFLAGS, NULL) < 0) + { + ffpa_context_unref(context); + ffpa_mainloop_free(mainloop); + return "Failed to connect to pulseaudio context"; + } + + int state; + while((state = ffpa_context_get_state(context)) != PA_CONTEXT_READY) + { + if(!PA_CONTEXT_IS_GOOD(state)) + { + ffpa_context_unref(context); + ffpa_mainloop_free(mainloop); + return "Failed to get pulseaudio context state"; + } + + ffpa_mainloop_iterate(mainloop, 1, NULL); + } + + pa_operation* operation = ffpa_context_get_sink_info_list(context, paSinkInfoCallback, devices); + if(!operation) + { + ffpa_context_unref(context); + ffpa_mainloop_free(mainloop); + return "Failed to get pulseaudio sink info list"; + } + + while(ffpa_operation_get_state(operation) == PA_OPERATION_RUNNING) + ffpa_mainloop_iterate(mainloop, 1, NULL); + + ffpa_operation_unref(operation); + + operation = ffpa_context_get_server_info(context, paServerInfoCallback, devices); + if(operation) + { + while(ffpa_operation_get_state(operation) == PA_OPERATION_RUNNING) + ffpa_mainloop_iterate(mainloop, 1, NULL); + + ffpa_operation_unref(operation); + } + + ffpa_context_unref(context); + ffpa_mainloop_free(mainloop); + return NULL; +} + +#endif // FF_HAVE_PULSE + +const char* ffDetectSound(const FFinstance* instance, FFlist* devices) +{ + #ifdef FF_HAVE_PULSE + return detectSound(instance, devices); + #else + FF_UNUSED(instance, devices); + return "Fastfetch was built without libpulse support"; + #endif +} diff --git a/src/detection/sound/sound_nosupport.c b/src/detection/sound/sound_nosupport.c new file mode 100644 index 000000000..8f8014341 --- /dev/null +++ b/src/detection/sound/sound_nosupport.c @@ -0,0 +1,6 @@ +#include "sound.h" + +const char* ffDetectSound(FF_MAYBE_UNUSED const FFinstance* instance, FF_MAYBE_UNUSED FFlist* devices /* List of FFSoundDevice */) +{ + return "Not supported on this platform"; +} diff --git a/src/detection/sound/sound_windows.cpp b/src/detection/sound/sound_windows.cpp new file mode 100644 index 000000000..5221c8368 --- /dev/null +++ b/src/detection/sound/sound_windows.cpp @@ -0,0 +1,92 @@ +extern "C" { + #include "sound.h" + #include "util/windows/unicode.h" +} +#include "util/windows/com.hpp" + +#include +#include +#include +#include + +const char* ffDetectSound(FF_MAYBE_UNUSED const FFinstance* instance, FF_MAYBE_UNUSED FFlist* devices /* List of FFSoundDevice */) +{ + const char* error = ffInitCom(); + if (error) + return error; + + IMMDeviceEnumerator* FF_AUTO_RELEASE_COM_OBJECT pEnum = NULL; + + if (FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void **)&pEnum))) + return "CoCreateInstance(__uuidof(MMDeviceEnumerator)) failed"; + + LPWSTR mainDeviceId = NULL; + + { + IMMDevice* FF_AUTO_RELEASE_COM_OBJECT pDefaultDevice = NULL; + + if (FAILED(pEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &pDefaultDevice))) + return "GetDefaultAudioEndpoint() failed"; + + if (FAILED(pDefaultDevice->GetId(&mainDeviceId))) + return "pDefaultDevice->GetId() failed"; + } + + IMMDeviceCollection* FF_AUTO_RELEASE_COM_OBJECT pDevices = NULL; + + if (FAILED(pEnum->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &pDevices))) + return "EnumAudioEndpoints() failed"; + + uint32_t deviceCount; + if (FAILED(pDevices->GetCount(&deviceCount))) + return "pDevices->GetCount() failed"; + + for (uint32_t deviceIdx = 0; deviceIdx < deviceCount; ++deviceIdx) + { + IMMDevice* FF_AUTO_RELEASE_COM_OBJECT immDevice = NULL; + if (FAILED(pDevices->Item(deviceIdx, &immDevice))) + continue; + + LPWSTR immDeviceId = NULL; + if (FAILED(immDevice->GetId(&immDeviceId))) + continue; + + IPropertyStore* FF_AUTO_RELEASE_COM_OBJECT immPropStore; + if (FAILED(immDevice->OpenPropertyStore(STGM_READ, &immPropStore))) + continue; + + DWORD immState; + if (FAILED(immDevice->GetState(&immState))) + continue; + + FFSoundDevice* device = (FFSoundDevice*) ffListAdd(devices); + device->main = wcscmp(mainDeviceId, immDeviceId) == 0; + device->active = !!(immState & DEVICE_STATE_ACTIVE); + device->volume = 0; + ffStrbufInit(&device->identifier); + ffStrbufInit(&device->name); + + ffStrbufSetWS(&device->identifier, immDeviceId); + + { + PROPVARIANT __attribute__((__cleanup__(PropVariantClear))) friendlyName; + PropVariantInit(&friendlyName); + if (SUCCEEDED(immPropStore->GetValue(PKEY_Device_FriendlyName, &friendlyName))) + ffStrbufSetWS(&device->name, friendlyName.pwszVal); + } + + IAudioEndpointVolume* FF_AUTO_RELEASE_COM_OBJECT immEndpointVolume; + if(SUCCEEDED(immDevice->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**) &immEndpointVolume))) + { + BOOL muted; + if (FAILED(immEndpointVolume->GetMute(&muted)) || !muted) + { + FLOAT volume; + if (SUCCEEDED(immEndpointVolume->GetMasterVolumeLevelScalar(&volume))) + device->volume = (uint8_t) (volume * 100 + 0.5); + } + } + } + + return NULL; +} diff --git a/src/detection/swap/swap_apple.c b/src/detection/swap/swap_apple.c index 34e72802a..15200da15 100644 --- a/src/detection/swap/swap_apple.c +++ b/src/detection/swap/swap_apple.c @@ -1,13 +1,13 @@ #include "swap.h" -#include "common/sysctl.h" #include +#include void ffDetectSwap(FFMemoryStorage* swap) { struct xsw_usage xsw; size_t size = sizeof(xsw); - if(sysctlbyname("vm.swapusage", &xsw, &size, 0, 0) != 0) + if(sysctl((int[]){ CTL_VM, VM_SWAPUSAGE }, 2, &xsw, &size, NULL, 0) != 0) { ffStrbufAppendS(&swap->error, "Failed to read vm.swapusage"); return; diff --git a/src/detection/swap/swap_windows.cpp b/src/detection/swap/swap_windows.cpp index 224a3ce35..d7f910f95 100644 --- a/src/detection/swap/swap_windows.cpp +++ b/src/detection/swap/swap_windows.cpp @@ -23,7 +23,7 @@ void ffDetectSwap(FFMemoryStorage* swap) { if(!(pstart = (SYSTEM_PAGEFILE_INFORMATION*)realloc(pstart, size))) { - ffStrbufAppendF(&swap->error, "relloc(pstart, %lu) failed", size); + ffStrbufAppendF(&swap->error, "realloc(pstart, %lu) failed", size); return; } } diff --git a/src/detection/temps/temps_apple.c b/src/detection/temps/temps_apple.c index 9daee1c91..041e1418e 100644 --- a/src/detection/temps/temps_apple.c +++ b/src/detection/temps/temps_apple.c @@ -397,6 +397,10 @@ const char *ffDetectCoreTemps(enum FFTempType type, FFlist *result) case FF_TEMP_BATTERY: detectTemp(conn, "TB1T", "Battery", result); break; + + case FF_TEMP_MEMORY: + detectTemp(conn, "Tm02", "Memory", result); + break; } return NULL; diff --git a/src/detection/temps/temps_apple.h b/src/detection/temps/temps_apple.h index 8ac83e22d..147c32d07 100644 --- a/src/detection/temps/temps_apple.h +++ b/src/detection/temps/temps_apple.h @@ -26,6 +26,8 @@ enum FFTempType FF_TEMP_GPU_M2X, FF_TEMP_BATTERY, + + FF_TEMP_MEMORY, }; const char *ffDetectCoreTemps(enum FFTempType type, FFlist *result); diff --git a/src/detection/temps/temps_linux.c b/src/detection/temps/temps_linux.c index 913e6f037..0ade8180f 100644 --- a/src/detection/temps/temps_linux.c +++ b/src/detection/temps/temps_linux.c @@ -1,5 +1,5 @@ #include "fastfetch.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/thread.h" #include "temps_linux.h" diff --git a/src/detection/terminalfont/terminalfont.c b/src/detection/terminalfont/terminalfont.c index 41ff5428b..db967b245 100644 --- a/src/detection/terminalfont/terminalfont.c +++ b/src/detection/terminalfont/terminalfont.c @@ -115,15 +115,15 @@ static const char* detectFromWTImpl(const FFinstance* instance, FFstrbuf* conten CJSONData cjsonData; FF_LIBRARY_LOAD(libcjson, &instance->config.libcJSON, "dlopen libcjson"FF_LIBRARY_EXTENSION" failed", "libcjson"FF_LIBRARY_EXTENSION, 1) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_Parse) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsObject) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_GetObjectItemCaseSensitive) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsString) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_GetStringValue) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsNumber) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_GetNumberValue) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_IsArray) - FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libcjson, cjsonData, cJSON_Delete) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_Parse, cJSON_Parse@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_IsObject, cJSON_IsObject@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_GetObjectItemCaseSensitive, cJSON_GetObjectItemCaseSensitive@8) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_IsString, cJSON_IsString@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_GetStringValue, cJSON_GetStringValue@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_IsNumber, cJSON_IsNumber@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_GetNumberValue, cJSON_GetNumberValue@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_IsArray, cJSON_IsArray@4) + FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE2(libcjson, cjsonData, cJSON_Delete, cJSON_Delete@4) const char* error = NULL; @@ -177,12 +177,11 @@ static const char* detectFromWTImpl(const FFinstance* instance, FFstrbuf* conten exit: cjsonData.ffcJSON_Delete(root); - dlclose(libcjson); return error; } #ifdef _WIN32 - #include "common/io.h" + #include "common/io/io.h" #include #endif @@ -285,7 +284,7 @@ static void detectFromWindowsTeriminal(const FFinstance* instance, const FFstrbu static void detectFromWindowsTeriminal(const FFinstance* instance, const FFstrbuf* terminalExe, FFTerminalFontResult* terminalFont) { FF_UNUSED(instance, terminalExe, terminalFont); - ffStrbufAppendS(&terminalFont->error, "fastfetch is built without libcjson support"); + ffStrbufAppendS(&terminalFont->error, "Fastfetch was built without libcjson support"); } #endif @@ -320,6 +319,37 @@ FF_MAYBE_UNUSED static bool detectKitty(const FFinstance* instance, FFTerminalFo return true; } +static void detectTerminator(const FFinstance* instance, FFTerminalFontResult* result) +{ + FF_STRBUF_AUTO_DESTROY useSystemFont; + ffStrbufInit(&useSystemFont); + + FF_STRBUF_AUTO_DESTROY fontName; + ffStrbufInit(&fontName); + + FFpropquery fontQuery[] = { + {"use_system_font =", &useSystemFont}, + {"font =", &fontName}, + }; + + if(!ffParsePropFileConfigValues(instance, "terminator/config", 2, fontQuery)) + { + ffStrbufAppendS(&result->error, "Couldn't read Terminator config file"); + return; + } + + if(ffStrbufIgnCaseEqualS(&useSystemFont, "True")) + { + ffFontInitCopy(&result->font, "System"); + return; + } + + if(fontName.length == 0) + ffFontInitValues(&result->font, "mono", "8"); + else + ffFontInitPango(&result->font, fontName.chars); +} + static bool detectWezterm(FF_MAYBE_UNUSED const FFinstance* instance, FFTerminalFontResult* result) { FF_STRBUF_AUTO_DESTROY fontName; @@ -354,6 +384,8 @@ static bool detectTerminalFontCommon(const FFinstance* instance, const FFTermina { if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "alacritty")) detectAlacritty(instance, terminalFont); + else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "terminator")) + detectTerminator(instance, terminalFont); else if(ffStrbufStartsWithIgnCaseS(&terminalShell->terminalProcessName, "wezterm-gui")) detectWezterm(instance, terminalFont); @@ -385,7 +417,7 @@ const FFTerminalFontResult* ffDetectTerminalFont(const FFinstance* instance) const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(instance); if(terminalShell->terminalProcessName.length == 0) - ffStrbufAppendS(&result.error, "Terminal font needs successfull terminal detection"); + ffStrbufAppendS(&result.error, "Terminal font needs successful terminal detection"); else if(!detectTerminalFontCommon(instance, terminalShell, &result)) ffDetectTerminalFontPlatform(instance, terminalShell, &result); diff --git a/src/detection/terminalfont/terminalfont_android.c b/src/detection/terminalfont/terminalfont_android.c index eaa4fa52d..251ada6c7 100644 --- a/src/detection/terminalfont/terminalfont_android.c +++ b/src/detection/terminalfont/terminalfont_android.c @@ -1,7 +1,7 @@ #include "fastfetch.h" #include "terminalfont.h" #include "detection/terminalshell/terminalshell.h" -#include "common/io.h" +#include "common/io/io.h" #ifdef FF_HAVE_FREETYPE #include "common/library.h" @@ -42,14 +42,13 @@ const char* detectTermux(const FFinstance* instance, FFTerminalFontResult* termi exit: if(face) ffFT_Done_Face(face); if(library) ffFT_Done_FreeType(library); - dlclose(freetype); return error; #else FF_UNUSED(terminalFont); - return "fastfetch is built without freetype2 support"; + return "Fastfetch was built without freetype2 support"; #endif } @@ -62,7 +61,7 @@ void ffDetectTerminalFontPlatform(const FFinstance* instance, const FFTerminalSh return; } - if(!ffFileExists(FF_TERMUX_FONT_PATH, S_IFREG)) + if(!ffPathExists(FF_TERMUX_FONT_PATH, FF_PATHTYPE_FILE)) { ffFontInitCopy(&terminalFont->font, "monospace"); return; diff --git a/src/detection/terminalfont/terminalfont_linux.c b/src/detection/terminalfont/terminalfont_linux.c index 1d06d09c1..b83724160 100644 --- a/src/detection/terminalfont/terminalfont_linux.c +++ b/src/detection/terminalfont/terminalfont_linux.c @@ -4,6 +4,7 @@ #include "common/parsing.h" #include "detection/terminalshell/terminalshell.h" #include "detection/displayserver/displayserver.h" +#include "util/stringUtils.h" static const char* getSystemMonospaceFont(const FFinstance* instance) { diff --git a/src/detection/terminalfont/terminalfont_windows.c b/src/detection/terminalfont/terminalfont_windows.c index 060108290..e84d73d9e 100644 --- a/src/detection/terminalfont/terminalfont_windows.c +++ b/src/detection/terminalfont/terminalfont_windows.c @@ -1,5 +1,5 @@ #include "common/properties.h" -#include "common/io.h" +#include "common/io/io.h" #include "detection/terminalshell/terminalshell.h" #include "terminalfont.h" #include "util/windows/unicode.h" diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index aa9d221f3..435885329 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -1,5 +1,5 @@ #include "fastfetch.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/processing.h" #include "common/properties.h" diff --git a/src/detection/terminalshell/terminalshell.h b/src/detection/terminalshell/terminalshell.h index a2a1f4200..f506381bb 100644 --- a/src/detection/terminalshell/terminalshell.h +++ b/src/detection/terminalshell/terminalshell.h @@ -12,12 +12,14 @@ typedef struct FFTerminalShellResult const char* shellExeName; //pointer to a char in shellExe FFstrbuf shellPrettyName; FFstrbuf shellVersion; + uint32_t shellPid; FFstrbuf terminalProcessName; FFstrbuf terminalExe; FFstrbuf terminalPrettyName; const char* terminalExeName; //pointer to a char in terminalExe FFstrbuf terminalVersion; + uint32_t terminalPid; FFstrbuf userShellExe; const char* userShellExeName; //pointer to a char in userShellExe diff --git a/src/detection/terminalshell/terminalshell_linux.c b/src/detection/terminalshell/terminalshell_linux.c index 1f30866c2..8db9f2901 100644 --- a/src/detection/terminalshell/terminalshell_linux.c +++ b/src/detection/terminalshell/terminalshell_linux.c @@ -1,9 +1,9 @@ -#include "fastfetch.h" -#include "common/io.h" +#include "terminalshell.h" +#include "common/io/io.h" #include "common/parsing.h" #include "common/processing.h" #include "common/thread.h" -#include "terminalshell.h" +#include "util/stringUtils.h" #include #include @@ -53,7 +53,7 @@ static void getProcessInformation(pid_t pid, FFstrbuf* processName, FFstrbuf* ex size_t size = exe->allocated; if(!sysctl( (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4, - exe->chars, &size, + exe->chars, &size, NULL, 0 )) exe->length = (uint32_t)size; @@ -162,6 +162,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) ) { if (result->shellProcessName.length == 0) { + result->shellPid = (uint32_t) pid; ffStrbufSetS(&result->shellProcessName, name); getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName); } @@ -170,6 +171,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid) return; } + result->terminalPid = (uint32_t) pid; ffStrbufSetS(&result->terminalProcessName, name); getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName); } @@ -336,10 +338,12 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) ffStrbufInitA(&result.shellExe, exePathLen); result.shellExeName = result.shellExe.chars; ffStrbufInit(&result.shellVersion); + result.shellPid = 0; ffStrbufInit(&result.terminalProcessName); ffStrbufInitA(&result.terminalExe, exePathLen); result.terminalExeName = result.terminalExe.chars; + result.terminalPid = 0; ffStrbufInit(&result.userShellExe); result.userShellExeName = result.userShellExe.chars; diff --git a/src/detection/terminalshell/terminalshell_windows.cpp b/src/detection/terminalshell/terminalshell_windows.cpp index b800228fa..58dc2c588 100644 --- a/src/detection/terminalshell/terminalshell_windows.cpp +++ b/src/detection/terminalshell/terminalshell_windows.cpp @@ -2,6 +2,7 @@ extern "C" { #include "terminalshell.h" #include "common/processing.h" #include "common/thread.h" +#include "util/mallocHelper.h" } #include @@ -10,6 +11,7 @@ extern "C" { #ifdef FF_USE_WIN_NTAPI +#include #include static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName) @@ -54,6 +56,45 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb return true; } +static bool getTerminalInfoByEnumeratingChildProcesses(FFTerminalShellResult* result, uint32_t ppid) +{ + ULONG size = 0; + if(NtQuerySystemInformation(SystemProcessInformation, nullptr, 0, &size) != STATUS_INFO_LENGTH_MISMATCH) + return false; + + size += sizeof(SystemProcessInformation) * 5; //What if new processes are created during two syscalls? + + SYSTEM_PROCESS_INFORMATION* FF_AUTO_FREE pstart = (SYSTEM_PROCESS_INFORMATION*)malloc(size); + if(!pstart) + return false; + + if(!NT_SUCCESS(NtQuerySystemInformation(SystemProcessInformation, pstart, size, nullptr))) + return false; + + uint32_t currentProcessId = (uint32_t) GetCurrentProcessId(); + + for (auto ptr = pstart; ptr->NextEntryOffset; ptr = (SYSTEM_PROCESS_INFORMATION*)((uint8_t*)ptr + ptr->NextEntryOffset)) + { + if ((uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId != ppid) + continue; + + uint32_t pid = (uint32_t)(uintptr_t) ptr->UniqueProcessId; + if (pid == currentProcessId) + continue; + + if(!getProcessInfo(pid, nullptr, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName)) + return false; + + result->terminalPid = pid; + ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); + if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) + ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4); + + return true; + } + return false; +} + #else #include "util/windows/wmi.hpp" @@ -95,6 +136,33 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb return true; } +static bool getTerminalInfoByEnumeratingChildProcesses(FFTerminalShellResult* result, uint32_t ppid) +{ + wchar_t sql[256] = {}; + swprintf(sql, 256, L"SELECT Name, ExecutablePath, ProcessId FROM Win32_Process WHERE ProcessId <> %" PRIu32 " AND ParentProcessId = %" PRIu32, + (uint32_t) GetCurrentProcessId(), + ppid); + + FFWmiQuery query(sql); + if(!query) + return false; + + if(FFWmiRecord record = query.next()) + { + record.getString(L"Name", &result->terminalProcessName); + record.getString(L"ExecutablePath", &result->terminalExe); + result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1; + uint64_t pid; + record.getUnsigned(L"ProcessId", &pid); + result->terminalPid = (uint32_t) pid; + ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); + if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) + ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4); + return true; + } + return false; +} + #endif extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); @@ -135,6 +203,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* if(instance->config.shellVersion) fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion); + result->shellPid = pid; if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh")) ffStrbufSetS(&result->shellPrettyName, "PowerShell"); else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell")) @@ -154,7 +223,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* module.dwSize = sizeof(module); for(BOOL success = Module32FirstW(snapshot, &module); success; success = Module32NextW(snapshot, &module)) { - if(wcsncmp(module.szModule, L"clink_dll_", wcslen(L"clink_dll_")) == 0) + if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0) { ffStrbufAppendS(&result->shellPrettyName, "CMD (with Clink)"); break; @@ -170,6 +239,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult* else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer")) { ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell + // In this case, terminal process will be created by fastfetch itself. return 0; } @@ -205,6 +275,21 @@ static uint32_t getTerminalInfo(const FFinstance* instance, FFTerminalShellResul return getTerminalInfo(instance, result, ppid); } + if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "sihost") || + ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer") + ) { + ffStrbufClear(&result->terminalProcessName); + ffStrbufClear(&result->terminalPrettyName); + ffStrbufClear(&result->terminalExe); + result->terminalExeName = ""; + + // Maybe terminal process is created by shell + if(!getTerminalInfoByEnumeratingChildProcesses(result, result->shellPid)) + return 0; + } + else + result->terminalPid = pid; + if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal")) ffStrbufSetS(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_") ? "Windows Terminal Preview" @@ -288,11 +373,13 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) result.shellExeName = ""; ffStrbufInit(&result.shellPrettyName); ffStrbufInit(&result.shellVersion); + result.shellPid = 0; ffStrbufInit(&result.terminalProcessName); ffStrbufInitA(&result.terminalExe, 128); result.terminalExeName = ""; ffStrbufInit(&result.terminalPrettyName); + result.terminalPid = 0; ffStrbufInit(&result.userShellExe); result.userShellExeName = ""; @@ -303,7 +390,9 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) goto exit; ppid = getShellInfo(instance, &result, ppid); - getTerminalInfo(instance, &result, ppid); + if(ppid) + getTerminalInfo(instance, &result, ppid); + if(result.terminalProcessName.length == 0) getTerminalFromEnv(&result); diff --git a/src/detection/vulkan.c b/src/detection/vulkan/vulkan.c similarity index 58% rename from src/detection/vulkan.c rename to src/detection/vulkan/vulkan.c index dbda127bb..d46f1879c 100644 --- a/src/detection/vulkan.c +++ b/src/detection/vulkan/vulkan.c @@ -1,12 +1,14 @@ #include "fastfetch.h" #include "common/thread.h" -#include "detection/vulkan.h" #include "detection/gpu/gpu.h" +#include "detection/vulkan/vulkan.h" #ifdef FF_HAVE_VULKAN #include "common/library.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/parsing.h" +#include "util/stringUtils.h" +#include "util/mallocHelper.h" #include #include @@ -41,19 +43,20 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu FF_LIBRARY_LOAD(vulkan, &instance->config.libVulkan, "dlopen libvulkan"FF_LIBRARY_EXTENSION " failed", #ifdef __APPLE__ "libMoltenVK"FF_LIBRARY_EXTENSION, -1 + #elif defined(_WIN32) + "vulkan-1"FF_LIBRARY_EXTENSION, -1 #else - "libvulkan"FF_LIBRARY_EXTENSION, 2, "vulkan-1"FF_LIBRARY_EXTENSION, -1 + "libvulkan"FF_LIBRARY_EXTENSION, 2 #endif ) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkGetInstanceProcAddr) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkCreateInstance) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkDestroyInstance) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkEnumeratePhysicalDevices) - FF_LIBRARY_LOAD_SYMBOL_MESSAGE(vulkan, vkGetPhysicalDeviceProperties) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE2(vulkan, vkGetInstanceProcAddr, vkGetInstanceProcAddr@8) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE2(vulkan, vkCreateInstance, vkCreateInstance@12) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE2(vulkan, vkDestroyInstance, vkDestroyInstance@8) + FF_LIBRARY_LOAD_SYMBOL_MESSAGE2(vulkan, vkEnumeratePhysicalDevices, vkEnumeratePhysicalDevices@12) //Some drivers (nvdc) print messages to stdout //and thats the best way i found to disable that - ffSuppressIO(true); + FF_SUPPRESS_IO(); FFVersion instanceVersion = FF_VERSION_INIT; @@ -73,66 +76,52 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu FASTFETCH_PROJECT_VERSION_PATCH ); - //We need to request 1.2 to get physicalDeviceDriverProperties - uint32_t requestedVkVersion = VK_API_VERSION_1_0; - if(instanceVersion.minor >= 2) - requestedVkVersion = VK_API_VERSION_1_2; - - const VkApplicationInfo applicationInfo = { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = NULL, - .pApplicationName = FASTFETCH_PROJECT_NAME, - .applicationVersion = projectVersion, - .pEngineName = "vulkanPrintGPUs", - .engineVersion = projectVersion, - .apiVersion = requestedVkVersion - }; - - const VkInstanceCreateInfo instanceCreateInfo = { + VkInstance vkInstance; + if(ffvkCreateInstance(&(VkInstanceCreateInfo) { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pNext = NULL, - .pApplicationInfo = &applicationInfo, + .pApplicationInfo = &(VkApplicationInfo) { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = NULL, + .pApplicationName = FASTFETCH_PROJECT_NAME, + .applicationVersion = projectVersion, + .pEngineName = "vulkanPrintGPUs", + .engineVersion = projectVersion, + + // We need to request 1.1 to get physicalDeviceDriverProperties + .apiVersion = instanceVersion.minor >= 1 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0 + }, .enabledLayerCount = 0, .ppEnabledLayerNames = NULL, .enabledExtensionCount = 0, .ppEnabledExtensionNames = NULL, .flags = 0 - }; - - VkInstance vkInstance; - if(ffvkCreateInstance(&instanceCreateInfo, NULL, &vkInstance) != VK_SUCCESS) - { - dlclose(vulkan); - ffSuppressIO(false); + }, NULL, &vkInstance) != VK_SUCCESS) return "ffvkCreateInstance() failed"; - } - //if instance creation succeeded, but vkEnumerateInstanceVersion didn't, this means we are running against a vulkan 1.0 implementation //explicitly set this version, if no device is found, so we still have at least this info if(instanceVersion.major == 0 && instanceVersion.minor == 0 && instanceVersion.patch == 0) instanceVersion.major = 1; - uint32_t physicalDeviceCount; - if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, NULL) != VK_SUCCESS) - { - ffvkDestroyInstance(vkInstance, NULL); - dlclose(vulkan); - ffSuppressIO(false); - return "ffvkEnumeratePhysicalDevices() failed"; - } - - VkPhysicalDevice* physicalDevices = malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); + VkPhysicalDevice physicalDevices[128]; + uint32_t physicalDeviceCount = (uint32_t) (sizeof(physicalDevices) / sizeof(*physicalDevices)); if(ffvkEnumeratePhysicalDevices(vkInstance, &physicalDeviceCount, physicalDevices) != VK_SUCCESS) { - free(physicalDevices); ffvkDestroyInstance(vkInstance, NULL); - dlclose(vulkan); - ffSuppressIO(false); return "ffvkEnumeratePhysicalDevices() failed"; } - PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2"); + PFN_vkGetPhysicalDeviceProperties ffvkGetPhysicalDeviceProperties = NULL; + PFN_vkGetPhysicalDeviceProperties2 ffvkGetPhysicalDeviceProperties2 = (PFN_vkGetPhysicalDeviceProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties2"); // 1.1 + if(!ffvkGetPhysicalDeviceProperties2) + ffvkGetPhysicalDeviceProperties = (PFN_vkGetPhysicalDeviceProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceProperties"); + + PFN_vkGetPhysicalDeviceMemoryProperties ffvkGetPhysicalDeviceMemoryProperties = NULL; + PFN_vkGetPhysicalDeviceMemoryProperties2 ffvkGetPhysicalDeviceMemoryProperties2 = + instance->config.allowSlowOperations ? (PFN_vkGetPhysicalDeviceMemoryProperties2) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceMemoryProperties2") : NULL; // 1.1 + if(!ffvkGetPhysicalDeviceMemoryProperties2) + ffvkGetPhysicalDeviceMemoryProperties = (PFN_vkGetPhysicalDeviceMemoryProperties) ffvkGetInstanceProcAddr(vkInstance, "vkGetPhysicalDeviceMemoryProperties"); FFVersion maxDeviceApiVersion = FF_VERSION_INIT; FFVersion maxDeviceConformanceVersion = FF_VERSION_INIT; @@ -140,18 +129,16 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu for(uint32_t i = 0; i < physicalDeviceCount; i++) { //Get device properties. - //On VK 1.2 and up, we use vkGetPhysicalDeviceProperties2, so we can put VkPhysicalDeviceDriverProperties in the pNext chain. + //On VK 1.1 and up, we use vkGetPhysicalDeviceProperties2, so we can put VkPhysicalDeviceDriverProperties in the pNext chain. //This is required to get the driver name and conformance version. - VkPhysicalDeviceDriverProperties driverProperties; - driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; - driverProperties.pNext = NULL; - driverProperties.driverName[0] = '\0'; - driverProperties.conformanceVersion = (VkConformanceVersion) {0, 0, 0, 0}; - - VkPhysicalDeviceProperties2 physicalDeviceProperties; - physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - physicalDeviceProperties.pNext = &driverProperties; + VkPhysicalDeviceDriverProperties driverProperties = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES, + }; + VkPhysicalDeviceProperties2 physicalDeviceProperties = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, + .pNext = &driverProperties, + }; if(ffvkGetPhysicalDeviceProperties2 != NULL) ffvkGetPhysicalDeviceProperties2(physicalDevices[i], &physicalDeviceProperties); @@ -161,6 +148,7 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu //If the device api version is higher than the current highest device api version, overwrite it //In this case, also use the current device driver name as the shown driver name + FFVersion deviceAPIVersion = FF_VERSION_INIT; applyVulkanVersion(physicalDeviceProperties.properties.apiVersion, &deviceAPIVersion); if(ffVersionCompare(&deviceAPIVersion, &maxDeviceApiVersion) > 0) @@ -170,14 +158,17 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu } //If the device conformance version is higher than the current highest device conformance version, overwrite it + if(ffvkGetPhysicalDeviceProperties2) + { + FFVersion deviceConformanceVersion = { + .major = driverProperties.conformanceVersion.major, + .minor = driverProperties.conformanceVersion.minor, + .patch = driverProperties.conformanceVersion.patch, + }; - FFVersion deviceConformanceVersion = FF_VERSION_INIT; - deviceConformanceVersion.major = driverProperties.conformanceVersion.major; - deviceConformanceVersion.minor = driverProperties.conformanceVersion.minor; - deviceConformanceVersion.patch = driverProperties.conformanceVersion.patch; - - if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0) - maxDeviceConformanceVersion = deviceConformanceVersion; + if(ffVersionCompare(&deviceConformanceVersion, &maxDeviceConformanceVersion) > 0) + maxDeviceConformanceVersion = deviceConformanceVersion; + } //Add the device to the list of devices shown by the GPU module @@ -190,14 +181,39 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu ffStrbufInit(&gpu->name); ffStrbufAppendS(&gpu->name, physicalDeviceProperties.properties.deviceName); - if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) - gpu->type = FF_GPU_TYPE_INTEGRATED; - else + if(physicalDeviceProperties.properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) gpu->type = FF_GPU_TYPE_DISCRETE; + else + gpu->type = FF_GPU_TYPE_INTEGRATED; + gpu->id = physicalDeviceProperties.properties.deviceID; + ffStrbufInitS(&gpu->vendor, ffGetGPUVendorString(physicalDeviceProperties.properties.vendorID)); + ffStrbufInitS(&gpu->driver, driverProperties.driverInfo); + + VkPhysicalDeviceMemoryBudgetPropertiesEXT budgetProperties = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT, + }; + VkPhysicalDeviceMemoryProperties2 memoryProperties2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2, + .pNext = &budgetProperties, + }; + + if(ffvkGetPhysicalDeviceMemoryProperties2) + ffvkGetPhysicalDeviceMemoryProperties2(physicalDevices[i], &memoryProperties2); + else + ffvkGetPhysicalDeviceMemoryProperties(physicalDevices[i], &memoryProperties2.memoryProperties); + + gpu->dedicated.total = gpu->shared.total = 0; + gpu->dedicated.used = gpu->shared.used = ffvkGetPhysicalDeviceMemoryProperties2 ? 0 : FF_GPU_VMEM_SIZE_UNSET; + for(uint32_t index = 0; index < memoryProperties2.memoryProperties.memoryHeapCount; ++index) + { + const VkMemoryHeap* heap = &memoryProperties2.memoryProperties.memoryHeaps[index]; + FFGPUMemory* vmem = gpu->type == FF_GPU_TYPE_DISCRETE && (heap->flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? &gpu->dedicated : &gpu->shared; + vmem->total += heap->size; + if(ffvkGetPhysicalDeviceMemoryProperties2) + vmem->used += heap->size - budgetProperties.heapBudget[index]; + } //No way to detect those using vulkan - ffStrbufInit(&gpu->vendor); - ffStrbufInit(&gpu->driver); gpu->coreCount = FF_GPU_CORE_COUNT_UNSET; gpu->temperature = FF_GPU_TEMP_UNSET; } @@ -212,10 +228,7 @@ static const char* detectVulkan(const FFinstance* instance, FFVulkanResult* resu //Use the highest device conformace version as our conformance version ffVersionToPretty(&maxDeviceConformanceVersion, &result->conformanceVersion); - free(physicalDevices); ffvkDestroyInstance(vkInstance, NULL); - dlclose(vulkan); - ffSuppressIO(false); return NULL; } diff --git a/src/detection/vulkan.h b/src/detection/vulkan/vulkan.h similarity index 100% rename from src/detection/vulkan.h rename to src/detection/vulkan/vulkan.h diff --git a/src/detection/wifi/wifi_android.c b/src/detection/wifi/wifi_android.c index af1012fe7..5a304de4c 100644 --- a/src/detection/wifi/wifi_android.c +++ b/src/detection/wifi/wifi_android.c @@ -3,16 +3,22 @@ #include "common/processing.h" #include "common/properties.h" +#define FF_TERMUX_API_PATH FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api" +#define FF_TERMUX_API_PARAM "WifiConnectionInfo" + const char* ffDetectWifi(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* result) { FF_STRBUF_AUTO_DESTROY buffer; ffStrbufInit(&buffer); if(ffProcessAppendStdOut(&buffer, (char* const[]){ - FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api", + FF_TERMUX_API_PATH, "WifiConnectionInfo" })) - return "Starting `" FASTFETCH_TARGET_DIR_ROOT "/libexec/termux-api" " WifiConnectionInfo` failed"; + return "Starting `" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` failed"; + + if(buffer.length == 0) + return "`" FF_TERMUX_API_PATH " " FF_TERMUX_API_PARAM "` prints empty"; FFWifiResult* item = (FFWifiResult*)ffListAdd(result); ffStrbufInit(&item->inf.description); diff --git a/src/detection/wifi/wifi_linux.c b/src/detection/wifi/wifi_linux.c index a8f70620d..edd5affc5 100644 --- a/src/detection/wifi/wifi_linux.c +++ b/src/detection/wifi/wifi_linux.c @@ -13,6 +13,12 @@ #define NM_NO_INCLUDE_EXTRA_HEADERS 1 #include +//https://developer-old.gnome.org/libnm/stable/libnm-nm-dbus-interface.html +#ifndef NM_VERSION_1_26 + #define NM_802_11_AP_SEC_KEY_MGMT_OWE 0x00000800 + #define NM_802_11_AP_SEC_KEY_MGMT_OWE_TM 0x00001000 +#endif + static const char* detectWifiWithLibnm(const FFinstance* instance, FFlist* result) { FF_LIBRARY_LOAD(nm, &instance->config.libnm, "dlopen libnm failed", "libnm" FF_LIBRARY_EXTENSION, 0); @@ -39,10 +45,7 @@ static const char* detectWifiWithLibnm(const FFinstance* instance, FFlist* resul NMClient* client = ffnm_client_new(NULL, NULL); if(!client) - { - dlclose(nm); return "Could not create NMClient"; - } /* Get all devices managed by NetworkManager */ const GPtrArray* devices = ffnm_client_get_devices(client); @@ -193,14 +196,13 @@ static const char* detectWifiWithLibnm(const FFinstance* instance, FFlist* resul } ffg_object_unref(client); - dlclose(nm); return NULL; } #endif -#include "common/io.h" +#include "common/io/io.h" #include #include @@ -219,7 +221,7 @@ static const char* detectWifiWithIoctls(FF_MAYBE_UNUSED const FFinstance* instan for(struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == NULL); ++i) { ffStrbufSetF(&path, "/sys/class/net/%s/phy80211", i->if_name); - if(!ffFileExists(path.chars, S_IFDIR)) + if(!ffPathExists(path.chars, FF_PATHTYPE_DIRECTORY)) continue; FFWifiResult* item = (FFWifiResult*)ffListAdd(result); diff --git a/src/detection/wifi/wifi_windows.c b/src/detection/wifi/wifi_windows.c index 70d7ea577..f13cc5484 100644 --- a/src/detection/wifi/wifi_windows.c +++ b/src/detection/wifi/wifi_windows.c @@ -207,7 +207,6 @@ const char* ffDetectWifi(FF_MAYBE_UNUSED const FFinstance* instance, FFlist* res exit: if(ifList) ffWlanFreeMemory(ifList); if(hClient) ffWlanCloseHandle(hClient, NULL); - dlclose(wlanapi); return error; } diff --git a/src/detection/wmtheme/wmtheme.h b/src/detection/wmtheme/wmtheme.h index e1475006f..33a15dd0f 100644 --- a/src/detection/wmtheme/wmtheme.h +++ b/src/detection/wmtheme/wmtheme.h @@ -3,6 +3,8 @@ #ifndef FASTFETCH_INCLUDED_detection_wmtheme #define FASTFETCH_INCLUDED_detection_wmtheme +#include "fastfetch.h" + bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError); #endif diff --git a/src/detection/wmtheme/wmtheme_linux.c b/src/detection/wmtheme/wmtheme_linux.c index 6efba12c5..e325e0bce 100644 --- a/src/detection/wmtheme/wmtheme_linux.c +++ b/src/detection/wmtheme/wmtheme_linux.c @@ -1,10 +1,10 @@ -#include "fastfetch.h" +#include "wmtheme.h" #include "common/properties.h" #include "common/parsing.h" #include "common/settings.h" -#include "detection/gtk.h" +#include "detection/gtk_qt/gtk_qt.h" #include "detection/displayserver/displayserver.h" -#include "wmtheme.h" +#include "util/stringUtils.h" static bool detectWMThemeFromConfigFile(FFinstance* instance, const char* configFile, const char* themeRegex, const char* defaultValue, FFstrbuf* themeOrError) { @@ -104,11 +104,13 @@ static bool detectMuffin(FFinstance* instance, FFstrbuf* themeOrError) ffStrbufAppendS(themeOrError, theme); return true; } + if(theme == NULL) { - ffStrbufAppendS(themeOrError, theme); + ffStrbufAppendS(themeOrError, name); return true; } + ffStrbufAppendF(themeOrError, "%s (%s)", name, theme); return true; } @@ -200,27 +202,27 @@ bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError) return false; } - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "KWin") == 0 || ffStrbufIgnCaseCompS(&wm->wmPrettyName, "KDE") == 0 || ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Plasma") == 0) + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_KWIN) == 0) return detectWMThemeFromConfigFile(instance, "kwinrc", "theme =", "Breeze", themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Xfwm4") == 0 || ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Xfwm") == 0) + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_XFWM4) == 0) return detectXFWM4(instance, themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Mutter") == 0) + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MUTTER) == 0) { - if(ffStrbufIgnCaseCompS(&wm->dePrettyName, "Gnome") == 0) + if(ffStrbufIgnCaseCompS(&wm->dePrettyName, FF_DE_PRETTY_GNOME) == 0) return detectMutter(instance, themeOrError); else return detectGTKThemeAsWMTheme(instance, themeOrError); } - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Muffin") == 0) + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MUFFIN) == 0) return detectMuffin(instance, themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Marco") == 0) + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_MARCO) == 0) return detectWMThemeFromSettings(instance, "/org/mate/Marco/general/theme", "org.mate.Marco.general", NULL, "theme", themeOrError); - if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, "Openbox") == 0) + if(ffStrbufIgnCaseCompS(&wm->wmPrettyName, FF_WM_PRETTY_OPENBOX) == 0) return detectOpenbox(instance, &wm->dePrettyName, themeOrError); ffStrbufAppendS(themeOrError, "Unknown WM: "); diff --git a/src/detection/wmtheme/wmtheme_windows.c b/src/detection/wmtheme/wmtheme_windows.c index cf070be69..0522b933b 100644 --- a/src/detection/wmtheme/wmtheme_windows.c +++ b/src/detection/wmtheme/wmtheme_windows.c @@ -60,64 +60,59 @@ const char* colorHexToString(DWORD hex) } } -bool ffDetectWmTheme(FFinstance* instance, FFstrbuf* themeOrError) +bool ffDetectWmTheme(FF_MAYBE_UNUSED FFinstance* instance, FFstrbuf* themeOrError) { - FF_UNUSED(instance); + { + FF_HKEY_AUTO_DESTROY hKey = NULL; + if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes", &hKey, NULL)) + { + FF_STRBUF_AUTO_DESTROY theme; + ffStrbufInit(&theme); + if(ffRegReadStrbuf(hKey, L"CurrentTheme", &theme, NULL)) + { + ffStrbufSubstrBeforeLastC(&theme, '.'); + ffStrbufSubstrAfterLastC(&theme, '\\'); + if(isalpha(theme.chars[0])) + theme.chars[0] = (char)toupper(theme.chars[0]); + + ffStrbufAppendF(themeOrError, "%s", theme.chars); + } + } + } do { uint32_t rgbColor; uint32_t bgrColor; DWORD bufSize = sizeof(bgrColor); if(RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", L"AccentColor", RRF_RT_REG_DWORD, NULL, &bgrColor, &bufSize) == ERROR_SUCCESS) - { - ffStrbufAppendS(themeOrError, "Accent Color - "); rgbColor = ((bgrColor & 0xFF) << 16) | (bgrColor & 0xFF00) | ((bgrColor >> 16) & 0xFF); - - } else if(RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", L"ColorizationColor", RRF_RT_REG_DWORD, NULL, &rgbColor, &bufSize) == ERROR_SUCCESS) - { - ffStrbufAppendS(themeOrError, "Colorization Color - "); rgbColor &= 0xFFFFFF; - } else break; + if(themeOrError->length > 0) ffStrbufAppendS(themeOrError, " - "); const char* text = colorHexToString(rgbColor); if(text) ffStrbufAppendS(themeOrError, text); else ffStrbufAppendF(themeOrError, "#%06lX", (long)rgbColor); - } while(false); + } while (false); - FF_HKEY_AUTO_DESTROY hKey = NULL; - if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", &hKey, NULL)) { - uint32_t value = 1; - if(ffRegReadUint(hKey, L"SystemUsesLightTheme", &value, NULL)) + FF_HKEY_AUTO_DESTROY hKey = NULL; + if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", &hKey, NULL)) { - if(themeOrError->length > 0) ffStrbufAppendS(themeOrError, ", "); - ffStrbufAppendF(themeOrError, "System - %s", value ? "Light" : "Dark"); - } - - if(ffRegReadUint(hKey, L"AppsUseLightTheme", &value, NULL)) - { - if(themeOrError->length > 0) ffStrbufAppendS(themeOrError, ", "); - ffStrbufAppendF(themeOrError, "Apps - %s", value ? "Light" : "Dark"); - } - } - else if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes", &hKey, NULL)) - { - FF_STRBUF_AUTO_DESTROY theme; - ffStrbufInit(&theme); - if(ffRegReadStrbuf(hKey, L"CurrentTheme", &theme, NULL)) - { - ffStrbufSubstrBeforeLastC(&theme, '.'); - ffStrbufSubstrAfterLastC(&theme, '\\'); - if(isalpha(theme.chars[0])) - theme.chars[0] = (char)toupper(theme.chars[0]); - - if(themeOrError->length > 0) ffStrbufAppendS(themeOrError, ", "); - ffStrbufAppendF(themeOrError, "Theme - %s", theme.chars); + uint32_t system = 1, apps = 1; + if (ffRegReadUint(hKey, L"SystemUsesLightTheme", &system, NULL) && ffRegReadUint(hKey, L"AppsUseLightTheme", &apps, NULL)) + { + bool paren = themeOrError->length > 0; + if (paren) + ffStrbufAppendS(themeOrError, " ("); + ffStrbufAppendF(themeOrError, "System: %s, Apps: %s", system ? "Light" : "Dark", apps ? "Light" : "Dark"); + if (paren) + ffStrbufAppendC(themeOrError, ')'); + } } } diff --git a/src/fastfetch.c b/src/fastfetch.c index 398ed03fe..deebe41d8 100644 --- a/src/fastfetch.c +++ b/src/fastfetch.c @@ -1,9 +1,10 @@ #include "fastfetch.h" -#include "util/FFvaluestore.h" #include "common/printing.h" #include "common/parsing.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/time.h" +#include "util/FFvaluestore.h" +#include "util/stringUtils.h" #include #include @@ -12,9 +13,6 @@ #ifdef WIN32 #include "util/windows/getline.h" - #include -#else - #include #endif typedef struct CustomValue @@ -176,11 +174,12 @@ static inline void printCommandHelp(const char* command) } else if(strcasecmp(command, "display-format") == 0) { - constructAndPrintCommandHelpFormat("display", "{}x{} @ {}Hz", 4, + constructAndPrintCommandHelpFormat("display", "{}x{} @ {}Hz", 5, "Screen width", "Screen height", "Screen refresh rate", - "Screen brightness" + "Screen scaled width", + "Screen scaled height" ); } else if(strcasecmp(command, "de-format") == 0) @@ -448,87 +447,50 @@ static inline void printCommandHelp(const char* command) "vendor" ); } + else if(strcasecmp(command, "bluetooth-format") == 0) + { + constructAndPrintCommandHelpFormat("bluetooth", "{1} (4%)", 4, + "Name", + "Address", + "Type", + "Battery percentage" + ); + } + else if(strcasecmp(command, "sound-format") == 0) + { + constructAndPrintCommandHelpFormat("sound", "{2} (3%)", 4, + "Main", + "Name", + "Volume", + "Identifier" + ); + } + else if(strcasecmp(command, "gamepad-format") == 0) + { + constructAndPrintCommandHelpFormat("gamepad", "{1}", 1, + "Name", + "Identifier" + ); + } else fprintf(stderr, "No specific help for command %s provided\n", command); } -static inline void listAvailablePresetsFromFolder(FFstrbuf* folder, uint8_t indentation, const char* folderName) -{ - #ifndef _WIN32 - DIR* dir = opendir(folder->chars); - if(dir == NULL) - return; - - uint32_t folderLength = folder->length; - - if(folderName != NULL) - printf("%s/\n", folderName); - - struct dirent* entry; - - while((entry = readdir(dir)) != NULL) - { - if(entry->d_type == DT_DIR) - { - if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - - ffStrbufAppendS(folder, entry->d_name); - ffStrbufAppendC(folder, '/'); - listAvailablePresetsFromFolder(folder, (uint8_t) (indentation + 1), entry->d_name); - ffStrbufSubstrBefore(folder, folderLength); - continue; - } - - for(uint8_t i = 0; i < indentation; i++) - fputs(" | ", stdout); - - puts(entry->d_name); - } - - closedir(dir); - #else - uint32_t folderLength = folder->length; - - if(folderName != NULL) - printf("%s/\n", folderName); - - ffStrbufAppendC(folder, '*'); - WIN32_FIND_DATAA entry; - HANDLE hFind = FindFirstFileA(folder->chars, &entry); - if(hFind == INVALID_HANDLE_VALUE) - return; - - do - { - if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - { - if(strcmp(entry.cFileName, ".") == 0 || strcmp(entry.cFileName, "..") == 0) - continue; - - ffStrbufSubstrBefore(folder, folderLength); - ffStrbufAppendS(folder, entry.cFileName); - ffStrbufAppendC(folder, '/'); - listAvailablePresetsFromFolder(folder, (uint8_t) (indentation + 1), entry.cFileName); - ffStrbufSubstrBefore(folder, folderLength); - continue; - } - - for(uint8_t i = 0; i < indentation; i++) - fputs(" | ", stdout); - - puts(entry.cFileName); - } while (FindNextFileA(hFind, &entry)); - FindClose(hFind); - #endif -} - -static inline void listAvailablePresets(FFinstance* instance) +static void listAvailablePresets(FFinstance* instance) { FF_LIST_FOR_EACH(FFstrbuf, path, instance->state.platform.dataDirs) { ffStrbufAppendS(path, "fastfetch/presets/"); - listAvailablePresetsFromFolder(path, 0, NULL); + ffListFilesRecursively(path->chars); + } +} + +static void listAvailableLogos(FFinstance* instance) +{ + FF_LIST_FOR_EACH(FFstrbuf, path, instance->state.platform.dataDirs) + { + ffStrbufAppendS(path, "fastfetch/logos/"); + ffListFilesRecursively(path->chars); } } @@ -537,7 +499,7 @@ static void listConfigPaths(FFinstance* instance) FF_LIST_FOR_EACH(FFstrbuf, folder, instance->state.platform.configDirs) { ffStrbufAppendS(folder, "fastfetch/config.conf"); - printf("%s%s\n", folder->chars, ffFileExists(folder->chars, S_IFREG) ? " (*)" : ""); + printf("%s%s\n", folder->chars, ffPathExists(folder->chars, FF_PATHTYPE_FILE) ? " (*)" : ""); } } @@ -621,7 +583,7 @@ static void generateConfigFile(FFinstance* instance, bool force) // Paths generated in `init.c/initConfigDirs` end with `/` ffStrbufAppendS(filename, "fastfetch/config.conf"); - if (!force && ffFileExists(filename->chars, S_IFREG)) + if (!force && ffPathExists(filename->chars, FF_PATHTYPE_FILE)) { fprintf(stderr, "Config file exists in `%s`, use `--gen-config-force` to overwrite\n", filename->chars); exit(1); @@ -953,7 +915,10 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con } else if(strcasecmp(subkey, "-logos") == 0) { + puts("Builtin logos:"); ffLogoBuiltinList(); + puts("\nCustom logos:"); + listAvailableLogos(instance); exit(0); } else if(strcasecmp(subkey, "-logos-autocompletion") == 0) @@ -971,8 +936,6 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con else if(strcasecmp(key, "-r") == 0 || strcasecmp(key, "--recache") == 0) instance->config.recache = optionParseBoolean(value); - else if(strcasecmp(key, "--nocache") == 0) - fputs("`--nocache` are obsoleted. Caching functions other than image caching are removed.\n\n", stderr); else if(strcasecmp(key, "--load-config") == 0) optionParseConfigFile(instance, data, key, value); else if(strcasecmp(key, "--gen-config") == 0) @@ -1210,6 +1173,9 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con else if(optionParseModuleArgs(key, value, "opengl", &instance->config.openGL)) {} else if(optionParseModuleArgs(key, value, "opencl", &instance->config.openCL)) {} else if(optionParseModuleArgs(key, value, "users", &instance->config.users)) {} + else if(optionParseModuleArgs(key, value, "bluetooth", &instance->config.bluetooth)) {} + else if(optionParseModuleArgs(key, value, "sound", &instance->config.sound)) {} + else if(optionParseModuleArgs(key, value, "gamepad", &instance->config.gamepad)) {} /////////////////// //Library options// @@ -1264,6 +1230,8 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con optionParseString(key, value, &instance->config.libcJSON); else if(strcasecmp(subkey, "-wlanapi") == 0) optionParseString(key, value, &instance->config.libwlanapi); + else if(strcasecmp(key, "-pulse") == 0) + optionParseString(key, value, &instance->config.libPulse); else if(strcasecmp(subkey, "-nm") == 0) optionParseString(key, value, &instance->config.libnm); else @@ -1300,10 +1268,23 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con instance->config.diskShowSubvolumes = optionParseBoolean(value); else if(strcasecmp(key, "--disk-show-unknown") == 0) instance->config.diskShowUnknown = optionParseBoolean(value); + else if(strcasecmp(key, "--bluetooth-show-disconnected") == 0) + instance->config.bluetoothShowDisconnected = optionParseBoolean(value); + else if(strcasecmp(key, "--sound-type") == 0) + { + optionParseEnum(key, value, &instance->config.soundType, + "main", FF_SOUND_TYPE_MAIN, + "active", FF_SOUND_TYPE_ACTIVE, + "all", FF_SOUND_TYPE_ALL, + NULL + ); + } else if(strcasecmp(key, "--battery-dir") == 0) optionParseString(key, value, &instance->config.batteryDir); else if(strcasecmp(key, "--separator-string") == 0) optionParseString(key, value, &instance->config.separatorString); + else if(strcasecmp(key, "--localip-v6first") == 0) + instance->config.localIpV6First = optionParseBoolean(value); else if(strcasecmp(key, "--localip-show-ipv4") == 0) instance->config.localIpShowIpV4 = optionParseBoolean(value); else if(strcasecmp(key, "--localip-show-ipv6") == 0) @@ -1312,6 +1293,15 @@ static void parseOption(FFinstance* instance, FFdata* data, const char* key, con instance->config.localIpShowLoop = optionParseBoolean(value); else if(strcasecmp(key, "--localip-name-prefix") == 0) optionParseString(key, value, &instance->config.localIpNamePrefix); + else if(strcasecmp(key, "--localip-compact-type") == 0) + { + optionParseEnum(key, value, &instance->config.localIpCompactType, + "none", FF_LOCALIP_COMPACT_TYPE_NONE, + "oneline", FF_LOCALIP_COMPACT_TYPE_ONELINE, + "multiline", FF_LOCALIP_COMPACT_TYPE_MULTILINE, + NULL + ); + } else if(strcasecmp(key, "--os-file") == 0) optionParseString(key, value, &instance->config.osFile); else if(strcasecmp(key, "--player-name") == 0) @@ -1505,6 +1495,12 @@ static void parseStructureCommand(FFinstance* instance, FFdata* data, const char ffPrintUsers(instance); else if(strcasecmp(line, "command") == 0) ffPrintCommand(instance); + else if(strcasecmp(line, "bluetooth") == 0) + ffPrintBluetooth(instance); + else if(strcasecmp(line, "sound") == 0) + ffPrintSound(instance); + else if(strcasecmp(line, "gamepad") == 0) + ffPrintGamepad(instance); else ffPrintErrorString(instance, line, 0, NULL, NULL, ""); } diff --git a/src/fastfetch.h b/src/fastfetch.h index 69121e4c9..627748c16 100644 --- a/src/fastfetch.h +++ b/src/fastfetch.h @@ -34,6 +34,20 @@ typedef enum FFLogoType FF_LOGO_TYPE_NONE, //--logo none } FFLogoType; +typedef enum FFSoundType +{ + FF_SOUND_TYPE_MAIN, + FF_SOUND_TYPE_ACTIVE, + FF_SOUND_TYPE_ALL, +} FFSoundType; + +typedef enum FFLocalIpCompactType +{ + FF_LOCALIP_COMPACT_TYPE_NONE, + FF_LOCALIP_COMPACT_TYPE_MULTILINE, + FF_LOCALIP_COMPACT_TYPE_ONELINE, +} FFLocalIpCompactType; + typedef enum FFBinaryPrefixType { FF_BINARY_PREFIX_TYPE_IEC, // 1024 Bytes = 1 KiB, 1024 KiB = 1 MiB, ... (standard) @@ -139,6 +153,9 @@ typedef struct FFconfig FFModuleArgs openGL; FFModuleArgs openCL; FFModuleArgs users; + FFModuleArgs bluetooth; + FFModuleArgs sound; + FFModuleArgs gamepad; FFstrbuf libPCI; FFstrbuf libVulkan; @@ -162,6 +179,7 @@ typedef struct FFconfig FFstrbuf libOpenCL; FFstrbuf libcJSON; FFstrbuf libfreetype; + FFstrbuf libPulse; FFstrbuf libwlanapi; FFstrbuf libnm; @@ -183,14 +201,18 @@ typedef struct FFconfig bool diskShowUnknown; bool diskShowSubvolumes; + bool bluetoothShowDisconnected; + FFstrbuf batteryDir; FFstrbuf separatorString; bool localIpShowLoop; + bool localIpV6First; bool localIpShowIpV4; bool localIpShowIpV6; FFstrbuf localIpNamePrefix; + FFLocalIpCompactType localIpCompactType; FFstrbuf publicIpUrl; uint32_t publicIpTimeout; @@ -198,6 +220,8 @@ typedef struct FFconfig FFstrbuf weatherOutputFormat; uint32_t weatherTimeout; + FFSoundType soundType; + FFstrbuf osFile; FFstrbuf playerName; @@ -310,5 +334,8 @@ void ffPrintOpenGL(FFinstance* instance); void ffPrintOpenCL(FFinstance* instance); void ffPrintUsers(FFinstance* instance); void ffPrintCommand(FFinstance* instance); +void ffPrintBluetooth(FFinstance* instance); +void ffPrintSound(FFinstance* instance); +void ffPrintGamepad(FFinstance* instance); #endif diff --git a/src/flashfetch.c b/src/flashfetch.c index 0c24732e3..8737c8fcf 100644 --- a/src/flashfetch.c +++ b/src/flashfetch.c @@ -63,6 +63,9 @@ int main(int argc, char** argv) //ffPrintOpenCL(&instance); //ffPrintUsers(&instance); //ffPrintWeather(&instance); + //ffPrintBluetooth(&instance); + //ffPrintSound(&instance); + //ffPrintGamepad(&instance); ffPrintBreak(&instance); ffPrintColors(&instance); diff --git a/src/logo/image/im6.c b/src/logo/image/im6.c index a235bb867..ba652a370 100644 --- a/src/logo/image/im6.c +++ b/src/logo/image/im6.c @@ -17,15 +17,10 @@ FFLogoImageResult ffLogoPrintImageIM6(FFinstance* instance, FFLogoRequestData* r FF_LIBRARY_LOAD(imageMagick, &instance->config.libImageMagick, FF_LOGO_IMAGE_RESULT_INIT_ERROR, "libMagickCore-6.Q16HDRI" FF_LIBRARY_EXTENSION, 8, "libMagickCore-6.Q16" FF_LIBRARY_EXTENSION, 8) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR); - FFIMData imData; - imData.resizeFunc = logoResize; - imData.library = imageMagick; - - FFLogoImageResult result = ffLogoPrintImageImpl(instance, requestData, &imData); - - dlclose(imageMagick); - - return result; + return ffLogoPrintImageImpl(instance, requestData, &(FFIMData) { + .resizeFunc = logoResize, + .library = imageMagick, + }); } #endif diff --git a/src/logo/image/im7.c b/src/logo/image/im7.c index d7cf4b6d0..0677b4911 100644 --- a/src/logo/image/im7.c +++ b/src/logo/image/im7.c @@ -21,15 +21,10 @@ FFLogoImageResult ffLogoPrintImageIM7(FFinstance* instance, FFLogoRequestData* r ) FF_LIBRARY_LOAD_SYMBOL_ADDRESS(imageMagick, ffResizeImage, ResizeImage, FF_LOGO_IMAGE_RESULT_INIT_ERROR); - FFIMData imData; - imData.resizeFunc = logoResize; - imData.library = imageMagick; - - FFLogoImageResult result = ffLogoPrintImageImpl(instance, requestData, &imData); - - dlclose(imageMagick); - - return result; + return ffLogoPrintImageImpl(instance, requestData, &(FFIMData) { + .resizeFunc = logoResize, + .library = imageMagick, + }); } #endif diff --git a/src/logo/image/image.c b/src/logo/image/image.c index b2bfff6b5..7010dd815 100644 --- a/src/logo/image/image.c +++ b/src/logo/image/image.c @@ -1,5 +1,5 @@ #include "image.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/printing.h" #ifdef __APPLE__ @@ -131,14 +131,9 @@ static bool compressBlob(const FFinstance* instance, void** blob, size_t* length uLong compressedLength = ffcompressBound(*length); void* compressed = malloc(compressedLength); if(compressed == NULL) - { - dlclose(zlib); return false; - } - int compressResult = ffcompress2(compressed, &compressedLength, *blob, *length, Z_BEST_COMPRESSION); - dlclose(zlib); - if(compressResult != Z_OK) + if(ffcompress2(compressed, &compressedLength, *blob, *length, Z_BEST_COMPRESSION) != Z_OK) { free(compressed); return false; @@ -229,7 +224,7 @@ static void printImagePixels(FFinstance* instance, FFLogoRequestData* requestDat ffPrintCharTimes('\n', instance->config.logo.paddingTop); ffPrintCharTimes(' ', instance->config.logo.paddingLeft); fflush(stdout); - ffWriteFDBuffer(STDOUT_FILENO, result); + ffWriteFDBuffer(FFUnixFD2NativeFD(STDOUT_FILENO), result); //Go to upper left corner fputs("\033[9999999D", stdout); @@ -336,10 +331,7 @@ static bool printImageChafa(FFinstance* instance, FFLogoRequestData* requestData size_t length; void* blob = imageData->ffImageToBlob(imageData->imageInfo, imageData->image, &length, imageData->exceptionInfo); if(!checkAllocationResult(blob, length)) - { - dlclose(chafa); return false; - } ChafaSymbolMap* symbolMap = ffchafa_symbol_map_new(); GError* error = NULL; @@ -408,7 +400,6 @@ static bool printImageChafa(FFinstance* instance, FFLogoRequestData* requestData ffchafa_canvas_unref(canvas); ffchafa_canvas_config_unref(canvasConfig); ffchafa_symbol_map_unref(symbolMap); - dlclose(chafa); return true; } @@ -614,8 +605,8 @@ static bool printCachedPixel(FFinstance* instance, FFLogoRequestData* requestDat char buffer[32768]; ssize_t readBytes; - while((readBytes = read(fd, buffer, sizeof(buffer))) > 0) - FF_UNUSED(write(STDOUT_FILENO, buffer, (size_t) readBytes)); + while((readBytes = ffReadFDData(FFUnixFD2NativeFD(fd), sizeof(buffer), buffer)) > 0) + ffWriteFDData(FFUnixFD2NativeFD(STDOUT_FILENO), (size_t) readBytes, buffer); close(fd); @@ -673,7 +664,7 @@ static bool getCharacterPixelDimensions(FFLogoRequestData* requestData) return requestData->characterPixelWidth > 1.0 && requestData->characterPixelHeight > 1.0; } -static bool printImageIfExistsSlowPath(FFinstance* instance, FFLogoType type) +static bool printImageIfExistsSlowPath(FFinstance* instance, FFLogoType type, bool printError) { FFLogoRequestData requestData; requestData.type = type; @@ -684,7 +675,8 @@ static bool printImageIfExistsSlowPath(FFinstance* instance, FFLogoType type) (type != FF_LOGO_TYPE_IMAGE_CHAFA || instance->config.logo.width == 0 || instance->config.logo.height == 0) && !getCharacterPixelDimensions(&requestData) ) { - fputs("Logo: getCharacterPixelDimensions() failed", stderr); + if(printError) + fputs("Logo: getCharacterPixelDimensions() failed", stderr); return false; } @@ -693,14 +685,15 @@ static bool printImageIfExistsSlowPath(FFinstance* instance, FFLogoType type) ffStrbufInit(&requestData.cacheDir); ffStrbufAppend(&requestData.cacheDir, &instance->state.platform.cacheDir); - ffStrbufAppendS(&requestData.cacheDir, "fastfetch"); + ffStrbufAppendS(&requestData.cacheDir, "fastfetch/images"); ffStrbufEnsureFree(&requestData.cacheDir, PATH_MAX); if(realpath(instance->config.logo.source.chars, requestData.cacheDir.chars + requestData.cacheDir.length) == NULL) { //We can safely return here, because if realpath failed, we surely won't be able to read the file ffStrbufDestroy(&requestData.cacheDir); - fputs("Logo: Querying realpath of the image source failed", stderr); + if(printError) + fputs("Logo: Querying realpath of the image source failed", stderr); return false; } ffStrbufRecalculateLength(&requestData.cacheDir); @@ -730,26 +723,28 @@ static bool printImageIfExistsSlowPath(FFinstance* instance, FFLogoType type) ffStrbufDestroy(&requestData.cacheDir); - switch(result) + if(result == FF_LOGO_IMAGE_RESULT_SUCCESS) + return true; + + if(printError) { - case FF_LOGO_IMAGE_RESULT_INIT_ERROR: - fputs("Logo: Init Image Magick library failed\n", stderr); - return false; - case FF_LOGO_IMAGE_RESULT_RUN_ERROR: + if(result == FF_LOGO_IMAGE_RESULT_INIT_ERROR) + fputs("Logo: Image Magick library not found\n", stderr); + else fputs("Logo: Failed to load / convert the image source\n", stderr); - return false; - default: - return true; } + + return false; } #endif //FF_HAVE_IMAGEMAGICK{6, 7} -bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type) +bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type, bool printError) { - if(!ffFileExists(instance->config.logo.source.chars, S_IFREG)) + if(!ffPathExists(instance->config.logo.source.chars, FF_PATHTYPE_FILE)) { - fputs("Logo: Image file not found\n", stderr); + if(printError) + fprintf(stderr, "Logo: Image source \"%s\" does not exist\n", instance->config.logo.source.chars); return false; } @@ -764,18 +759,20 @@ bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type) ) return printImageKittyDirect(instance); - #ifndef FF_HAVE_CHAFA + #if !defined(FF_HAVE_CHAFA) if(type == FF_LOGO_TYPE_IMAGE_CHAFA) { - fputs("Logo: Fastfetch was built without Chafa support\n", stderr); + if(printError) + fputs("Logo: Chafa support is not compiled in\n", stderr); return false; } #endif - #if defined(FF_HAVE_IMAGEMAGICK7) || defined(FF_HAVE_IMAGEMAGICK6) - return printImageIfExistsSlowPath(instance, type); - #else - fputs("Logo: Fastfetch was built without ImageMagick support\n", stderr); + #if !defined(FF_HAVE_IMAGEMAGICK7) && !defined(FF_HAVE_IMAGEMAGICK6) + if(printError) + fputs("Logo: Image Magick support is not compiled in\n", stderr); return false; + #else + return printImageIfExistsSlowPath(instance, type, printError); #endif } diff --git a/src/logo/logo.c b/src/logo/logo.c index 60cbdf8bb..43d39bc97 100644 --- a/src/logo/logo.c +++ b/src/logo/logo.c @@ -1,5 +1,5 @@ #include "logo.h" -#include "common/io.h" +#include "common/io/io.h" #include "common/printing.h" #include "detection/os/os.h" #include "detection/terminalshell/terminalshell.h" @@ -280,15 +280,19 @@ static inline void logoPrintDetected(FFinstance* instance) logoPrintStruct(instance, logoGetBuiltinDetected(instance)); } -static void logoPrintData(FFinstance* instance, bool doColorReplacement) { +static bool logoPrintData(FFinstance* instance, bool doColorReplacement) { + if(instance->config.logo.source.length == 0) + return false; + ffLogoPrintChars(instance, instance->config.logo.source.chars, doColorReplacement); logoApplyColorsDetected(instance); + return true; } -static bool loadLogoFile(const FFinstance* instance, FFstrbuf* buffer) +static void updateLogoPath(FFinstance* instance) { - if(ffAppendFileBuffer(instance->config.logo.source.chars, buffer)) - return true; + if(ffPathExists(instance->config.logo.source.chars, FF_PATHTYPE_FILE)) + return; FFstrbuf fullPath; ffStrbufInit(&fullPath); @@ -300,15 +304,14 @@ static bool loadLogoFile(const FFinstance* instance, FFstrbuf* buffer) ffStrbufAppendS(&fullPath, "fastfetch/logos/"); ffStrbufAppend(&fullPath, &instance->config.logo.source); - if(ffAppendFileBuffer(fullPath.chars, buffer)) + if(ffPathExists(fullPath.chars, FF_PATHTYPE_FILE)) { - ffStrbufDestroy(&fullPath); - return true; + ffStrbufSet(&instance->config.logo.source, &fullPath); + break; } } ffStrbufDestroy(&fullPath); - return false; } static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement, bool raw) @@ -316,7 +319,7 @@ static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement, FFstrbuf content; ffStrbufInit(&content); - if(!loadLogoFile(instance, &content)) + if(!ffAppendFileBuffer(instance->config.logo.source.chars, &content)) { ffStrbufDestroy(&content); fputs("Logo: Failed to load file content from logo source\n", stderr); @@ -332,45 +335,57 @@ static bool logoPrintFileIfExists(FFinstance* instance, bool doColorReplacement, return true; } -static bool logoPrintImageIfExists(FFinstance* instance, FFLogoType logo) +static bool logoPrintImageIfExists(FFinstance* instance, FFLogoType logo, bool printError) { - if(!ffLogoPrintImageIfExists(instance, logo)) + if(!ffLogoPrintImageIfExists(instance, logo, printError)) return false; logoApplyColorsDetected(instance); return true; } -static void logoPrintKnownType(FFinstance* instance) +static bool logoTryKnownType(FFinstance* instance) { - bool successfull = true; + if(instance->config.logo.type == FF_LOGO_TYPE_NONE) + { + logoApplyColorsDetected(instance); + return true; + } if(instance->config.logo.type == FF_LOGO_TYPE_BUILTIN) - successfull = logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars); - else if(instance->config.logo.type == FF_LOGO_TYPE_FILE) - successfull = logoPrintFileIfExists(instance, true, false); - else if(instance->config.logo.type == FF_LOGO_TYPE_FILE_RAW) - successfull = logoPrintFileIfExists(instance, false, false); - else if(instance->config.logo.type == FF_LOGO_TYPE_DATA) - logoPrintData(instance, true); - else if(instance->config.logo.type == FF_LOGO_TYPE_DATA_RAW) - logoPrintData(instance, false); - else if(instance->config.logo.type == FF_LOGO_TYPE_IMAGE_RAW) + return logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars); + + if(instance->config.logo.type == FF_LOGO_TYPE_DATA) + return logoPrintData(instance, true); + + if(instance->config.logo.type == FF_LOGO_TYPE_DATA_RAW) + return logoPrintData(instance, false); + + updateLogoPath(instance); //We sure have a file, resolve relative paths + + if(instance->config.logo.type == FF_LOGO_TYPE_FILE) + return logoPrintFileIfExists(instance, true, false); + + if(instance->config.logo.type == FF_LOGO_TYPE_FILE_RAW) + return logoPrintFileIfExists(instance, false, false); + + if(instance->config.logo.type == FF_LOGO_TYPE_IMAGE_RAW) { if(instance->config.logo.width == 0 || instance->config.logo.height == 0) { fputs("both `--logo-width` and `--logo-height` must be specified\n", stderr); - successfull = false; + return false; } - else - successfull = logoPrintFileIfExists(instance, false, true); - } - else if(instance->config.logo.type == FF_LOGO_TYPE_NONE) - logoApplyColorsDetected(instance); - else //image - successfull = logoPrintImageIfExists(instance, instance->config.logo.type); - if(!successfull) + return logoPrintFileIfExists(instance, false, true); + } + + return logoPrintImageIfExists(instance, instance->config.logo.type, true); +} + +static void logoPrintKnownType(FFinstance* instance) +{ + if(!logoTryKnownType(instance)) logoPrintDetected(instance); } @@ -404,6 +419,9 @@ void ffLogoPrint(FFinstance* instance) if(logoPrintBuiltinIfExists(instance, instance->config.logo.source.chars)) return; + //Make sure the logo path is set correctly. + updateLogoPath(instance); + const FFTerminalShellResult* terminalShell = ffDetectTerminalShell(instance); //Terminal emulators that support kitty graphics protocol. @@ -414,7 +432,7 @@ void ffLogoPrint(FFinstance* instance) ffStrbufIgnCaseCompS(&terminalShell->terminalProcessName, "wayst") == 0; //Try to load the logo as an image. If it succeeds, print it and return. - if(logoPrintImageIfExists(instance, supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA)) + if(logoPrintImageIfExists(instance, supportsKitty ? FF_LOGO_TYPE_IMAGE_KITTY : FF_LOGO_TYPE_IMAGE_CHAFA, false)) return; //Try to load the logo as a file. If it succeeds, print it and return. diff --git a/src/logo/logo.h b/src/logo/logo.h index 4bdc6a54a..0664f6f98 100644 --- a/src/logo/logo.h +++ b/src/logo/logo.h @@ -24,6 +24,6 @@ const FFlogo* ffLogoBuiltinGetUnknown(); GetLogoMethod* ffLogoBuiltinGetAll(); //image/image.c -bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type); +bool ffLogoPrintImageIfExists(FFinstance* instance, FFLogoType type, bool printError); #endif diff --git a/src/modules/battery.c b/src/modules/battery.c index 79cdf4c79..6bafb0ee7 100644 --- a/src/modules/battery.c +++ b/src/modules/battery.c @@ -36,7 +36,8 @@ static void printBattery(FFinstance* instance, BatteryResult* result, uint8_t in { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffStrbufAppendF(&str, str.length > 0 ? "(%u%%)" : "%u%%", (unsigned) result->capacity); + + ffAppendPercentNum(instance, &str, (uint8_t) result->capacity, 51, 21, str.length > 0); } } diff --git a/src/modules/bluetooth.c b/src/modules/bluetooth.c new file mode 100644 index 000000000..6038acf01 --- /dev/null +++ b/src/modules/bluetooth.c @@ -0,0 +1,64 @@ +#include "common/printing.h" +#include "detection/bluetooth/bluetooth.h" + +#define FF_BLUETOOTH_MODULE_NAME "Bluetooth" +#define FF_BLUETOOTH_NUM_FORMAT_ARGS 4 + +static void printDevice(FFinstance* instance, const FFBluetoothDevice* device, uint8_t index) +{ + if(instance->config.bluetooth.outputFormat.length == 0) + { + ffPrintLogoAndKey(instance, FF_BLUETOOTH_MODULE_NAME, index, &instance->config.bluetooth.key); + ffStrbufWriteTo(&device->name, stdout); + + if(device->battery > 0) + printf(" (%d%%)", device->battery); + + putchar('\n'); + } + else + { + ffPrintFormat(instance, FF_BLUETOOTH_MODULE_NAME, index, &instance->config.bluetooth, FF_BLUETOOTH_NUM_FORMAT_ARGS, (FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->address}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->type}, + {FF_FORMAT_ARG_TYPE_UINT8, &device->battery} + }); + } +} + +void ffPrintBluetooth(FFinstance* instance) +{ + const FFBluetoothResult* bluetooth = ffDetectBluetooth(instance); + + if(bluetooth->error.length > 0) + { + ffPrintError(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth, "%s", bluetooth->error.chars); + return; + } + + FFlist filtered; + ffListInit(&filtered, sizeof(FFBluetoothDevice*)); + + FF_LIST_FOR_EACH(FFBluetoothDevice, device, bluetooth->devices) + { + if(!device->connected && !instance->config.bluetoothShowDisconnected) + continue; + + *(FFBluetoothDevice**)ffListAdd(&filtered) = device; + } + + if(filtered.length == 0) + { + ffPrintError(instance, FF_BLUETOOTH_MODULE_NAME, 0, &instance->config.bluetooth, "No bluetooth devices found"); + return; + } + + for(uint32_t i = 0; i < filtered.length; i++) + { + uint8_t index = (uint8_t) (filtered.length == 1 ? 0 : i + 1); + printDevice(instance, *(FFBluetoothDevice**)ffListGet(&filtered, i), index); + } + + ffListDestroy(&filtered); +} diff --git a/src/modules/cpuUsage.c b/src/modules/cpuUsage.c index 3e4165b90..f46de6259 100644 --- a/src/modules/cpuUsage.c +++ b/src/modules/cpuUsage.c @@ -29,7 +29,7 @@ void ffPrintCPUUsage(FFinstance* instance) { if(str.length > 0) ffStrbufAppendC(&str, ' '); - ffStrbufAppendF(&str, "%.2lf%%", percentage); + ffAppendPercentNum(instance, &str, (uint8_t) percentage, 50, 80, str.length > 0); } ffStrbufPutTo(&str, stdout); ffStrbufDestroy(&str); diff --git a/src/modules/date.c b/src/modules/date.c index 96ea03e1e..a92209ed0 100644 --- a/src/modules/date.c +++ b/src/modules/date.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/printing.h" -#include "detection/datetime.h" +#include "detection/datetime/datetime.h" #define FF_DATE_MODULE_NAME "Date" diff --git a/src/modules/datetime.c b/src/modules/datetime.c index 61745c16a..25f08da5a 100644 --- a/src/modules/datetime.c +++ b/src/modules/datetime.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/printing.h" -#include "detection/datetime.h" +#include "detection/datetime/datetime.h" #define FF_DATETIME_MODULE_NAME "Date & Time" #define FF_DATETIME_NUM_FORMAT_ARGS 20 diff --git a/src/modules/disk.c b/src/modules/disk.c index c1e074812..d2311f11f 100644 --- a/src/modules/disk.c +++ b/src/modules/disk.c @@ -53,7 +53,8 @@ static void printDisk(FFinstance* instance, const FFDisk* disk) if(instance->config.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) { - ffStrbufAppendF(&str, str.length > 0 ? "(%u%%) " : "%u%% ", bytesPercentage); + ffAppendPercentNum(instance, &str, (uint8_t) bytesPercentage, 50, 80, str.length > 0); + ffStrbufAppendC(&str, ' '); } } else diff --git a/src/modules/display.c b/src/modules/display.c index 45d93234b..cc6971f1a 100644 --- a/src/modules/display.c +++ b/src/modules/display.c @@ -3,7 +3,7 @@ #include "detection/displayserver/displayserver.h" #define FF_RESOLUTION_MODULE_NAME "Display" -#define FF_RESOLUTION_NUM_FORMAT_ARGS 3 +#define FF_RESOLUTION_NUM_FORMAT_ARGS 5 void ffPrintDisplay(FFinstance* instance) { diff --git a/src/modules/font.c b/src/modules/font.c index 0b2e05e16..29d3fac15 100644 --- a/src/modules/font.c +++ b/src/modules/font.c @@ -77,7 +77,7 @@ void ffPrintFont(FFinstance* instance) const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); - if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0) + if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) { ffPrintError(instance, FF_FONT_MODULE_NAME, 0, &instance->config.font, "Font isn't supported in TTY"); return; diff --git a/src/modules/gamepad.c b/src/modules/gamepad.c new file mode 100644 index 000000000..7b935a972 --- /dev/null +++ b/src/modules/gamepad.c @@ -0,0 +1,48 @@ +#include "common/printing.h" +#include "detection/gamepad/gamepad.h" + +#define FF_GAMEPAD_MODULE_NAME "Gamepad" +#define FF_GAMEPAD_NUM_FORMAT_ARGS 2 + +static void printDevice(FFinstance* instance, const FFGamepadDevice* device, uint8_t index) +{ + if(instance->config.sound.outputFormat.length == 0) + { + ffPrintLogoAndKey(instance, FF_GAMEPAD_MODULE_NAME, index, &instance->config.sound.key); + ffStrbufPutTo(&device->name, stdout); + } + else + { + ffPrintFormat(instance, FF_GAMEPAD_MODULE_NAME, index, &instance->config.sound, FF_GAMEPAD_NUM_FORMAT_ARGS, (FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier}, + }); + } +} + +void ffPrintGamepad(FFinstance* instance) +{ + FF_LIST_AUTO_DESTROY result; + ffListInit(&result, sizeof(FFGamepadDevice)); + const char* error = ffDetectGamepad(instance, &result); + + if(error) + { + ffPrintError(instance, FF_GAMEPAD_MODULE_NAME, 0, &instance->config.sound, "%s", error); + return; + } + + if(!result.length) + { + ffPrintError(instance, FF_GAMEPAD_MODULE_NAME, 0, &instance->config.sound, "No devices detected"); + return; + } + + uint8_t index = 0; + FF_LIST_FOR_EACH(FFGamepadDevice, device, result) + { + printDevice(instance, device, result.length > 1 ? ++index : 0); + ffStrbufDestroy(&device->identifier); + ffStrbufDestroy(&device->name); + } +} diff --git a/src/modules/gpu.c b/src/modules/gpu.c index 6c673df36..0033d33be 100644 --- a/src/modules/gpu.c +++ b/src/modules/gpu.c @@ -1,4 +1,6 @@ #include "fastfetch.h" +#include "common/bar.h" +#include "common/parsing.h" #include "common/printing.h" #include "detection/host/host.h" #include "detection/gpu/gpu.h" @@ -14,7 +16,7 @@ static void printGPUResult(FFinstance* instance, uint8_t index, const FFGPUResul { ffPrintLogoAndKey(instance, FF_GPU_MODULE_NAME, index, &instance->config.gpu.key); - FFstrbuf output; + FF_STRBUF_AUTO_DESTROY output; ffStrbufInitA(&output, gpu->vendor.length + 1 + gpu->name.length); if(gpu->vendor.length > 0 && !ffStrbufStartsWith(&gpu->name, &gpu->vendor)) @@ -31,9 +33,25 @@ static void printGPUResult(FFinstance* instance, uint8_t index, const FFGPUResul if(gpu->temperature == gpu->temperature) //FF_GPU_TEMP_UNSET ffStrbufAppendF(&output, " - %.1f°C", gpu->temperature); - ffStrbufPutTo(&output, stdout); + if(gpu->dedicated.total != FF_GPU_VMEM_SIZE_UNSET && gpu->dedicated.total != 0) + { + ffStrbufAppendS(&output, " ("); - ffStrbufDestroy(&output); + if(gpu->dedicated.used != FF_GPU_VMEM_SIZE_UNSET) + { + ffParseSize(gpu->dedicated.used, instance->config.binaryPrefixType, &output); + ffStrbufAppendS(&output, " / "); + } + ffParseSize(gpu->dedicated.total, instance->config.binaryPrefixType, &output); + if(gpu->dedicated.used != FF_GPU_VMEM_SIZE_UNSET) + { + ffStrbufAppendS(&output, ", "); + ffAppendPercentNum(instance, &output, (uint8_t) (gpu->dedicated.used * 100 / gpu->dedicated.total), 50, 80, false); + } + ffStrbufAppendC(&output, ')'); + } + + ffStrbufPutTo(&output, stdout); } else { diff --git a/src/modules/icons.c b/src/modules/icons.c index 4597cf2e8..81fa3af9d 100644 --- a/src/modules/icons.c +++ b/src/modules/icons.c @@ -1,8 +1,7 @@ #include "fastfetch.h" #include "common/printing.h" #include "common/parsing.h" -#include "detection/qt.h" -#include "detection/gtk.h" +#include "detection/gtk_qt/gtk_qt.h" #include "detection/displayserver/displayserver.h" #define FF_ICONS_MODULE_NAME "Icons" @@ -20,7 +19,7 @@ void ffPrintIcons(FFinstance* instance) const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); - if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0) + if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) { ffPrintError(instance, FF_ICONS_MODULE_NAME, 0, &instance->config.icons, "Icons aren't supported in TTY"); return; diff --git a/src/modules/localip.c b/src/modules/localip.c index 3a445c5e5..f0429e0a0 100644 --- a/src/modules/localip.c +++ b/src/modules/localip.c @@ -5,9 +5,79 @@ #define FF_LOCALIP_MODULE_NAME "Local IP" #define FF_LOCALIP_NUM_FORMAT_ARGS 2 +static int sortIpsV4First(const FFLocalIpResult* left, const FFLocalIpResult* right) +{ + int name = ffStrbufComp(&left->name, &right->name); + if (name != 0) + return name; + + if (left->ipv6 != right->ipv6) + return left->ipv6 == false ? -1 : 1; + + return ffStrbufComp(&left->addr, &right->addr); +} + +static int sortIpsV6First(const FFLocalIpResult* left, const FFLocalIpResult* right) +{ + int name = ffStrbufComp(&left->name, &right->name); + if (name != 0) + return name; + + if (left->ipv6 != right->ipv6) + return left->ipv6 == true ? -1 : 1; + + return ffStrbufComp(&left->addr, &right->addr); +} + +static void formatKey(const FFinstance* instance, const FFLocalIpResult* ip, FFstrbuf* key) +{ + if(instance->config.localIP.key.length == 0) + { + if(ip->name.length) + ffStrbufSetF(key, FF_LOCALIP_MODULE_NAME " (%*s)", ip->name.length, ip->name.chars); + else + ffStrbufSetS(key, FF_LOCALIP_MODULE_NAME); + } + else + { + ffStrbufClear(key); + ffParseFormatString(key, &instance->config.localIP.key, 1, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRBUF, &ip->name} + }); + } +} + +static void printIpsOneline(FFlist* ips) +{ + uint32_t index = 0; + FF_LIST_FOR_EACH(FFLocalIpResult, ip, *ips) + { + if (index++ > 0) + putchar(' '); + ffStrbufWriteTo(&ip->addr, stdout); + } +} + +static void printIpsWithKey(FFinstance* instance, FFlist* ips) +{ + FFLocalIpResult* ip = (FFLocalIpResult*) ffListGet(ips, 0); + if (instance->config.localIpCompactType == FF_LOCALIP_COMPACT_TYPE_MULTILINE) + { + FF_STRBUF_AUTO_DESTROY key; + ffStrbufInit(&key); + formatKey(instance, ip, &key); + ffPrintLogoAndKey(instance, key.chars, 0, NULL); + } + printIpsOneline(ips); + if (instance->config.localIpCompactType == FF_LOCALIP_COMPACT_TYPE_ONELINE) + printf(" (%s) ", ip->name.chars); + else + putchar('\n'); +} + void ffPrintLocalIp(FFinstance* instance) { - FFlist results; + FF_LIST_AUTO_DESTROY results; ffListInit(&results, sizeof(FFLocalIpResult)); const char* error = ffDetectLocalIps(instance, &results); @@ -15,56 +85,59 @@ void ffPrintLocalIp(FFinstance* instance) if(error) { ffPrintError(instance, FF_LOCALIP_MODULE_NAME, 0, &instance->config.localIP, "%s", error); - goto exit; + return; } if(results.length == 0) { ffPrintError(instance, FF_LOCALIP_MODULE_NAME, 0, &instance->config.localIP, "Failed to detect any IPs"); - goto exit; + return; } - FFstrbuf key; - ffStrbufInit(&key); + ffListSort(&results, instance->config.localIpV6First ? (void*) sortIpsV6First : (void*) sortIpsV4First); - for(uint32_t i = 0; i < results.length; ++i) + if (instance->config.localIpCompactType != FF_LOCALIP_COMPACT_TYPE_NONE) { - FFLocalIpResult* ip = (FFLocalIpResult*) ffListGet(&results, i); + if (instance->config.localIpCompactType == FF_LOCALIP_COMPACT_TYPE_ONELINE) + ffPrintLogoAndKey(instance, FF_LOCALIP_MODULE_NAME, 0, &instance->config.localIP.key); - if(instance->config.localIP.key.length == 0) - { - if(ip->name.length) - ffStrbufSetF(&key, FF_LOCALIP_MODULE_NAME " (%*s)", ip->name.length, ip->name.chars); - else - ffStrbufSetS(&key, FF_LOCALIP_MODULE_NAME); - } - else - { - ffStrbufClear(&key); - ffParseFormatString(&key, &instance->config.localIP.key, 1, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRBUF, &ip->name} - }); - } + FF_LIST_AUTO_DESTROY ips; + ffListInit(&ips, sizeof(FFLocalIpResult)); // weak references - if(instance->config.localIP.outputFormat.length == 0) + FF_LIST_FOR_EACH(FFLocalIpResult, ip, results) { - ffPrintLogoAndKey(instance, key.chars, 0, NULL); - ffStrbufPutTo(&ip->addr, stdout); + if (ips.length > 0 && !ffStrbufEqual(&ip->name, &ip[-1].name)) + { + printIpsWithKey(instance, &ips); + ips.length = 0; + } + *(FFLocalIpResult*)ffListAdd(&ips) = *ip; } - else - { - ffPrintFormatString(instance, key.chars, 0, NULL, &instance->config.localIP.outputFormat, FF_LOCALIP_NUM_FORMAT_ARGS, (FFformatarg[]){ - {FF_FORMAT_ARG_TYPE_STRBUF, &ip->addr}, - {FF_FORMAT_ARG_TYPE_STRING, ip->ipv6 ? "IPv6" : "IPv4"} - }); - } - - ffStrbufDestroy(&ip->name); - ffStrbufDestroy(&ip->addr); + printIpsWithKey(instance, &ips); } + else + { + FF_STRBUF_AUTO_DESTROY key; + ffStrbufInit(&key); - ffStrbufDestroy(&key); + FF_LIST_FOR_EACH(FFLocalIpResult, ip, results) + { + formatKey(instance, ip, &key); + if(instance->config.localIP.outputFormat.length == 0) + { + ffPrintLogoAndKey(instance, key.chars, 0, NULL); + ffStrbufPutTo(&ip->addr, stdout); + } + else + { + ffPrintFormatString(instance, key.chars, 0, NULL, &instance->config.localIP.outputFormat, FF_LOCALIP_NUM_FORMAT_ARGS, (FFformatarg[]){ + {FF_FORMAT_ARG_TYPE_STRBUF, &ip->addr}, + {FF_FORMAT_ARG_TYPE_STRING, ip->ipv6 ? "IPv6" : "IPv4"} + }); + } -exit: - ffListDestroy(&results); + ffStrbufDestroy(&ip->name); + ffStrbufDestroy(&ip->addr); + } + } } diff --git a/src/modules/memory.c b/src/modules/memory.c index fbb893f02..05d7c33cf 100644 --- a/src/modules/memory.c +++ b/src/modules/memory.c @@ -56,7 +56,7 @@ static void printMemory(FFinstance* instance, const char* name, const FFModuleAr ffStrbufAppendF(&str, "%s / %s ", usedPretty.chars, totalPretty.chars); if(instance->config.percentType & FF_PERCENTAGE_TYPE_NUM_BIT) - ffStrbufAppendF(&str, str.length > 0 ? "(%u%%)" : "%u%%", percentage); + ffAppendPercentNum(instance, &str, (uint8_t) percentage, 50, 80, str.length > 0); ffStrbufTrimRight(&str, ' '); ffStrbufPutTo(&str, stdout); diff --git a/src/modules/opencl.c b/src/modules/opencl.c index debfcd45e..621165742 100644 --- a/src/modules/opencl.c +++ b/src/modules/opencl.c @@ -7,13 +7,14 @@ #if defined(FF_HAVE_OPENCL) || defined(__APPLE__) #include "common/library.h" #include "common/parsing.h" +#include "util/stringUtils.h" #include #define CL_TARGET_OPENCL_VERSION 100 -#ifdef __APPLE__ - #include -#else +#ifdef FF_HAVE_OPENCL #include +#else + #include #endif typedef struct OpenCLData @@ -23,7 +24,7 @@ typedef struct OpenCLData FF_LIBRARY_SYMBOL(clGetDeviceInfo) } OpenCLData; -static const char* openCLHandelData(FFinstance* instance, OpenCLData* data) +static const char* openCLHandleData(FFinstance* instance, OpenCLData* data) { cl_platform_id platformID; cl_uint numPlatforms; @@ -83,17 +84,20 @@ static const char* printOpenCL(FFinstance* instance) { OpenCLData data; - FF_LIBRARY_LOAD(opencl, &instance->config.libOpenCL, "dlopen libOpenCL"FF_LIBRARY_EXTENSION" failed", "libOpenCL"FF_LIBRARY_EXTENSION, 1); + FF_LIBRARY_LOAD(opencl, &instance->config.libOpenCL, "dlopen libOpenCL"FF_LIBRARY_EXTENSION" failed", + #ifdef _WIN32 + "OpenCL"FF_LIBRARY_EXTENSION, -1, + #endif + "libOpenCL"FF_LIBRARY_EXTENSION, 1 + ); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetPlatformIDs); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetDeviceIDs); FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(opencl, data, clGetDeviceInfo); - const char* error = openCLHandelData(instance, &data); - dlclose(opencl); - return error; + return openCLHandleData(instance, &data); } -#elif __APPLE__ // FF_HAVE_OPENCL +#elif defined(__APPLE__) // FF_HAVE_OPENCL static const char* printOpenCL(FFinstance* instance) { @@ -102,10 +106,10 @@ static const char* printOpenCL(FFinstance* instance) data.ffclGetDeviceIDs = clGetDeviceIDs; data.ffclGetDeviceInfo = clGetDeviceInfo; - return openCLHandelData(instance, &data); + return openCLHandleData(instance, &data); } -#endif // __APPLE__ +#endif // FF_HAVE_OPENCL void ffPrintOpenCL(FFinstance* instance) { diff --git a/src/modules/sound.c b/src/modules/sound.c new file mode 100644 index 000000000..4ef58cdc2 --- /dev/null +++ b/src/modules/sound.c @@ -0,0 +1,82 @@ +#include "common/printing.h" +#include "detection/sound/sound.h" + +#define FF_SOUND_MODULE_NAME "Sound" +#define FF_SOUND_NUM_FORMAT_ARGS 4 + +static void printDevice(FFinstance* instance, const FFSoundDevice* device, uint8_t index) +{ + if(instance->config.sound.outputFormat.length == 0) + { + ffPrintLogoAndKey(instance, FF_SOUND_MODULE_NAME, index, &instance->config.sound.key); + ffStrbufWriteTo(&device->name, stdout); + + if(device->volume > 0) + printf(" (%d%%)", device->volume); + else + fputs(" (muted)", stdout); + + if(device->main && index > 0) + fputs(" (*)", stdout); + + putchar('\n'); + } + else + { + ffPrintFormat(instance, FF_SOUND_MODULE_NAME, index, &instance->config.sound, FF_SOUND_NUM_FORMAT_ARGS, (FFformatarg[]) { + {FF_FORMAT_ARG_TYPE_BOOL, &device->main}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->name}, + {FF_FORMAT_ARG_TYPE_UINT8, &device->volume}, + {FF_FORMAT_ARG_TYPE_STRBUF, &device->identifier} + }); + } +} + +static void printSound(FFinstance* instance, FFlist* devices) +{ + FF_LIST_AUTO_DESTROY filtered; + ffListInit(&filtered, sizeof(FFSoundDevice*)); + + FF_LIST_FOR_EACH(FFSoundDevice, device, *devices) + { + switch (instance->config.soundType) + { + case FF_SOUND_TYPE_MAIN: if (!device->main) continue; break; + case FF_SOUND_TYPE_ACTIVE: if (!device->active) continue; break; + case FF_SOUND_TYPE_ALL: break; + } + + *(FFSoundDevice**)ffListAdd(&filtered) = device; + } + + if(filtered.length == 0) + { + ffPrintError(instance, FF_SOUND_MODULE_NAME, 0, &instance->config.sound, "No active sound devices found"); + return; + } + + uint8_t index = 1; + FF_LIST_FOR_EACH(FFSoundDevice*, device, filtered) + printDevice(instance, *device, filtered.length == 1 ? 0 : index++); +} + +void ffPrintSound(FFinstance* instance) +{ + FF_LIST_AUTO_DESTROY result; + ffListInit(&result, sizeof(FFSoundDevice)); + const char* error = ffDetectSound(instance, &result); + + if(error) + { + ffPrintError(instance, FF_SOUND_MODULE_NAME, 0, &instance->config.sound, "%s", error); + return; + } + + printSound(instance, &result); + + FF_LIST_FOR_EACH(FFSoundDevice, device, result) + { + ffStrbufDestroy(&device->identifier); + ffStrbufDestroy(&device->name); + } +} diff --git a/src/modules/theme.c b/src/modules/theme.c index 5c10ee485..04a2e1d7b 100644 --- a/src/modules/theme.c +++ b/src/modules/theme.c @@ -1,8 +1,7 @@ #include "fastfetch.h" #include "common/printing.h" #include "common/parsing.h" -#include "detection/qt.h" -#include "detection/gtk.h" +#include "detection/gtk_qt/gtk_qt.h" #include "detection/displayserver/displayserver.h" #define FF_THEME_MODULE_NAME "Theme" @@ -20,7 +19,7 @@ void ffPrintTheme(FFinstance* instance) const FFDisplayServerResult* wmde = ffConnectDisplayServer(instance); - if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, "TTY") == 0) + if(ffStrbufIgnCaseCompS(&wmde->wmProtocolName, FF_WM_PROTOCOL_TTY) == 0) { ffPrintError(instance, FF_THEME_MODULE_NAME, 0, &instance->config.theme, "Theme isn't supported in TTY"); return; diff --git a/src/modules/time.c b/src/modules/time.c index d06b5b714..523e4fa19 100644 --- a/src/modules/time.c +++ b/src/modules/time.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/printing.h" -#include "detection/datetime.h" +#include "detection/datetime/datetime.h" #define FF_TIME_MODULE_NAME "Time" diff --git a/src/modules/vulkan.c b/src/modules/vulkan.c index 4b3d19fea..23c6f60df 100644 --- a/src/modules/vulkan.c +++ b/src/modules/vulkan.c @@ -1,6 +1,6 @@ #include "fastfetch.h" #include "common/printing.h" -#include "detection/vulkan.h" +#include "detection/vulkan/vulkan.h" #define FF_VULKAN_MODULE_NAME "Vulkan" #define FF_VULKAN_NUM_FORMAT_ARGS 3 diff --git a/src/util/FFstrbuf.c b/src/util/FFstrbuf.c index 375c53aaa..94f436d51 100644 --- a/src/util/FFstrbuf.c +++ b/src/util/FFstrbuf.c @@ -3,17 +3,6 @@ #include #include -bool ffStrSet(const char* str) -{ - if(str == NULL) - return false; - - while(isspace(*str)) - str++; - - return *str != '\0'; -} - static char* CHAR_NULL_PTR = ""; void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate) diff --git a/src/util/FFstrbuf.h b/src/util/FFstrbuf.h index 7342cb607..7755225a7 100644 --- a/src/util/FFstrbuf.h +++ b/src/util/FFstrbuf.h @@ -18,8 +18,6 @@ #define strcasestr StrStrIA #endif -bool ffStrSet(const char* str); - #define FASTFETCH_STRBUF_DEFAULT_ALLOC 32 typedef struct FFstrbuf diff --git a/src/util/FFvaluestore.c b/src/util/FFvaluestore.c index 6b0407500..68040045b 100644 --- a/src/util/FFvaluestore.c +++ b/src/util/FFvaluestore.c @@ -2,7 +2,7 @@ #include -typedef char KeyType[33]; //32 byte key + \0 +typedef char KeyType[32]; //31 byte key + \0 void ffValuestoreInit(FFvaluestore* vs, uint32_t valueSize) { diff --git a/src/util/FFvaluestore.h b/src/util/FFvaluestore.h index c59b584a6..4d966837c 100644 --- a/src/util/FFvaluestore.h +++ b/src/util/FFvaluestore.h @@ -10,7 +10,7 @@ typedef FFlist FFvaluestore; void ffValuestoreInit(FFvaluestore* vs, uint32_t valueSize); FF_C_NODISCARD void* ffValuestoreGet(FFvaluestore* vs, const char* key); -void* ffValuestoreSet(FFvaluestore* vs, const char* key, bool* created); //created may be NULL +FF_C_NODISCARD void* ffValuestoreSet(FFvaluestore* vs, const char* key, bool* created); //created may be NULL void ffValuestoreDestroy(FFvaluestore* vs); #endif diff --git a/src/util/apple/cf_helpers.h b/src/util/apple/cf_helpers.h index d3cb66d43..52755bb8b 100644 --- a/src/util/apple/cf_helpers.h +++ b/src/util/apple/cf_helpers.h @@ -13,4 +13,17 @@ const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result) const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result); const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result); +static inline CFNumberRef ffCfCreateInt(int value) +{ + return CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &value); +} + +static inline void cfReleaseWrapper(void* type) +{ + if (*(CFTypeRef*) type) + CFRelease(*(CFTypeRef*) type); +} + +#define FF_CFTYPE_AUTO_RELEASE __attribute__((__cleanup__(cfReleaseWrapper))) + #endif diff --git a/src/util/mallocHelper.h b/src/util/mallocHelper.h index a4fd8eb6e..18aa801bf 100644 --- a/src/util/mallocHelper.h +++ b/src/util/mallocHelper.h @@ -2,6 +2,7 @@ static inline void ffWrapFree(void* pPtr) { + assert(pPtr); if(*(void**)pPtr) free(*(void**)pPtr); } diff --git a/src/util/platform/FFPlatform.c b/src/util/platform/FFPlatform.c index d549b6501..2a880aed1 100644 --- a/src/util/platform/FFPlatform.c +++ b/src/util/platform/FFPlatform.c @@ -1,4 +1,5 @@ #include "FFPlatform_private.h" +#include "util/stringUtils.h" void ffPlatformInit(FFPlatform* platform) { diff --git a/src/util/platform/FFPlatform_unix.c b/src/util/platform/FFPlatform_unix.c index 393d2290b..a971d75c5 100644 --- a/src/util/platform/FFPlatform_unix.c +++ b/src/util/platform/FFPlatform_unix.c @@ -1,5 +1,5 @@ #include "FFPlatform_private.h" - +#include "util/stringUtils.h" #include "fastfetch_config.h" #include @@ -8,10 +8,7 @@ static void getHomeDir(FFPlatform* platform, const struct passwd* pwd) { - const char* home = getenv("HOME"); - if(!ffStrSet(home) && pwd) - home = pwd->pw_dir; - + const char* home = pwd ? pwd->pw_dir : getenv("HOME"); ffStrbufAppendS(&platform->homeDir, home); ffStrbufEnsureEndsWithC(&platform->homeDir, '/'); } @@ -29,8 +26,6 @@ static void getCacheDir(FFPlatform* platform) ffStrbufAppend(&platform->cacheDir, &platform->homeDir); ffStrbufAppendS(&platform->cacheDir, ".cache/"); } - - ffStrbufAppendS(&platform->cacheDir, "fastfetch/"); } static void getConfigDirs(FFPlatform* platform) @@ -46,11 +41,11 @@ static void getConfigDirs(FFPlatform* platform) ffPlatformPathAddEnv(&platform->configDirs, "XDG_CONFIG_DIRS"); #if !defined(__APPLE__) - ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC"/xdg/"); + ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/xdg/"); #endif - ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC"/"); - ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_INSTALL_SYSCONF"/"); + ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_ETC "/"); + ffPlatformPathAddAbsolute(&platform->configDirs, FASTFETCH_TARGET_DIR_INSTALL_SYSCONF "/"); } static void getDataDirs(FFPlatform* platform) @@ -59,13 +54,13 @@ static void getDataDirs(FFPlatform* platform) ffPlatformPathAddHome(&platform->dataDirs, platform, ".local/share/"); #if defined(__APPLE__) - ffPlatformPathAddHome(&platform->dataDirs, platform, "/Library/Application Support/"); + ffPlatformPathAddHome(&platform->dataDirs, platform, "Library/Application Support/"); #endif ffPlatformPathAddHome(&platform->dataDirs, platform, ""); ffPlatformPathAddEnv(&platform->dataDirs, "XDG_DATA_DIRS"); - ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR"/local/share/"); - ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR"/share/"); + ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/local/share/"); + ffPlatformPathAddAbsolute(&platform->dataDirs, FASTFETCH_TARGET_DIR_USR "/share/"); } static void getUserName(FFPlatform* platform, const struct passwd* pwd) diff --git a/src/util/platform/FFPlatform_windows.c b/src/util/platform/FFPlatform_windows.c index 2fff50ef5..60e4249b4 100644 --- a/src/util/platform/FFPlatform_windows.c +++ b/src/util/platform/FFPlatform_windows.c @@ -1,4 +1,5 @@ #include "FFPlatform_private.h" +#include "util/stringUtils.h" #define WIN32_LEAN_AND_MEAN #include @@ -33,8 +34,6 @@ static void getCacheDir(FFPlatform* platform) ffStrbufAppendS(&platform->cacheDir, "AppData/Local/"); } CoTaskMemFree(pPath); - - ffStrbufAppendS(&platform->cacheDir, "fastfetch/"); } static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId) @@ -70,40 +69,33 @@ static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* static void getConfigDirs(FFPlatform* platform) { - ffListInit(&platform->configDirs, sizeof(FFstrbuf)); - - ffPlatformPathAddEnv(&platform->configDirs, "XDG_CONFIG_HOME"); - ffPlatformPathAddHome(&platform->configDirs, platform, "/.config/"); - platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_RoamingAppData); - platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_LocalAppData); - ffPlatformPathAddHome(&platform->configDirs, platform, ""); - - if(getenv("MSYSTEM") && getenv("HOME")) + if(getenv("MSYSTEM")) { // We are in MSYS2 / Git Bash platformPathAddEnvSuffix(&platform->configDirs, "HOME", ".config/"); platformPathAddEnvSuffix(&platform->configDirs, "HOME", ""); + platformPathAddEnvSuffix(&platform->configDirs, "MINGW_PREFIX", "etc"); } - ffPlatformPathAddEnv(&platform->configDirs, "XDG_CONFIG_DIRS"); + ffPlatformPathAddHome(&platform->configDirs, platform, ".config/"); + platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_RoamingAppData); + platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_LocalAppData); + ffPlatformPathAddHome(&platform->configDirs, platform, ""); } static void getDataDirs(FFPlatform* platform) { - ffPlatformPathAddEnv(&platform->dataDirs, "XDG_DATA_HOME"); - ffPlatformPathAddHome(&platform->dataDirs, platform, "/.local/share/"); - platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_RoamingAppData); - platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_LocalAppData); - ffPlatformPathAddHome(&platform->dataDirs, platform, ""); - if(getenv("MSYSTEM") && getenv("HOME")) { // We are in MSYS2 / Git Bash platformPathAddEnvSuffix(&platform->dataDirs, "HOME", ".local/share/"); platformPathAddEnvSuffix(&platform->dataDirs, "HOME", ""); + platformPathAddEnvSuffix(&platform->dataDirs, "MINGW_PREFIX", "share"); } - - ffPlatformPathAddEnv(&platform->dataDirs, "XDG_DATA_DIRS"); + ffPlatformPathAddHome(&platform->dataDirs, platform, ".local/share/"); + platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_RoamingAppData); + platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_LocalAppData); + ffPlatformPathAddHome(&platform->dataDirs, platform, ""); } static void getUserName(FFPlatform* platform) diff --git a/src/util/stringUtils.c b/src/util/stringUtils.c new file mode 100644 index 000000000..703c81a45 --- /dev/null +++ b/src/util/stringUtils.c @@ -0,0 +1,29 @@ +#include "stringUtils.h" + +#include +#include + +bool ffStrSet(const char* str) +{ + if(str == NULL) + return false; + + while(isspace(*str)) + str++; + + return *str != '\0'; +} + +bool ffStrHasNChars(const char* str, char c, uint32_t n) +{ + for(uint32_t i = 0; i < n; i++) + { + char* current = strchr(str, c); + if(current == NULL) + return false; + + str = current + 1; + } + + return true; +} diff --git a/src/util/stringUtils.h b/src/util/stringUtils.h new file mode 100644 index 000000000..7c2475353 --- /dev/null +++ b/src/util/stringUtils.h @@ -0,0 +1,12 @@ +#pragma once + +#ifndef FF_INCLUDED_util_stringUtils_h +#define FF_INCLUDED_util_stringUtils_h + +#include +#include + +bool ffStrSet(const char* str); +bool ffStrHasNChars(const char* str, char c, uint32_t n); + +#endif diff --git a/src/util/windows/com.cpp b/src/util/windows/com.cpp new file mode 100644 index 000000000..c11cccf95 --- /dev/null +++ b/src/util/windows/com.cpp @@ -0,0 +1,51 @@ +#include "com.hpp" +#include "fastfetch.h" + +#include +#include + +//https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer +//https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes +static void CoUninitializeWrap() +{ + CoUninitialize(); +} + +static BOOL CALLBACK InitHandleFunction(FF_MAYBE_UNUSED PINIT_ONCE lpInitOnce, FF_MAYBE_UNUSED PVOID lpParameter, PVOID* lpContext) +{ + // Initialize COM + if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED))) + { + *lpContext = (PVOID) "CoInitializeEx() failed"; + return FALSE; + } + + // Set general COM security levels + if (FAILED(CoInitializeSecurity( + NULL, + -1, // COM authentication + NULL, // Authentication services + NULL, // Reserved + RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication + RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation + NULL, // Authentication info + EOAC_NONE, // Additional capabilities + NULL // Reserved + ))) + { + CoUninitialize(); + *lpContext = (PVOID) "CoInitializeSecurity() failed"; + return FALSE; + } + + atexit(CoUninitializeWrap); + return TRUE; +} + +const char* ffInitCom(void) +{ + const char* error = NULL; + static INIT_ONCE s_InitOnce; + InitOnceExecuteOnce(&s_InitOnce, &InitHandleFunction, NULL, (void**)&error); + return error; +} diff --git a/src/util/windows/com.hpp b/src/util/windows/com.hpp new file mode 100644 index 000000000..e0f1051ae --- /dev/null +++ b/src/util/windows/com.hpp @@ -0,0 +1,25 @@ +#pragma once + +#ifndef FF_INCLUDED_util_windows_com +#define FF_INCLUDED_util_windows_com + +#ifdef __cplusplus + +#include + +const char* ffInitCom(void); + +static inline void ffReleaseComObject(void* ppUnknown) +{ + IUnknown* pUnknown = *(IUnknown**) ppUnknown; + if (pUnknown) pUnknown->Release(); +} + +#define FF_AUTO_RELEASE_COM_OBJECT __attribute__((__cleanup__(ffReleaseComObject))) + +#else + // Win32 COM headers requires C++ compiler + #error Must be included in C++ source file +#endif + +#endif diff --git a/src/util/windows/registry.c b/src/util/windows/registry.c index 2257e1963..0a80781d3 100644 --- a/src/util/windows/registry.c +++ b/src/util/windows/registry.c @@ -1,82 +1,99 @@ -#include "registry.h" -#include "unicode.h" -#include "util/mallocHelper.h" - -static const char* hKey2Str(HKEY hKey) -{ - #define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey; - HKEY_CASE(HKEY_CLASSES_ROOT) - HKEY_CASE(HKEY_CURRENT_USER) - HKEY_CASE(HKEY_LOCAL_MACHINE) - HKEY_CASE(HKEY_USERS) - HKEY_CASE(HKEY_PERFORMANCE_DATA) - HKEY_CASE(HKEY_PERFORMANCE_TEXT) - HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT) - HKEY_CASE(HKEY_CURRENT_CONFIG) - HKEY_CASE(HKEY_DYN_DATA) - HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS) - #undef HKEY_CASE - - return "UNKNOWN"; -} - -bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error) -{ - if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS) - { - if(error) - { - FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW); - ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars); - } - return false; - } - return true; -} - -bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error) -{ - DWORD bufSize; //with tailing '\0' - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueA(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars); - } - return false; - } - wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueA(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars); - } - return false; - } - ffStrbufSetWS(result, resultW); - return true; -} - -bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) -{ - DWORD bufSize = sizeof(*result); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueA(%s, result, RRF_RT_DWORD) failed", valueNameA.chars); - } - return false; - } - return true; -} +#include "registry.h" +#include "unicode.h" +#include "util/mallocHelper.h" + +static const char* hKey2Str(HKEY hKey) +{ + #define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey; + HKEY_CASE(HKEY_CLASSES_ROOT) + HKEY_CASE(HKEY_CURRENT_USER) + HKEY_CASE(HKEY_LOCAL_MACHINE) + HKEY_CASE(HKEY_USERS) + HKEY_CASE(HKEY_PERFORMANCE_DATA) + HKEY_CASE(HKEY_PERFORMANCE_TEXT) + HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT) + HKEY_CASE(HKEY_CURRENT_CONFIG) + HKEY_CASE(HKEY_DYN_DATA) + HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS) + #undef HKEY_CASE + + return "UNKNOWN"; +} + +bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error) +{ + if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS) + { + if(error) + { + FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW); + ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars); + } + return false; + } + return true; +} + +bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error) +{ + DWORD bufSize; //with tailing '\0' + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars); + } + return false; + } + wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize); + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars); + } + return false; + } + ffStrbufSetWS(result, resultW); + return true; +} + +bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) +{ + DWORD bufSize = sizeof(*result); + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_DWORD) failed", valueNameA.chars); + } + return false; + } + return true; +} + +bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error) +{ + DWORD bufSize = sizeof(*result); + if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_QWORD, NULL, result, &bufSize) != ERROR_SUCCESS) + { + if(error) + { + if(!valueNameW) + valueNameW = L"(default)"; + FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); + ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_QWORD) failed", valueNameA.chars); + } + return false; + } + return true; +} diff --git a/src/util/windows/registry.h b/src/util/windows/registry.h index 22aa6f9ce..d9eb67666 100644 --- a/src/util/windows/registry.h +++ b/src/util/windows/registry.h @@ -5,8 +5,7 @@ #include "fastfetch.h" -#define WIN32_LEAN_AND_MEAN -#include +#include static inline void wrapRegCloseKey(HKEY* phKey) { @@ -19,5 +18,6 @@ static inline void wrapRegCloseKey(HKEY* phKey) bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error); bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error); bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error); +bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error); #endif diff --git a/src/util/windows/wmi.cpp b/src/util/windows/wmi.cpp index 1da4ac0ff..b8e576fd5 100644 --- a/src/util/windows/wmi.cpp +++ b/src/util/windows/wmi.cpp @@ -1,4 +1,5 @@ #include "wmi.hpp" +#include "util/windows/com.hpp" #include #include @@ -19,40 +20,10 @@ namespace }; } -//https://learn.microsoft.com/en-us/windows/win32/wmisdk/example--getting-wmi-data-from-the-local-computer -//https://learn.microsoft.com/en-us/windows/win32/cimwin32prov/computer-system-hardware-classes -static void CoUninitializeWrap() -{ - CoUninitialize(); -} - static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lpContext) { HRESULT hres; - // Initialize COM - hres = CoInitializeEx(nullptr, COINIT_MULTITHREADED); - - // Set general COM security levels - hres = CoInitializeSecurity( - nullptr, - -1, // COM authentication - nullptr, // Authentication services - nullptr, // Reserved - RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication - RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation - nullptr, // Authentication info - EOAC_NONE, // Additional capabilities - nullptr // Reserved - ); - - if (FAILED(hres)) - { - CoUninitialize(); - *((const char**)lpContext) = "Failed to initialize security"; - return FALSE; - } - // Obtain the initial locator to WMI IWbemLocator* pLoc = nullptr; hres = CoCreateInstance( @@ -64,7 +35,6 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp if (FAILED(hres)) { - CoUninitialize(); *((const char**)lpContext) = "Failed to create IWbemLocator object"; return FALSE; } @@ -90,7 +60,6 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp if (FAILED(hres)) { - CoUninitialize(); *((const char**)lpContext) = "Could not connect WMI server"; return FALSE; } @@ -110,21 +79,26 @@ static BOOL CALLBACK InitHandleFunction(PINIT_ONCE, PVOID lpParameter, PVOID* lp if (FAILED(hres)) { pSvc->Release(); - CoUninitialize(); *((const char**)lpContext) = "Could not set proxy blanket"; return FALSE; } *((IWbemServices**)lpContext) = pSvc; - atexit(CoUninitializeWrap); return TRUE; } FFWmiQuery::FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error, FFWmiNamespace wmiNs) : pEnumerator(nullptr) { + const char* context = ffInitCom(); + if (context) + { + if (error) + ffStrbufAppendS(error, context); + return; + } + static INIT_ONCE s_InitOnce[(int) FFWmiNamespace::LAST] = {}; - const char* context; if (InitOnceExecuteOnce( &s_InitOnce[(int)wmiNs], &InitHandleFunction, @@ -137,9 +111,7 @@ FFWmiQuery::FFWmiQuery(const wchar_t* queryStr, FFstrbuf* error, FFWmiNamespace } // Use the IWbemServices pointer to make requests of WMI - HRESULT hres; - - hres = ((IWbemServices*)context)->ExecQuery( + HRESULT hres = ((IWbemServices*)context)->ExecQuery( bstr_t(L"WQL"), bstr_t(queryStr), WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, diff --git a/src/util/windows/wmi.hpp b/src/util/windows/wmi.hpp index 25bef6e91..32ce0bcb4 100644 --- a/src/util/windows/wmi.hpp +++ b/src/util/windows/wmi.hpp @@ -9,6 +9,7 @@ extern "C" { #include "util/FFstrbuf.h" } +#include #include enum class FFWmiNamespace { @@ -17,6 +18,10 @@ enum class FFWmiNamespace { LAST, }; +enum { + FF_WMI_QUERY_TIMEOUT = 5000 +}; + struct FFWmiRecord { IWbemClassObject* obj; @@ -25,7 +30,7 @@ struct FFWmiRecord if(!pEnumerator) return; ULONG ret; - bool ok = SUCCEEDED(pEnumerator->Next((LONG)WBEM_INFINITE, 1, &obj, &ret)) && ret; + bool ok = SUCCEEDED(pEnumerator->Next(FF_WMI_QUERY_TIMEOUT, 1, &obj, &ret)) && ret; if(!ok) obj = nullptr; } FFWmiRecord(const FFWmiRecord&) = delete;