mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 10:22:12 +02:00
Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e0452d9db5 | |||
| d8e74ba84c | |||
| 04b13096ac | |||
| 64d4035cae | |||
| 5e0ba57f53 | |||
| d89263c218 | |||
| 6a42588786 | |||
| 5883bf359c | |||
| 6a6b4070ca | |||
| 2c80cd6d29 | |||
| fa4b00b027 | |||
| 5fdc924b5d | |||
| 3d4a117093 | |||
| 7ec0c664c5 | |||
| 9d2df589b5 | |||
| 7107d08e92 | |||
| 4c34f99c12 | |||
| d7a8c92b46 | |||
| bbb29ff766 | |||
| 35235b9557 | |||
| 6b94605804 | |||
| 4b2fa07fdc | |||
| e203f4eeaf | |||
| 8db70b40e2 | |||
| 1f967849e5 | |||
| d60b2ddfd4 | |||
| fb68d8a841 | |||
| 047411ba87 | |||
| 08ed14b42a | |||
| d94a41cc1b | |||
| 81b7fb06c1 | |||
| c8debccd16 | |||
| 2853bd15c0 | |||
| 2f4146fde8 | |||
| eeceade14e | |||
| 1875c78e96 | |||
| f389864e17 | |||
| b9317734b9 | |||
| 4df4a1de78 | |||
| 0cd8c6ead6 | |||
| f8479dae94 | |||
| a7d623fa75 | |||
| 7a8ffb27bd | |||
| 73c0347469 | |||
| fde5f3bd0f | |||
| 9e1b1302fb | |||
| 7e235b6be0 | |||
| f43e1fd614 | |||
| c7b061eebd | |||
| a0f579072f | |||
| d439ce8eb5 | |||
| e2a714732a | |||
| a993a6f126 | |||
| 8eb8f710d0 | |||
| 526868e355 | |||
| 768238cb46 | |||
| 2d938042d0 | |||
| 9a54d92e9f | |||
| 839abab744 | |||
| c054570308 | |||
| ed69a7059b | |||
| 6b92659512 | |||
| 7e04305d1c | |||
| 87e13543da | |||
| 7a2cbc060f | |||
| f22d73d473 | |||
| e629126d73 | |||
| 9ac635e2e6 | |||
| 1b1b0521f4 | |||
| 41d0f61ee0 | |||
| 9de5d9008b | |||
| 576a9cc6fe | |||
| bd61d08afe | |||
| 4672b78481 | |||
| 36b0fdbcda | |||
| 7626ef6eaa | |||
| 115108b3f1 | |||
| 154f9f462b | |||
| a96a9fc31d | |||
| 23b43244c5 | |||
| 9dfb404a0d | |||
| ff3028c656 | |||
| 2f706ed494 | |||
| 06427ee62b | |||
| fe66eb3df0 | |||
| 6e1ab12399 | |||
| 484e05eae3 | |||
| 5d3fb98072 | |||
| 0c30590088 | |||
| 20cd4ce125 | |||
| 1c7aa89228 | |||
| f270255770 | |||
| 4b62a3c75b | |||
| 1557f0c556 | |||
| ef7f61309f | |||
| f59491b25d | |||
| e3592eb2c3 | |||
| 305776eb94 | |||
| 599e0d393d | |||
| 561574ae94 | |||
| 3dd78422eb | |||
| 5c546ab8e7 | |||
| 3e9274040d | |||
| 630d876e2d | |||
| 1938be86ff | |||
| 0980d5f0ad | |||
| d8c1b3b61b | |||
| 969523ae8a | |||
| 5d960ec744 | |||
| 3b36b8ca57 | |||
| 05f14764e6 | |||
| 3a180b24e3 | |||
| 02ab58e001 | |||
| fd158b41e1 | |||
| 89e0ede12f | |||
| 4d7b2410ef | |||
| c1f6a2f755 | |||
| 9c455c3b0f | |||
| d4ea9dfd21 | |||
| 08071e6e7e | |||
| ec87174f30 | |||
| 835e5b51c9 | |||
| 07c5ef255e | |||
| 476b55c17d | |||
| 4a53cfa312 | |||
| 50ea515476 | |||
| cbd9f72bc8 | |||
| 29eaa35f4c | |||
| 97c89c39d3 |
+1
-1
@@ -1,5 +1,5 @@
|
||||
[codespell]
|
||||
check-filenames =
|
||||
builtin = clear,rare,usage,informal
|
||||
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
|
||||
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii,./src/detection/gpu/asahi_drm.h
|
||||
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,slave,sur,doas,conexant,ags,bu
|
||||
|
||||
@@ -383,7 +383,7 @@ jobs:
|
||||
run: |
|
||||
cat /etc/alpine-release
|
||||
uname -a
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
shell: alpine.sh --root {0}
|
||||
|
||||
- name: build
|
||||
@@ -597,6 +597,80 @@ jobs:
|
||||
name: fastfetch-netbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
dragonfly-amd64:
|
||||
name: DragonFly-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
with:
|
||||
usesh: yes
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update
|
||||
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-dragonfly-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
haiku-amd64:
|
||||
name: Haiku-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: 'r1beta5'
|
||||
run: |
|
||||
uname -a
|
||||
ls -l
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-haiku-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
windows-amd64:
|
||||
name: Windows-amd64
|
||||
runs-on: windows-latest
|
||||
|
||||
+89
-4
@@ -1,12 +1,97 @@
|
||||
# 2.45.0
|
||||
|
||||
Features:
|
||||
* Support OnePlus marketing name detection (#1768, Host, Android)
|
||||
* Recognize additional GPU vendors (GPU, Linux)
|
||||
* Support CTWM, FVWM and I3 window manager version detection (WM)
|
||||
* Support KDE version detection on *BSD (DE, FreeBSD)
|
||||
* Support `"logo": { "type": "command-raw" }` to run a command and display its output as logo (#1780, Logo)
|
||||
* Useful for displaying custom logos generated by other programs such as `pokeget`: `{ "type": "command-raw", "source": "pokeget random --hide-name" }`
|
||||
* Supported in JSONC config file only. `pokeget random --hide-name | fastfetch --file-raw -` should be used in shell.
|
||||
* Acquire SMBIOS information on DragonFly BSD from `/dev/mem`; legacy BIOS only (PhysicalMemory, DragonFly)
|
||||
* Support swap usage detection on DragonFly BSD (Swap, DragonFly)
|
||||
* Support `--swap-separate` to display detailed swap devices on separate lines (Swap)
|
||||
|
||||
Bugfixes
|
||||
* Fix MacBook Air model name (#1779, Host, macOS)
|
||||
* Don't ignore sshfs mountpoints (#1776, Disk, Linux / FreeBSD)
|
||||
* Fix dnf package count detection (#1777, Packages, Linux)
|
||||
|
||||
Logos:
|
||||
* Add Starry Linux (#1771)
|
||||
* Add rhel_small (#1774)
|
||||
* Update color palette of voidlinux (#1775)
|
||||
* Add void2
|
||||
* Update Xenia Linux (#1783)
|
||||
|
||||
# 2.44.0
|
||||
|
||||
Features:
|
||||
* Add option `--disk-hide-folders` and `--disk-hide-fs` to hide specific mountpoints and filesystems in Disk module (Disk)
|
||||
* `--disk-hide-folders` defaults to `/efi:/boot:/boot/efi` on Linux and *BSD. Previously these EFI-related folders were hardcoded to be hidden on Linux.
|
||||
|
||||
Bugfixes:
|
||||
* Fix Apple Terminal compatibility with `--stat` (macOS, #1755)
|
||||
* Ignore `/usr/bin/script` when detecting shell and terminal (Terminal / Shell, #1761)
|
||||
* Fix compatibility with KDE Plasma 6.4 which is in beta currently (Display, Linux, #1765)
|
||||
|
||||
Logos:
|
||||
* Add Kylin (#1760)
|
||||
* Add UBLinux (#1764)
|
||||
|
||||
# 2.43.0
|
||||
|
||||
Features:
|
||||
* Support physical core count and package count detection on Solaris (CPU, SunOS)
|
||||
* Improve physical core count detection on FreeBSD (CPU, FreeBSD)
|
||||
* Add option to hide unknown GPUs (GPU)
|
||||
* Detect VRAM type of AMD GPUs on Linux (GPU, Linux)
|
||||
* Support playing media detection on macOS 15.4 (#1737, Media, macOS)
|
||||
* Whether it works on newer versions is unknown
|
||||
* Detect player name for Windows UMP apps (Media, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix disk usage detection on 32-bit Linux (#1734, Disk, Linux)
|
||||
* Fix compiling on Asahi Linux (GPU, Linux)
|
||||
* Fix duplicated playback status (Media, Linux)
|
||||
* Don't show 255 in custom format when muted on macOS (#1750, Sound, macOS)
|
||||
* Remove shared memory detection for AMD GPUs, which doesn't work as expected (GPU, Windows)
|
||||
|
||||
Logos:
|
||||
* new AthenaOS
|
||||
* add Hydra Framework
|
||||
|
||||
# 2.42.0
|
||||
|
||||
Changes:
|
||||
* Normalize the module name `Bios` to `BIOS` (#1721)
|
||||
* No configuration file changes are required because fastfetch parses module names case-insensitively.
|
||||
|
||||
Bugfixes:
|
||||
* Disable disk type detection for virtual disks (PhysicalDisk, Linux, #1669)
|
||||
* Fix incorrect CPU temperature reporting (CPU, OpenBSD)
|
||||
* Fix setting `logo.chafa.symbols` in JSON configuration (Logo, #1709)
|
||||
* Fix non-normalized time display (Uptime, #1720)
|
||||
* Miscellaneous minor fixes
|
||||
|
||||
Features:
|
||||
* Add CPU temperature detection support (CPU, SunOS)
|
||||
* Improve CPU frequency detection (CPU, NetBSD)
|
||||
* Add Wi-Fi detection support (Wifi, NetBSD)
|
||||
* Add Webcam detection support (Camera, OpenBSD)
|
||||
* Requires root privileges
|
||||
|
||||
Logos:
|
||||
* Remove GoralixOS logo (#1699)
|
||||
* Add Aurora logo (#1700)
|
||||
* Add Codex Linux logo (#1701)
|
||||
|
||||
# 2.41.0
|
||||
|
||||
Changes:
|
||||
* Due to [the deprecation](https://github.com/actions/runner-images/issues/11101), Linux x86_64 binaries are now built with Ubuntu 22.04 (Glibc 2.35, Debian 12)
|
||||
* You can always build fastfetch yourself on your own. Please don't report bugs related to this change.
|
||||
|
||||
Bugfixes:
|
||||
* Don't detect disk type for virtual disks (PhysicalDisk, Linux, #1669)
|
||||
|
||||
Features:
|
||||
* Support physical core count detection on non-x86 platforms (CPU, Linux / FreeBSD)
|
||||
* Support CPU frequency detection on PPC64 (CPU, FreeBSD)
|
||||
@@ -881,7 +966,7 @@ Bugfixes:
|
||||
* Fix some presets
|
||||
* Better detection for XTerm terminal fonts (#1095, TerminalFont, Linux)
|
||||
* Remove debug output (#1097, Windows)
|
||||
* Fix command line option `--gpu-hide-type` doesn't work (#1098, GPU)
|
||||
* Fix flag `--gpu-hide-type` doesn't work (#1098, GPU)
|
||||
* Fix wrong date on Raspbian 10 (#1108, DateTime, Linux)
|
||||
* Use `brightness` instead of `actuall_brightness` when detecting current brightness level (Brightness, Linux)
|
||||
* Ref: https://bugzilla.kernel.org/show_bug.cgi?id=203905
|
||||
|
||||
+36
-11
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.12.0) # target_link_libraries with OBJECT libs & project homepage url
|
||||
|
||||
project(fastfetch
|
||||
VERSION 2.41.0
|
||||
VERSION 2.45.0
|
||||
LANGUAGES C
|
||||
DESCRIPTION "Fast neofetch-like system information tool"
|
||||
HOMEPAGE_URL "https://github.com/fastfetch-cli/fastfetch"
|
||||
@@ -326,6 +326,11 @@ endif()
|
||||
fastfetch_encode_c_string("${DATATEXT_JSON_HELP}" DATATEXT_JSON_HELP)
|
||||
fastfetch_load_text(src/data/structure.txt DATATEXT_STRUCTURE)
|
||||
|
||||
if(APPLE)
|
||||
# See src/detection/media/media_apple.m
|
||||
fastfetch_load_text(src/data/nowPlaying.scptd DATATEXT_NOWPLAYING)
|
||||
endif()
|
||||
|
||||
configure_file(src/fastfetch_config.h.in fastfetch_config.h @ONLY)
|
||||
configure_file(src/fastfetch_datatext.h.in fastfetch_datatext.h @ONLY)
|
||||
if(APPLE)
|
||||
@@ -342,7 +347,6 @@ foreach(file ${LOGO_FILES})
|
||||
fastfetch_load_text("${file}" content)
|
||||
get_filename_component(file "${file}" NAME_WE)
|
||||
string(TOUPPER "${file}" file)
|
||||
string(REGEX REPLACE "\\$\\{c([0-9]+)\\}" "$\\1" content "${content}")
|
||||
set(LOGO_BUILTIN_H "${LOGO_BUILTIN_H}#define FASTFETCH_DATATEXT_LOGO_${file} ${content}\n")
|
||||
endforeach()
|
||||
file(GENERATE OUTPUT logo_builtin.h CONTENT "${LOGO_BUILTIN_H}")
|
||||
@@ -783,7 +787,7 @@ elseif(NetBSD)
|
||||
src/detection/netio/netio_bsd.c
|
||||
src/detection/opengl/opengl_linux.c
|
||||
src/detection/os/os_nbsd.c
|
||||
src/detection/packages/packages_obsd.c
|
||||
src/detection/packages/packages_nbsd.c
|
||||
src/detection/poweradapter/poweradapter_nosupport.c
|
||||
src/detection/processes/processes_nbsd.c
|
||||
src/detection/gtk_qt/qt.c
|
||||
@@ -797,8 +801,8 @@ elseif(NetBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_linux.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nosupport.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wifi/wifi_nbsd.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -879,8 +883,8 @@ elseif(OpenBSD)
|
||||
src/detection/uptime/uptime_bsd.c
|
||||
src/detection/users/users_obsd.c
|
||||
src/detection/wallpaper/wallpaper_linux.c
|
||||
src/detection/wifi/wifi_nbsd.c
|
||||
src/detection/wm/wm_nosupport.c
|
||||
src/detection/wifi/wifi_obsd.c
|
||||
src/detection/wm/wm_linux.c
|
||||
src/detection/de/de_linux.c
|
||||
src/detection/wmtheme/wmtheme_linux.c
|
||||
src/detection/camera/camera_linux.c
|
||||
@@ -1834,10 +1838,26 @@ if (BUILD_TESTS)
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-color
|
||||
tests/color.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-color
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
add_executable(fastfetch-test-duration
|
||||
tests/duration.c
|
||||
)
|
||||
target_link_libraries(fastfetch-test-duration
|
||||
PRIVATE libfastfetch
|
||||
)
|
||||
|
||||
enable_testing()
|
||||
add_test(NAME test-strbuf COMMAND fastfetch-test-strbuf)
|
||||
add_test(NAME test-list COMMAND fastfetch-test-list)
|
||||
add_test(NAME test-format COMMAND fastfetch-test-format)
|
||||
add_test(NAME test-color COMMAND fastfetch-test-color)
|
||||
add_test(NAME test-duration COMMAND fastfetch-test-duration)
|
||||
endif()
|
||||
|
||||
##################
|
||||
@@ -1941,12 +1961,17 @@ if(LINUX)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_program(HAVE_RPMBUILD "rpmbuild")
|
||||
if(HAVE_RPMBUILD)
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||
if(NOT IS_MUSL)
|
||||
find_program(HAVE_RPMBUILD "rpmbuild")
|
||||
if(HAVE_RPMBUILD)
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};RPM")
|
||||
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
endif()
|
||||
endif()
|
||||
elseif(FreeBSD)
|
||||
set(CPACK_FREEBSD_PACKAGE_LICENSE "MIT")
|
||||
set(CPACK_GENERATOR "${CPACK_GENERATOR};FREEBSD")
|
||||
endif()
|
||||
|
||||
set(CPACK_SET_DESTDIR ON)
|
||||
|
||||
@@ -21,6 +21,8 @@ Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for
|
||||
<img src="screenshots/example3.png" width="48%" align="top" />
|
||||
<img src="screenshots/example5.png" height="15%" align="top" />
|
||||
|
||||
According configuration files for examples are located [here](https://github.com/fastfetch-cli/fastfetch/tree/dev/presets/examples).
|
||||
|
||||
There are [screenshots on different platforms](https://github.com/fastfetch-cli/fastfetch/wiki).
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -62,11 +62,17 @@ end
|
||||
echo '
|
||||
import json, subprocess, sys
|
||||
|
||||
|
||||
def main():
|
||||
data: dict[str, list[dict]] = json.loads(subprocess.check_output(["fastfetch", "--help-raw"]))
|
||||
|
||||
for key in data:
|
||||
for flag in data[key]:
|
||||
if flag["long"] == "logo-color-[1-9]":
|
||||
for i in range(1, 10):
|
||||
print(f"""complete -c fastfetch -d "{flag["desc"]}" -l "logo-color-{i}" -x -a "(__fastfetch_complete_color)" """)
|
||||
continue
|
||||
|
||||
if flag.get("pseudo", False):
|
||||
continue
|
||||
|
||||
@@ -75,7 +81,7 @@ def main():
|
||||
command_prefix += f""" -o {flag["short"]}"""
|
||||
|
||||
if "arg" in flag:
|
||||
type: str = flag["arg"]["type"];
|
||||
type: str = flag["arg"]["type"]
|
||||
if type == "bool":
|
||||
print(f"{command_prefix} -x -a \"(__fastfetch_complete_bool)\"")
|
||||
elif type == "color":
|
||||
@@ -98,6 +104,7 @@ def main():
|
||||
else:
|
||||
print(f"{command_prefix} -f")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
main()
|
||||
|
||||
Vendored
+36
@@ -1,3 +1,39 @@
|
||||
fastfetch (2.44.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.44.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 26 May 2025 14:59:01 +0800
|
||||
|
||||
fastfetch (2.43.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.43.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 14 May 2025 09:49:50 +0800
|
||||
|
||||
fastfetch (2.42.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.42.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 30 Apr 2025 14:08:57 +0800
|
||||
|
||||
fastfetch (2.41.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.41.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 16 Apr 2025 13:42:58 +0800
|
||||
|
||||
fastfetch (2.40.4) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.4
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 10 Apr 2025 15:38:21 +0800
|
||||
|
||||
fastfetch (2.40.3) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.3
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 07 Apr 2025 09:29:27 +0800
|
||||
|
||||
fastfetch (2.40.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.40.0
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
fastfetch_2.40.0_source.buildinfo universe/utils optional
|
||||
fastfetch_2.44.0_source.buildinfo universe/utils optional
|
||||
|
||||
+12
-2
@@ -115,7 +115,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"biosFormat": {
|
||||
"description": "Output format of the module `Bios`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
|
||||
"description": "Output format of the module `BIOS`. See Wiki for formatting syntax\n 1. {date}: Bios date\n 2. {release}: Bios release\n 3. {vendor}: Bios vendor\n 4. {version}: Bios version\n 5. {type}: Firmware type",
|
||||
"type": "string"
|
||||
},
|
||||
"bluetoothFormat": {
|
||||
@@ -339,7 +339,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"titleFormat": {
|
||||
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)",
|
||||
"description": "Output format of the module `Title`. See Wiki for formatting syntax\n 1. {user-name}: User name\n 2. {host-name}: Host name\n 3. {home-dir}: Home directory\n 4. {exe-path}: Executable path of current process\n 5. {user-shell}: User's default shell\n 6. {user-name-colored}: User name (colored)\n 7. {at-symbol-colored}: @ symbol (colored)\n 8. {host-name-colored}: Host name (colored)\n 9. {full-user-name}: Full user name",
|
||||
"type": "string"
|
||||
},
|
||||
"themeFormat": {
|
||||
@@ -429,6 +429,7 @@
|
||||
"file-raw",
|
||||
"data",
|
||||
"data-raw",
|
||||
"command-raw",
|
||||
"sixel",
|
||||
"kitty",
|
||||
"kitty-direct",
|
||||
@@ -1754,6 +1755,14 @@
|
||||
"type": "string",
|
||||
"description": "A colon (semicolon on Windows) separated list of folder paths for the disk output\nDefault: auto detection using mount-points\nThis option overrides other `show*` options"
|
||||
},
|
||||
"hideFolders": {
|
||||
"type": "string",
|
||||
"description": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output\nDefault: /efi:/boot:/boot/efi"
|
||||
},
|
||||
"hideFS": {
|
||||
"type": "string",
|
||||
"description": "A colon separated file systems to hide from the disk output"
|
||||
},
|
||||
"showExternal": {
|
||||
"type": "boolean",
|
||||
"description": "Set if external volume should be printed",
|
||||
@@ -2053,6 +2062,7 @@
|
||||
"enum": [
|
||||
"integrated",
|
||||
"discrete",
|
||||
"unknown",
|
||||
"none"
|
||||
],
|
||||
"default": "none"
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ibireme/yyjson",
|
||||
"license": "MIT ( embed in source )",
|
||||
"version": "0.10.0",
|
||||
"version": "0.11.1",
|
||||
"author": "ibireme"
|
||||
}
|
||||
|
||||
Vendored
+2508
-1264
File diff suppressed because it is too large
Load Diff
Vendored
+800
-570
File diff suppressed because it is too large
Load Diff
@@ -134,7 +134,7 @@ void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ static const char* printJsonConfig(bool prepare, yyjson_mut_doc* jsonDoc)
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e[s\e[1A\e[9999999C\e[%dD%s\e[u", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
if (ffCharIsEnglishAlphabet(value[0]))
|
||||
{
|
||||
FF_APPEND_COLOR_CODE_COND(reset_, FF_COLOR_MODE_RESET)
|
||||
else FF_APPEND_COLOR_CODE_COND(bold_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(bright_, FF_COLOR_MODE_BOLD)
|
||||
else FF_APPEND_COLOR_CODE_COND(dim_, FF_COLOR_MODE_DIM)
|
||||
else FF_APPEND_COLOR_CODE_COND(italic_, FF_COLOR_MODE_ITALIC)
|
||||
@@ -212,6 +213,35 @@ void ffOptionParseColorNoClear(const char* value, FFstrbuf* buffer)
|
||||
exit(479);
|
||||
}
|
||||
}
|
||||
else if (value[0] == '#')
|
||||
{
|
||||
// RGB color
|
||||
++value;
|
||||
char* pend = NULL;
|
||||
uint32_t rgb = (uint32_t) strtoul(value, &pend, 16);
|
||||
if (pend == value) {
|
||||
fprintf(stderr, "Error: invalid RGB color code found: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
if (pend - value > 6) {
|
||||
fprintf(stderr, "Error: RGB color code too long: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
else if (pend - value == 3) {
|
||||
rgb = ((rgb & 0xF00) >> 8) * 0x110000 +
|
||||
((rgb & 0x0F0) >> 4) * 0x001100 +
|
||||
((rgb & 0x00F) >> 0) * 0x000011;
|
||||
}
|
||||
else if (pend - value != 6) {
|
||||
fprintf(stderr, "Error: invalid RGB color code length: %s\n", value);
|
||||
exit(479);
|
||||
}
|
||||
|
||||
uint32_t r = rgb >> 16, g = (rgb >> 8) & 0xFF, b = rgb & 0xFF;
|
||||
ffStrbufAppendF(buffer, FF_COLOR_FG_RGB "%u;%u;%u", r, g, b);
|
||||
value = pend;
|
||||
continue;
|
||||
}
|
||||
ffStrbufAppendC(buffer, *value);
|
||||
++value;
|
||||
|
||||
|
||||
+15
-8
@@ -190,19 +190,26 @@ void ffParseGTK(FFstrbuf* buffer, const FFstrbuf* gtk2, const FFstrbuf* gtk3, co
|
||||
}
|
||||
}
|
||||
|
||||
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result)
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
if(days == 0 && hours == 0 && minutes == 0)
|
||||
if(totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendF(result, "%u seconds", seconds);
|
||||
ffStrbufAppendF(result, "%u second", (unsigned) totalSeconds);
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
if(seconds >= 30)
|
||||
{
|
||||
minutes++;
|
||||
seconds = 0;
|
||||
}
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
totalSeconds++;
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
uint32_t hours = (uint32_t) (totalSeconds % 24);
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if(days > 0)
|
||||
{
|
||||
|
||||
@@ -27,4 +27,4 @@ int8_t ffVersionCompare(const FFVersion* version1, const FFVersion* version2);
|
||||
|
||||
void ffParseSize(uint64_t bytes, FFstrbuf* result);
|
||||
bool ffParseFrequency(uint32_t mhz, FFstrbuf* result);
|
||||
void ffParseDuration(uint32_t days, uint32_t hours, uint32_t minutes, uint32_t seconds, FFstrbuf* result);
|
||||
void ffParseDuration(uint64_t totalSeconds, FFstrbuf* result);
|
||||
|
||||
@@ -100,7 +100,7 @@ void ffPrintFormat(const char* moduleName, uint8_t moduleIndex, const FFModuleAr
|
||||
ffStrbufPutTo(&buffer, stdout);
|
||||
}
|
||||
|
||||
static void printError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, va_list arguments)
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
if(!instance.config.display.showErrors)
|
||||
return;
|
||||
@@ -110,7 +110,10 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_ERROR, stdout);
|
||||
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
vprintf(message, arguments);
|
||||
va_end(arguments);
|
||||
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
@@ -118,14 +121,6 @@ static void printError(const char* moduleName, uint8_t moduleIndex, const FFModu
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
void ffPrintError(const char* moduleName, uint8_t moduleIndex, const FFModuleArgs* moduleArgs, FFPrintType printType, const char* message, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, message);
|
||||
printError(moduleName, moduleIndex, moduleArgs, printType, message, arguments);
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
void ffPrintColor(const FFstrbuf* colorValue)
|
||||
{
|
||||
//If the color is not set, this would reset in \033[m, which resets everything.
|
||||
|
||||
+18
-1
@@ -840,6 +840,22 @@
|
||||
"default": "Auto detection using mount-points"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-folders",
|
||||
"desc": "A colon (semicolon on Windows) separated list of folder paths to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "path",
|
||||
"default": "/efi:/boot:/boot/efi"
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-hide-fs",
|
||||
"desc": "A colon separated list of file systems to hide from the disk output",
|
||||
"arg": {
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"long": "disk-show-regular",
|
||||
"desc": "Specify whether regular volumes should be displayed",
|
||||
@@ -1139,12 +1155,13 @@
|
||||
},
|
||||
{
|
||||
"long": "gpu-hide-type",
|
||||
"desc": "Specify which types of GPUs should not be displayed",
|
||||
"desc": "Specify which types of GPUs should not be displayed (default: all GPUs are shown, regardless of recognition)",
|
||||
"arg": {
|
||||
"type": "enum",
|
||||
"enum": {
|
||||
"integrated": "Hide integrated GPUs",
|
||||
"discrete": "Hide discrete GPUs",
|
||||
"unknown": "Hide unknown (unrecognized) GPUs",
|
||||
"none": "Do not hide any GPUs"
|
||||
},
|
||||
"default": "none"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
use scripting additions
|
||||
use framework "/System/Library/PrivateFrameworks/MediaRemote.framework"
|
||||
|
||||
set MRNowPlayingRequest to current application's NSClassFromString("MRNowPlayingRequest")
|
||||
|
||||
if MRNowPlayingRequest's localNowPlayingItem() is missing value then
|
||||
return
|
||||
end if
|
||||
|
||||
if MRNowPlayingRequest's localIsPlaying() then
|
||||
set status to "Playing"
|
||||
else
|
||||
set status to "Paused"
|
||||
end if
|
||||
|
||||
set infoDict to MRNowPlayingRequest's localNowPlayingItem()'s nowPlayingInfo()
|
||||
set bundleObj to MRNowPlayingRequest's localNowPlayingPlayerPath()'s client()
|
||||
|
||||
return status & "
|
||||
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoTitle" as text) & "
|
||||
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoArtist" as text) & "
|
||||
" & (infoDict's valueForKey:"kMRMediaRemoteNowPlayingInfoAlbum" as text) & "
|
||||
" & (bundleObj's bundleIdentifier() as text) & "
|
||||
" & (bundleObj's displayName() as text)
|
||||
@@ -232,7 +232,7 @@ static uint32_t connectedDevices(void)
|
||||
|
||||
#endif
|
||||
|
||||
const char* ffDetectBluetooth(FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
const char* ffDetectBluetooth(FF_MAYBE_UNUSED FFBluetoothOptions* options, FF_MAYBE_UNUSED FFlist* devices /* FFBluetoothResult */)
|
||||
{
|
||||
#ifdef FF_HAVE_DBUS
|
||||
int32_t connectedCount = -1;
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#if FF_HAVE_LINUX_VIDEODEV2
|
||||
#include <linux/videodev2.h>
|
||||
#elif __has_include(<sys/videoio.h>) // OpenBSD
|
||||
#include <sys/videoio.h>
|
||||
#define FF_HAVE_LINUX_VIDEODEV2 1
|
||||
#endif
|
||||
|
||||
const char* ffDetectCamera(FFlist* result)
|
||||
@@ -19,7 +22,13 @@ const char* ffDetectCamera(FFlist* result)
|
||||
path[ARRAY_SIZE(path) - 2] = (char) (i + '0');
|
||||
FF_AUTO_CLOSE_FD int fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
break;
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
return "Failed to open /dev/videoN";
|
||||
}
|
||||
|
||||
struct v4l2_capability cap = {};
|
||||
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || !(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
|
||||
@@ -36,7 +36,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
return "sysctlbyname(hw.model) failed";
|
||||
|
||||
cpu->coresLogical = (uint16_t) ffSysctlGetInt("hw.ncpu", 1);
|
||||
cpu->coresPhysical = 0;
|
||||
cpu->coresPhysical = (uint16_t) ffSysctlGetInt("kern.smp.cores", 0);
|
||||
cpu->coresOnline = (uint16_t) ffSysctlGetInt("kern.smp.cpus", cpu->coresLogical);
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
@@ -57,39 +57,8 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
// </children>
|
||||
// </group>
|
||||
// </groups>
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
bool inLvl2 = false, threadGroup = false;
|
||||
uint32_t cpuCount = 0;
|
||||
while (ffStrbufGetline(&line, &len, &buffer))
|
||||
{
|
||||
if (!inLvl2)
|
||||
{
|
||||
if (ffStrStartsWith(line, " <group level=\"2\""))
|
||||
{
|
||||
inLvl2 = true;
|
||||
cpuCount = 0;
|
||||
threadGroup = false;
|
||||
}
|
||||
else if (ffStrStartsWith(line, " <group level=\"1\""))
|
||||
cpu->packages++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ffStrEquals(line, " </group>"))
|
||||
{
|
||||
cpu->coresPhysical += threadGroup ? 1 : cpuCount;
|
||||
inLvl2 = false;
|
||||
}
|
||||
else if (cpuCount == 0 && ffStrStartsWith(line, " <cpu count=\""))
|
||||
cpuCount = (uint32_t) strtoul(line + strlen(" <cpu count=\""), NULL, 10);
|
||||
else if (cpuCount > 0 && ffStrStartsWith(line, " <flags>"))
|
||||
{
|
||||
if (ffStrContains(line, "<flag name=\"THREAD\">THREAD group</flag>"))
|
||||
threadGroup = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (char* p = buffer.chars; (p = strstr(p, "\n </group>\n")); ++p)
|
||||
cpu->packages++;
|
||||
}
|
||||
|
||||
#if FF_HAVE_CPUSET && (__x86_64__ || __i386__)
|
||||
|
||||
@@ -67,6 +67,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
|
||||
uint32_t freq = (uint32_t) ffSysctlGetInt("machdep.cpu.frequency.target", 0);
|
||||
if (freq == 0) freq = (uint32_t) (ffSysctlGetInt64("hw.cpu0.clock_frequency", 0) / 1000000);
|
||||
if (freq == 0) freq = (uint32_t) ffSysctlGetInt("machdep.dmi.processor-frequency", 0);
|
||||
if (freq > cpu->frequencyBase) cpu->frequencyBase = freq;
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
|
||||
@@ -1,10 +1,53 @@
|
||||
#include "cpu.h"
|
||||
#include "common/sysctl.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/sensors.h>
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
static const char* detectCPUTemp(FFCPUResult* cpu)
|
||||
{
|
||||
int mib[5] = {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0};
|
||||
|
||||
for (mib[2] = 0; mib[2] < 1024; mib[2]++)
|
||||
{
|
||||
struct sensordev sensordev;
|
||||
size_t sdlen = sizeof(struct sensordev);
|
||||
if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
break;
|
||||
if (errno == ENXIO)
|
||||
continue;
|
||||
return "sysctl(sensordev) failed";
|
||||
}
|
||||
|
||||
if (!ffStrStartsWith(sensordev.xname, "cpu"))
|
||||
continue;
|
||||
|
||||
for (mib[4] = 0; mib[4] < sensordev.maxnumt[SENSOR_TEMP]; mib[4]++)
|
||||
{
|
||||
struct sensor sensor;
|
||||
size_t slen = sizeof(struct sensor);
|
||||
if (sysctl(mib, 5, &sensor, &slen, NULL, 0) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return "sysctl(sensor) failed";
|
||||
continue;
|
||||
}
|
||||
if (sensor.flags & SENSOR_FINVALID)
|
||||
continue;
|
||||
|
||||
cpu->temperature = (double)(sensor.value - 273150000) / 1E6;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "No sensor for CPU temp found";
|
||||
}
|
||||
|
||||
const char *ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
if (ffSysctlGetString(CTL_HW, HW_MODEL, &cpu->name))
|
||||
return "sysctl(hw.model) failed";
|
||||
@@ -19,13 +62,7 @@ const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
if (cpuspeed > cpu->frequencyBase) cpu->frequencyBase = cpuspeed;
|
||||
|
||||
cpu->temperature = FF_CPU_TEMP_UNSET;
|
||||
if (options->temp)
|
||||
{
|
||||
struct sensor sensors;
|
||||
size_t size = sizeof(sensors);
|
||||
if (sysctl((int[]) {CTL_HW, HW_SENSORS, 0, SENSOR_TEMP, 0}, 5, &sensors, &size, NULL, 0) == 0)
|
||||
cpu->temperature = (double) (sensors.value - 273150000) / 1E6;
|
||||
}
|
||||
if (options->temp) detectCPUTemp(cpu);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,60 @@
|
||||
#include "cpu.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include <kstat.h>
|
||||
|
||||
static const char* detectCPUTempByKstat(kstat_ctl_t* kc, FFCPUResult* cpu)
|
||||
{
|
||||
const char* possibleModules[] = {"temperature", "cpu_temp", "acpi_thermal", NULL};
|
||||
|
||||
for (int i = 0; possibleModules[i] != NULL; i++) {
|
||||
kstat_t* ks = kstat_lookup(kc, possibleModules[i], -1, NULL);
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0) {
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "temperature");
|
||||
if (kn) {
|
||||
switch (kn->data_type) {
|
||||
case KSTAT_DATA_INT32:
|
||||
cpu->temperature = (float)kn->value.i32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_UINT32:
|
||||
cpu->temperature = (float)kn->value.ui32;
|
||||
return NULL;
|
||||
case KSTAT_DATA_FLOAT:
|
||||
cpu->temperature = kn->value.f;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "Failed to find CPU temperature using kstat";
|
||||
}
|
||||
|
||||
static const char* detectCPUTempByIpmiTool(FFCPUResult* cpu)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]){
|
||||
"ipmitool",
|
||||
"-c",
|
||||
"sdr",
|
||||
"list",
|
||||
NULL
|
||||
});
|
||||
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
while (ffStrbufGetline(&line, &len, &buffer))
|
||||
{
|
||||
if (sscanf(line, "CPU%*d Temp,%lf,degrees C,ok", &cpu->temperature) == 1)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "ipmitool sdr list failed to find CPU temperature";
|
||||
}
|
||||
|
||||
static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
{
|
||||
assert(pkc);
|
||||
@@ -8,7 +62,46 @@ static inline void kstatFreeWrap(kstat_ctl_t** pkc)
|
||||
kstat_close(*pkc);
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
static inline uint16_t countTypeId(kstat_ctl_t* kc, const char* type)
|
||||
{
|
||||
uint64_t low = 0, high = 0;
|
||||
for (kstat_t* ksp = kc->kc_chain; ksp; ksp = ksp->ks_next)
|
||||
{
|
||||
if (ffStrStartsWith(ksp->ks_module, "cpu_info"))
|
||||
{
|
||||
if (kstat_read(kc, ksp, NULL) < 0)
|
||||
continue;
|
||||
|
||||
kstat_named_t* stat = kstat_data_lookup(ksp, type);
|
||||
if (!stat)
|
||||
continue;
|
||||
|
||||
uint32_t id = 0;
|
||||
switch (stat->data_type)
|
||||
{
|
||||
#ifdef _INT64_TYPE
|
||||
case KSTAT_DATA_INT64:
|
||||
case KSTAT_DATA_UINT64:
|
||||
id = (uint32_t) stat->value.ui64;
|
||||
break;
|
||||
#endif
|
||||
case KSTAT_DATA_INT32:
|
||||
case KSTAT_DATA_UINT32:
|
||||
id = stat->value.ui32;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if (__builtin_expect(id > 64, false))
|
||||
high |= 1ULL << (id - 64);
|
||||
else
|
||||
low |= 1ULL << id;
|
||||
}
|
||||
}
|
||||
return (uint16_t) (__builtin_popcountll(low) + __builtin_popcountll(high));
|
||||
}
|
||||
|
||||
const char* ffDetectCPUImpl(const FFCPUOptions* options, FFCPUResult* cpu)
|
||||
{
|
||||
__attribute__((__cleanup__(kstatFreeWrap))) kstat_ctl_t* kc = kstat_open();
|
||||
if (!kc)
|
||||
@@ -40,7 +133,16 @@ const char* ffDetectCPUImpl(FF_MAYBE_UNUSED const FFCPUOptions* options, FFCPURe
|
||||
if (ks && kstat_read(kc, ks, NULL) >= 0)
|
||||
{
|
||||
kstat_named_t* kn = kstat_data_lookup(ks, "ncpus");
|
||||
if (kn) cpu->coresLogical = cpu->coresPhysical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
if (kn) cpu->coresLogical = cpu->coresOnline = (uint16_t) kn->value.ui32;
|
||||
}
|
||||
|
||||
cpu->packages = countTypeId(kc, "chip_id");
|
||||
cpu->coresPhysical = countTypeId(kc, "core_id");
|
||||
|
||||
if (options->temp)
|
||||
{
|
||||
if (detectCPUTempByKstat(kc, cpu) != NULL)
|
||||
detectCPUTempByIpmiTool(cpu);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -22,11 +22,11 @@ static const char* detectThermalTemp(double* result)
|
||||
|
||||
__attribute__((__cleanup__(ffPdhOpenCloseQuery))) HQUERY query = NULL;
|
||||
|
||||
if (PdhOpenQuery(NULL, 0, &query) != ERROR_SUCCESS)
|
||||
if (PdhOpenQueryW(NULL, 0, &query) != ERROR_SUCCESS)
|
||||
return "Failed to open PDH query";
|
||||
|
||||
HCOUNTER counter = NULL;
|
||||
if (PdhAddEnglishCounter(query,
|
||||
if (PdhAddEnglishCounterW(query,
|
||||
L"\\Thermal Zone Information(*)\\Temperature",
|
||||
0,
|
||||
&counter) != ERROR_SUCCESS)
|
||||
@@ -151,7 +151,7 @@ static const char* detectNCores(FFCPUResult* cpu)
|
||||
else if (ptr->Relationship == RelationProcessorCore)
|
||||
++cpu->coresPhysical;
|
||||
else if (ptr->Relationship == RelationProcessorPackage)
|
||||
cpu->packages++;
|
||||
++cpu->packages;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
||||
@@ -10,18 +10,29 @@
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#ifdef __FreeBSD__
|
||||
#include <paths.h>
|
||||
#ifndef _PATH_LOCALBASE
|
||||
#define _PATH_LOCALBASE "/usr/local"
|
||||
#endif
|
||||
#elif __OpenBSD__
|
||||
#define _PATH_LOCALBASE "/usr/local"
|
||||
#elif __NetBSD__
|
||||
#define _PATH_LOCALBASE "/usr/pkg"
|
||||
#endif
|
||||
|
||||
static void getKDE(FFstrbuf* result, FFDEOptions* options)
|
||||
{
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", 1, (FFpropquery[]) {
|
||||
{"X-KDE-PluginInfo-Version =", result}
|
||||
});
|
||||
#ifdef _PATH_LOCALBASE
|
||||
ffParsePropFile(_PATH_LOCALBASE "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
{
|
||||
ffParsePropFileValues(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", 1, (FFpropquery[]) {
|
||||
{"X-KDE-PluginInfo-Version =", result}
|
||||
});
|
||||
}
|
||||
ffParsePropFile(_PATH_LOCALBASE "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
#else
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/wayland-sessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
ffParsePropFile(FASTFETCH_TARGET_DIR_USR "/share/xsessions/plasmax11.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
#endif
|
||||
|
||||
if(result->length == 0)
|
||||
ffParsePropFileData("xsessions/plasma.desktop", "X-KDE-PluginInfo-Version =", result);
|
||||
if(result->length == 0)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "disk.h"
|
||||
|
||||
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
|
||||
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char separator = ';';
|
||||
@@ -11,12 +11,12 @@ bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint)
|
||||
uint32_t mountpointLength = (uint32_t) strlen(mountpoint);
|
||||
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < options->folders.length)
|
||||
while(startIndex < folders->length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&options->folders, startIndex, separator);
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(folders, startIndex, separator);
|
||||
|
||||
uint32_t folderLength = colonIndex - startIndex;
|
||||
if (folderLength == mountpointLength && memcmp(options->folders.chars + startIndex, mountpoint, mountpointLength) == 0)
|
||||
if (folderLength == mountpointLength && memcmp(folders->chars + startIndex, mountpoint, mountpointLength) == 0)
|
||||
return true;
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
|
||||
@@ -28,4 +28,4 @@ typedef struct FFDisk
|
||||
const char* ffDetectDisks(FFDiskOptions* options, FFlist* disks /* list of FFDisk */);
|
||||
|
||||
const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks);
|
||||
bool ffDiskMatchMountpoint(FFDiskOptions* options, const char* mountpoint);
|
||||
bool ffDiskMatchMountpoint(FFstrbuf* folders, const char* mountpoint);
|
||||
|
||||
@@ -52,7 +52,7 @@ static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static const char* detectFsLabel(struct statfs* fs, FFDisk* disk)
|
||||
static const char* detectFsLabel(FF_MAYBE_UNUSED struct statfs* fs, FF_MAYBE_UNUSED FFDisk* disk)
|
||||
{
|
||||
return "Fastfetch was compiled without libgeom support";
|
||||
}
|
||||
@@ -145,10 +145,10 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if(__builtin_expect(options->folders.length > 0, 0))
|
||||
{
|
||||
if(!ffDiskMatchMountpoint(options, fs->f_mntonname))
|
||||
if(!ffDiskMatchMountpoint(&options->folders, fs->f_mntonname))
|
||||
continue;
|
||||
}
|
||||
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs"))
|
||||
else if(!ffStrEquals(fs->f_mntonname, "/") && !ffStrStartsWith(fs->f_mntfromname, "/dev/") && !ffStrEquals(fs->f_fstypename, "zfs") && !ffStrEquals(fs->f_fstypename, "fusefs.sshfs"))
|
||||
continue;
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
@@ -159,13 +159,13 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
FFDisk* disk = ffListAdd(disks);
|
||||
|
||||
disk->bytesTotal = (uint64_t)fs->f_blocks * fs->f_bsize;
|
||||
disk->bytesFree = (uint64_t)fs->f_bfree * fs->f_bsize;
|
||||
disk->bytesAvailable = (uint64_t)fs->f_bavail * fs->f_bsize;
|
||||
disk->bytesTotal = (uint64_t)fs->f_blocks * (uint64_t)fs->f_bsize;
|
||||
disk->bytesFree = (uint64_t)fs->f_bfree * (uint64_t)fs->f_bsize;
|
||||
disk->bytesAvailable = (uint64_t)fs->f_bavail * (uint64_t)fs->f_bsize;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
disk->filesTotal = (uint32_t) fs->f_files;
|
||||
disk->filesUsed = (uint32_t) (fs->f_files - fs->f_ffree);
|
||||
disk->filesUsed = (uint32_t) fs->f_files - (uint32_t) fs->f_ffree;
|
||||
|
||||
ffStrbufInitS(&disk->mountFrom, fs->f_mntfromname);
|
||||
ffStrbufInitS(&disk->mountpoint, fs->f_mntonname);
|
||||
|
||||
@@ -23,7 +23,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, path.Path()))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, path.Path()))
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ static bool isPhysicalDevice(const struct mntent* device)
|
||||
if(ffStrEquals(device->mnt_type, "zfs"))
|
||||
return true;
|
||||
|
||||
//sshfs
|
||||
if(ffStrEquals(device->mnt_type, "fuse.sshfs"))
|
||||
return true;
|
||||
|
||||
//Pseudo filesystems don't have a device in /dev
|
||||
if(!ffStrStartsWith(device->mnt_fsname, "/dev/"))
|
||||
return false;
|
||||
@@ -220,7 +224,7 @@ static bool isRemovable(FFDisk* currentDisk)
|
||||
|
||||
static void detectType(const FFlist* disks, FFDisk* currentDisk, struct mntent* device)
|
||||
{
|
||||
if(ffStrbufStartsWithS(¤tDisk->mountpoint, "/boot") || ffStrbufStartsWithS(¤tDisk->mountpoint, "/efi"))
|
||||
if(hasmntopt(device, "x-gvfs-hide") || hasmntopt(device, "hidden"))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_HIDDEN_BIT;
|
||||
else if(isSubvolume(disks, currentDisk))
|
||||
currentDisk->type = FF_DISK_VOLUME_TYPE_SUBVOLUME_BIT;
|
||||
@@ -240,9 +244,9 @@ static void detectStats(FFDisk* disk)
|
||||
if(statvfs(disk->mountpoint.chars, &fs) != 0)
|
||||
memset(&fs, 0, sizeof(fs)); //Set all values to 0, so our values get initialized to 0 too
|
||||
|
||||
disk->bytesTotal = fs.f_blocks * fs.f_frsize;
|
||||
disk->bytesFree = fs.f_bfree * fs.f_frsize;
|
||||
disk->bytesAvailable = fs.f_bavail * fs.f_frsize;
|
||||
disk->bytesTotal = fs.f_blocks * (uint64_t) fs.f_frsize;
|
||||
disk->bytesFree = fs.f_bfree * (uint64_t) fs.f_frsize;
|
||||
disk->bytesAvailable = fs.f_bavail * (uint64_t) fs.f_frsize;
|
||||
disk->bytesUsed = 0; // To be filled in ./disk.c
|
||||
|
||||
if (fs.f_files >= fs.f_ffree)
|
||||
@@ -281,7 +285,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, device->mnt_dir))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, device->mnt_dir))
|
||||
continue;
|
||||
}
|
||||
else if(!isPhysicalDevice(device))
|
||||
|
||||
@@ -113,7 +113,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
{
|
||||
if (__builtin_expect(options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, device.mnt_mountp))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, device.mnt_mountp))
|
||||
continue;
|
||||
}
|
||||
else if(!isPhysicalDevice(&device))
|
||||
|
||||
@@ -47,7 +47,7 @@ const char* ffDetectDisksImpl(FFDiskOptions* options, FFlist* disks)
|
||||
|
||||
if (__builtin_expect((long) options->folders.length, 0))
|
||||
{
|
||||
if (!ffDiskMatchMountpoint(options, buffer.chars))
|
||||
if (!ffDiskMatchMountpoint(&options->folders, buffer.chars))
|
||||
continue;
|
||||
}
|
||||
else if(driveType == DRIVE_NO_ROOT_DIR)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -214,6 +214,26 @@ enum kde_output_device_v2_capability {
|
||||
* @since 9
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS = 0x80,
|
||||
/**
|
||||
* if this outputdevice supports the built-in color profile
|
||||
* @since 12
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR = 0x100,
|
||||
/**
|
||||
* if this outputdevice supports DDC/CI
|
||||
* @since 14
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI = 0x200,
|
||||
/**
|
||||
* if this outputdevice supports setting max bpc
|
||||
* @since 15
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR = 0x400,
|
||||
/**
|
||||
* if this outputdevice supports EDR
|
||||
* @since 16
|
||||
*/
|
||||
KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR = 0x800,
|
||||
};
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
@@ -235,6 +255,22 @@ enum kde_output_device_v2_capability {
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BRIGHTNESS_SINCE_VERSION 9
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_BUILT_IN_COLOR_SINCE_VERSION 12
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_DDC_CI_SINCE_VERSION 14
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_MAX_BITS_PER_COLOR_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_CAPABILITY_EDR_SINCE_VERSION 16
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_CAPABILITY_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_VRR_POLICY_ENUM
|
||||
@@ -316,6 +352,18 @@ enum kde_output_device_v2_color_power_tradeoff {
|
||||
};
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_COLOR_POWER_TRADEOFF_ENUM */
|
||||
|
||||
#ifndef KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
* when the compositor may make use of EDR
|
||||
*/
|
||||
enum kde_output_device_v2_edr_policy {
|
||||
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_NEVER = 0,
|
||||
KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ALWAYS = 1,
|
||||
};
|
||||
#endif /* KDE_OUTPUT_DEVICE_V2_EDR_POLICY_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
* @struct kde_output_device_v2_listener
|
||||
@@ -658,6 +706,74 @@ struct kde_output_device_v2_listener {
|
||||
void (*dimming)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t multiplier);
|
||||
/**
|
||||
* source output for mirroring
|
||||
*
|
||||
*
|
||||
* @param source uuid of the source output
|
||||
* @since 13
|
||||
*/
|
||||
void (*replication_source)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
const char *source);
|
||||
/**
|
||||
* if DDC/CI should be used to control brightness etc.
|
||||
*
|
||||
* If the ddc_ci capability is present, this determines if
|
||||
* settings such as brightness, contrast or others should be set
|
||||
* using DDC/CI.
|
||||
* @param allowed 1 if allowed, 0 if disabled
|
||||
* @since 14
|
||||
*/
|
||||
void (*ddc_ci_allowed)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t allowed);
|
||||
/**
|
||||
* override max bpc
|
||||
*
|
||||
* This limits the amount of bits per color that are sent to the
|
||||
* display.
|
||||
* @param max_bpc 0 for the default / automatic
|
||||
* @since 15
|
||||
*/
|
||||
void (*max_bits_per_color)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t max_bpc);
|
||||
/**
|
||||
* range of max bits per color value
|
||||
*
|
||||
*
|
||||
* @param min_value the minimum supported by the driver
|
||||
* @param max_value the maximum supported by the driver
|
||||
* @since 15
|
||||
*/
|
||||
void (*max_bits_per_color_range)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t min_value,
|
||||
uint32_t max_value);
|
||||
/**
|
||||
* if and to what value automatic max bpc is limited
|
||||
*
|
||||
*
|
||||
* @param max_bpc_limit which value automatic bpc gets limited to. 0 if not limited
|
||||
* @since 15
|
||||
*/
|
||||
void (*automatic_max_bits_per_color_limit)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t max_bpc_limit);
|
||||
/**
|
||||
* when the compositor may apply EDR
|
||||
*
|
||||
* When EDR is enabled, the compositor may increase the backlight
|
||||
* beyond the user-specified setting, in order to present HDR
|
||||
* content on displays without native HDR support. This will
|
||||
* usually result in better visuals, but also increases battery
|
||||
* usage.
|
||||
* @since 16
|
||||
*/
|
||||
void (*edr_policy)(void *data,
|
||||
struct kde_output_device_v2 *kde_output_device_v2,
|
||||
uint32_t policy);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -779,6 +895,30 @@ kde_output_device_v2_add_listener(struct kde_output_device_v2 *kde_output_device
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_DIMMING_SINCE_VERSION 11
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_REPLICATION_SOURCE_SINCE_VERSION 13
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_DDC_CI_ALLOWED_SINCE_VERSION 14
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_MAX_BITS_PER_COLOR_RANGE_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_AUTOMATIC_MAX_BITS_PER_COLOR_LIMIT_SINCE_VERSION 15
|
||||
/**
|
||||
* @ingroup iface_kde_output_device_v2
|
||||
*/
|
||||
#define KDE_OUTPUT_DEVICE_V2_EDR_POLICY_SINCE_VERSION 16
|
||||
|
||||
|
||||
/** @ingroup iface_kde_output_device_v2 */
|
||||
|
||||
@@ -60,12 +60,18 @@ static const struct wl_message kde_output_device_v2_events[] = {
|
||||
{ "brightness", "8u", kde_output_device_v2_types + 0 },
|
||||
{ "color_power_tradeoff", "10u", kde_output_device_v2_types + 0 },
|
||||
{ "dimming", "11u", kde_output_device_v2_types + 0 },
|
||||
{ "replication_source", "13s", kde_output_device_v2_types + 0 },
|
||||
{ "ddc_ci_allowed", "14u", kde_output_device_v2_types + 0 },
|
||||
{ "max_bits_per_color", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "max_bits_per_color_range", "15uu", kde_output_device_v2_types + 0 },
|
||||
{ "automatic_max_bits_per_color_limit", "15u", kde_output_device_v2_types + 0 },
|
||||
{ "edr_policy", "16u", kde_output_device_v2_types + 0 },
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface kde_output_device_v2_interface = {
|
||||
"kde_output_device_v2", 11,
|
||||
"kde_output_device_v2", 16,
|
||||
0, NULL,
|
||||
27, kde_output_device_v2_events,
|
||||
33, kde_output_device_v2_events,
|
||||
};
|
||||
|
||||
static const struct wl_message kde_output_device_mode_v2_events[] = {
|
||||
|
||||
@@ -137,6 +137,12 @@ static void waylandKdeHdrListener(void *data, FF_MAYBE_UNUSED struct kde_output_
|
||||
display->hdrEnabled = !!hdr_enabled;
|
||||
}
|
||||
|
||||
static void waylandKdeMaxBitsPerColorListener(void *data, FF_MAYBE_UNUSED struct kde_output_device_v2 *kde_output_device_v2, uint32_t max_bpc)
|
||||
{
|
||||
WaylandDisplay* display = data;
|
||||
display->bitDepth = (uint8_t) max_bpc;
|
||||
}
|
||||
|
||||
static struct kde_output_device_v2_listener outputListener = {
|
||||
.geometry = waylandKdeGeometryListener,
|
||||
.current_mode = waylandKdeCurrentModeListener,
|
||||
@@ -165,6 +171,12 @@ static struct kde_output_device_v2_listener outputListener = {
|
||||
.brightness = (void*) stubListener,
|
||||
.color_power_tradeoff = (void*) stubListener,
|
||||
.dimming = (void*) stubListener,
|
||||
.replication_source = (void*) stubListener,
|
||||
.ddc_ci_allowed = (void*) stubListener,
|
||||
.max_bits_per_color = (void*) waylandKdeMaxBitsPerColorListener,
|
||||
.max_bits_per_color_range = (void*) stubListener,
|
||||
.automatic_max_bits_per_color_limit = (void*) stubListener,
|
||||
.edr_policy = (void*) stubListener,
|
||||
};
|
||||
|
||||
const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* registry, uint32_t name, uint32_t version)
|
||||
@@ -237,6 +249,7 @@ const char* ffWaylandHandleKdeOutput(WaylandData* wldata, struct wl_registry* re
|
||||
item->manufactureYear = display.myear;
|
||||
item->manufactureWeek = display.mweek;
|
||||
item->serial = display.serial;
|
||||
item->bitDepth = display.bitDepth;
|
||||
}
|
||||
|
||||
ffStrbufDestroy(&display.description);
|
||||
|
||||
@@ -34,6 +34,7 @@ typedef struct WaylandData
|
||||
typedef struct WaylandDisplay
|
||||
{
|
||||
WaylandData* parent;
|
||||
void* internal;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
int32_t refreshRate;
|
||||
@@ -55,7 +56,7 @@ typedef struct WaylandDisplay
|
||||
uint16_t myear;
|
||||
uint16_t mweek;
|
||||
uint32_t serial;
|
||||
void* internal;
|
||||
uint8_t bitDepth;
|
||||
} WaylandDisplay;
|
||||
|
||||
inline static void stubListener(void* data, ...)
|
||||
|
||||
@@ -335,6 +335,7 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
{
|
||||
FF_LIBRARY_LOAD(xcbRandr, "dlopen libxcb-randr failed", "libxcb-randr" FF_LIBRARY_EXTENSION, 1)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connect)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_connection_has_error)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_get_setup)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_setup_roots_iterator)
|
||||
FF_LIBRARY_LOAD_SYMBOL_MESSAGE(xcbRandr, xcb_screen_next)
|
||||
@@ -368,8 +369,11 @@ const char* ffdsConnectXcbRandr(FFDisplayServerResult* result)
|
||||
|
||||
|
||||
data.connection = ffxcb_connect(NULL, NULL);
|
||||
if(data.connection == NULL)
|
||||
if(ffxcb_connection_has_error(data.connection) > 0)
|
||||
{
|
||||
ffxcb_disconnect(data.connection);
|
||||
return "xcb_connect() failed";
|
||||
}
|
||||
|
||||
|
||||
data.result = result;
|
||||
|
||||
@@ -20,9 +20,6 @@ extern int ADL2_Adapter_Graphic_Core_Info_Get(ADL_CONTEXT_HANDLE context, int iA
|
||||
// Function to retrieve memory information from the adapter. Version 2
|
||||
extern int ADL2_Adapter_MemoryInfo2_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, ADLMemoryInfo2* lpMemoryInfo2);
|
||||
|
||||
// This function retrieves the VRAM usage of given adapter.
|
||||
extern int ADL2_Adapter_VRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
|
||||
|
||||
// This function retrieves the Dedicated VRAM usage of given adapter.
|
||||
extern int ADL2_Adapter_DedicatedVRAMUsage_Get(ADL_CONTEXT_HANDLE context, int iAdapterIndex, int* iVRAMUsageInMB);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+12
-2
@@ -15,6 +15,11 @@ const char* FF_GPU_VENDOR_NAME_PARALLEL = "Parallel";
|
||||
const char* FF_GPU_VENDOR_NAME_MICROSOFT = "Microsoft";
|
||||
const char* FF_GPU_VENDOR_NAME_REDHAT = "RedHat";
|
||||
const char* FF_GPU_VENDOR_NAME_ORACLE = "Oracle";
|
||||
const char* FF_GPU_VENDOR_NAME_BROADCOM = "Broadcom";
|
||||
const char* FF_GPU_VENDOR_NAME_LOONGSON = "Loongson";
|
||||
const char* FF_GPU_VENDOR_NAME_JINGJIA_MICRO = "Jingjia Micro";
|
||||
const char* FF_GPU_VENDOR_NAME_HUAWEI = "Huawei";
|
||||
const char* FF_GPU_VENDOR_NAME_ZHAOXIN = "Zhaoxin";
|
||||
|
||||
const char* ffGPUGetVendorString(unsigned vendorId)
|
||||
{
|
||||
@@ -22,17 +27,22 @@ const char* ffGPUGetVendorString(unsigned vendorId)
|
||||
switch (vendorId)
|
||||
{
|
||||
case 0x106b: return FF_GPU_VENDOR_NAME_APPLE;
|
||||
case 0x1002: case 0x1022: return FF_GPU_VENDOR_NAME_AMD;
|
||||
case 0x1002: case 0x1022: case 0x1dd8: return FF_GPU_VENDOR_NAME_AMD;
|
||||
case 0x8086: case 0x8087: case 0x03e7: return FF_GPU_VENDOR_NAME_INTEL;
|
||||
case 0x0955: case 0x10de: case 0x12d2: return FF_GPU_VENDOR_NAME_NVIDIA;
|
||||
case 0x1ed5: return FF_GPU_VENDOR_NAME_MTHREADS;
|
||||
case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
|
||||
case 0x17cb: case 0x5143: return FF_GPU_VENDOR_NAME_QUALCOMM;
|
||||
case 0x14c3: return FF_GPU_VENDOR_NAME_MTK;
|
||||
case 0x15ad: return FF_GPU_VENDOR_NAME_VMWARE;
|
||||
case 0x1af4: return FF_GPU_VENDOR_NAME_REDHAT;
|
||||
case 0x1ab8: return FF_GPU_VENDOR_NAME_PARALLEL;
|
||||
case 0x1414: return FF_GPU_VENDOR_NAME_MICROSOFT;
|
||||
case 0x108e: return FF_GPU_VENDOR_NAME_ORACLE;
|
||||
case 0x182f: case 0x14e4: return FF_GPU_VENDOR_NAME_BROADCOM;
|
||||
case 0x0014: return FF_GPU_VENDOR_NAME_LOONGSON;
|
||||
case 0x0731: return FF_GPU_VENDOR_NAME_JINGJIA_MICRO;
|
||||
case 0x19e5: return FF_GPU_VENDOR_NAME_HUAWEI;
|
||||
case 0x1d17: return FF_GPU_VENDOR_NAME_ZHAOXIN;
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ struct FFAdlData {
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_Graphic_Core_Info_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_MemoryInfo2_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_DedicatedVRAMUsage_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_VRAMUsage_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Adapter_ASICFamilyType_Get)
|
||||
FF_LIBRARY_SYMBOL(ADL2_Overdrive_Caps)
|
||||
FF_LIBRARY_SYMBOL(ADL2_OverdriveN_CapabilitiesX2_Get)
|
||||
@@ -91,7 +90,6 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_Graphic_Core_Info_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_MemoryInfo2_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_DedicatedVRAMUsage_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_VRAMUsage_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Adapter_ASICFamilyType_Get)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_Overdrive_Caps)
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(atiadl, adlData, ADL2_OverdriveN_CapabilitiesX2_Get)
|
||||
@@ -188,29 +186,12 @@ const char* ffDetectAmdGpuInfo(const FFGpuDriverCondition* cond, FFGpuDriverResu
|
||||
FF_DEBUG("ADL2_Adapter_DedicatedVRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
if (status == ADL_OK && vramUsage >= 0) {
|
||||
result.memory->used = (uint64_t) vramUsage * 1024 * 1024;
|
||||
FF_DEBUG("Dedicated VRAM usage: %llu bytes (%d MB)", result.memory->used, vramUsage);
|
||||
} else {
|
||||
FF_DEBUG("Failed to get dedicated VRAM usage");
|
||||
}
|
||||
|
||||
if (result.sharedMemory)
|
||||
{
|
||||
vramUsage = 0;
|
||||
status = adlData.ffADL2_Adapter_VRAMUsage_Get(adlData.apiHandle, device->iAdapterIndex, &vramUsage);
|
||||
FF_DEBUG("ADL2_Adapter_VRAMUsage_Get returned %s (%d), usage: %d MB",
|
||||
ffAdlStatusToString(status), status, vramUsage);
|
||||
|
||||
if (status == ADL_OK) {
|
||||
uint64_t totalUsage = (uint64_t) vramUsage * 1024 * 1024;
|
||||
result.sharedMemory->used = totalUsage - result.memory->used;
|
||||
FF_DEBUG("Total VRAM usage: %llu bytes, Shared VRAM usage: %llu bytes (%llu MB)",
|
||||
totalUsage, result.sharedMemory->used, result.sharedMemory->used / (1024 * 1024));
|
||||
} else {
|
||||
FF_DEBUG("Failed to get total VRAM usage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.memoryType)
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#if __aarch64__ && FF_HAVE_DRM
|
||||
|
||||
#include <drm.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if __has_include(<drm/asahi_drm.h>)
|
||||
|
||||
#include <drm/asahi_drm.h>
|
||||
|
||||
#else
|
||||
|
||||
// https://github.com/AsahiLinux/linux/blob/asahi/include/uapi/drm/asahi_drm.h
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/* Copyright (C) The Asahi Linux Contributors */
|
||||
|
||||
#define DRM_ASAHI_UNSTABLE_UABI_VERSION 10011
|
||||
|
||||
#define DRM_ASAHI_GET_PARAMS 0x00
|
||||
#define DRM_ASAHI_MAX_CLUSTERS 32
|
||||
struct drm_asahi_params_global
|
||||
{
|
||||
__u32 unstable_uabi_version;
|
||||
__u32 pad0;
|
||||
|
||||
__u64 feat_compat;
|
||||
__u64 feat_incompat;
|
||||
|
||||
__u32 gpu_generation;
|
||||
__u32 gpu_variant;
|
||||
__u32 gpu_revision;
|
||||
__u32 chip_id;
|
||||
|
||||
__u32 num_dies;
|
||||
__u32 num_clusters_total;
|
||||
__u32 num_cores_per_cluster;
|
||||
__u32 num_frags_per_cluster;
|
||||
__u32 num_gps_per_cluster;
|
||||
__u32 num_cores_total_active;
|
||||
__u64 core_masks[DRM_ASAHI_MAX_CLUSTERS];
|
||||
|
||||
__u32 vm_page_size;
|
||||
__u32 pad1;
|
||||
__u64 vm_user_start;
|
||||
__u64 vm_user_end;
|
||||
__u64 vm_usc_start;
|
||||
__u64 vm_usc_end;
|
||||
__u64 vm_kernel_min_size;
|
||||
|
||||
__u32 max_syncs_per_submission;
|
||||
__u32 max_commands_per_submission;
|
||||
__u32 max_commands_in_flight;
|
||||
__u32 max_attachments;
|
||||
|
||||
__u32 timer_frequency_hz;
|
||||
__u32 min_frequency_khz;
|
||||
__u32 max_frequency_khz;
|
||||
__u32 max_power_mw;
|
||||
|
||||
__u32 result_render_size;
|
||||
__u32 result_compute_size;
|
||||
|
||||
__u32 firmware_version[4];
|
||||
};
|
||||
|
||||
struct drm_asahi_get_params
|
||||
{
|
||||
/** @extensions: Pointer to the first extension struct, if any */
|
||||
__u64 extensions;
|
||||
|
||||
/** @param: Parameter group to fetch (MBZ) */
|
||||
__u32 param_group;
|
||||
|
||||
/** @pad: MBZ */
|
||||
__u32 pad;
|
||||
|
||||
/** @value: User pointer to write parameter struct */
|
||||
__u64 pointer;
|
||||
|
||||
/** @value: Size of user buffer, max size supported on return */
|
||||
__u64 size;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DRM_IOCTL_ASAHI_GET_PARAMS = DRM_IOWR(DRM_COMMAND_BASE + DRM_ASAHI_GET_PARAMS, struct drm_asahi_get_params),
|
||||
};
|
||||
|
||||
#endif // __has_include
|
||||
|
||||
#endif // FF_HAVE_DRM
|
||||
@@ -21,10 +21,16 @@
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include "gpu_asahi.h"
|
||||
|
||||
#define FF_STR_INDIR(x) #x
|
||||
#define FF_STR(x) FF_STR_INDIR(x)
|
||||
#if defined(FF_HAVE_DRM) && defined(__aarch64__)
|
||||
// https://github.com/alyssarosenzweig/linux/blob/agx-uapi-v7/include/uapi/drm/asahi_drm.h
|
||||
// Found in kernel-headers-6.14.4-400.asahi.fc42.aarch64
|
||||
#if __has_include(<drm/asahi_drm.h>)
|
||||
#include <drm/asahi_drm.h>
|
||||
#else
|
||||
#include "asahi_drm.h"
|
||||
#endif
|
||||
#define FF_HAVE_DRM_ASAHI 1
|
||||
#endif
|
||||
|
||||
static bool pciDetectDriver(FFstrbuf* result, FFstrbuf* pciDir, FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
|
||||
{
|
||||
@@ -140,6 +146,26 @@ static const char* drmDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult
|
||||
gpu->frequency = (uint32_t) (gpuInfo.max_engine_clk / 1000u);
|
||||
gpu->index = FF_GPU_INDEX_UNSET;
|
||||
gpu->type = gpuInfo.ids_flags & AMDGPU_IDS_FLAGS_FUSION ? FF_GPU_TYPE_INTEGRATED : FF_GPU_TYPE_DISCRETE;
|
||||
#define FF_VRAM_CASE(name, value) case value /* AMDGPU_VRAM_TYPE_ ## name */: ffStrbufSetStatic(&gpu->memoryType, #name); break
|
||||
switch (gpuInfo.vram_type)
|
||||
{
|
||||
FF_VRAM_CASE(UNKNOWN, 0);
|
||||
FF_VRAM_CASE(GDDR1, 1);
|
||||
FF_VRAM_CASE(DDR2, 2);
|
||||
FF_VRAM_CASE(GDDR3, 3);
|
||||
FF_VRAM_CASE(GDDR4, 4);
|
||||
FF_VRAM_CASE(GDDR5, 5);
|
||||
FF_VRAM_CASE(HBM, 6);
|
||||
FF_VRAM_CASE(DDR3, 7);
|
||||
FF_VRAM_CASE(DDR4, 8);
|
||||
FF_VRAM_CASE(GDDR6, 9);
|
||||
FF_VRAM_CASE(DDR5, 10);
|
||||
FF_VRAM_CASE(LPDDR4, 11);
|
||||
FF_VRAM_CASE(LPDDR5, 12);
|
||||
default:
|
||||
ffStrbufAppendF(&gpu->memoryType, "Unknown (%u)", gpuInfo.vram_type);
|
||||
break;
|
||||
}
|
||||
|
||||
struct amdgpu_heap_info heapInfo;
|
||||
if (ffamdgpu_query_heap_info(handle, AMDGPU_GEM_DOMAIN_VRAM, 0, &heapInfo) >= 0)
|
||||
@@ -225,6 +251,11 @@ static void pciDetectAmdSpecific(const FFGPUOptions* options, FFGPUResult* gpu,
|
||||
gpu->shared.used = value;
|
||||
}
|
||||
}
|
||||
|
||||
ffStrbufSubstrBefore(pciDir, pciDirLen);
|
||||
ffStrbufAppendS(pciDir, "/gpu_busy_percent");
|
||||
if (ffReadFileBuffer(pciDir->chars, buffer) && (value = ffStrbufToUInt(buffer, 0)))
|
||||
gpu->coreUsage = (double) value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,10 +351,7 @@ static const char* drmDetectIntelSpecific(FFGPUResult* gpu, const char* drmKey,
|
||||
{
|
||||
{
|
||||
struct drm_xe_device_query query = {
|
||||
.extensions = 0,
|
||||
.query = DRM_XE_DEVICE_QUERY_GT_TOPOLOGY,
|
||||
.size = 0,
|
||||
.data = 0,
|
||||
};
|
||||
if (ioctl(fd, DRM_IOCTL_XE_DEVICE_QUERY, &query) >= 0)
|
||||
{
|
||||
@@ -590,13 +618,13 @@ static const char* detectPci(const FFGPUOptions* options, FFlist* gpus, FFstrbuf
|
||||
|
||||
#if __aarch64__
|
||||
|
||||
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FFstrbuf* buffer, const char* drmKey)
|
||||
FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, const char* name, FF_MAYBE_UNUSED FFstrbuf* buffer, FF_MAYBE_UNUSED const char* drmKey)
|
||||
{
|
||||
if (sscanf(name, "agx-t%lu", &gpu->deviceId) == 1)
|
||||
ffStrbufSetStatic(&gpu->name, ffCPUAppleCodeToName((uint32_t) gpu->deviceId));
|
||||
ffStrbufSetStatic(&gpu->vendor, FF_GPU_VENDOR_NAME_APPLE);
|
||||
|
||||
#if FF_HAVE_DRM
|
||||
#if FF_HAVE_DRM_ASAHI
|
||||
ffStrbufSetS(buffer, "/dev/dri/");
|
||||
ffStrbufAppendS(buffer, drmKey);
|
||||
FF_AUTO_CLOSE_FD int fd = open(buffer->chars, O_RDONLY);
|
||||
@@ -609,38 +637,32 @@ FF_MAYBE_UNUSED static const char* drmDetectAsahiSpecific(FFGPUResult* gpu, cons
|
||||
.size = sizeof(paramsGlobal),
|
||||
}) >= 0)
|
||||
{
|
||||
ffStrbufAppendF(&gpu->driver, " %u", paramsGlobal.unstable_uabi_version);
|
||||
// They removed `unstable_uabi_version` from the struct. Hopefully they won't introduce new ABI changes.
|
||||
gpu->coreCount = (int32_t) (paramsGlobal.num_clusters_total * paramsGlobal.num_cores_per_cluster);
|
||||
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
|
||||
gpu->deviceId = paramsGlobal.chip_id;
|
||||
|
||||
// FIXME: They will introduce ABI breaking changes. Always check the latest version
|
||||
// https://www.reddit.com/r/AsahiLinux/comments/1ei2qiv/comment/lgm0v5s/
|
||||
if (paramsGlobal.unstable_uabi_version == DRM_ASAHI_UNSTABLE_UABI_VERSION)
|
||||
if (!gpu->name.length)
|
||||
{
|
||||
gpu->coreCount = (int) paramsGlobal.num_cores_total_active;
|
||||
gpu->frequency = paramsGlobal.max_frequency_khz / 1000;
|
||||
gpu->deviceId = paramsGlobal.chip_id;
|
||||
|
||||
if (!gpu->name.length)
|
||||
{
|
||||
const char* variant = " Unknown";
|
||||
switch (paramsGlobal.gpu_variant) {
|
||||
case 'G':
|
||||
variant = "";
|
||||
break;
|
||||
case 'S':
|
||||
variant = " Pro";
|
||||
break;
|
||||
case 'C':
|
||||
variant = " Max";
|
||||
break;
|
||||
case 'D':
|
||||
variant = " Ultra";
|
||||
break;
|
||||
}
|
||||
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
|
||||
paramsGlobal.gpu_generation - 12, variant,
|
||||
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
|
||||
paramsGlobal.gpu_revision + 0xA0);
|
||||
const char* variant = " Unknown";
|
||||
switch (paramsGlobal.gpu_variant) {
|
||||
case 'G':
|
||||
variant = "";
|
||||
break;
|
||||
case 'S':
|
||||
variant = " Pro";
|
||||
break;
|
||||
case 'C':
|
||||
variant = " Max";
|
||||
break;
|
||||
case 'D':
|
||||
variant = " Ultra";
|
||||
break;
|
||||
}
|
||||
ffStrbufSetF(&gpu->name, "Apple M%d%s (G%d%c %02X)",
|
||||
paramsGlobal.gpu_generation - 12, variant,
|
||||
paramsGlobal.gpu_generation, paramsGlobal.gpu_variant,
|
||||
paramsGlobal.gpu_revision + 0xA0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ const char* ffDetectHost(FFHostResult* host)
|
||||
|| ffSettingsGetAndroidProperty("ro.vivo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.oppo_model", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.oppo.market.name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.vendor.oplus.market.enname", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.devicename", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.config.marketing_name", &host->name)
|
||||
|| ffSettingsGetAndroidProperty("ro.product.vendor.model", &host->name)
|
||||
|
||||
@@ -121,7 +121,7 @@ const char* ffHostGetMacProductNameWithHwModel(const FFstrbuf* hwModel)
|
||||
ffStrEquals(version, "16,5")) return "MacBook Pro (16-inch, 2024, Three Thunderbolt 5 ports)";
|
||||
if(ffStrEquals(version, "15,14")) return "Mac Studio (M3 Ultra, 2025)";
|
||||
if(ffStrEquals(version, "15,13")) return "MacBook Air (15-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,2")) return "MacBook Air (13-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,12")) return "MacBook Air (13-inch, M3, 2024)";
|
||||
if(ffStrEquals(version, "15,3")) return "MacBook Pro (14-inch, Nov 2023, Two Thunderbolt / USB 4 ports)";
|
||||
if(ffStrEquals(version, "15,4")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports)";
|
||||
if(ffStrEquals(version, "15,5")) return "iMac (24-inch, 2023, Two Thunderbolt / USB 4 ports, Two USB 3 ports)";
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#include "fastfetch.h"
|
||||
#include "detection/media/media.h"
|
||||
#include "common/library.h"
|
||||
#include "common/processing.h"
|
||||
#include "util/apple/cf_helpers.h"
|
||||
#include "util/apple/osascript.h"
|
||||
#include "fastfetch_datatext.h"
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
@@ -13,7 +15,7 @@ extern CFStringRef MRNowPlayingClientGetBundleIdentifier(id clientObj) __attribu
|
||||
extern CFStringRef MRNowPlayingClientGetParentAppBundleIdentifier(id clientObj) __attribute__((weak_import));
|
||||
void MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_queue_t queue, void (^callback)(BOOL playing)) __attribute__((weak_import));
|
||||
|
||||
static const char* getMedia(FFMediaResult* result)
|
||||
static const char* getMediaByMediaRemote(FFMediaResult* result)
|
||||
{
|
||||
#define FF_TEST_FN_EXISTANCE(fn) if (!fn) return "MediaRemote function " #fn " is not available"
|
||||
FF_TEST_FN_EXISTANCE(MRMediaRemoteGetNowPlayingInfo);
|
||||
@@ -79,8 +81,34 @@ static const char* getMedia(FFMediaResult* result)
|
||||
return error;
|
||||
}
|
||||
|
||||
static const char* getMediaByOsascript(FFMediaResult* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
|
||||
// The script must be executed by `/usr/bin/osascript`. `ffOsascript` doesn't work here
|
||||
const char* error = ffProcessAppendStdOut(&buffer, (char* const[]) {
|
||||
"/usr/bin/osascript",
|
||||
"-e",
|
||||
FASTFETCH_DATATEXT_NOWPLAYING,
|
||||
nil
|
||||
});
|
||||
if (error) return error;
|
||||
if (buffer.length == 0) return "No media found";
|
||||
|
||||
// status\ntitle\nartist\nalbum\nbundleName\nappName
|
||||
FFstrbuf* const varList[] = { &result->status, &result->song, &result->artist, &result->album, &result->playerId, &result->player };
|
||||
char* line = NULL;
|
||||
size_t len = 0;
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(varList) && ffStrbufGetline(&line, &len, &buffer); ++i)
|
||||
ffStrbufSetS(varList[i], line);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDetectMediaImpl(FFMediaResult* media)
|
||||
{
|
||||
const char* error = getMedia(media);
|
||||
ffStrbufAppendS(&media->error, error);
|
||||
const char* error;
|
||||
if (@available(macOS 15.4, *))
|
||||
error = getMediaByOsascript(media);
|
||||
else
|
||||
error = getMediaByMediaRemote(media);
|
||||
if (error) ffStrbufAppendS(&media->error, error);
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ static bool getBusProperties(FFDBusData* data, const char* busName, FFMediaResul
|
||||
ffStrbufClear(&result->artist);
|
||||
ffStrbufClear(&result->album);
|
||||
ffStrbufClear(&result->url);
|
||||
ffStrbufClear(&result->status);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,11 +19,16 @@ static const char* getMedia(FFMediaResult* media)
|
||||
}
|
||||
|
||||
ffStrbufSetWS(&media->playerId, result.playerId);
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
if (result.playerName[0])
|
||||
{
|
||||
ffStrbufSetWS(&media->player, result.playerName);
|
||||
}
|
||||
else
|
||||
ffStrbufSubstrAfterFirstC(&media->player, '!'); // UWP ID
|
||||
{
|
||||
ffStrbufSet(&media->player, &media->playerId);
|
||||
if (ffStrbufEndsWithIgnCaseS(&media->player, ".exe"))
|
||||
ffStrbufSubstrBefore(&media->player, media->player.length - 4);
|
||||
}
|
||||
ffStrbufSetWS(&media->song, result.song);
|
||||
ffStrbufSetWS(&media->artist, result.artist);
|
||||
ffStrbufSetWS(&media->album, result.album);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.ApplicationModel.h>
|
||||
#include <wchar.h>
|
||||
|
||||
extern "C"
|
||||
@@ -11,6 +12,7 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
|
||||
// C++/WinRT requires Windows 8.1+ and C++ runtime (std::string, exceptions and other stuff)
|
||||
// Make it a separate dll in order not to break Windows 7 support
|
||||
using namespace winrt::Windows::Media::Control;
|
||||
using namespace winrt::Windows::ApplicationModel;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -48,6 +50,11 @@ const char* ffWinrtDetectMedia(FFWinrtMediaResult* result)
|
||||
::wcsncpy(result->song, mediaProps.Title().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
::wcsncpy(result->artist, mediaProps.Artist().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
::wcsncpy(result->album, mediaProps.AlbumTitle().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
try
|
||||
{
|
||||
// Only works for UWP apps
|
||||
::wcsncpy(result->playerName, AppInfo::GetFromAppUserModelId(session.SourceAppUserModelId()).DisplayInfo().DisplayName().data(), FF_MEDIA_WIN_RESULT_BUFLEN);
|
||||
} catch (...) { }
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
typedef struct FFWinrtMediaResult
|
||||
{
|
||||
wchar_t playerId[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t playerName[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t song[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t artist[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
wchar_t album[FF_MEDIA_WIN_RESULT_BUFLEN];
|
||||
|
||||
@@ -8,8 +8,9 @@ const char* ffDetectMemory(FFMemoryResult* ram)
|
||||
if (get_system_info(&info) != B_OK)
|
||||
return "Error getting system info";
|
||||
|
||||
ram->bytesTotal = B_PAGE_SIZE * info.max_pages;
|
||||
ram->bytesUsed = B_PAGE_SIZE * info.used_pages;
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
ram->bytesTotal = pageSize * info.max_pages;
|
||||
ram->bytesUsed = pageSize * info.used_pages;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -554,7 +554,11 @@ static void getPackageCounts(FFstrbuf* baseDir, FFPackagesResult* packageCounts,
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PACMAN_BIT)) packageCounts->pacman += getNumElements(baseDir, "/var/lib/pacman/local", true);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_LPKGBUILD_BIT)) packageCounts->lpkgbuild += getNumElements(baseDir, "/opt/Loc-OS-LPKG/lpkgbuild/remove", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGTOOL_BIT)) packageCounts->pkgtool += getNumElements(baseDir, "/var/log/packages", false);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT)) packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Packages", "rpm");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_RPM_BIT))
|
||||
{
|
||||
// `Sigmd5` is the only table that doesn't contain the virtual `gpg-pubkey` package
|
||||
packageCounts->rpm += getSQLite3Int(baseDir, "/var/lib/rpm/rpmdb.sqlite", "SELECT count(*) FROM Sigmd5", "rpm");
|
||||
}
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_SNAP_BIT)) packageCounts->snap += getSnap(baseDir);
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_XBPS_BIT)) packageCounts->xbps += getXBPS(baseDir, "/var/db/xbps");
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_BREW_BIT))
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "packages.h"
|
||||
|
||||
#include "common/io/io.h"
|
||||
|
||||
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
{
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
|
||||
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
|
||||
}
|
||||
@@ -4,11 +4,6 @@
|
||||
|
||||
void ffDetectPackagesImpl(FFPackagesResult* result, FFPackagesOptions* options)
|
||||
{
|
||||
#if __OpenBSD__
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKG_BIT))
|
||||
result->pkg = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/var/db/pkg", true);
|
||||
#elif __NetBSD__
|
||||
if (!(options->disabled & FF_PACKAGES_FLAG_PKGSRC_BIT))
|
||||
result->pkgsrc = ffPackagesGetNumElements(FASTFETCH_TARGET_DIR_ROOT "/usr/pkg/pkgdb", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ const char* ffDetectPhysicalDisk(FFlist* result, FFPhysicalDiskOptions* options)
|
||||
FFPhysicalDiskResult* device = (FFPhysicalDiskResult*) ffListAdd(result);
|
||||
ffStrbufInitF(&device->devPath, "/dev/%s", provider->lg_name);
|
||||
ffStrbufInitMove(&device->serial, &identifier);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
ffStrbufInit(&device->revision);
|
||||
ffStrbufInit(&device->interconnect);
|
||||
switch (snapIter->device_type & DEVSTAT_TYPE_IF_MASK)
|
||||
|
||||
@@ -106,7 +106,10 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
|
||||
else if (strstr(pathSysDeviceReal, "/nvme") != NULL)
|
||||
ffStrbufSetStatic(&device->interconnect, "NVMe");
|
||||
else if (strstr(pathSysDeviceReal, "/virtio") != NULL)
|
||||
{
|
||||
ffStrbufSetStatic(&device->interconnect, "Virtual");
|
||||
isVirtual = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ffAppendFileBufferRelative(devfd, "transport", &device->interconnect))
|
||||
@@ -150,7 +153,7 @@ static void parsePhysicalDisk(int dfd, const char* devName, FFPhysicalDiskOption
|
||||
{
|
||||
ffStrbufInit(&device->serial);
|
||||
if (ffReadFileBufferRelative(devfd, "serial", &device->serial))
|
||||
ffStrbufTrimRightSpace(&device->serial);
|
||||
ffStrbufTrim(&device->serial, ' ');
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -94,7 +94,9 @@ const char* ffDetectSound(FFlist* devices /* List of FFSoundDevice */)
|
||||
}, 0, NULL, &dataSize, &active) == kAudioHardwareNoError)
|
||||
device->active = !!active;
|
||||
|
||||
if (!muted)
|
||||
if (muted)
|
||||
device->volume = 0;
|
||||
else
|
||||
{
|
||||
float volume;
|
||||
dataSize = sizeof(volume);
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
typedef struct FFSwapResult
|
||||
{
|
||||
FFstrbuf name;
|
||||
uint64_t bytesUsed;
|
||||
uint64_t bytesTotal;
|
||||
} FFSwapResult;
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap);
|
||||
const char* ffDetectSwap(FFlist* result /* List of FFSwapResult */);
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
#include <mach/mach.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
struct xsw_usage xsw;
|
||||
size_t size = sizeof(xsw);
|
||||
if(sysctl((int[]){ CTL_VM, VM_SWAPUSAGE }, 2, &xsw, &size, NULL, 0) != 0)
|
||||
return "Failed to read vm.swapusage";
|
||||
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitStatic(&swap->name, xsw.xsu_encrypted ? "Encrypted" : "Normal");
|
||||
swap->bytesTotal = xsw.xsu_total;
|
||||
swap->bytesUsed = xsw.xsu_used;
|
||||
return NULL;
|
||||
|
||||
@@ -2,15 +2,57 @@
|
||||
#include "common/sysctl.h"
|
||||
|
||||
#include <vm/vm_param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
static void addSwapEntry(FFlist* result, struct xswdev* xsw, uint32_t pageSize)
|
||||
{
|
||||
if (xsw->xsw_nblks == 0) // DFBSD reports some /dev/wdog devices with nblks == 0
|
||||
return;
|
||||
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
if (xsw->xsw_dev == NODEV)
|
||||
ffStrbufInitStatic(&swap->name, "[NFS]");
|
||||
else
|
||||
ffStrbufInitF(&swap->name, "/dev/%s", devname(xsw->xsw_dev, S_IFCHR));
|
||||
swap->bytesUsed = (uint64_t) xsw->xsw_used * pageSize;
|
||||
swap->bytesTotal = (uint64_t) xsw->xsw_nblks * pageSize;
|
||||
}
|
||||
|
||||
#if __DragonFly__
|
||||
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
struct xswdev xsws[32];
|
||||
size_t size = sizeof(xsws);
|
||||
if (sysctlbyname("vm.swap_info_array", xsws, &size, NULL, 0) < 0)
|
||||
return "sysctlbyname(\"vm.swap_info_array\") failed";
|
||||
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
|
||||
size_t count = size / sizeof(struct xswdev);
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
|
||||
if (xsws->xsw_version != XSWDEV_VERSION)
|
||||
return "xswdev version mismatch";
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i)
|
||||
addSwapEntry(result, &xsws[i], pageSize);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#elif __FreeBSD__
|
||||
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
int mib[16];
|
||||
size_t mibsize = ARRAY_SIZE(mib);
|
||||
if (sysctlnametomib("vm.swap_info", mib, &mibsize) < 0)
|
||||
return "sysctlnametomib(\"vm.swap_info\") failed";
|
||||
|
||||
swap->bytesUsed = swap->bytesTotal = 0;
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
|
||||
for (int n = 0; ; ++n)
|
||||
{
|
||||
@@ -21,12 +63,11 @@ const char* ffDetectSwap(FFSwapResult* swap)
|
||||
break;
|
||||
if (xsw.xsw_version != XSWDEV_VERSION)
|
||||
return "xswdev version mismatch";
|
||||
swap->bytesUsed += (uint64_t) xsw.xsw_used;
|
||||
swap->bytesTotal += (uint64_t) xsw.xsw_nblks;
|
||||
}
|
||||
|
||||
swap->bytesUsed *= instance.state.platform.sysinfo.pageSize;
|
||||
swap->bytesTotal *= instance.state.platform.sysinfo.pageSize;
|
||||
addSwapEntry(result, &xsw, pageSize);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,27 @@
|
||||
#include "swap.h"
|
||||
|
||||
#include <OS.h>
|
||||
#include <driver_settings.h>
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
system_info info;
|
||||
if (get_system_info(&info) != B_OK)
|
||||
return "Error getting system info";
|
||||
|
||||
swap->bytesTotal = B_PAGE_SIZE * (uint64_t) info.max_swap_pages;
|
||||
swap->bytesUsed = B_PAGE_SIZE * (uint64_t) (info.max_swap_pages - info.free_swap_pages);
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitStatic(&swap->name, "System");
|
||||
void* kvms = load_driver_settings("virtual_memory"); // /boot/home/config/settings/kernel/drivers/virtual_memory
|
||||
if (kvms)
|
||||
{
|
||||
const char* swapAuto = get_driver_parameter(kvms, "swap_auto", NULL, NULL);
|
||||
if (swapAuto)
|
||||
ffStrbufSetStatic(&swap->name, swapAuto[0] == 'y' ? "Auto" : "Manual");
|
||||
unload_driver_settings(kvms);
|
||||
}
|
||||
swap->bytesTotal = pageSize * (uint64_t) info.max_swap_pages;
|
||||
swap->bytesUsed = pageSize * (uint64_t) (info.max_swap_pages - info.free_swap_pages);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
static const char* detectByProcMeminfo(FFlist* result)
|
||||
{
|
||||
// For Android
|
||||
// Ref: #620
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData("/proc/meminfo", ARRAY_SIZE(buf) - 1, buf);
|
||||
@@ -23,8 +24,59 @@ const char* ffDetectSwap(FFSwapResult* swap)
|
||||
if ((token = strstr(buf, "SwapFree:")) != NULL)
|
||||
swapFree = strtoul(token + strlen("SwapFree:"), NULL, 10);
|
||||
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitStatic(&swap->name, "Total");
|
||||
swap->bytesTotal = swapTotal * 1024lu;
|
||||
swap->bytesUsed = (swapTotal - swapFree) * 1024lu;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char* detectByProcSwaps(FFlist* result)
|
||||
{
|
||||
// Ref: #620
|
||||
char buf[PROC_FILE_BUFFSIZ];
|
||||
ssize_t nRead = ffReadFileData("/proc/swaps", ARRAY_SIZE(buf) - 1, buf);
|
||||
if(nRead <= 0)
|
||||
return "ffReadFileData(\"/proc/swaps\", ARRAY_SIZE(buf)-1, buf) failed";
|
||||
buf[nRead] = '\0';
|
||||
|
||||
// Skip header
|
||||
char* line = memchr(buf, '\n', (size_t) nRead);
|
||||
|
||||
while(line && *++line)
|
||||
{
|
||||
uint64_t total, used;
|
||||
char name[256];
|
||||
if(sscanf(line, "%255s %*[^\t]%" SCNu64 "%" SCNu64, name, &total, &used) != 3)
|
||||
return "Invalid /proc/swaps format found";
|
||||
|
||||
uint32_t nameLen = (uint32_t) strnlen(name, sizeof(name));
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitA(&swap->name, nameLen);
|
||||
for (size_t i = 0; i < nameLen; ++i)
|
||||
{
|
||||
if(name[i] == '\\')
|
||||
{
|
||||
char octal[4] = { name[i + 1], name[i + 2], name[i + 3], '\0' };
|
||||
ffStrbufAppendC(&swap->name, (char) strtol(octal, NULL, 8));
|
||||
i += 3;
|
||||
}
|
||||
else
|
||||
ffStrbufAppendC(&swap->name, name[i]);
|
||||
}
|
||||
swap->bytesTotal = total * 1024u;
|
||||
swap->bytesUsed = used * 1024u;
|
||||
|
||||
line = memchr(line, '\n', (size_t) (nRead - (line - buf)));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
if (detectByProcSwaps(result) == NULL)
|
||||
return NULL;
|
||||
return detectByProcMeminfo(result);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "swap.h"
|
||||
#include "util/FFlist.h"
|
||||
#include "util/mallocHelper.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
@@ -6,7 +7,7 @@
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
int nswap = swapctl(SWAP_NSWAP, 0, 0);
|
||||
if (nswap < 0) return "swapctl(SWAP_NSWAP) failed";
|
||||
@@ -17,17 +18,16 @@ const char* ffDetectSwap(FFSwapResult* swap)
|
||||
if (swapctl(SWAP_STATS, swdev, nswap) < 0)
|
||||
return "swapctl(SWAP_STATS) failed";
|
||||
|
||||
uint64_t swapTotal = 0, swapUsed = 0;
|
||||
for (int i = 0; i < nswap; i++)
|
||||
{
|
||||
if (swdev[i].se_flags & SWF_ENABLE)
|
||||
{
|
||||
swapUsed += (uint64_t) swdev[i].se_inuse;
|
||||
swapTotal += (uint64_t) swdev[i].se_nblks;
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitS(&swap->name, swdev[i].se_path);
|
||||
swap->bytesUsed = (uint64_t) swdev[i].se_inuse * DEV_BSIZE;
|
||||
swap->bytesTotal = (uint64_t) swdev[i].se_nblks * DEV_BSIZE;
|
||||
}
|
||||
}
|
||||
swap->bytesUsed = swapUsed * DEV_BSIZE;
|
||||
swap->bytesTotal = swapTotal * DEV_BSIZE;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
enum { FFMaxNSwap = 8 };
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
char strings[FFMaxNSwap][PATH_MAX];
|
||||
uint8_t buffer[sizeof(swaptbl_t) + sizeof(swapent_t) * (FFMaxNSwap - 1)] = {};
|
||||
@@ -18,16 +18,14 @@ const char* ffDetectSwap(FFSwapResult* swap)
|
||||
if (size < 0)
|
||||
return "swapctl() failed";
|
||||
|
||||
swap->bytesTotal = swap->bytesUsed = 0;
|
||||
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
swap->bytesTotal += (uint64_t) table->swt_ent[i].ste_pages;
|
||||
swap->bytesUsed += (uint64_t) table->swt_ent[i].ste_free;
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitS(&swap->name, table->swt_ent[i].ste_path);
|
||||
swap->bytesTotal = (uint64_t) table->swt_ent[i].ste_pages * pageSize;
|
||||
swap->bytesUsed = swap->bytesTotal - (uint64_t) table->swt_ent[i].ste_free * pageSize;
|
||||
}
|
||||
swap->bytesUsed = swap->bytesTotal - swap->bytesUsed;
|
||||
swap->bytesTotal *= instance.state.platform.sysinfo.pageSize;
|
||||
swap->bytesUsed *= instance.state.platform.sysinfo.pageSize;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "swap.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "util/windows/unicode.h"
|
||||
|
||||
#include <winternl.h>
|
||||
#include <ntstatus.h>
|
||||
#include <windows.h>
|
||||
|
||||
const char* ffDetectSwap(FFSwapResult* swap)
|
||||
const char* ffDetectSwap(FFlist* result)
|
||||
{
|
||||
uint8_t buffer[4096];
|
||||
ULONG size = sizeof(buffer);
|
||||
@@ -13,16 +14,18 @@ const char* ffDetectSwap(FFSwapResult* swap)
|
||||
if(!NT_SUCCESS(NtQuerySystemInformation(SystemPagefileInformation, pstart, size, &size)))
|
||||
return "NtQuerySystemInformation(SystemPagefileInformation, size) failed";
|
||||
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
for (SYSTEM_PAGEFILE_INFORMATION* current = pstart; ; current = (SYSTEM_PAGEFILE_INFORMATION*)((uint8_t*) current + current->NextEntryOffset))
|
||||
{
|
||||
swap->bytesUsed += current->TotalUsed;
|
||||
swap->bytesTotal += current->CurrentSize;
|
||||
FFSwapResult* swap = ffListAdd(result);
|
||||
ffStrbufInitNWS(&swap->name, current->FileName.Length / sizeof(wchar_t), current->FileName.Buffer);
|
||||
if (ffStrbufStartsWithS(&swap->name, "\\??\\"))
|
||||
ffStrbufSubstrAfter(&swap->name, strlen("\\??\\") - 1);
|
||||
swap->bytesUsed = current->TotalUsed * pageSize;
|
||||
swap->bytesTotal = current->CurrentSize * pageSize;
|
||||
if (current->NextEntryOffset == 0)
|
||||
break;
|
||||
}
|
||||
uint32_t pageSize = instance.state.platform.sysinfo.pageSize;
|
||||
swap->bytesUsed *= pageSize;
|
||||
swap->bytesTotal *= pageSize;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ static bool getShellVersionBash(FFstrbuf* exe, FFstrbuf* exePath, FFstrbuf* vers
|
||||
if (*path == '\0')
|
||||
path = exe->chars;
|
||||
ffBinaryExtractStrings(path, extractBashVersion, version, (uint32_t) strlen("@(#)Bash version 0.0.0(0) release GNU"));
|
||||
if (version->length > 0) return true;
|
||||
|
||||
if(!getExeVersionRaw(exe, version))
|
||||
return false;
|
||||
|
||||
@@ -55,9 +55,10 @@ static pid_t getShellInfo(FFShellResult* result, pid_t pid)
|
||||
ffStrbufEqualS(&result->processName, "valgrind") ||
|
||||
ffStrbufEqualS(&result->processName, "fastfetch") || //994
|
||||
ffStrbufEqualS(&result->processName, "flashfetch") ||
|
||||
ffStrbufEqualS(&result->processName, "proot") ||
|
||||
ffStrbufEqualS(&result->processName, "script") ||
|
||||
ffStrbufContainS(&result->processName, "debug") ||
|
||||
ffStrbufContainS(&result->processName, "command-not-") ||
|
||||
ffStrbufEqualS(&result->processName, "proot") ||
|
||||
ffStrbufEndsWithS(&result->processName, ".sh")
|
||||
)
|
||||
{
|
||||
@@ -107,6 +108,7 @@ static pid_t getTerminalInfo(FFTerminalResult* result, pid_t pid)
|
||||
ffStrbufEqualS(&result->processName, "clifm") || // https://github.com/leo-arch/clifm/issues/289
|
||||
ffStrbufEqualS(&result->processName, "chezmoi") || // #762
|
||||
ffStrbufEqualS(&result->processName, "proot") ||
|
||||
ffStrbufEqualS(&result->processName, "script") ||
|
||||
#ifdef __linux__
|
||||
ffStrbufStartsWithS(&result->processName, "flatpak-") || // #707
|
||||
#endif
|
||||
|
||||
@@ -17,6 +17,7 @@ const char* ffDetectWifi(FFlist* result)
|
||||
|
||||
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sock < 0) {
|
||||
if_freenameindex(infs);
|
||||
return "socket() failed";
|
||||
}
|
||||
|
||||
@@ -82,22 +83,23 @@ const char* ffDetectWifi(FFlist* result)
|
||||
item->conn.channel = curchan.ic_ieee;
|
||||
item->conn.frequency = curchan.ic_freq;
|
||||
|
||||
if (IEEE80211_IS_CHAN_FHSS(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11 (FHSS)");
|
||||
if (IEEE80211_IS_CHAN_A(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
|
||||
if (IEEE80211_IS_CHAN_B(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11b");
|
||||
if (IEEE80211_IS_CHAN_ANYG(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
|
||||
if (IEEE80211_IS_CHAN_HT(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
if (IEEE80211_IS_CHAN_VHT(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
#ifdef IEEE80211_IS_CHAN_HE // for future use
|
||||
if (IEEE80211_IS_CHAN_HE(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
|
||||
else
|
||||
#endif
|
||||
if (IEEE80211_IS_CHAN_VHT(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
else if (IEEE80211_IS_CHAN_HT(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
else if (IEEE80211_IS_CHAN_ANYG(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
|
||||
else if (IEEE80211_IS_CHAN_B(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11b");
|
||||
else if (IEEE80211_IS_CHAN_A(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
|
||||
else if (IEEE80211_IS_CHAN_FHSS(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11 (FHSS)");
|
||||
}
|
||||
|
||||
union {
|
||||
|
||||
+107
-49
@@ -2,12 +2,21 @@
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#define COMPAT_FREEBSD_NET80211 1
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_media.h>
|
||||
#include <net80211/ieee80211.h>
|
||||
#include <net80211/ieee80211_ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// ieee80211 header of NetBSD is full of mess. Add compatibility macros from FreeBSD
|
||||
#undef IEEE80211_IS_CHAN_ANYG
|
||||
#define IEEE80211_IS_CHAN_ANYG(x) (IEEE80211_IS_CHAN_PUREG(x) || IEEE80211_IS_CHAN_G(x))
|
||||
#undef IEEE80211_IS_CHAN_HT
|
||||
#define IEEE80211_IS_CHAN_HT(x) (((x)->ic_flags & IEEE80211_CHAN_HT) != 0)
|
||||
#undef IEEE80211_IS_CHAN_VHT
|
||||
#define IEEE80211_IS_CHAN_VHT(x) (((x)->ic_flags & IEEE80211_CHAN_VHT) != 0)
|
||||
|
||||
const char* ffDetectWifi(FFlist* result)
|
||||
{
|
||||
@@ -18,6 +27,7 @@ const char* ffDetectWifi(FFlist* result)
|
||||
|
||||
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sock < 0) {
|
||||
if_freenameindex(infs);
|
||||
return "socket() failed";
|
||||
}
|
||||
|
||||
@@ -41,67 +51,115 @@ const char* ffDetectWifi(FFlist* result)
|
||||
item->conn.channel = 0;
|
||||
item->conn.frequency = 0;
|
||||
|
||||
struct ieee80211_nodereq nr = {};
|
||||
strlcpy(nr.nr_ifname, i->if_name, sizeof(nr.nr_ifname));
|
||||
char ssid[IEEE80211_NWID_LEN + 1] = {};
|
||||
struct ieee80211req ireq = {};
|
||||
strlcpy(ireq.i_name, i->if_name, sizeof(ireq.i_name));
|
||||
ireq.i_type = IEEE80211_IOC_SSID;
|
||||
ireq.i_data = ssid;
|
||||
ireq.i_len = sizeof(ssid) - 1;
|
||||
|
||||
struct ifreq ifr = {};
|
||||
strlcpy(ifr.ifr_name, i->if_name, sizeof(ifr.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
ffStrbufSetStatic(&item->inf.status, "Unknown");
|
||||
} else {
|
||||
ffStrbufSetStatic(&item->inf.status, ifr.ifr_flags & IFF_UP ? "Up" : "Down");
|
||||
}
|
||||
|
||||
if (ioctl(sock, SIOCG80211NODE, &nr) < 0) {
|
||||
ffStrbufSetStatic(&item->conn.status, "Not associated");
|
||||
if (ioctl(sock, SIOCG80211, &ireq) < 0 || ireq.i_len == 0) {
|
||||
struct ifreq ifr;
|
||||
strlcpy(ifr.ifr_name, i->if_name, sizeof(ifr.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
ffStrbufSetStatic(&item->inf.status, "Unknown");
|
||||
} else {
|
||||
ffStrbufSetStatic(&item->inf.status, ifr.ifr_flags & IFF_UP ? "Up" : "Down");
|
||||
}
|
||||
ffStrbufAppendS(&item->conn.status, "Not associated");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nr.nr_nwid_len > 0) {
|
||||
ffStrbufSetStatic(&item->conn.status, "Associated");
|
||||
ffStrbufAppendNS(&item->conn.ssid, nr.nr_nwid_len, (char*)nr.nr_nwid);
|
||||
} else {
|
||||
ffStrbufSetStatic(&item->conn.status, "Not associated");
|
||||
continue;
|
||||
ffStrbufSetStatic(&item->inf.status, "Up");
|
||||
ffStrbufSetStatic(&item->conn.status, "Associated");
|
||||
ffStrbufAppendNS(&item->conn.ssid, ireq.i_len, ssid);
|
||||
|
||||
uint8_t bssid[IEEE80211_ADDR_LEN] = {};
|
||||
ireq.i_type = IEEE80211_IOC_BSSID;
|
||||
ireq.i_data = bssid;
|
||||
ireq.i_len = sizeof(bssid);
|
||||
|
||||
if (ioctl(sock, SIOCG80211, &ireq) >= 0) {
|
||||
ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
|
||||
}
|
||||
|
||||
ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
nr.nr_bssid[0], nr.nr_bssid[1], nr.nr_bssid[2],
|
||||
nr.nr_bssid[3], nr.nr_bssid[4], nr.nr_bssid[5]);
|
||||
struct ieee80211_channel curchan = {};
|
||||
ireq.i_type = IEEE80211_IOC_CHANNEL;
|
||||
ireq.i_data = &curchan;
|
||||
ireq.i_len = sizeof(curchan);
|
||||
|
||||
item->conn.channel = nr.nr_channel;
|
||||
if (ioctl(sock, SIOCG80211, &ireq) >= 0) {
|
||||
// item->conn.channel = curchan.ic_ieee; // No ic_ieee in NetBSD
|
||||
item->conn.channel = ffWifiFreqToChannel(curchan.ic_freq);
|
||||
item->conn.frequency = curchan.ic_freq;
|
||||
|
||||
if (nr.nr_max_rssi) {
|
||||
item->conn.signalQuality = ((float)nr.nr_rssi / nr.nr_max_rssi) * 100.0;
|
||||
#ifdef IEEE80211_IS_CHAN_HE // for future use
|
||||
if (IEEE80211_IS_CHAN_HE(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ax (Wi-Fi 6)");
|
||||
else
|
||||
#endif
|
||||
if (IEEE80211_IS_CHAN_VHT(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
else if (IEEE80211_IS_CHAN_HT(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
else if (IEEE80211_IS_CHAN_ANYG(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
|
||||
else if (IEEE80211_IS_CHAN_B(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11b");
|
||||
else if (IEEE80211_IS_CHAN_A(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
|
||||
else if (IEEE80211_IS_CHAN_FHSS(&curchan))
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11 (FHSS)");
|
||||
}
|
||||
|
||||
if (nr.nr_flags & IEEE80211_NODEREQ_HT) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
} else if (nr.nr_flags & IEEE80211_NODEREQ_VHT) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
} else if (nr.nr_chan_flags & IEEE80211_CHANINFO_5GHZ) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
|
||||
} else if (nr.nr_chan_flags & IEEE80211_CHANINFO_2GHZ) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
|
||||
union {
|
||||
struct ieee80211req_sta_req req;
|
||||
uint8_t buf[1024];
|
||||
} stareq = {};
|
||||
memcpy(stareq.req.is_u.macaddr, bssid, sizeof(bssid));
|
||||
ireq.i_type = IEEE80211_IOC_STA_INFO;
|
||||
ireq.i_data = &stareq;
|
||||
ireq.i_len = sizeof(stareq);
|
||||
|
||||
if (ioctl(sock, SIOCG80211, &ireq) >= 0) {
|
||||
struct ieee80211req_sta_info* sta = stareq.req.info;
|
||||
if (sta->isi_len != 0) {
|
||||
int8_t rssi = (int8_t) sta->isi_rssi; // Strangely, `sta->isi_rssi` is unsigned
|
||||
item->conn.signalQuality = (rssi >= -50 ? 100 : rssi <= -100 ? 0 : (rssi + 100) * 2);
|
||||
|
||||
if (sta->isi_txrate) {
|
||||
item->conn.txRate = (double)sta->isi_txrate / 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ieee80211_wpaparams wpa = {};
|
||||
strlcpy(wpa.i_name, i->if_name, sizeof(wpa.i_name));
|
||||
|
||||
if (ioctl(sock, SIOCG80211WPAPARMS, &wpa) >= 0 && wpa.i_enabled) {
|
||||
if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2)
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA2");
|
||||
else if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1)
|
||||
ireq.i_type = IEEE80211_IOC_AUTHMODE;
|
||||
ireq.i_data = NULL;
|
||||
ireq.i_len = 0;
|
||||
if (ioctl(sock, SIOCG80211, &ireq) >= 0) {
|
||||
switch (ireq.i_val) {
|
||||
case IEEE80211_AUTH_NONE:
|
||||
ffStrbufSetStatic(&item->conn.security, "Insecure");
|
||||
break;
|
||||
case IEEE80211_AUTH_OPEN:
|
||||
ffStrbufSetStatic(&item->conn.security, "Open");
|
||||
break;
|
||||
case IEEE80211_AUTH_SHARED:
|
||||
ffStrbufSetStatic(&item->conn.security, "Shared");
|
||||
break;
|
||||
case IEEE80211_AUTH_8021X:
|
||||
ffStrbufSetStatic(&item->conn.security, "8021X");
|
||||
break;
|
||||
case IEEE80211_AUTH_AUTO:
|
||||
ffStrbufSetStatic(&item->conn.security, "Auto");
|
||||
break;
|
||||
case IEEE80211_AUTH_WPA:
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA");
|
||||
} else {
|
||||
struct ieee80211_nwkey nwkey = {};
|
||||
strlcpy(nwkey.i_name, i->if_name, sizeof(nwkey.i_name));
|
||||
|
||||
if (ioctl(sock, SIOCG80211NWKEY, &nwkey) >= 0) {
|
||||
if (nwkey.i_wepon)
|
||||
ffStrbufSetStatic(&item->conn.security, "WEP");
|
||||
else
|
||||
ffStrbufSetStatic(&item->conn.security, "Open");
|
||||
break;
|
||||
default:
|
||||
ffStrbufSetF(&item->conn.security, "Unknown (%d)", ireq.i_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "wifi.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net80211/ieee80211.h>
|
||||
#include <net80211/ieee80211_ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const char* ffDetectWifi(FFlist* result)
|
||||
{
|
||||
struct if_nameindex* infs = if_nameindex();
|
||||
if(!infs) {
|
||||
return "if_nameindex() failed";
|
||||
}
|
||||
|
||||
FF_AUTO_CLOSE_FD int sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(sock < 0) {
|
||||
return "socket() failed";
|
||||
}
|
||||
|
||||
for(struct if_nameindex* i = infs; !(i->if_index == 0 && i->if_name == NULL); ++i)
|
||||
{
|
||||
if (!ffStrStartsWith(i->if_name, "iwm")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
FFWifiResult* item = (FFWifiResult*) ffListAdd(result);
|
||||
ffStrbufInitS(&item->inf.description, i->if_name);
|
||||
ffStrbufInit(&item->inf.status);
|
||||
ffStrbufInit(&item->conn.status);
|
||||
ffStrbufInit(&item->conn.ssid);
|
||||
ffStrbufInit(&item->conn.bssid);
|
||||
ffStrbufInit(&item->conn.protocol);
|
||||
ffStrbufInit(&item->conn.security);
|
||||
item->conn.signalQuality = 0.0/0.0;
|
||||
item->conn.rxRate = 0.0/0.0;
|
||||
item->conn.txRate = 0.0/0.0;
|
||||
item->conn.channel = 0;
|
||||
item->conn.frequency = 0;
|
||||
|
||||
struct ieee80211_nodereq nr = {};
|
||||
strlcpy(nr.nr_ifname, i->if_name, sizeof(nr.nr_ifname));
|
||||
|
||||
struct ifreq ifr = {};
|
||||
strlcpy(ifr.ifr_name, i->if_name, sizeof(ifr.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
ffStrbufSetStatic(&item->inf.status, "Unknown");
|
||||
} else {
|
||||
ffStrbufSetStatic(&item->inf.status, ifr.ifr_flags & IFF_UP ? "Up" : "Down");
|
||||
}
|
||||
|
||||
if (ioctl(sock, SIOCG80211NODE, &nr) < 0) {
|
||||
ffStrbufSetStatic(&item->conn.status, "Not associated");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nr.nr_nwid_len > 0) {
|
||||
ffStrbufSetStatic(&item->conn.status, "Associated");
|
||||
ffStrbufAppendNS(&item->conn.ssid, nr.nr_nwid_len, (char*)nr.nr_nwid);
|
||||
} else {
|
||||
ffStrbufSetStatic(&item->conn.status, "Not associated");
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufSetF(&item->conn.bssid, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
nr.nr_bssid[0], nr.nr_bssid[1], nr.nr_bssid[2],
|
||||
nr.nr_bssid[3], nr.nr_bssid[4], nr.nr_bssid[5]);
|
||||
|
||||
item->conn.channel = nr.nr_channel;
|
||||
|
||||
if (nr.nr_max_rssi) {
|
||||
item->conn.signalQuality = ((float)nr.nr_rssi / nr.nr_max_rssi) * 100.0;
|
||||
}
|
||||
|
||||
if (nr.nr_flags & IEEE80211_NODEREQ_HT) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11n (Wi-Fi 4)");
|
||||
} else if (nr.nr_flags & IEEE80211_NODEREQ_VHT) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11ac (Wi-Fi 5)");
|
||||
} else if (nr.nr_chan_flags & IEEE80211_CHANINFO_5GHZ) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11a");
|
||||
} else if (nr.nr_chan_flags & IEEE80211_CHANINFO_2GHZ) {
|
||||
ffStrbufSetStatic(&item->conn.protocol, "802.11g");
|
||||
}
|
||||
|
||||
struct ieee80211_wpaparams wpa = {};
|
||||
strlcpy(wpa.i_name, i->if_name, sizeof(wpa.i_name));
|
||||
|
||||
if (ioctl(sock, SIOCG80211WPAPARMS, &wpa) >= 0 && wpa.i_enabled) {
|
||||
if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA2)
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA2");
|
||||
else if (wpa.i_protos & IEEE80211_WPA_PROTO_WPA1)
|
||||
ffStrbufSetStatic(&item->conn.security, "WPA");
|
||||
} else {
|
||||
struct ieee80211_nwkey nwkey = {};
|
||||
strlcpy(nwkey.i_name, i->if_name, sizeof(nwkey.i_name));
|
||||
|
||||
if (ioctl(sock, SIOCG80211NWKEY, &nwkey) >= 0) {
|
||||
if (nwkey.i_wepon)
|
||||
ffStrbufSetStatic(&item->conn.security, "WEP");
|
||||
else
|
||||
ffStrbufSetStatic(&item->conn.security, "Open");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if_freenameindex(infs);
|
||||
return NULL;
|
||||
}
|
||||
@@ -128,6 +128,39 @@ static const char* getSway(FFstrbuf* result)
|
||||
return "Failed to run command `sway --version`";
|
||||
}
|
||||
|
||||
static bool extractI3Version(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
|
||||
{
|
||||
int count = 0;
|
||||
sscanf(line, "%*d.%*d%n", &count);
|
||||
if (count == 0) return true;
|
||||
|
||||
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* getI3(FFstrbuf* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
const char* error = ffFindExecutableInPath("i3", &path);
|
||||
if (error) return "Failed to find i3 executable path";
|
||||
|
||||
ffBinaryExtractStrings(path.chars, extractI3Version, result, (uint32_t) strlen("0.0"));
|
||||
if (result->length > 0) return NULL;
|
||||
|
||||
if (ffProcessAppendStdOut(result, (char* const[]){
|
||||
path.chars,
|
||||
"--version",
|
||||
NULL
|
||||
}) == NULL)
|
||||
{ // i3 version 1.10 C 2009...
|
||||
ffStrbufSubstrAfterFirstS(result, "version ");
|
||||
ffStrbufSubstrBeforeFirstC(result, ' ');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "Failed to run command `i3 --version`";
|
||||
}
|
||||
|
||||
static const char* getWslg(FFstrbuf* result)
|
||||
{
|
||||
if (!ffAppendFileBuffer("/mnt/wslg/versions.txt", result))
|
||||
@@ -143,6 +176,62 @@ static const char* getWslg(FFstrbuf* result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool extractCtFvWmVersion(const char* line, FF_MAYBE_UNUSED uint32_t len, void *userdata)
|
||||
{
|
||||
int count = 0;
|
||||
sscanf(line, "%*d.%*d.%*d%n", &count);
|
||||
if (count == 0) return true;
|
||||
|
||||
ffStrbufSetNS((FFstrbuf*) userdata, len, line);
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* getCtwm(FFstrbuf* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
const char* error = ffFindExecutableInPath("ctwm", &path);
|
||||
if (error) return "Failed to find ctwm executable path";
|
||||
|
||||
ffBinaryExtractStrings(path.chars, extractCtFvWmVersion, result, (uint32_t) strlen("0.0.0"));
|
||||
if (result->length > 0) return NULL;
|
||||
|
||||
if (ffProcessAppendStdOut(result, (char* const[]){
|
||||
path.chars,
|
||||
"--version",
|
||||
NULL
|
||||
}) == NULL)
|
||||
{ // ctwm version 4.0.1\n...
|
||||
ffStrbufSubstrBeforeFirstC(result, '\n');
|
||||
ffStrbufSubstrAfterLastC(result, ' ');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "Failed to run command `ctwm --version`";
|
||||
}
|
||||
|
||||
static const char* getFvwm(FFstrbuf* result)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
const char* error = ffFindExecutableInPath("fvwm", &path);
|
||||
if (error) return "Failed to find fvwm executable path";
|
||||
|
||||
ffBinaryExtractStrings(path.chars, extractCtFvWmVersion, result, (uint32_t) strlen("0.0.0"));
|
||||
if (result->length > 0) return NULL;
|
||||
|
||||
if (ffProcessAppendStdOut(result, (char* const[]){
|
||||
path.chars,
|
||||
"-version",
|
||||
NULL
|
||||
}) == NULL)
|
||||
{ // [FVWM][main]: fvwm Version 2.2.5\n...
|
||||
ffStrbufSubstrBeforeFirstC(result, '\n');
|
||||
ffStrbufSubstrAfterLastC(result, ' ');
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return "Failed to run command `fvwm -version`";
|
||||
}
|
||||
|
||||
const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE_UNUSED FFWMOptions* options)
|
||||
{
|
||||
if (!wmName)
|
||||
@@ -154,8 +243,17 @@ const char* ffDetectWMVersion(const FFstrbuf* wmName, FFstrbuf* result, FF_MAYBE
|
||||
if (ffStrbufEqualS(wmName, "sway"))
|
||||
return getSway(result);
|
||||
|
||||
if (ffStrbufEqualS(wmName, "i3"))
|
||||
return getI3(result);
|
||||
|
||||
if (ffStrbufEqualS(wmName, "WSLg"))
|
||||
return getWslg(result);
|
||||
|
||||
if (ffStrbufEqualS(wmName, "ctwm"))
|
||||
return getCtwm(result);
|
||||
|
||||
if (ffStrbufEqualS(wmName, "fvwm"))
|
||||
return getFvwm(result);
|
||||
|
||||
return "Unsupported WM";
|
||||
}
|
||||
|
||||
+3
-1
@@ -26,7 +26,9 @@
|
||||
#include "options/general.h"
|
||||
|
||||
#ifdef __has_builtin
|
||||
#if __has_builtin(__builtin_types_compatible_p)
|
||||
#if __has_builtin(__is_array)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#elif __has_builtin(__builtin_types_compatible_p)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -2,3 +2,7 @@
|
||||
|
||||
#define FASTFETCH_DATATEXT_JSON_HELP @DATATEXT_JSON_HELP@
|
||||
#define FASTFETCH_DATATEXT_STRUCTURE @DATATEXT_STRUCTURE@
|
||||
|
||||
#ifdef __APPLE__
|
||||
#define FASTFETCH_DATATEXT_NOWPLAYING @DATATEXT_NOWPLAYING@
|
||||
#endif
|
||||
|
||||
+21
-21
@@ -1,21 +1,21 @@
|
||||
${c1}rrrrrraaaaaaaaaaaayyyy
|
||||
${c1}xxrrrrrrrraaaaaaaaaaaayyyyyyyyy
|
||||
${c1}xxxxxrrrrrrrraaaaaaaaaaaayyyyyyy${c3}yyyyy${c2}yyyyyyyyyy
|
||||
${c1}xxxxxxxrrrrrrrraaaaa ${c2}aaaaayyyyyyyyyyyyyyyyyyy
|
||||
${c1}xxxxxx${c3}xxx${c1}rrrrrrrraaaa ${c2}aaaaaaayyyyyyyyyyyyyyyyy
|
||||
${c1}xxxxxx${c3}xxxxxr${c1}rrrrrrraa ${c2}aaaaaaaaay${c3}yyyyyyyyy${c2}yyyy ${c1}yy
|
||||
${c1}xxxxxxx${c3}xxx${c1}xxrrrrrrrra ${c2}aaaaaaaaa${c3}ayyyyyyyyyyyy${c1}yyyyyy
|
||||
${c1}xxxxxxxxxxxxrrrrrrrr ${c2}aaaaaaaaaaa${c3}yyyyyyyyyyyy${c1}yyyyyyy
|
||||
${c1}xxxxxxxxxxxxxrrrrrr ${c2}raaaaaaaaaaaayyy${c3}yyyyyyyy${c1}yyyyyy${c1}yyy
|
||||
${c1}xxxxxxxxxxxxxrrrrr ${c2}rraaaaaaaaaaaayyyyy${c3}yy${c2}yyyyyy ${c1}yyyyyy
|
||||
${c1}xxxxxxxx${c3}xxxx${c1}xrrrrr${c2}rr${c3}raaaaaaa${c2}aaaaayyyyyyyyyy ${c1}yyyyyyyyy
|
||||
${c1}xxxxxxx${c3}xxxx${c1}xxrrrrrrr${c3}raaaaaa${c2}aaaaaayyyyyyy ${c1}yyyyyyyyyyyy
|
||||
${c1}xxxxxxx${c3}xxx${c1}xxxrrrrrrrr${c3}aaaaaa${c2}aaaaaayyyy ${c1}yyyyyyyyyyyyyy
|
||||
${c1}xxxxxxxxxxxxrrrrrrrra ${c2}aaaaaaaaaay ${c1}yyyyyyyyyyyyyyyy
|
||||
${c1}xxxxxxxxxxxrrrrrrr ${c2}aaaaaaaaaaaayyyy${c1}yyyyyyyyyyyyy
|
||||
${c1}xxxxxxx${c3}xxxrr${c1}rrrr ${c2}raaaaaaaaaaaa ${c1}yyyyyyyyyyyyyyy
|
||||
${c1}xxxxxxxxrrrr ${c2}rrraaaaaaaaa ${c1}aayyyyyyyyyyyyyy
|
||||
${c1}xxxxxxrrrrrrr ${c2}aaaaaa ${c1}aaaayyyyyyyyyyyy
|
||||
${c1}xxxrrrrrr ${c2}raaa ${c1}aaaaaaayyyyyyyyy
|
||||
${c1}rrrr ${c2}rr ${c1}aaaaaaaaaayyyyyy
|
||||
${c2}r ${c1}aaaaaaaaaa
|
||||
$1rrrrrraaaaaaaaaaaayyyy
|
||||
$1xxrrrrrrrraaaaaaaaaaaayyyyyyyyy
|
||||
$1xxxxxrrrrrrrraaaaaaaaaaaayyyyyyy$3yyyyy$2yyyyyyyyyy
|
||||
$1xxxxxxxrrrrrrrraaaaa $2aaaaayyyyyyyyyyyyyyyyyyy
|
||||
$1xxxxxx$3xxx$1rrrrrrrraaaa $2aaaaaaayyyyyyyyyyyyyyyyy
|
||||
$1xxxxxx$3xxxxxr$1rrrrrrraa $2aaaaaaaaay$3yyyyyyyyy$2yyyy $1yy
|
||||
$1xxxxxxx$3xxx$1xxrrrrrrrra $2aaaaaaaaa$3ayyyyyyyyyyyy$1yyyyyy
|
||||
$1xxxxxxxxxxxxrrrrrrrr $2aaaaaaaaaaa$3yyyyyyyyyyyy$1yyyyyyy
|
||||
$1xxxxxxxxxxxxxrrrrrr $2raaaaaaaaaaaayyy$3yyyyyyyy$1yyyyyy$1yyy
|
||||
$1xxxxxxxxxxxxxrrrrr $2rraaaaaaaaaaaayyyyy$3yy$2yyyyyy $1yyyyyy
|
||||
$1xxxxxxxx$3xxxx$1xrrrrr$2rr$3raaaaaaa$2aaaaayyyyyyyyyy $1yyyyyyyyy
|
||||
$1xxxxxxx$3xxxx$1xxrrrrrrr$3raaaaaa$2aaaaaayyyyyyy $1yyyyyyyyyyyy
|
||||
$1xxxxxxx$3xxx$1xxxrrrrrrrr$3aaaaaa$2aaaaaayyyy $1yyyyyyyyyyyyyy
|
||||
$1xxxxxxxxxxxxrrrrrrrra $2aaaaaaaaaay $1yyyyyyyyyyyyyyyy
|
||||
$1xxxxxxxxxxxrrrrrrr $2aaaaaaaaaaaayyyy$1yyyyyyyyyyyyy
|
||||
$1xxxxxxx$3xxxrr$1rrrr $2raaaaaaaaaaaa $1yyyyyyyyyyyyyyy
|
||||
$1xxxxxxxxrrrr $2rrraaaaaaaaa $1aayyyyyyyyyyyyyy
|
||||
$1xxxxxxrrrrrrr $2aaaaaa $1aaaayyyyyyyyyyyy
|
||||
$1xxxrrrrrr $2raaa $1aaaaaaayyyyyyyyy
|
||||
$1rrrr $2rr $1aaaaaaaaaayyyyyy
|
||||
$2r $1aaaaaaaaaa
|
||||
+11
-11
@@ -1,16 +1,16 @@
|
||||
${c3} ,-^-___
|
||||
${c3} /\\\///
|
||||
${c2}refined.${c1} /\\\\//
|
||||
${c2}reliable.${c1} /\\\///
|
||||
${c2}ready.${c1} /\\/////\
|
||||
$3 ,-^-___
|
||||
$3 /\\\///
|
||||
$2refined.$1 /\\\\//
|
||||
$2reliable.$1 /\\\///
|
||||
$2ready.$1 /\\/////\
|
||||
__///\\\\/////\
|
||||
${c3} _//////\\\\\\\////
|
||||
${c1} ///////${c3}\\\\\\\\\\//
|
||||
//////${c1}\\\\\/
|
||||
$3 _//////\\\\\\\////
|
||||
$1 ///////$3\\\\\\\\\\//
|
||||
//////$1\\\\\/
|
||||
/////\\\\\/
|
||||
/////${c3}\\\\/
|
||||
/////$3\\\\/
|
||||
/\\///\\\/
|
||||
/\\\/${c1}\\/
|
||||
/\\\/$1\\/
|
||||
/\\\\//
|
||||
//////
|
||||
/// ${c3}\\\\\
|
||||
/// $3\\\\\
|
||||
@@ -1,15 +1,15 @@
|
||||
${c2}.
|
||||
${c1}. ${c2}.{!
|
||||
${c1}.L! ${c2}J@||*
|
||||
${c1}gJJJJL` ${c2}g@FFS"
|
||||
${c1},@FFFJF`${c2}_g@@LLP`
|
||||
${c1}_@FFFFF`${c2}_@@@@@P` ${c4}.
|
||||
${c1}J@@@LLF ${c2}_@@@@@P` ${c4}.J!
|
||||
${c1}g@@@@@" ${c2}_@@@@@P`${c3}. ${c4}.L|||*
|
||||
${c1}g@@@@M" ${c2}"VP`${c3}.L! ${c4}<@JJJJ`
|
||||
${c1}"@N" ${c3}:||||! ${c4}JFFFFS"
|
||||
${c3}.{JJ||F`${c4}_gFFFF@'
|
||||
${c3}.@FJJJF`${c4},@LFFFF`
|
||||
${c3}_@FFFFF ${c4}VLLLP`
|
||||
${c3}J@@LL@" ${c4}`"
|
||||
${c3}V@@"
|
||||
$2.
|
||||
$1. $2.{!
|
||||
$1.L! $2J@||*
|
||||
$1gJJJJL` $2g@FFS"
|
||||
$1,@FFFJF`$2_g@@LLP`
|
||||
$1_@FFFFF`$2_@@@@@P` $4.
|
||||
$1J@@@LLF $2_@@@@@P` $4.J!
|
||||
$1g@@@@@" $2_@@@@@P`$3. $4.L|||*
|
||||
$1g@@@@M" $2"VP`$3.L! $4<@JJJJ`
|
||||
$1"@N" $3:||||! $4JFFFFS"
|
||||
$3.{JJ||F`$4_gFFFF@'
|
||||
$3.@FJJJF`$4,@LFFFF`
|
||||
$3_@FFFFF $4VLLLP`
|
||||
$3J@@LL@" $4`"
|
||||
$3V@@"
|
||||
@@ -1,6 +1,6 @@
|
||||
${c1} /\ /\
|
||||
/${c2}/ ${c1}\ \
|
||||
/${c2}// ${c1}\ \
|
||||
/${c2}// ${c1}\ \
|
||||
${c2}// ${c1}\ \
|
||||
$1 /\ /\
|
||||
/$2/ $1\ \
|
||||
/$2// $1\ \
|
||||
/$2// $1\ \
|
||||
$2// $1\ \
|
||||
\
|
||||
@@ -1,9 +1,9 @@
|
||||
___________
|
||||
/ \
|
||||
/ ${c2}______${c1} \
|
||||
/ ${c2}/ \${c1} \
|
||||
| ${c2}( )${c1} \
|
||||
/ ${c2}\______/${c1} |
|
||||
/ $2______$1 \
|
||||
/ $2/ \$1 \
|
||||
| $2( )$1 \
|
||||
/ $2\______/$1 |
|
||||
| |
|
||||
/ \
|
||||
| |
|
||||
|
||||
+28
-28
@@ -1,28 +1,28 @@
|
||||
${c2}..${c1}
|
||||
${c2}..${c1}
|
||||
${c2}:..${c1}
|
||||
${c2}:+++.${c1}
|
||||
.:::++${c2}++++${c1}+::.
|
||||
.:+######${c2}++++${c1}######+:.
|
||||
.+#########${c2}+++++${c1}##########:.
|
||||
.+##########${c2}+++++++${c1}##${c2}+${c1}#########+.
|
||||
+###########${c2}+++++++++${c1}############:
|
||||
+##########${c2}++++++${c1}#${c2}++++${c1}#${c2}+${c1}###########+
|
||||
+###########${c2}+++++${c1}###${c2}++++${c1}#${c2}+${c1}###########+
|
||||
:##########${c2}+${c1}#${c2}++++${c1}####${c2}++++${c1}#${c2}+${c1}############:
|
||||
###########${c2}+++++${c1}#####${c2}+++++${c1}#${c2}+${c1}###${c2}++${c1}######+
|
||||
.##########${c2}++++++${c1}#####${c2}++++++++++++${c1}#######.
|
||||
.##########${c2}+++++++++++++++++++${c1}###########.
|
||||
#####${c2}++++++++++++++${c1}###${c2}++++++++${c1}#########+
|
||||
:###${c2}++++++++++${c1}#########${c2}+++++++${c1}#########:
|
||||
+######${c2}+++++${c1}##########${c2}++++++++${c1}#######+
|
||||
+####${c2}+++++${c1}###########${c2}+++++++++${c1}#####+
|
||||
:##${c2}++++++${c1}############${c2}++++++++++${c1}##:
|
||||
.${c2}++++++${c1}#############${c2}++++++++++${c1}+.
|
||||
:${c2}++++${c1}###############${c2}+++++++${c1}::
|
||||
.${c2}++. .:+${c1}##############${c2}+++++++${c1}..
|
||||
${c2}.:.${c1} ..::++++++::..:${c2}++++${c1}+.
|
||||
${c2}.${c1} ${c2}.:+++${c1}.
|
||||
${c2}.:${c1}:
|
||||
${c2}..${c1}
|
||||
${c2}..${c1}
|
||||
$2..$1
|
||||
$2..$1
|
||||
$2:..$1
|
||||
$2:+++.$1
|
||||
.:::++$2++++$1+::.
|
||||
.:+######$2++++$1######+:.
|
||||
.+#########$2+++++$1##########:.
|
||||
.+##########$2+++++++$1##$2+$1#########+.
|
||||
+###########$2+++++++++$1############:
|
||||
+##########$2++++++$1#$2++++$1#$2+$1###########+
|
||||
+###########$2+++++$1###$2++++$1#$2+$1###########+
|
||||
:##########$2+$1#$2++++$1####$2++++$1#$2+$1############:
|
||||
###########$2+++++$1#####$2+++++$1#$2+$1###$2++$1######+
|
||||
.##########$2++++++$1#####$2++++++++++++$1#######.
|
||||
.##########$2+++++++++++++++++++$1###########.
|
||||
#####$2++++++++++++++$1###$2++++++++$1#########+
|
||||
:###$2++++++++++$1#########$2+++++++$1#########:
|
||||
+######$2+++++$1##########$2++++++++$1#######+
|
||||
+####$2+++++$1###########$2+++++++++$1#####+
|
||||
:##$2++++++$1############$2++++++++++$1##:
|
||||
.$2++++++$1#############$2++++++++++$1+.
|
||||
:$2++++$1###############$2+++++++$1::
|
||||
.$2++. .:+$1##############$2+++++++$1..
|
||||
$2.:.$1 ..::++++++::..:$2++++$1+.
|
||||
$2.$1 $2.:+++$1.
|
||||
$2.:$1:
|
||||
$2..$1
|
||||
$2..$1
|
||||
+12
-12
@@ -1,19 +1,19 @@
|
||||
${c2} `.-/::/-``
|
||||
$2 `.-/::/-``
|
||||
.-/osssssssso/.
|
||||
:osyysssssssyyys+-
|
||||
`.+yyyysssssssssyyyyy+.
|
||||
`/syyyyyssssssssssyyyyys-`
|
||||
`/yhyyyyysss${c1}++${c2}ssosyyyyhhy/`
|
||||
.ohhhyyyys${c1}o++/+o${c2}so${c1}+${c2}syy${c1}+${c2}shhhho.
|
||||
.shhhhys${c1}oo++//+${c2}sss${c1}+++${c2}yyy${c1}+s${c2}hhhhs.
|
||||
-yhhhhs${c1}+++++++o${c2}ssso${c1}+++${c2}yyy${c1}s+o${c2}hhddy:
|
||||
-yddhhy${c1}o+++++o${c2}syyss${c1}++++${c2}yyy${c1}yooy${c2}hdddy-
|
||||
.yddddhs${c1}o++o${c2}syyyyys${c1}+++++${c2}yyhh${c1}sos${c2}hddddy`
|
||||
`odddddhyosyhyyyyyy${c1}++++++${c2}yhhhyosddddddo
|
||||
.dmdddddhhhhhhhyyyo${c1}+++++${c2}shhhhhohddddmmh.
|
||||
ddmmdddddhhhhhhhso${c1}++++++${c2}yhhhhhhdddddmmdy
|
||||
dmmmdddddddhhhyso${c1}++++++${c2}shhhhhddddddmmmmh
|
||||
-dmmmdddddddhhys${c1}o++++o${c2}shhhhdddddddmmmmd-
|
||||
`/yhyyyyysss$1++$2ssosyyyyhhy/`
|
||||
.ohhhyyyys$1o++/+o$2so$1+$2syy$1+$2shhhho.
|
||||
.shhhhys$1oo++//+$2sss$1+++$2yyy$1+s$2hhhhs.
|
||||
-yhhhhs$1+++++++o$2ssso$1+++$2yyy$1s+o$2hhddy:
|
||||
-yddhhy$1o+++++o$2syyss$1++++$2yyy$1yooy$2hdddy-
|
||||
.yddddhs$1o++o$2syyyyys$1+++++$2yyhh$1sos$2hddddy`
|
||||
`odddddhyosyhyyyyyy$1++++++$2yhhhyosddddddo
|
||||
.dmdddddhhhhhhhyyyo$1+++++$2shhhhhohddddmmh.
|
||||
ddmmdddddhhhhhhhso$1++++++$2yhhhhhhdddddmmdy
|
||||
dmmmdddddddhhhyso$1++++++$2shhhhhddddddmmmmh
|
||||
-dmmmdddddddhhys$1o++++o$2shhhhdddddddmmmmd-
|
||||
.smmmmddddddddhhhhhhhhhdddddddddmmmms.
|
||||
`+ydmmmdddddddddddddddddddmmmmdy/.
|
||||
`.:+ooyyddddddddddddyyso+:.`
|
||||
+17
-17
@@ -1,17 +1,17 @@
|
||||
${c2}__
|
||||
${c2}gpBBBBBBBBBP
|
||||
${c2}_gBBBBBBBBBRP
|
||||
${c2}4BBBBBBBBRP ${c4},_____
|
||||
${c2}`"" ${c4}_g@@@@@@@@@@@@@%g>
|
||||
${c4}__@@@@@@@@@@@@@@@@P" ${c1}___
|
||||
${c4}_g@@@@@@@@@@@@@@@N"` ${c1}_gN@@@@@N^
|
||||
${c4}_w@@@@@@@@@@@@@@@@P" ${c1}_g@@@@@@@P"
|
||||
${c4}_g@@@@@@@@@@@@@@@N"` ${c1}VMNN@NNNM^`
|
||||
${c4}^MMM@@@@@@@@@@@MP" ${c3},ggppww__
|
||||
${c4}`""""" ${c3}_wNNNNNNNNNNNNNNNNNNN
|
||||
${c3}_gBNNNNNNNNNNNNNNNNNP"
|
||||
${c3}_wNNNNNNNNNNNNNNNNNNMP`
|
||||
${c3}_gBNNNNNNNNNNNNNNNNNP"
|
||||
${c3}_wNNNNNNNNNNNNNNNNNNNM^
|
||||
${c3}""Y^^MNNNNNNNNNNNNP`
|
||||
${c3}`"""""""
|
||||
$2__
|
||||
$2gpBBBBBBBBBP
|
||||
$2_gBBBBBBBBBRP
|
||||
$24BBBBBBBBRP $4,_____
|
||||
$2`"" $4_g@@@@@@@@@@@@@%g>
|
||||
$4__@@@@@@@@@@@@@@@@P" $1___
|
||||
$4_g@@@@@@@@@@@@@@@N"` $1_gN@@@@@N^
|
||||
$4_w@@@@@@@@@@@@@@@@P" $1_g@@@@@@@P"
|
||||
$4_g@@@@@@@@@@@@@@@N"` $1VMNN@NNNM^`
|
||||
$4^MMM@@@@@@@@@@@MP" $3,ggppww__
|
||||
$4`""""" $3_wNNNNNNNNNNNNNNNNNNN
|
||||
$3_gBNNNNNNNNNNNNNNNNNP"
|
||||
$3_wNNNNNNNNNNNNNNNNNNMP`
|
||||
$3_gBNNNNNNNNNNNNNNNNNP"
|
||||
$3_wNNNNNNNNNNNNNNNNNNNM^
|
||||
$3""Y^^MNNNNNNNNNNNNP`
|
||||
$3`"""""""
|
||||
@@ -1,18 +1,18 @@
|
||||
${c2} .........
|
||||
$2 .........
|
||||
...................
|
||||
.....................${c1}################${c2}
|
||||
.............. ....${c1}################${c2}
|
||||
.............. ...${c1}################${c2}
|
||||
............. ..${c1}****************${c2}
|
||||
............ . .${c1}****************${c2}
|
||||
........... ... ${c1}................${c2}
|
||||
.......... ..... ${c1}...............${c2}
|
||||
.....................$1################$2
|
||||
.............. ....$1################$2
|
||||
.............. ...$1################$2
|
||||
............. ..$1****************$2
|
||||
............ . .$1****************$2
|
||||
........... ... $1................$2
|
||||
.......... ..... $1...............$2
|
||||
......... ....... ...
|
||||
.${c3}...... ${c2}.
|
||||
${c3}..... .....${c2}.... ${c4}...........
|
||||
${c3}.... ......${c2}. ${c4}...........
|
||||
${c3}... ....... ${c4}...........
|
||||
${c3}................ ${c4}***********
|
||||
${c3}................ ${c4}###########
|
||||
${c3}****************
|
||||
${c3}################
|
||||
.$3...... $2.
|
||||
$3..... .....$2.... $4...........
|
||||
$3.... ......$2. $4...........
|
||||
$3... ....... $4...........
|
||||
$3................ $4***********
|
||||
$3................ $4###########
|
||||
$3****************
|
||||
$3################
|
||||
@@ -1,9 +1,9 @@
|
||||
${c2} _____ ${c1}_____${c2}
|
||||
-' '-${c1}| |${c2}
|
||||
/ ___ ${c1}| |${c2}
|
||||
| / _ \${c1}|_____|${c2}
|
||||
$2 _____ $1_____$2
|
||||
-' '-$1| |$2
|
||||
/ ___ $1| |$2
|
||||
| / _ \$1|_____|$2
|
||||
' / /_\ \
|
||||
\ / _____ \${c4}___
|
||||
${c3}|${c2}/_/ ${c3}| ${c4}| |
|
||||
${c3}| | ${c4}|___|
|
||||
${c3}|_____|
|
||||
\ / _____ \$4___
|
||||
$3|$2/_/ $3| $4| |
|
||||
$3| | $4|___|
|
||||
$3|_____|
|
||||
+10
-10
@@ -2,15 +2,15 @@
|
||||
_=(SDGJT=_
|
||||
_GTDJHGGFCVS)
|
||||
,GTDJGGDTDFBGX0
|
||||
${c1} JDJDIJHRORVFSBSVL${c2}-=+=,_
|
||||
${c1} IJFDUFHJNXIXCDXDSV,${c2} "DEBL
|
||||
${c1} [LKDSDJTDU=OUSCSBFLD.${c2} '?ZWX,
|
||||
${c1} ,LMDSDSWH' `DCBOSI${c2} DRDS],
|
||||
${c1} SDDFDFH' !YEWD,${c2} )HDROD
|
||||
${c1} !KMDOCG &GSU|${c2}\_GFHRGO\'
|
||||
${c1} HKLSGP'${c2} __${c1}\TKM0${c2}\GHRBV)'
|
||||
${c1}JSNRVW'${c2} __+MNAEC${c1}\IOI,${c2}\BN'
|
||||
${c1}HELK['${c2} __,=OFFXCBGHC${c1}\FD)
|
||||
${c1}?KGHE ${c2}\_-#DASDFLSV='${c1} 'EF
|
||||
$1 JDJDIJHRORVFSBSVL$2-=+=,_
|
||||
$1 IJFDUFHJNXIXCDXDSV,$2 "DEBL
|
||||
$1 [LKDSDJTDU=OUSCSBFLD.$2 '?ZWX,
|
||||
$1 ,LMDSDSWH' `DCBOSI$2 DRDS],
|
||||
$1 SDDFDFH' !YEWD,$2 )HDROD
|
||||
$1 !KMDOCG &GSU|$2\_GFHRGO\'
|
||||
$1 HKLSGP'$2 __$1\TKM0$2\GHRBV)'
|
||||
$1JSNRVW'$2 __+MNAEC$1\IOI,$2\BN'
|
||||
$1HELK['$2 __,=OFFXCBGHC$1\FD)
|
||||
$1?KGHE $2\_-#DASDFLSV='$1 'EF
|
||||
'EHTI !H
|
||||
`0F' '!
|
||||
@@ -1,20 +1,20 @@
|
||||
${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢰⡆${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢠⣿⣿⡄${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢀⣾⣿⣿⣿⡀${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c4}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣼⣿⣿⣿⣿⣷⡀${c4}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c5}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣼⣿⣿⣿⣿⣿⣿⣷${c5}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c6}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢼⣿⣿⣿⣿⣿⣿⣿⣿⣧${c6}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣰⣤⣈⠻⢿⣿⣿⣿⣿⣿⣿⣧${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣰⣿⣿⣿⣿⣮⣿⣿⣿⣿⣿⣿⣿⣧${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧${c3}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c4}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧${c4}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c5}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧${c5}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c6}⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣼⣿⣿⣿⣿⣿⡿⣿⣿⡟${c6}⠄⠄${c1}⠸⣿⣿⡿⣿⣿⣿⣿⣿⣷⡀${c6}⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
${c1}⠄⠄⠄⠄⠄⠄⠄⠄${c1}⣼⣿⣿⣿⣿⣿⡏${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠈⣿⣿⣿⣿⣿⣷⡀${c1}⠄⠄⠄⠄⠄⠄⠄
|
||||
${c2}⠄⠄⠄⠄⠄⠄${c1}⢀⣼⣿⣿⣿⣿⣿⣿⡗${c2}⠄⠄⠄${c1}⢀⣠⣤⣀⠄⠄⠄${c1}⠸⣿⣿⣿⣿⣿⣿⣷⡀${c2}⠄⠄⠄⠄⠄⠄
|
||||
${c3}⠄⠄⠄⠄⠄${c1}⢀⣾⣿⣿⣿⣿⣿⡏⠁${c3}⠄⠄⠄${c1}⢠⣿⣿⣿⣿⡇${c3}⠄⠄⠄⠄${c1}⢙⣿⣿⣻⠿⣿⣷⡀${c3}⠄⠄⠄⠄⠄
|
||||
${c4}⠄⠄⠄⠄${c1}⢀⣾⣿⣿⣿⣿⣿⣿⣷⣤⡀${c4}⠄⠄⠄${c1}⠻⣿⣿⡿⠃${c4}⠄⠄⠄${c1}⢀⣼⣿⣿⣿⣿⣦⣌⠙⠄${c4}⠄⠄⠄⠄
|
||||
${c5}⠄⠄⠄${c1}⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏${c5}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⢿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀${c5}⠄⠄⠄
|
||||
${c6}⠄⠄${c1}⢠⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁${c6}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⡄${c6}⠄⠄
|
||||
${c1}⠄${c1}⣠⣿⣿⣿⣿⠿⠛⠋⠁${c1}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠉⠙⠻⢿⣿⣿⣿⣿⣆${c1}⠄
|
||||
${c1}⡰⠟⠛⠉⠁${c2}⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄${c1}⠉⠙⠛⠿⢆
|
||||
$1⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⢰⡆$1⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$2⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⢠⣿⣿⡄$2⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$3⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⢀⣾⣿⣿⣿⡀$3⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$4⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣼⣿⣿⣿⣿⣷⡀$4⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$5⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣼⣿⣿⣿⣿⣿⣿⣷$5⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$6⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⢼⣿⣿⣿⣿⣿⣿⣿⣿⣧$6⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$1⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣰⣤⣈⠻⢿⣿⣿⣿⣿⣿⣿⣧$1⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$2⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣰⣿⣿⣿⣿⣮⣿⣿⣿⣿⣿⣿⣿⣧$2⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$3⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧$3⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$4⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧$4⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$5⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧$5⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$6⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⣼⣿⣿⣿⣿⣿⡿⣿⣿⡟$6⠄⠄$1⠸⣿⣿⡿⣿⣿⣿⣿⣿⣷⡀$6⠄⠄⠄⠄⠄⠄⠄⠄
|
||||
$1⠄⠄⠄⠄⠄⠄⠄⠄$1⣼⣿⣿⣿⣿⣿⡏$1⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⠈⣿⣿⣿⣿⣿⣷⡀$1⠄⠄⠄⠄⠄⠄⠄
|
||||
$2⠄⠄⠄⠄⠄⠄$1⢀⣼⣿⣿⣿⣿⣿⣿⡗$2⠄⠄⠄$1⢀⣠⣤⣀⠄⠄⠄$1⠸⣿⣿⣿⣿⣿⣿⣷⡀$2⠄⠄⠄⠄⠄⠄
|
||||
$3⠄⠄⠄⠄⠄$1⢀⣾⣿⣿⣿⣿⣿⡏⠁$3⠄⠄⠄$1⢠⣿⣿⣿⣿⡇$3⠄⠄⠄⠄$1⢙⣿⣿⣻⠿⣿⣷⡀$3⠄⠄⠄⠄⠄
|
||||
$4⠄⠄⠄⠄$1⢀⣾⣿⣿⣿⣿⣿⣿⣷⣤⡀$4⠄⠄⠄$1⠻⣿⣿⡿⠃$4⠄⠄⠄$1⢀⣼⣿⣿⣿⣿⣦⣌⠙⠄$4⠄⠄⠄⠄
|
||||
$5⠄⠄⠄$1⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏$5⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⢿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀$5⠄⠄⠄
|
||||
$6⠄⠄$1⢠⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⠁$6⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⠙⠻⣿⣿⣿⣿⣿⣿⣿⣿⡄$6⠄⠄
|
||||
$1⠄$1⣠⣿⣿⣿⣿⠿⠛⠋⠁$1⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⠉⠙⠻⢿⣿⣿⣿⣿⣆$1⠄
|
||||
$1⡰⠟⠛⠉⠁$2⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄⠄$1⠉⠙⠛⠿⢆
|
||||
@@ -1,17 +1,17 @@
|
||||
${c1} *
|
||||
$1 *
|
||||
**.
|
||||
****
|
||||
******
|
||||
*******
|
||||
** *******
|
||||
**** *******
|
||||
${c1}****${c2}_____${c1}***${c2}/${c1}*
|
||||
***${c2}/${c1}*******${c2}//${c1}***
|
||||
**${c2}/${c1}********${c2}///${c1}*${c2}/${c1}**
|
||||
**${c2}/${c1}*******${c2}////${c1}***${c2}/${c1}**
|
||||
**${c2}/${c1}****${c2}//////.,${c1}****${c2}/${c1}**
|
||||
***${c2}/${c1}*****${c2}/////////${c1}**${c2}/${c1}***
|
||||
****${c2}/${c1}**** ${c2}/////${c1}***${c2}/${c1}****
|
||||
******${c2}/${c1}*** ${c2}//// ${c1}**${c2}/${c1}******
|
||||
********${c2}/${c1}* ${c2}/// ${c1}*${c2}/${c1}********
|
||||
,****** ${c2}// ______ / ${c1}******,
|
||||
$1****$2_____$1***$2/$1*
|
||||
***$2/$1*******$2//$1***
|
||||
**$2/$1********$2///$1*$2/$1**
|
||||
**$2/$1*******$2////$1***$2/$1**
|
||||
**$2/$1****$2//////.,$1****$2/$1**
|
||||
***$2/$1*****$2/////////$1**$2/$1***
|
||||
****$2/$1**** $2/////$1***$2/$1****
|
||||
******$2/$1*** $2//// $1**$2/$1******
|
||||
********$2/$1* $2/// $1*$2/$1********
|
||||
,****** $2// ______ / $1******,
|
||||
@@ -6,6 +6,6 @@
|
||||
ooooo ooooo
|
||||
ooooo ooooo
|
||||
ooooo ooooo
|
||||
ooooo ${c2}<oooooooo>${c1}
|
||||
ooooo ${c2}<oooooo>${c1}
|
||||
ooooo ${c2}<oooo>
|
||||
ooooo $2<oooooooo>$1
|
||||
ooooo $2<oooooo>$1
|
||||
ooooo $2<oooo>
|
||||
+15
-15
@@ -1,15 +1,15 @@
|
||||
${c1} `oyyy/${c2}-yyyyyy+
|
||||
${c1} -syyyy/${c2}-yyyyyy+
|
||||
${c1} .syyyyy/${c2}-yyyyyy+
|
||||
${c1} :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} `/ :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} .+s :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} .oys :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} -oyys :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} :syyys :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} /syyyys :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} +yyyyyys :yyyyyy/${c2}-yyyyyy+
|
||||
${c1} .oyyyyyyo. :yyyyyy/${c2}-yyyyyy+ ---------
|
||||
${c1} .syyyyyy+` :yyyyyy/${c2}-yyyyy+-+syyyyyyyy
|
||||
${c1} -syyyyyy/ :yyyyyy/${c2}-yyys:.syyyyyyyyyy
|
||||
${c1}:syyyyyy/ :yyyyyy/${c2}-yyo.:syyyyyyyyyyy
|
||||
$1 `oyyy/$2-yyyyyy+
|
||||
$1 -syyyy/$2-yyyyyy+
|
||||
$1 .syyyyy/$2-yyyyyy+
|
||||
$1 :yyyyyy/$2-yyyyyy+
|
||||
$1 `/ :yyyyyy/$2-yyyyyy+
|
||||
$1 .+s :yyyyyy/$2-yyyyyy+
|
||||
$1 .oys :yyyyyy/$2-yyyyyy+
|
||||
$1 -oyys :yyyyyy/$2-yyyyyy+
|
||||
$1 :syyys :yyyyyy/$2-yyyyyy+
|
||||
$1 /syyyys :yyyyyy/$2-yyyyyy+
|
||||
$1 +yyyyyys :yyyyyy/$2-yyyyyy+
|
||||
$1 .oyyyyyyo. :yyyyyy/$2-yyyyyy+ ---------
|
||||
$1 .syyyyyy+` :yyyyyy/$2-yyyyy+-+syyyyyyyy
|
||||
$1 -syyyyyy/ :yyyyyy/$2-yyys:.syyyyyyyyyy
|
||||
$1:syyyyyy/ :yyyyyy/$2-yyo.:syyyyyyyyyyy
|
||||
@@ -1,17 +1,17 @@
|
||||
${c1} ***
|
||||
${c1} *****
|
||||
${c1} **********
|
||||
${c1} ***************
|
||||
${c1} *///****////****////.
|
||||
${c2} (/////// /////// ///////(
|
||||
${c2} /(((((//* //, //((((((.
|
||||
${c2} ((((((((((( ((( ((((((((
|
||||
${c2} *((((((((((((((((((((((( ((((((((
|
||||
${c3} (((((#(((((((#((((( ((#(((((
|
||||
${c3} (#(#(#####(#(#, ####(#(#
|
||||
${c3} ######### ########
|
||||
${c3} /######## ########
|
||||
${c4} #######%#######
|
||||
${c4} (#%%%%%%%#
|
||||
${c4} %%%%%
|
||||
${c4} %%%
|
||||
$1 ***
|
||||
$1 *****
|
||||
$1 **********
|
||||
$1 ***************
|
||||
$1 *///****////****////.
|
||||
$2 (/////// /////// ///////(
|
||||
$2 /(((((//* //, //((((((.
|
||||
$2 ((((((((((( ((( ((((((((
|
||||
$2 *((((((((((((((((((((((( ((((((((
|
||||
$3 (((((#(((((((#((((( ((#(((((
|
||||
$3 (#(#(#####(#(#, ####(#(#
|
||||
$3 ######### ########
|
||||
$3 /######## ########
|
||||
$4 #######%#######
|
||||
$4 (#%%%%%%%#
|
||||
$4 %%%%%
|
||||
$4 %%%
|
||||
@@ -1,22 +1,22 @@
|
||||
AA
|
||||
AaaA
|
||||
Aa${c2}/\${c1}aA
|
||||
${c1} Aa${c2}/${c1}aa${c2}\${c1}aA
|
||||
${c1} Aa${c2}/${c1}aAAa${c2}\${c1}aA
|
||||
${c1} aA${c2}/${c1}aaAAaa${c2}\${c1}Aa
|
||||
${c1} aA${c2}/${c1}aaAAAAaa${c2}\${c1}Aa
|
||||
${c1} aaaaaaAAAAa${c2}/${c1}aaAAAAAAaa${c2}\${c1}aAAAAaaaaa
|
||||
${c1}aAAa${c2}-----${c1}aaaaaAAAAAAAAAAaaaaa${c2}-----${c1}aAAa
|
||||
${c1} aAA${c2}\ ${c1}aAAAAAAAAAAAAAAAAAAAAAAa${c2} /${c1}AAa
|
||||
${c1} aAa${c2}\${c1}aAAA${c2}\${c1}AAAA${c2}\${c1}AAAA${c2}\${c1}AAA${c2}\${c1}AAa${c2}/${c1}aAa
|
||||
${c1} aAa${c2}\${c1}aA${c2}\\${c1}AAA${c2}\\${c1}AAA${c2}\\${c1}AA${c2}\\/${c1}aAa
|
||||
${c1} aAA${c2}\${c1}aA${c2}\\${c1}AAA${c2}\\${c1}AAA${c2}\\${c1}Aa${c2}/${c1}AAa
|
||||
${c1} aA${c2}\${c1}aA${c2}\\${c1}AAA${c2}\\${c1}AAA${c2}\\/${c1}Aa
|
||||
${c1} aA${c2}/${c1}AA${c2}\\\${c1}AA${c2}\\\${c1}AA${c2}\\\${c1}Aa
|
||||
${c1} aA${c2}/\${c1}AAa${c2}\\\${c1}Aa${c2}\\\${c1}Aa${c2}\\\${c1}Aa
|
||||
${c1} aA${c2}/\\${c1}AAa${c2}\\/\${c1}a${c2}\\\${c1}Aa${c2}\\${c1}Aa
|
||||
${c1} aA${c2}/${c1}a${c2}\\\${c1}Aa${c2}\/${c1}AA${c2}\\\\\${c1}Aa${c2}\\${c1}Aa
|
||||
${c1} aA${c2}/${c1}aA${c2}\\/${c1}aAa aAa${c2}\\\${c1}Aa${c2}\${c1}Aa
|
||||
${c1} aA${c2}/\${c1}A${c2}\/${c1}Aa aA${c2}\\${c1}A${c2}\\${c1}Aa
|
||||
${c1} A${c2}|/${c1}aaAa aAaa${c2}\|${c1}A
|
||||
${c1} aAaa aaAa
|
||||
Aa$2/\$1aA
|
||||
$1 Aa$2/$1aa$2\$1aA
|
||||
$1 Aa$2/$1aAAa$2\$1aA
|
||||
$1 aA$2/$1aaAAaa$2\$1Aa
|
||||
$1 aA$2/$1aaAAAAaa$2\$1Aa
|
||||
$1 aaaaaaAAAAa$2/$1aaAAAAAAaa$2\$1aAAAAaaaaa
|
||||
$1aAAa$2-----$1aaaaaAAAAAAAAAAaaaaa$2-----$1aAAa
|
||||
$1 aAA$2\ $1aAAAAAAAAAAAAAAAAAAAAAAa$2 /$1AAa
|
||||
$1 aAa$2\$1aAAA$2\$1AAAA$2\$1AAAA$2\$1AAA$2\$1AAa$2/$1aAa
|
||||
$1 aAa$2\$1aA$2\\$1AAA$2\\$1AAA$2\\$1AA$2\\/$1aAa
|
||||
$1 aAA$2\$1aA$2\\$1AAA$2\\$1AAA$2\\$1Aa$2/$1AAa
|
||||
$1 aA$2\$1aA$2\\$1AAA$2\\$1AAA$2\\/$1Aa
|
||||
$1 aA$2/$1AA$2\\\$1AA$2\\\$1AA$2\\\$1Aa
|
||||
$1 aA$2/\$1AAa$2\\\$1Aa$2\\\$1Aa$2\\\$1Aa
|
||||
$1 aA$2/\\$1AAa$2\\/\$1a$2\\\$1Aa$2\\$1Aa
|
||||
$1 aA$2/$1a$2\\\$1Aa$2\/$1AA$2\\\\\$1Aa$2\\$1Aa
|
||||
$1 aA$2/$1aA$2\\/$1aAa aAa$2\\\$1Aa$2\$1Aa
|
||||
$1 aA$2/\$1A$2\/$1Aa aA$2\\$1A$2\\$1Aa
|
||||
$1 A$2|/$1aaAa aAaa$2\|$1A
|
||||
$1 aAaa aaAa
|
||||
@@ -1,24 +0,0 @@
|
||||
${c1} . ..
|
||||
${c1} :####: ####.
|
||||
${c1} .################
|
||||
${c1} :##################
|
||||
${c1}.###################.
|
||||
${c1}######## #######
|
||||
${c1}####### ${c2}####${c1} #####
|
||||
${c1}:#######. ####
|
||||
${c1} ######### ${c2}#${c1} ## #
|
||||
${c1} ####### ${c2}##${c1} ####
|
||||
${c1}######## ${c2}####${c1} #######
|
||||
${c1}######## ${c2}#####${c1} ########
|
||||
${c1}######## ${c2}#######${c1} #######
|
||||
${c1} ####### ${c2}########${c1} #######
|
||||
${c1} ######## ${c2}#########${c1} ######
|
||||
${c1} ######## ${c2}#########${c1} #####
|
||||
${c1} ####### ${c2}#########${c1} ####
|
||||
${c1} ####### ${c2}#########${c1} ##
|
||||
${c1} ####### ${c2}########${c1} ##
|
||||
${c1} ###### ${c2}########${c1} #
|
||||
${c1} ### ${c2}#######${c1}
|
||||
${c1} ${c2}######${c1}
|
||||
${c1} ${c2}####${c1}
|
||||
${c1} ${c2}##${c1}
|
||||
@@ -0,0 +1,29 @@
|
||||
u.
|
||||
..:Y
|
||||
.Y..1
|
||||
..::i::.. .br7S.
|
||||
.::::...::::. 5dDr:
|
||||
..:::.. .:i::.. Y7:
|
||||
..:::::.. ..::::.
|
||||
...:i:i:i:.. $2... $1:.:..:i:::...
|
||||
::i:. $2.USL Yr $1..i::.
|
||||
.:::. $2:K :u. $1.::.
|
||||
:... $2jB. .:vUi: 77 KB: $1..::
|
||||
...: $2iBR vP::5X5PgSKXvLjS. iBB $1.::.
|
||||
:i:: $2BBQr jgDIuj1UuJjXbbi 2BBP $1:::;
|
||||
'i:: $2sQBg: i2S55121XSSU. YBQZ: $1.:::
|
||||
r::: $2r:JgBMu. Q :BqEqZEB: Q :qBBK7i: $1:i:i
|
||||
.rir. $2IBqPDgQBDr P rB :q 1QBRgEqgB $1.::i.
|
||||
:i:i $2:JsXPDDRQQPBL P qQXBQRDDPIYY $1rir:
|
||||
:iii $25qvLUDDMgMgBB5 :DBQZRgMDdJ7Ygi $1iir:
|
||||
iri: $2MBRgdZZggQgRBMIBQQRRggdZdMBBr $1riri
|
||||
irii $2IBQgdZbDDRRRgQgQQMZDdZdgBB. $1iiri
|
||||
i7rr $2.BBQZZbEEMQQDBQMEZdDDBBP $1.rir:
|
||||
:7ir. $27BBQMDMQSbB5ZBggQBBQ. $1ivr7.
|
||||
:r7r. $27BBBB:rBbQ.1BBBM. $1:r7vi
|
||||
::rLrr. $2.b:rBQ7QB uU. $1:7vLi.
|
||||
.BB .iLYv: $1idL B1 $1:r77r.
|
||||
LBB :vrvvr rvu7r:
|
||||
ZB. ':7v177Lsvurr:'
|
||||
.d2 ''::r:''
|
||||
:'
|
||||
@@ -0,0 +1,24 @@
|
||||
. ..
|
||||
$1 :####: ####.
|
||||
$1 .################
|
||||
$1 :##################
|
||||
$1.###################.
|
||||
$1######## #######
|
||||
$1####### $2####$1 #####
|
||||
$1:#######. ####
|
||||
$1 ######### $2#$1 ## #
|
||||
$1 ####### $2##$1 ####
|
||||
$1######## $2####$1 #######
|
||||
$1######## $2#####$1 ########
|
||||
$1######## $2#######$1 #######
|
||||
$1 ####### $2########$1 #######
|
||||
$1 ######## $2#########$1 ######
|
||||
$1 ######## $2#########$1 #####
|
||||
$1 ####### $2#########$1 ####
|
||||
$1 ####### $2#########$1 ##
|
||||
$1 ####### $2########$1 ##
|
||||
$1 ###### $2########$1 #
|
||||
$1 ### $2#######$1
|
||||
$1 $2######$1
|
||||
$1 $2####$1
|
||||
$1 $2##$1
|
||||
@@ -0,0 +1,28 @@
|
||||
+++++++++
|
||||
+++++$4+$1++++++$4+$1++
|
||||
++++++$4+$1+++ +++++++++++
|
||||
+++++++++++ $2+$1 +++++$4+$1+++++
|
||||
++++++$4+$1++++ $4+++$1 +++++++++++
|
||||
++++++++++$4 + +++++ ++ $2+++++$4+$2++++
|
||||
+++$4+$1++++$4 + + + +++++++ + + $2+++++$4+$2++
|
||||
++++++$4 $2+$4 +++ +++++++++ +++ $2++++++++
|
||||
+++$4+$1++$4 + +++++ +++++ +
|
||||
++++++$4 $2+$4 +++++ +++++ +++++
|
||||
++$4+$2+++$4 + +++++ ++++++ ++++++++++
|
||||
++++++$4 +++++ +++++ + +++++++++++++++++++
|
||||
++++++$4 + +++++ + +++++++++++++++
|
||||
+++$4++$2+$4 ++++++ +++++++++++++
|
||||
++++++$4 + ++++++ +++++++++++++ $2+++ $4++
|
||||
++++++$4 ++++++++++++++++ $2++$4+$2+ $4++ $1+
|
||||
++++++$4 ++++++++++++++ $3+ $2++++
|
||||
++++++$4 +++++++++++ + $4+ $3++++++
|
||||
++$4+$3+++$4 ++++++++++ +++ $3+++++++++++++
|
||||
+++++ $4+++++++++ + $3+++++++++++++
|
||||
+++ $4++++++++ $2++$4 + $3++++++++++++++ ++++
|
||||
++ $4++++++++ $3+ ++++++++++++++ +++++++
|
||||
$4++++++ $2+ $3+++++++++++++ +++++++$2++
|
||||
$4++++ $3+++++++++++++ ++++++$2+++
|
||||
+++++++++++ ++++++$2+++
|
||||
+++++ ++++++$2+++
|
||||
++++++$2++
|
||||
+++++
|
||||
+17
-17
@@ -1,17 +1,17 @@
|
||||
${c1} ////. ${c2} (((((
|
||||
${c1}//////// ${c2} @((((((((
|
||||
${c1}//////// ${c2} @((((((((
|
||||
${c1}//////// /////// ${c2} ((((((( @((((((((
|
||||
${c1}//////// ///////// ${c2} ((((((((( @((((((((
|
||||
${c1}//////// ///////// ${c2} ((((((((( @((((((((
|
||||
${c1}//////// ///////// ////// ${c2} (((((( ((((((((( @((((((((
|
||||
${c1}//////// ///////// //////// ${c2} (((((((( ((((((((( @((((((((
|
||||
${c1}//////// ///////// //////// ${c2} (((((((( ((((((((( @((((((((
|
||||
${c1}//////// ///////// //////// ${c2} ((((((( ((((((((( @((((((((
|
||||
${c1}//////// ///////// /// ${c2} ( ((((((((( @((((((((
|
||||
${c1}//////// ///////// ${c2} ((((((((( @((((((((
|
||||
${c1}//////// ///////// ${c2} &(((((((( @((((((((
|
||||
${c1}//////// ////// ${c2} @(((( @((((((((
|
||||
${c1}//////// ${c2} @((((((((
|
||||
${c1}//////// ${c2} @((((((((
|
||||
${c1} ///// ${c2} (((((
|
||||
$1 ////. $2 (((((
|
||||
$1//////// $2 @((((((((
|
||||
$1//////// $2 @((((((((
|
||||
$1//////// /////// $2 ((((((( @((((((((
|
||||
$1//////// ///////// $2 ((((((((( @((((((((
|
||||
$1//////// ///////// $2 ((((((((( @((((((((
|
||||
$1//////// ///////// ////// $2 (((((( ((((((((( @((((((((
|
||||
$1//////// ///////// //////// $2 (((((((( ((((((((( @((((((((
|
||||
$1//////// ///////// //////// $2 (((((((( ((((((((( @((((((((
|
||||
$1//////// ///////// //////// $2 ((((((( ((((((((( @((((((((
|
||||
$1//////// ///////// /// $2 ( ((((((((( @((((((((
|
||||
$1//////// ///////// $2 ((((((((( @((((((((
|
||||
$1//////// ///////// $2 &(((((((( @((((((((
|
||||
$1//////// ////// $2 @(((( @((((((((
|
||||
$1//////// $2 @((((((((
|
||||
$1//////// $2 @((((((((
|
||||
$1 ///// $2 (((((
|
||||
@@ -5,14 +5,14 @@
|
||||
: xMMMMMW. kMMMMNc lW.
|
||||
:x NMMMMMO ,MMMM0. 'l
|
||||
Xx "lkk" kMMMX .okx,
|
||||
${c2}.MX .cc;. .xXKx. KMMM: .OMMMMMl
|
||||
$2.MX .cc;. .xXKx. KMMM: .OMMMMMl
|
||||
:MM' 'KMMMMWK: 0MMMMk xMMM. lWMMMMMMM'
|
||||
cMMN:;xMMMMk::MMO oMMMMX .XMM. .KMMMWOOMMMd
|
||||
'MMMMMMMMN, NMMx OMMMMl .kM0OMMMMk. ;MMd
|
||||
xMMMMMMd .MMMW :NMMMd .ckKKx' KMc
|
||||
dWMNd. oMMMN lkNMX, oM.
|
||||
;. ;MMMMx "MM:. cO
|
||||
${c3} .X. oMMMMW. l.
|
||||
$3 .X. oMMMMW. l.
|
||||
dMk:..;xWMMMMW,
|
||||
kMMMMMMMMMMX.
|
||||
:XMMMMMMK:
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
${c3} 00
|
||||
$3 00
|
||||
11
|
||||
====${c1}
|
||||
.${c3}//${c1}
|
||||
`o${c3}//${c1}:
|
||||
`+o${c3}//${c1}o:
|
||||
`+oo${c3}//${c1}oo:
|
||||
-+oo${c3}//${c1}oo+:
|
||||
`/:-:+${c3}//${c1}ooo+:
|
||||
`/+++++${c3}//${c1}+++++:
|
||||
`/++++++${c3}//${c1}++++++:
|
||||
`/+++o${c2}ooo${c3}//${c2}ooo${c1}oooo/`
|
||||
${c2} ${c1}./${c2}ooosssso${c3}//${c2}osssssso${c1}+`
|
||||
${c2} .oossssso-`${c3}//${c1}`/ossssss+`
|
||||
-osssssso. ${c3}//${c1} :ssssssso.
|
||||
:osssssss/ ${c3}//${c1} osssso+++.
|
||||
/ossssssss/ ${c3}//${c1} +ssssooo/-
|
||||
`/ossssso+/:- ${c3}//${c1} -:/+osssso+-
|
||||
`+sso+:-` ${c3}//${c1} `.-/+oso:
|
||||
`++:. ${c3}//${c1} `-/+/
|
||||
.` ${c3}/${c1} `/
|
||||
====$1
|
||||
.$3//$1
|
||||
`o$3//$1:
|
||||
`+o$3//$1o:
|
||||
`+oo$3//$1oo:
|
||||
-+oo$3//$1oo+:
|
||||
`/:-:+$3//$1ooo+:
|
||||
`/+++++$3//$1+++++:
|
||||
`/++++++$3//$1++++++:
|
||||
`/+++o$2ooo$3//$2ooo$1oooo/`
|
||||
$2 $1./$2ooosssso$3//$2osssssso$1+`
|
||||
$2 .oossssso-`$3//$1`/ossssss+`
|
||||
-osssssso. $3//$1 :ssssssso.
|
||||
:osssssss/ $3//$1 osssso+++.
|
||||
/ossssssss/ $3//$1 +ssssooo/-
|
||||
`/ossssso+/:- $3//$1 -:/+osssso+-
|
||||
`+sso+:-` $3//$1 `.-/+oso:
|
||||
`++:. $3//$1 `-/+/
|
||||
.` $3/$1 `/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user