├── .github
└── workflows
│ ├── build-appimage.yml
│ └── build-flatpak.yml
├── .gitignore
├── .vscode
├── settings.json
└── tasks.json
├── LICENSE
├── README.md
├── build-aux
├── flatpak
│ ├── io.github.radiolamp.mangojuice.json
│ └── patches
│ │ ├── 0001-wayland-dlopen-correct-library.patch
│ │ └── libxnvctrl_so_0.patch
└── mangojuice-appimage.sh
├── data
├── assets
│ ├── boosty_qrcode.png
│ ├── donationalerts_qrcode.png
│ ├── icons
│ │ ├── io.github.radiolamp.mangojuice-extras-symbolic.svg
│ │ ├── io.github.radiolamp.mangojuice-metrics-symbolic.svg
│ │ ├── io.github.radiolamp.mangojuice-other-symbolic.svg
│ │ ├── io.github.radiolamp.mangojuice-performance-symbolic.svg
│ │ ├── io.github.radiolamp.mangojuice-visual-symbolic.svg
│ │ ├── io.github.radiolamp.mangojuice.donate-symbolic.svg
│ │ └── list-drag-handle-symbolic.svg
│ └── tbank_qrcode.png
├── gresource.xml
├── icons
│ └── hicolor
│ │ └── scalable
│ │ └── apps
│ │ └── io.github.radiolamp.mangojuice.svg
├── images
│ ├── advanced.png
│ ├── default.png
│ ├── fps.png
│ ├── full.png
│ └── minimal.png
├── io.github.radiolamp.mangojuice.desktop
├── io.github.radiolamp.mangojuice.metainfo.xml
├── meson.build
└── style.css
├── docs
└── README-ru.md
├── meson.build
├── meson_options.txt
├── po
├── LINGUAS
├── POTFILES
├── mangojuice.pot
├── meson.build
├── pt_BR.po
├── ru.po
└── update_potfiles.sh
└── src
├── advanced.vala
├── config.vapi
├── dialog.vala
├── intel_power_fix_handler.vala
├── load_states.vala
├── mangojuice.vala
├── meson.build
├── other
├── OtherBox.vala
├── other_load.vala
└── other_save.vala
├── reset_manager.vala
└── save_states.vala
/.github/workflows/build-appimage.yml:
--------------------------------------------------------------------------------
1 | name: Build MangoJuice AppImage
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 | workflow_dispatch: {}
9 |
10 | jobs:
11 | build:
12 | name: "${{ matrix.name }} (${{ matrix.arch }})"
13 | runs-on: ${{ matrix.runs-on }}
14 | strategy:
15 | matrix:
16 | include:
17 | - runs-on: ubuntu-latest
18 | name: "mangojuice build"
19 | arch: x86_64
20 | - runs-on: ubuntu-24.04-arm
21 | name: "mangojuice build"
22 | arch: aarch64
23 | container: ghcr.io/pkgforge-dev/archlinux:latest
24 |
25 | steps:
26 | - uses: actions/checkout@v4
27 | with:
28 | persist-credentials: false
29 |
30 | - name: Update system and install dependencies
31 | run: |
32 | pacman -Syu --noconfirm \
33 | appstream \
34 | base-devel \
35 | cmocka \
36 | dbus \
37 | fmt \
38 | fontconfig \
39 | gcc-libs \
40 | gettext \
41 | git \
42 | glew \
43 | glfw \
44 | glib2 \
45 | glslang \
46 | gtk4 \
47 | hicolor-icon-theme \
48 | libadwaita \
49 | libgee \
50 | libglvnd \
51 | libsodium \
52 | libx11 \
53 | libxkbcommon \
54 | libxrandr \
55 | meson \
56 | ninja \
57 | nlohmann-json \
58 | patchelf \
59 | python \
60 | python-mako \
61 | python-matplotlib \
62 | python-numpy \
63 | strace \
64 | vala \
65 | vulkan-headers \
66 | vulkan-tools \
67 | wget \
68 | xorg-server-xvfb \
69 | zsync
70 |
71 | - name: Build mangohud
72 | run: |
73 | echo "Building mangohud..."
74 | echo "---------------------------------------------------------------"
75 | sed -i 's|EUID == 0|EUID == 69|g' /usr/bin/makepkg
76 | mkdir -p /usr/local/bin
77 | cp /usr/bin/makepkg /usr/local/bin
78 |
79 | sed -i -e 's|-O2|-Os|' \
80 | -e 's|MAKEFLAGS=.*|MAKEFLAGS="-j$(nproc)"|' \
81 | -e 's|#MAKEFLAGS|MAKEFLAGS|' \
82 | /etc/makepkg.conf
83 |
84 | cat /etc/makepkg.conf
85 |
86 | git clone https://gitlab.archlinux.org/archlinux/packaging/packages/mangohud.git ./mangohud
87 | ( cd ./mangohud
88 | sed -i -e "s|x86_64|$(uname -m)|" \
89 | -e 's|-Dmangohudctl=true|-Dmangohudctl=true -Dwith_xnvctrl=disabled|' \
90 | -e '/libxnvctrl/d' ./PKGBUILD
91 | makepkg -f
92 | ls -la .
93 | pacman --noconfirm -U *.pkg.tar.*
94 | )
95 | rm -rf ./mangohud
96 |
97 | - name: Build and install MangoJuice
98 | run: |
99 | meson setup build --prefix=/usr
100 | ninja -C build
101 | sudo ninja -C build install
102 |
103 | - name: Create AppImage
104 | run: |
105 | chmod +x ./build-aux/mangojuice-appimage.sh
106 | ./build-aux/mangojuice-appimage.sh
107 |
108 | - name: Upload AppImage artifact
109 | uses: actions/upload-artifact@v4
110 | with:
111 | name: MangoJuice-AppImagename-${{ matrix.arch }}
112 | path: MangoJuice-*.AppImage
113 |
--------------------------------------------------------------------------------
/.github/workflows/build-flatpak.yml:
--------------------------------------------------------------------------------
1 | name: Flatpak Build
2 |
3 | on:
4 | push:
5 | branches: [ "main" ]
6 | paths-ignore:
7 | - '**/README.md'
8 | pull_request:
9 | branches: [ "main" ]
10 | types: [ "review_requested", "ready_for_review" ]
11 | workflow_dispatch:
12 |
13 | permissions:
14 | id-token: write
15 | contents: read
16 |
17 | jobs:
18 | flatpak:
19 | name: "Build Flatpak"
20 | runs-on: ubuntu-latest
21 | container:
22 | image: fedora:latest
23 | options: --privileged
24 | steps:
25 | - uses: actions/checkout@v4
26 |
27 | - name: Install dependencies
28 | run: |
29 | dnf install -y flatpak flatpak-builder
30 |
31 | - name: Setup Flatpak
32 | run: |
33 | flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
34 | flatpak install --user -y flathub org.gnome.Platform//48
35 | flatpak install --user -y flathub org.gnome.Sdk//48
36 | flatpak install --user -y flathub org.freedesktop.Platform.VulkanLayer.MangoHud//24.08
37 |
38 | - name: Build
39 | run: |
40 | flatpak-builder --user --force-clean --arch=x86_64 build-dir build-aux/flatpak/io.github.radiolamp.mangojuice.json
41 |
42 | - name: Create Bundle
43 | run: |
44 | flatpak build-export repo build-dir
45 | flatpak build-bundle repo io.github.radiolamp.mangojuice-x86_64.flatpak io.github.radiolamp.mangojuice
46 |
47 | - name: Upload Artifact
48 | uses: actions/upload-artifact@v4
49 | with:
50 | name: mangojuice-x86_64.flatpak
51 | path: io.github.radiolamp.mangojuice-x86_64.flatpak
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | Ссылка на MangoHud.conf
3 | /.flatpak-builder
4 | /.flatpak
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "mesonbuild.configureOnOpen": true,
3 | "files.watcherExclude": {
4 | "**/.git/objects/**": true,
5 | "**/.git/subtree-cache/**": true,
6 | "**/.hg/store/**": true,
7 | ".flatpak/**": true,
8 | "_build/**": true
9 | }
10 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build and run",
6 | "type": "shell",
7 | "command": "rm -rf ./build/ && meson setup build --reconfigure -Dis_devel=true --buildtype=debug && ninja -C build && ./build/src/mangojuice",
8 | "group": {
9 | "kind": "build",
10 | "isDefault": true
11 | },
12 | "problemMatcher": []
13 |
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](README.md) [](docs/README-ru.md)
2 |
3 |
4 |
5 |
9 | MangoJuice
10 |
11 |
12 |
13 | ### This program will be a convenient alternative to GOverlay for setting up MangoHud
14 |
15 |
16 |
17 |
18 |
19 | | Page 1 | Page 2 | Page 3 | Page 4 | Page 5 |
20 | | :---------------------------------: | :---------------------------------: | :---------------------------------: | :---------------------------------: | :---------------------------------: |
21 | |  |  |  |  |  |
22 |
23 | ## Install
24 |
25 | **Flathub:**
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ## Repositories
34 |
35 | [](https://repology.org/project/mangojuice/versions)
36 |
37 | And also in the repository for [`openSUSE`](https://software.opensuse.org/package/mangojuice)
38 |
39 | ## Source code build
40 |
41 | ### Dependencies
42 |
43 | #### Build utilities
44 |
45 | - `meson`
46 | - `ninja`
47 | - `cmake`
48 | - `gcc`
49 | - `valac`
50 |
51 | #### Build requires
52 |
53 | - `gtk4`
54 | - `libadwaita-1`
55 | - `gio-2.0`
56 | - `fontconfig`
57 | - `mangohud`
58 |
59 | #### Optional dependencies
60 |
61 | - `mesa-demos`
62 | - `vulkan-tools`
63 | - `vkbasalt`
64 |
65 | ### Build
66 |
67 | ```shell
68 | meson setup build
69 | ```
70 |
71 | ### Install
72 |
73 | ```shell
74 | sudo ninja -C build install
75 | ```
76 |
77 | ### Uninstall
78 |
79 | ```shell
80 | sudo ninja -C build uninstall
81 | ```
82 |
83 | ## Devel
84 |
85 | Also in the app there is Devel mode. It is intended for development and it is not recommended to use it on a permanent basis. In this mode new features of mangojuice and [mangohud-git](https://aur.archlinux.org/packages/mangohud-git) versions are tested. If you still want to use it, there is [mangojuice-git](https://aur.archlinux.org/packages/mangojuice-git) package in AUR or you can build it yourself with the following command:
86 |
87 | ```shell
88 | meson setup build
89 | meson configure build --no-pager -Dis_devel=true
90 | sudo ninja -C build install
91 | ```
92 |
93 | ## Support
94 |
95 | You can support in several ways:
96 |
97 | - Create an issue with a problem or a suggestion for improvement;
98 | - Submit a merge request with a fix or new functionality;
99 | - Support financially (please include your nickname in message when sending via T-Bank).
100 |
101 |
102 |
103 |
114 |
115 | ## Gratitude
116 |
117 | Thank to [Rirusha](https://gitlab.gnome.org/Rirusha) for important clarifications about Vala and GTK4.
118 |
119 | ### Projects that have become muses
120 |
121 | - [`MangoHud`](https://github.com/flightlessmango/MangoHud)
122 | - [`Goverlay`](https://github.com/benjamimgois/goverlay)
123 | - [`Colloid`](https://github.com/vinceliuice/Colloid-icon-theme/)
124 |
125 | ### Attention, this is my first project on GTK4 + Vala, so please treat with understanding.
126 |
--------------------------------------------------------------------------------
/build-aux/flatpak/io.github.radiolamp.mangojuice.json:
--------------------------------------------------------------------------------
1 | {
2 | "app-id": "io.github.radiolamp.mangojuice",
3 | "runtime": "org.gnome.Platform",
4 | "runtime-version": "48",
5 | "sdk": "org.gnome.Sdk",
6 | "command": "mangojuice",
7 | "finish-args": [
8 | "--socket=wayland",
9 | "--share=ipc",
10 | "--socket=fallback-x11",
11 | "--device=dri",
12 | "--env=PATH=/app/bin:/usr/bin:/app/utils/bin",
13 | "--filesystem=home",
14 | "--filesystem=xdg-config/MangoHud:create"
15 | ],
16 | "cleanup": [
17 | "/include",
18 | "/lib/pkgconfig",
19 | "/man",
20 | "/share/doc",
21 | "/share/gtk-doc",
22 | "/share/man",
23 | "/share/pkgconfig",
24 | "/share/vala",
25 | "*.la",
26 | "*.a"
27 | ],
28 | "modules": [
29 | {
30 | "name": "vulkan-tools",
31 | "buildsystem": "cmake-ninja",
32 | "config-opts": [
33 | "-DGLSLANG_INSTALL_DIR=/app",
34 | "-DVULKAN_HEADERS_INSTALL_DIR=/app",
35 | "-DCMAKE_BUILD_TYPE=Release"
36 | ],
37 | "sources": [
38 | {
39 | "type": "archive",
40 | "url": "https://github.com/KhronosGroup/Vulkan-Tools/archive/v1.3.297/Vulkan-Tools-1.3.297.tar.gz",
41 | "sha256": "95bffa39d90f3ec81d8e3a0fa6c846ac1a10442152cc0b6d0d6567ce48932f89"
42 | }
43 | ],
44 | "modules": [
45 | {
46 | "name": "volk",
47 | "buildsystem": "cmake-ninja",
48 | "config-opts": [
49 | "-DVOLK_INSTALL=ON"
50 | ],
51 | "sources": [
52 | {
53 | "type": "archive",
54 | "url": "https://github.com/zeux/volk/archive/vulkan-sdk-1.3.296.0.tar.gz",
55 | "sha256": "8ffd0e81e29688f4abaa39e598937160b098228f37503903b10d481d4862ab85"
56 | }
57 | ],
58 | "modules": [
59 | {
60 | "name": "vulkan-headers",
61 | "buildsystem": "cmake-ninja",
62 | "sources": [
63 | {
64 | "type": "archive",
65 | "url": "https://github.com/KhronosGroup/Vulkan-Headers/archive/v1.3.297/Vulkan-Headers-v1.3.297.tar.gz",
66 | "sha256": "1d679e2edc43cb7ad818b81dea960e374f1d6dd082325eb9b4c6113e76263c02"
67 | }
68 | ]
69 | }
70 | ]
71 | }
72 | ]
73 | },
74 | {
75 | "name": "MangoHud",
76 | "buildsystem": "meson",
77 | "config-opts": [
78 | "-Dwith_xnvctrl=enabled",
79 | "-Dappend_libdir_mangohud=false",
80 | "-Dmangoplot=disabled",
81 | "-Dmangoapp=true"
82 | ],
83 | "sources": [
84 | {
85 | "type": "archive",
86 | "url": "https://github.com/flightlessmango/MangoHud/releases/download/v0.8.1/MangoHud-v0.8.1-Source.tar.xz",
87 | "sha256": "4c8d8098f5deff7737978d792eef909b7469933f456a47132dccc06804825482",
88 | "x-checker-data": {
89 | "type": "json",
90 | "url": "https://api.github.com/repos/flightlessmango/MangoHud/releases",
91 | "url-query": "map(select(.tag_name | startswith(\"v\"))) | first |\n.assets | map((select(.name | endswith(\"Source.tar.xz\")))) | first | .browser_download_url\n",
92 | "version-query": "map(select(.tag_name | startswith(\"v\"))) | first |\n.tag_name | sub(\"^[vV]\"; \"\")\n"
93 | }
94 | },
95 | {
96 | "type": "patch",
97 | "path": "patches/0001-wayland-dlopen-correct-library.patch"
98 | }
99 | ],
100 | "modules": [
101 | {
102 | "name": "glew",
103 | "no-autogen": true,
104 | "make-args": [
105 | "GLEW_PREFIX=${FLATPAK_DEST}",
106 | "GLEW_DEST=${FLATPAK_DEST}",
107 | "LIBDIR=${FLATPAK_DEST}/lib",
108 | "PKGDIR=${FLATPAK_DEST}/lib/pkgconfig",
109 | "CFLAGS.EXTRA:=${CFLAGS} -fPIC",
110 | "LDFLAGS.EXTRA=${LDFLAGS}"
111 | ],
112 | "make-install-args": [
113 | "GLEW_PREFIX=${FLATPAK_DEST}",
114 | "GLEW_DEST=${FLATPAK_DEST}",
115 | "LIBDIR=${FLATPAK_DEST}/lib",
116 | "PKGDIR=${FLATPAK_DEST}/lib/pkgconfig",
117 | "CFLAGS.EXTRA:=${CFLAGS} -fPIC",
118 | "LDFLAGS.EXTRA=${LDFLAGS}"
119 | ],
120 | "sources": [
121 | {
122 | "type": "archive",
123 | "url": "https://downloads.sourceforge.net/project/glew/glew/2.2.0/glew-2.2.0.tgz",
124 | "sha256": "d4fc82893cfb00109578d0a1a2337fb8ca335b3ceccf97b97e5cc7f08e4353e1"
125 | }
126 | ],
127 | "modules": [
128 | {
129 | "name": "glu",
130 | "buildsystem": "meson",
131 | "sources": [
132 | {
133 | "type": "archive",
134 | "url": "https://archive.mesa3d.org/glu/glu-9.0.3.tar.xz",
135 | "sha256": "bd43fe12f374b1192eb15fe20e45ff456b9bc26ab57f0eee919f96ca0f8a330f"
136 | }
137 | ]
138 | }
139 | ]
140 | },
141 | {
142 | "name": "glfw",
143 | "buildsystem": "cmake-ninja",
144 | "config-opts": [
145 | "-DGLFW_BUILD_EXAMPLES:BOOL=OFF",
146 | "-DGLFW_BUILD_TESTS:BOOL=OFF",
147 | "-DGLFW_BUILD_DOCS:BOOL=OFF"
148 | ],
149 | "sources": [
150 | {
151 | "type": "git",
152 | "url": "https://github.com/glfw/glfw.git",
153 | "tag": "3.4",
154 | "commit": "7b6aead9fb88b3623e3b3725ebb42670cbe4c579"
155 | }
156 | ]
157 | },
158 | {
159 | "name": "nlohmann-json",
160 | "buildsystem": "cmake-ninja",
161 | "config-opts": [
162 | "-DJSON_BuildTests:BOOL=OFF"
163 | ],
164 | "sources": [
165 | {
166 | "type": "git",
167 | "url": "https://github.com/nlohmann/json.git",
168 | "tag": "v3.11.2",
169 | "commit": "bc889afb4c5bf1c0d8ee29ef35eaaf4c8bef8a5d"
170 | }
171 | ]
172 | },
173 | {
174 | "name": "libNVCtrl",
175 | "no-autogen": true,
176 | "no-make-install": true,
177 | "build-commands": [
178 | "mkdir -p ${FLATPAK_DEST}/lib",
179 | "cp -a libXNVCtrl.so* ${FLATPAK_DEST}/lib/",
180 | "install -D *.h -t ${FLATPAK_DEST}/include/NVCtrl"
181 | ],
182 | "subdir": "src/libXNVCtrl",
183 | "sources": [
184 | {
185 | "type": "archive",
186 | "archive-type": "tar",
187 | "url": "https://api.github.com/repos/NVIDIA/nvidia-settings/tarball/refs/tags/470.63.01",
188 | "sha256": "0ede63515851d85ac0d1ed5f00e355f539968e6d1fd226120a27b2c66c3575de"
189 | },
190 | {
191 | "type": "patch",
192 | "path": "patches/libxnvctrl_so_0.patch",
193 | "x-checker-data": {
194 | "type": "json",
195 | "url": "https://api.github.com/repos/NVIDIA/nvidia-settings/tags",
196 | "url-query": ".[0].tarball_url",
197 | "version-query": ".[0].na"
198 | }
199 | }
200 | ]
201 | }
202 | ]
203 | },
204 | {
205 | "name": "mangojuice",
206 | "buildsystem": "meson",
207 | "sources": [
208 | {
209 | "type": "dir",
210 | "path": "../../"
211 | }
212 | ]
213 | }
214 | ]
215 | }
--------------------------------------------------------------------------------
/build-aux/flatpak/patches/0001-wayland-dlopen-correct-library.patch:
--------------------------------------------------------------------------------
1 | From 6d2176a0e6280b13fa128589d2b3362be6de19e3 Mon Sep 17 00:00:00 2001
2 | From: 17314642 <48242771@protonmail.ch>
3 | Date: Fri, 4 Apr 2025 07:58:39 +0300
4 | Subject: [PATCH] wayland: dlopen correct library
5 |
6 | ---
7 | src/gl/inject_egl.cpp | 4 ++--
8 | src/vulkan.cpp | 2 +-
9 | 2 files changed, 3 insertions(+), 3 deletions(-)
10 |
11 | diff --git a/src/gl/inject_egl.cpp b/src/gl/inject_egl.cpp
12 | index e40d174..34fea7a 100644
13 | --- a/src/gl/inject_egl.cpp
14 | +++ b/src/gl/inject_egl.cpp
15 | @@ -99,7 +99,7 @@ EXPORT_C_(void*) eglGetPlatformDisplay( unsigned int platform, void* native_disp
16 | {
17 | wl_display_ptr = (struct wl_display*)native_display;
18 | HUDElements.display_server = HUDElements.display_servers::WAYLAND;
19 | - wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
20 | + wl_handle = real_dlopen("libwayland-client.so.0", RTLD_LAZY);
21 | init_wayland_data();
22 | }
23 | #endif
24 | @@ -125,7 +125,7 @@ EXPORT_C_(void*) eglGetDisplay( void* native_display )
25 | {
26 | wl_display_ptr = (struct wl_display*)native_display;
27 | HUDElements.display_server = HUDElements.display_servers::WAYLAND;
28 | - wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
29 | + wl_handle = real_dlopen("libwayland-client.so.0", RTLD_LAZY);
30 | init_wayland_data();
31 | }
32 | }
33 | diff --git a/src/vulkan.cpp b/src/vulkan.cpp
34 | index 9a10d61..d50c43a 100644
35 | --- a/src/vulkan.cpp
36 | +++ b/src/vulkan.cpp
37 | @@ -2034,7 +2034,7 @@ static VkResult overlay_CreateWaylandSurfaceKHR(
38 | {
39 | struct instance_data *instance_data = FIND(struct instance_data, instance);
40 | if (!wl_handle)
41 | - wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY);
42 | + wl_handle = real_dlopen("libwayland-client.so.0", RTLD_LAZY);
43 | wl_display_ptr = pCreateInfo->display;
44 | HUDElements.display_server = HUDElements.display_servers::WAYLAND;
45 | init_wayland_data();
46 | --
47 | 2.49.0
48 |
49 |
--------------------------------------------------------------------------------
/build-aux/flatpak/patches/libxnvctrl_so_0.patch:
--------------------------------------------------------------------------------
1 | diff -up nvidia-settings-435.17/src/libXNVCtrl/Makefile.shared nvidia-settings-435.17/src/libXNVCtrl/Makefile
2 | --- nvidia-settings-435.17/src/libXNVCtrl/Makefile.shared 2019-08-07 06:12:32.000000000 +0200
3 | +++ nvidia-settings-435.17/src/libXNVCtrl/Makefile 2019-08-26 16:23:41.921778088 +0200
4 | @@ -50,8 +50,9 @@ LDFLAGS += $(XNVCTRL_LDFLAGS)
5 |
6 | .PHONY: clean
7 |
8 | -all: $(LIBXNVCTRL)
9 | +all: $(LIBXNVCTRL) libXNVCtrl.so
10 |
11 | clean:
12 | rm -rf $(LIBXNVCTRL) *~ \
13 | $(OUTPUTDIR)/*.o $(OUTPUTDIR)/*.d
14 | + rm -f libXNVCtrl.so libXNVCtrl.so.*
15 | diff -up nvidia-settings-435.17/src/Makefile.shared nvidia-settings-435.17/src/Makefile
16 | --- nvidia-settings-435.17/src/Makefile.shared 2019-08-07 06:12:31.000000000 +0200
17 | +++ nvidia-settings-435.17/src/Makefile 2019-08-26 16:17:31.133406921 +0200
18 | @@ -106,6 +106,9 @@ endif
19 | XNVCTRL_DIR ?= libXNVCtrl
20 | XCONFIG_PARSER_DIR ?= XF86Config-parser
21 | COMMON_UTILS_DIR ?= common-utils
22 | +XNVCTRL_SHARED ?= $(XNVCTRL_DIR)/libXNVCtrl.so.0
23 | +#XNVCTRL_LIB ?= $(XNVCTRL_ARCHIVE)
24 | +XNVCTRL_LIB ?= $(XNVCTRL_SHARED)
25 | COMMON_UNIX_DIR ?= common-unix
26 | VIRTUAL_RESOLUTIONS_DIR ?= $(COMMON_UNIX_DIR)/virtual-resolutions
27 |
28 | diff -up nvidia-settings-435.17/src/libXNVCtrl/xnvctrl.mk.shared nvidia-settings-435.17/src/libXNVCtrl/xnvctrl.mk
29 | --- nvidia-settings-435.17/src/libXNVCtrl/xnvctrl.mk.shared 2019-08-07 06:12:32.000000000 +0200
30 | +++ nvidia-settings-435.17/src/libXNVCtrl/xnvctrl.mk 2019-08-26 16:54:44.518016474 +0200
31 | @@ -47,3 +47,8 @@ $(eval $(call DEFINE_OBJECT_RULE,TARGET,
32 |
33 | $(LIBXNVCTRL) : $(LIBXNVCTRL_OBJ)
34 | $(call quiet_cmd,AR) ru $@ $(LIBXNVCTRL_OBJ)
35 | +
36 | +libXNVCtrl.so: $(LIBXNVCTRL_OBJ)
37 | + $(CC) -shared -Wl,-soname=$@.0 -o $@.0.0.0 $(LDFLAGS) $^ -lXext -lX11
38 | + ln -s $@.0.0.0 $@.0
39 | + ln -s $@.0 $@
40 |
--------------------------------------------------------------------------------
/build-aux/mangojuice-appimage.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu
4 |
5 | export ARCH="$(uname -m)"
6 | export APPIMAGE_EXTRACT_AND_RUN=1
7 | export VERSION="${GITHUB_SHA:-$(date +%Y%m%d)}"
8 | UPINFO="gh-releases-zsync|${GITHUB_REPOSITORY:-radiolamp/mangojuice}|latest|*$ARCH.AppImage.zsync"
9 |
10 | LIB4BN="https://raw.githubusercontent.com/VHSgunzo/sharun/refs/heads/main/lib4bin"
11 | URUNTIME="https://github.com/VHSgunzo/uruntime/releases/latest/download/uruntime-appimage-dwarfs-$ARCH"
12 | URUNTIME_LITE="https://github.com/VHSgunzo/uruntime/releases/latest/download/uruntime-appimage-dwarfs-lite-$ARCH"
13 |
14 | # add debloated packages
15 | if [ "$(uname -m)" = 'x86_64' ]; then
16 | PKG_TYPE='x86_64.pkg.tar.zst'
17 | else
18 | PKG_TYPE='aarch64.pkg.tar.xz'
19 | fi
20 |
21 | LLVM_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/llvm-libs-nano-$PKG_TYPE"
22 | LIBXML_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/libxml2-iculess-$PKG_TYPE"
23 | MESA_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/mesa-mini-$PKG_TYPE"
24 | VK_RADEON_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/vulkan-radeon-mini-$PKG_TYPE"
25 | VK_INTEL_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/vulkan-intel-mini-$PKG_TYPE"
26 | VK_NOUVEAU_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/vulkan-nouveau-mini-$PKG_TYPE"
27 | VK_PANFROST_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/vulkan-panfrost-mini-$PKG_TYPE"
28 | VK_FREEDRENO_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/vulkan-freedreno-mini-$PKG_TYPE"
29 | VK_BROADCOM_URL="https://github.com/pkgforge-dev/llvm-libs-debloated/releases/download/continuous/vulkan-broadcom-mini-$PKG_TYPE"
30 |
31 | echo "Installing debloated pckages..."
32 | echo "---------------------------------------------------------------"
33 | wget --retry-connrefused --tries=30 "$LLVM_URL" -O ./llvm-libs.pkg.tar.zst
34 | wget --retry-connrefused --tries=30 "$LIBXML_URL" -O ./libxml2.pkg.tar.zst
35 | wget --retry-connrefused --tries=30 "$MESA_URL" -O ./mesa.pkg.tar.zst
36 | wget --retry-connrefused --tries=30 "$VK_RADEON_URL" -O ./vulkan-radeon.pkg.tar.zst
37 | wget --retry-connrefused --tries=30 "$VK_NOUVEAU_URL" -O ./vulkan-nouveau.pkg.tar.zst
38 |
39 | if [ "$(uname -m)" = 'x86_64' ]; then
40 | wget --retry-connrefused --tries=30 "$VK_INTEL_URL" -O ./vulkan-intel.pkg.tar.zst
41 | else
42 | wget --retry-connrefused --tries=30 "$VK_PANFROST_URL" -O ./vulkan-panfrost.pkg.tar.zst
43 | wget --retry-connrefused --tries=30 "$VK_FREEDRENO_URL" -O ./vulkan-freedreno.pkg.tar.zst
44 | wget --retry-connrefused --tries=30 "$VK_BROADCOM_URL" -O ./vulkan-broadcom.pkg.tar.zst
45 | fi
46 |
47 | pacman -U --noconfirm ./*.pkg.tar.zst
48 | rm -f ./*.pkg.tar.zst
49 |
50 | echo "Making AppImage..."
51 | echo "---------------------------------------------------------------"
52 | mkdir -p ./AppDir
53 | cd ./AppDir || exit
54 |
55 | if [ -f "/usr/share/applications/io.github.radiolamp.mangojuice.desktop" ]; then
56 | cp "/usr/share/applications/io.github.radiolamp.mangojuice.desktop" ./
57 | sed -i 's|^Exec=.*|Exec=mangojuice|' ./io.github.radiolamp.mangojuice.desktop
58 | else
59 | echo "Ошибка: desktop-файл не найден"
60 | exit 1
61 | fi
62 |
63 | if [ -f "/usr/share/icons/hicolor/scalable/apps/io.github.radiolamp.mangojuice.svg" ]; then
64 | cp "/usr/share/icons/hicolor/scalable/apps/io.github.radiolamp.mangojuice.svg" ./
65 | cp "./io.github.radiolamp.mangojuice.svg" ./.DirIcon
66 | else
67 | echo "Предупреждение: значёк не найден"
68 | fi
69 |
70 | for icon in /usr/share/icons/hicolor/scalable/apps/io.github.radiolamp.mangojuice*.svg; do
71 | mkdir -p ./share/icons/hicolor/scalable/apps/
72 | cp "$icon" ./share/icons/hicolor/scalable/apps/
73 | done
74 |
75 | mkdir -p ./share/locale
76 | for mo_file in /usr/share/locale/*/LC_MESSAGES/mangojuice.mo; do
77 | lang_dir=$(dirname "$(dirname "$mo_file")")
78 | lang=$(basename "$lang_dir")
79 | if [[ "$lang" =~ ^[a-z]{2}$ ]]; then
80 | lang="${lang}_${lang^^}"
81 | fi
82 | mkdir -p "./share/locale/$lang/LC_MESSAGES"
83 | cp "$mo_file" "./share/locale/$lang/LC_MESSAGES/mangojuice.mo"
84 | done
85 |
86 | echo "Загрузка lib4bin..."
87 | wget --retry-connrefused --tries=30 "$LIB4BN" -O ./lib4bin || {
88 | echo "Ошибка загрузки lib4bin"
89 | exit 1
90 | }
91 | chmod +x ./lib4bin
92 |
93 | echo "Копирование файлов mangojuice..."
94 | xvfb-run -a -- ./lib4bin -p -v -e -s -k \
95 | /usr/bin/mangojuice \
96 | /usr/bin/vkcube \
97 | /usr/lib/mangohud/* \
98 | /usr/bin/lspci \
99 | /usr/lib/libintl.so* \
100 | /usr/lib/gdk-pixbuf-*/*/*/* || {
101 | echo "Ошибка при копировании файлов"
102 | exit 1
103 | }
104 |
105 | mkdir -p ./share/vulkan
106 | if [ -d "/usr/share/vulkan/implicit_layer.d" ]; then
107 | cp -rv "/usr/share/vulkan/implicit_layer.d" "./share/vulkan/"
108 | sed -i 's|/usr/lib/mangohud/||' ./share/vulkan/implicit_layer.d/*
109 | else
110 | echo "Предупреждение: Vulkan layers не найдены"
111 | fi
112 |
113 | # mangojuice is also going to run mangohud vkcube so we need to wrap this
114 | echo '#!/bin/sh
115 | CURRENTDIR="$(dirname "$(readlink -f "$0")")"
116 | export MANGOHUD=1
117 | shift
118 | "$CURRENTDIR"/vkcube "$@"' > ./bin/mangohud
119 | chmod +x ./bin/mangohud
120 |
121 | # copy anything that remains in ./usr/share to ./share
122 | cp -rv ./usr/share/* ./share || true
123 | rm -rf ./usr/share
124 |
125 | # prepare sharun
126 | ln ./sharun ./AppRun
127 | ./sharun -g
128 |
129 | echo 'MANGOJUICE=1' > ./.env
130 | echo 'TEXTDOMAINDIR="${SHARUN_DIR}/share/locale' >> ./.env
131 | echo 'TEXTDOMAIN="mangojuice' >> ./.env
132 | echo 'libMangoHud_shim.so' > ./.preload
133 |
134 | cd .. || exit
135 | echo "Загрузка uruntime..."
136 | wget --retry-connrefused --tries=30 "$URUNTIME" -O ./uruntime || {
137 | echo "Ошибка загрузки uruntime"
138 | exit 1
139 | }
140 | wget --retry-connrefused --tries=30 "$URUNTIME_LITE" -O ./uruntime-lite || {
141 | echo "Ошибка загрузки uruntime-lite"
142 | exit 1
143 | }
144 | chmod +x ./uruntime*
145 |
146 | echo "Добавление информации об обновлениях..."
147 | ./uruntime-lite --appimage-addupdinfo "$UPINFO" || {
148 | echo "Ошибка добавления информации об обновлении"
149 | exit 1
150 | }
151 |
152 | echo "Создание AppImage..."
153 | ./uruntime --appimage-mkdwarfs -f \
154 | --set-owner 0 --set-group 0 \
155 | --no-history --no-create-timestamp \
156 | --compression zstd:level=22 -S26 -B8 \
157 | --header uruntime-lite \
158 | -i ./AppDir -o "MangoJuice-${VERSION}-${ARCH}.AppImage" || {
159 | echo "Ошибка создания AppImage"
160 | exit 1
161 | }
162 |
163 | echo "Готово! Создан AppImage: MangoJuice-${VERSION}-${ARCH}.AppImage"
164 |
--------------------------------------------------------------------------------
/data/assets/boosty_qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/assets/boosty_qrcode.png
--------------------------------------------------------------------------------
/data/assets/donationalerts_qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/assets/donationalerts_qrcode.png
--------------------------------------------------------------------------------
/data/assets/icons/io.github.radiolamp.mangojuice-extras-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/data/assets/icons/io.github.radiolamp.mangojuice-metrics-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/data/assets/icons/io.github.radiolamp.mangojuice-other-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/data/assets/icons/io.github.radiolamp.mangojuice-performance-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/data/assets/icons/io.github.radiolamp.mangojuice-visual-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/data/assets/icons/io.github.radiolamp.mangojuice.donate-symbolic.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/assets/icons/list-drag-handle-symbolic.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/data/assets/tbank_qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/assets/tbank_qrcode.png
--------------------------------------------------------------------------------
/data/gresource.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | io.github.radiolamp.mangojuice.metainfo.xml
5 | style.css
6 | images/fps.png
7 | images/minimal.png
8 | images/default.png
9 | images/advanced.png
10 | images/full.png
11 |
12 |
13 |
--------------------------------------------------------------------------------
/data/images/advanced.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/images/advanced.png
--------------------------------------------------------------------------------
/data/images/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/images/default.png
--------------------------------------------------------------------------------
/data/images/fps.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/images/fps.png
--------------------------------------------------------------------------------
/data/images/full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/images/full.png
--------------------------------------------------------------------------------
/data/images/minimal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/radiolamp/mangojuice/ac8c390be976e61b4f8cc8d31c253c84e47783ee/data/images/minimal.png
--------------------------------------------------------------------------------
/data/io.github.radiolamp.mangojuice.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=MangoJuice
3 | Comment=A convenient alternative to GOverlay for configuring MangoHud
4 | Exec=mangojuice
5 | Icon=io.github.radiolamp.mangojuice
6 | Terminal=false
7 | Type=Application
8 | Categories=Utility;Application;
9 |
--------------------------------------------------------------------------------
/data/io.github.radiolamp.mangojuice.metainfo.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | io.github.radiolamp.mangojuice
4 | CC0-1.0
5 | GPL-3.0-or-later
6 | Mango Juice
7 | Customizable performance display
8 |
9 |
10 | MangoJuice is an application for easily editing MangoHUD settings, which in turn is an Overlay solution for tracking load and other parameters in games and other software.
11 |
12 |
13 | https://github.com/radiolamp/mangojuice
14 | https://github.com/radiolamp/mangojuice/issues
15 |
16 |
17 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen1.png?raw=true
18 | Main interface of MangoJuice
19 |
20 |
21 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen2.png?raw=true
22 | Extra
23 |
24 |
25 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen3.png?raw=true
26 | Metric
27 |
28 |
29 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen4.png?raw=true
30 | Visual
31 |
32 |
33 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen5.png?raw=true
34 | Your profiles
35 |
36 |
37 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen7.png?raw=true
38 | Change order
39 |
40 |
41 | https://github.com/radiolamp/mangojuice-donate/blob/0.3/images/screen6.png?raw=true
42 | Visual
43 |
44 |
45 |
46 | Radiolamp
47 |
48 | anton.osi@outlook.com
49 |
50 |
51 |
52 | Profiles and sorting
53 |
54 | Full update information is available on GitHub.
55 |
56 |
57 |
58 |
59 |
60 | Initial release of MangoJuice.
61 |
62 |
63 |
64 |
65 | Utility
66 |
67 |
68 |
69 | io.github.radiolamp.mangojuice.desktop
70 |
71 | #fee372
72 | #dd624b
73 |
74 |
75 |
--------------------------------------------------------------------------------
/data/meson.build:
--------------------------------------------------------------------------------
1 | resources = gnome.compile_resources(
2 | 'resources',
3 | 'gresource.xml',
4 | source_dir: meson.current_build_dir()
5 | )
6 |
7 | install_data(
8 | 'assets/icons/io.github.radiolamp.mangojuice-metrics-symbolic.svg',
9 | 'assets/icons/io.github.radiolamp.mangojuice-extras-symbolic.svg',
10 | 'assets/icons/io.github.radiolamp.mangojuice-performance-symbolic.svg',
11 | 'assets/icons/io.github.radiolamp.mangojuice-visual-symbolic.svg',
12 | 'assets/icons/io.github.radiolamp.mangojuice-other-symbolic.svg',
13 | 'assets/icons/io.github.radiolamp.mangojuice.donate-symbolic.svg',
14 | 'assets/icons/list-drag-handle-symbolic.svg',
15 | 'icons/hicolor/scalable/apps/io.github.radiolamp.mangojuice.svg',
16 | install_dir: join_paths(get_option('datadir'), 'icons', 'hicolor', 'scalable', 'apps')
17 | )
18 |
19 | install_data(
20 | 'io.github.radiolamp.mangojuice.desktop',
21 | install_dir: get_option('datadir') / 'applications'
22 | )
23 |
24 | install_data(
25 | 'io.github.radiolamp.mangojuice.metainfo.xml',
26 | install_dir: join_paths(get_option('datadir'), 'metainfo')
27 | )
--------------------------------------------------------------------------------
/data/style.css:
--------------------------------------------------------------------------------
1 | .love-hover {
2 | color: rgb(245, 94, 119);
3 | }
4 | .row-drop-indicator {
5 | border-top: 2px solid @accent_color;
6 | }
7 |
8 |
--------------------------------------------------------------------------------
/docs/README-ru.md:
--------------------------------------------------------------------------------
1 | [](/README.md) [](/docs/README-ru.md)
2 |
3 |
4 |
5 |
9 | MangoJuice
10 |
11 |
12 | ### Эта программа станет удобной альтернативой GOverlay для настройки MangoHud
13 |
14 |
15 |
16 |
17 |
18 | | Страница 1 | Страница 2 | Страница 3 | Страница 4 | Страница 5 |
19 | | :---------------------------------: | :---------------------------------: | :---------------------------------: | :---------------------------------: | :---------------------------------: |
20 | |  |  |  |  |  |
21 |
22 | ## Установить
23 |
24 | **Flathub:**
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ## Репозитории
33 |
34 | [](https://repology.org/project/mangojuice/versions)
35 |
36 | Также доступен в репозитории для [`openSUSE`](https://software.opensuse.org/package/mangojuice).
37 |
38 | ## Сборка исходного кода
39 |
40 | ### Зависимости
41 |
42 | #### Инструменты сборки
43 |
44 | - `meson`
45 | - `ninja`
46 | - `cmake`
47 | - `gcc`
48 | - `valac`
49 |
50 | #### Требования для сборки
51 |
52 | - `gtk4`
53 | - `libadwaita-1`
54 | - `gio-2.0`
55 | - `fontconfig`
56 | - `mangohud`
57 |
58 | #### Опциональные зависимости
59 |
60 | - `mesa-demos`
61 | - `vulkan-tools`
62 | - `vkbasalt`
63 |
64 | ### Сборка
65 |
66 | ```shell
67 | meson setup build
68 | ```
69 |
70 | ### Установка
71 |
72 | ```shell
73 | sudo ninja -C build install
74 | ```
75 |
76 | ### Удаление
77 |
78 | ```shell
79 | sudo ninja -C build uninstall
80 | ```
81 |
82 | ## Режим разрабочика
83 |
84 | Также в приложении есть режим Devel. Он предназначен для разработки и не рекомендуется использовать его на постоянной основе. В этом режиме тестируются новые возможности версий mangojuice и [mangohud-git](https://aur.archlinux.org/packages/mangohud-git). Если вы все же хотите использовать его, в AUR есть пакет [mangojuice-git]((https://aur.archlinux.org/packages/mangojuice-git)) или вы можете собрать его самостоятельно с помощью следующей команды:
85 |
86 | ```shell
87 | meson setup build
88 | meson configure build --no-pager -Dis_devel=true
89 | sudo ninja -C build install
90 | ```
91 |
92 | ## Поддержка проекта
93 |
94 | Вы можете поддержать проект несколькими способами:
95 |
96 | - Создать задачу с проблемой или предложением по улучшению;
97 | - Отправить запрос на слияние с исправлениями или новой функциональностью;
98 | - Оказать финансовую поддержку (укажите ваш ник в сообщении при отправке через Т-Банк).
99 |
100 |
101 |
102 |
113 |
114 | ## Благодарность
115 |
116 | Благодарю [Rirusha](https://gitlab.gnome.org/Rirusha) за важные разъяснения по Vala и GTK4.
117 |
118 | ### Проекты, ставшие вдохновлением
119 |
120 | - [`MangoHud`](https://github.com/flightlessmango/MangoHud)
121 | - [`Goverlay`](https://github.com/benjamimgois/goverlay)
122 | - [`Colloid`](https://github.com/vinceliuice/Colloid-icon-theme/)
123 |
124 | ### Обращаю ваше внимание, что это мой первый проект на GTK4 + Vala, прошу отнестись с пониманием.
125 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project(
2 | 'mangojuice', 'vala',
3 | version: '0.8.5',
4 | default_options: [
5 | 'warning_level=0',
6 | ]
7 | )
8 |
9 | i18n = import('i18n')
10 | gnome = import('gnome')
11 |
12 | add_project_arguments(
13 | '-DGETTEXT_PACKAGE="@0@"'.format(meson.project_name()),
14 | language: 'c'
15 | )
16 |
17 | name_suffix = ''
18 | app_id_suffix = ''
19 | version_suffix = ''
20 |
21 | if get_option('is_devel')
22 | name_suffix = ' (Devel)'
23 | app_id_suffix = '-Devel'
24 |
25 | find_program('git', required: true)
26 | vcs_tag = run_command('git', 'rev-parse', '--short', 'HEAD', check: true).stdout().strip()
27 | version_suffix = '-dev.@0@'.format(vcs_tag)
28 | endif
29 |
30 | conf = configuration_data()
31 | conf.set10('IS_DEVEL', get_option('is_devel'))
32 | conf.set_quoted('DATADIR', join_paths(get_option('prefix'), get_option('datadir')))
33 | conf.set_quoted('GNOMELOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
34 | conf.set_quoted('VERSION', meson.project_version() + version_suffix)
35 |
36 | add_project_arguments(
37 | '-Wno-discarded-qualifiers',
38 | language: 'c'
39 | )
40 |
41 | subdir('data')
42 | subdir('src')
43 | subdir('po')
--------------------------------------------------------------------------------
/meson_options.txt:
--------------------------------------------------------------------------------
1 | option(
2 | 'is_devel',
3 | type: 'boolean',
4 | value: false
5 | )
6 |
--------------------------------------------------------------------------------
/po/LINGUAS:
--------------------------------------------------------------------------------
1 | ru
2 | pt_BR
3 |
--------------------------------------------------------------------------------
/po/POTFILES:
--------------------------------------------------------------------------------
1 | data/io.github.radiolamp.mangojuice.desktop
2 | data/io.github.radiolamp.mangojuice.metainfo.xml
3 | src/advanced.vala
4 | src/dialog.vala
5 | src/intel_power_fix_handler.vala
6 | src/load_states.vala
7 | src/mangojuice.vala
8 | src/other/OtherBox.vala
9 | src/reset_manager.vala
10 | src/save_states.vala
11 |
--------------------------------------------------------------------------------
/po/meson.build:
--------------------------------------------------------------------------------
1 | i18n.gettext(meson.project_name(), preset: 'glib')
2 |
--------------------------------------------------------------------------------
/po/update_potfiles.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Should run from project root dir
3 |
4 | touch ./po/unsort-POTFILES
5 |
6 | find ./src -iname "*.vala" -type f -exec grep -lrE '_\(|C_|ngettext' {} + | while read file; do echo "${file#./}" >> ./po/unsort-POTFILES; done
7 | find ./data/ -iname "*.desktop" | while read file; do echo "${file#./}" >> ./po/unsort-POTFILES; done
8 | find ./data/ -iname "*.metainfo.xml" | while read file; do echo "${file#./}" >> ./po/unsort-POTFILES; done
9 |
10 | cat ./po/unsort-POTFILES | sort | uniq > ./po/POTFILES
11 |
12 | rm ./po/unsort-POTFILES
13 |
14 | # To add translation, please use Damned Lies service https://l10n.gnome.org/
15 |
--------------------------------------------------------------------------------
/src/advanced.vala:
--------------------------------------------------------------------------------
1 | /* advanced.vala // Licence: GPL-v3.0 */
2 | using Gtk;
3 | using Adw;
4 |
5 | public class AdvancedDialog : Adw.Dialog {
6 | File config_file;
7 | List all_config_lines;
8 | List filtered_config_lines;
9 | ListBox list_box;
10 | private Gtk.ListBoxRow? drop_indicator_row = null;
11 |
12 | string[] allowed_prefixes = { "custom_text_center=", "custom_text=", "gpu_stats", "vram", "cpu_stats",
13 | "core_load", "ram", "io_read", "io_write", "procmem", "swap", "fan", "fps", "fps_metrics=avg,0.01",
14 | "fps_metrics=avg,0.1", "version", "gamemode", "vkbasalt", "exec_name", "fsr", "hdr", "vulkan_driver",
15 | "engine_version", "refresh_rate", "resolution", "arch", "present_mode", "display_server", "show_fps_limit",
16 | "frame_timing", "frame_count", "battery", "battery_watt", "battery_time", "device_battery_icon",
17 | "device_battery=gamepad,mouse", "network", "media_player", "wine", "winesync" };
18 |
19 | public static void show_advanced_dialog(Gtk.Window parent_window, MangoJuice app) {
20 | var advanced_dialog = new AdvancedDialog(parent_window, app);
21 | advanced_dialog.set_content_width(1000);
22 | advanced_dialog.set_content_height(2000);
23 | advanced_dialog.present(parent_window);
24 | }
25 |
26 | public AdvancedDialog (Gtk.Window parent, MangoJuice app) {
27 | Object ();
28 |
29 | var header_bar = new Adw.HeaderBar ();
30 | header_bar.add_css_class ("flat");
31 | header_bar.set_size_request (320, -1);
32 |
33 | var warning_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
34 | warning_box.set_halign(Gtk.Align.CENTER);
35 | warning_box.set_margin_start(12);
36 | warning_box.set_margin_end(12);
37 |
38 | var warning_icon = new Gtk.Image.from_icon_name("dialog-warning-symbolic");
39 | var warning_label = new Gtk.Label(_("The setting is reset when the configuration is changed"));
40 | warning_label.set_ellipsize(Pango.EllipsizeMode.END);
41 | warning_label.add_css_class("warning");
42 |
43 | warning_box.append(warning_icon);
44 | warning_box.append(warning_label);
45 | header_bar.set_title_widget(warning_box);
46 |
47 | var main_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0);
48 | main_box.append (header_bar);
49 |
50 | main_box.append (create_advanced_content ());
51 |
52 | this.closed.connect(() => {
53 | // LoadStates.load_states_from_file.begin(app);
54 | });
55 |
56 | this.set_child (main_box);
57 | this.present (parent);
58 | }
59 |
60 | Gtk.Widget create_advanced_content () {
61 | var scrolled_window = new Gtk.ScrolledWindow ();
62 | scrolled_window.set_hexpand (true);
63 | scrolled_window.set_vexpand (true);
64 |
65 | var clamp = new Adw.Clamp ();
66 | var group = new Adw.PreferencesGroup ();
67 |
68 | list_box = new ListBox ();
69 | list_box.set_selection_mode (SelectionMode.NONE);
70 | list_box.set_hexpand (true);
71 | list_box.set_margin_start (12);
72 | list_box.set_margin_end (12);
73 | list_box.set_margin_top (12);
74 | list_box.set_margin_bottom (12);
75 | list_box.add_css_class ("boxed-list");
76 |
77 | var config_dir = File.new_for_path (Environment.get_home_dir ()).get_child (".config").get_child ("MangoHud");
78 | config_file = config_dir.get_child ("MangoHud.conf");
79 |
80 | if (config_file.query_exists ()) {
81 | try {
82 | var input_stream = config_file.read ();
83 | var data_stream = new DataInputStream (input_stream);
84 | string line;
85 |
86 | all_config_lines = new List ();
87 | filtered_config_lines = new List ();
88 |
89 | while ((line = data_stream.read_line ()) != null) {
90 | all_config_lines.append (line);
91 |
92 | if (!line.contains ("color") &&
93 | !line.contains ("fps_limit_method=") &&
94 | !line.contains ("media_player_format=") &&
95 | !line.contains ("fps_value=")) {
96 |
97 | foreach (var prefix in allowed_prefixes) {
98 | if (line.has_prefix(prefix) || line.has_suffix ("#custom_command")) {
99 | filtered_config_lines.append (line);
100 | add_config_row (list_box, line);
101 | break;
102 | }
103 | }
104 | }
105 | }
106 | input_stream.close ();
107 | } catch (Error e) {
108 | print (_("Error when selecting a file: %s\n"), e.message);
109 | }
110 | } else {
111 | print (_("MangoHud.conf does not exist at: %s\n"), config_file.get_path ());
112 | }
113 |
114 | clamp.set_child (list_box);
115 | group.add (clamp);
116 | scrolled_window.set_child (group);
117 |
118 | var overlay = new Gtk.Overlay ();
119 | overlay.set_child (scrolled_window);
120 |
121 | var add_space_button = new Gtk.Button.with_label (_("Add space"));
122 | add_space_button.add_css_class ("suggested-action");
123 | add_space_button.set_halign (Gtk.Align.CENTER);
124 | add_space_button.set_valign (Gtk.Align.END);
125 | add_space_button.set_margin_bottom (16);
126 | add_space_button.clicked.connect (() => {
127 | var space_line = "custom_text= #space";
128 | filtered_config_lines.append (space_line);
129 | add_config_row (list_box, space_line);
130 | save_config_to_file (list_box);
131 | });
132 |
133 | overlay.add_overlay (add_space_button);
134 |
135 | return overlay;
136 | }
137 |
138 | public void add_config_row (ListBox list_box, string line) {
139 | var action_row = new Adw.ActionRow ();
140 |
141 | string key = line.split ("=")[0];
142 | if (line.strip() == "custom_text= #space") {
143 | action_row.title = "space";
144 | } else {
145 | action_row.title = get_localized_title (key);
146 | }
147 | action_row.subtitle = line;
148 |
149 | var drag_icon = new Gtk.Image.from_icon_name("list-drag-handle-symbolic");
150 | drag_icon.add_css_class("dim-label");
151 | action_row.add_prefix (drag_icon);
152 |
153 | var up_button = new Gtk.Button ();
154 | up_button.icon_name = "go-up-symbolic";
155 | up_button.add_css_class("circular");
156 | up_button.set_valign (Align.CENTER);
157 | up_button.has_frame = false;
158 | up_button.clicked.connect (() => {
159 | move_row_up (list_box, action_row);
160 | save_config_to_file (list_box);
161 | });
162 | action_row.add_suffix (up_button);
163 |
164 | var down_button = new Gtk.Button ();
165 | down_button.icon_name = "go-down-symbolic";
166 | down_button.add_css_class("circular");
167 | down_button.set_valign (Align.CENTER);
168 | down_button.has_frame = false;
169 | down_button.clicked.connect (() => {
170 | move_row_down (list_box, action_row);
171 | save_config_to_file (list_box);
172 | });
173 | action_row.add_suffix (down_button);
174 |
175 | var delete_button = new Gtk.Button ();
176 | delete_button.icon_name = "user-trash-symbolic";
177 | delete_button.add_css_class ("circular");
178 | delete_button.set_valign (Align.CENTER);
179 | delete_button.has_frame = false;
180 | delete_button.clicked.connect (() => {
181 | list_box.remove (action_row);
182 | save_config_to_file (list_box);
183 | });
184 | action_row.add_suffix (delete_button);
185 |
186 | enable_drag_and_drop (action_row, list_box, action_row);
187 |
188 | list_box.append (action_row);
189 | }
190 |
191 | void enable_drag_and_drop(Gtk.Widget widget, ListBox list_box, ListBoxRow row) {
192 | var drag_source = new Gtk.DragSource();
193 | drag_source.set_actions(Gdk.DragAction.MOVE);
194 |
195 | drag_source.drag_begin.connect((source, drag) => {
196 | row.add_css_class("card");
197 | var paintable = new Gtk.WidgetPaintable(row);
198 | drag_source.set_icon(paintable, 0, 0);
199 | });
200 |
201 | drag_source.drag_end.connect((source, drag) => {
202 | row.remove_css_class("card");
203 | clear_drop_highlight(list_box);
204 | });
205 |
206 | drag_source.prepare.connect((source, x, y) => {
207 | Value value = Value(typeof(ListBoxRow));
208 | value.set_object(row);
209 | return new Gdk.ContentProvider.for_value(value);
210 | });
211 |
212 | widget.add_controller(drag_source);
213 |
214 | var drop_target = new Gtk.DropTarget(typeof(ListBoxRow), Gdk.DragAction.MOVE);
215 |
216 | drop_target.drop.connect((target, value, x, y) => {
217 | var source_row = value.get_object() as ListBoxRow;
218 | var dest_row = list_box.get_row_at_y((int)y);
219 |
220 | if (source_row == null || dest_row == null || source_row == dest_row) {
221 | return false;
222 | }
223 |
224 | var scrolled_window = get_scrolled_parent(list_box);
225 | double scroll_position = 0;
226 | if (scrolled_window != null) {
227 | scroll_position = get_scroll_position(scrolled_window);
228 | }
229 |
230 | int source_index = get_row_index(list_box, source_row);
231 | int dest_index = get_row_index(list_box, dest_row);
232 |
233 | if (source_index < dest_index) {
234 | dest_index++;
235 | }
236 |
237 | list_box.remove(source_row);
238 | list_box.insert(source_row, dest_index);
239 | save_config_to_file(list_box);
240 |
241 | if (scrolled_window != null) {
242 | restore_scroll_position(scrolled_window, scroll_position);
243 | }
244 |
245 | return true;
246 | });
247 |
248 | drop_target.enter.connect((target, x, y) => {
249 | update_drop_highlight(list_box, (int)y);
250 | return Gdk.DragAction.MOVE;
251 | });
252 |
253 | drop_target.motion.connect((target, x, y) => {
254 | update_drop_highlight(list_box, (int)y);
255 | return Gdk.DragAction.MOVE;
256 | });
257 |
258 | drop_target.leave.connect((target) => {
259 | clear_drop_highlight(list_box);
260 | });
261 |
262 | list_box.add_controller(drop_target);
263 | }
264 |
265 | private void update_drop_highlight (ListBox list_box, int y) {
266 | clear_drop_highlight (list_box);
267 |
268 | var dest_row = list_box.get_row_at_y (y);
269 | if (dest_row != null) {
270 | drop_indicator_row = dest_row;
271 | drop_indicator_row.add_css_class ("row-drop-indicator");
272 | }
273 | }
274 |
275 | private void clear_drop_highlight (ListBox list_box) {
276 | if (drop_indicator_row != null) {
277 | drop_indicator_row.remove_css_class ("row-drop-indicator");
278 | drop_indicator_row = null;
279 | }
280 | }
281 |
282 | int get_row_index (ListBox list_box, ListBoxRow row) {
283 | int index = 0;
284 | var child = list_box.get_first_child ();
285 | while (child != null) {
286 | if (child == row) return index;
287 | index++;
288 | child = child.get_next_sibling ();
289 | }
290 | return -1;
291 | }
292 |
293 | int get_row_count (ListBox list_box) {
294 | int count = 0;
295 | var child = list_box.get_first_child ();
296 | while (child != null) {
297 | count++;
298 | child = child.get_next_sibling ();
299 | }
300 | return count;
301 | }
302 |
303 | void move_row_up (ListBox list_box, ListBoxRow row) {
304 | var scrolled_window = get_scrolled_parent(list_box);
305 | if (scrolled_window != null) {
306 | double vpos = get_scroll_position(scrolled_window);
307 |
308 | int index = get_row_index (list_box, row);
309 | if (index > 0) {
310 | list_box.remove (row);
311 | list_box.insert (row, index - 1);
312 | }
313 |
314 | restore_scroll_position(scrolled_window, vpos);
315 | }
316 | }
317 |
318 | void move_row_down (ListBox list_box, ListBoxRow row) {
319 | var scrolled_window = get_scrolled_parent(list_box);
320 | if (scrolled_window != null) {
321 | double vpos = get_scroll_position(scrolled_window);
322 |
323 | int index = get_row_index (list_box, row);
324 | if (index < get_row_count (list_box) - 1) {
325 | list_box.remove (row);
326 | list_box.insert (row, index + 1);
327 | }
328 |
329 | restore_scroll_position(scrolled_window, vpos);
330 | }
331 | }
332 |
333 | Gtk.ScrolledWindow? get_scrolled_parent(Gtk.Widget widget) {
334 | Gtk.Widget? parent = widget.get_parent();
335 | while (parent != null) {
336 | if (parent is Gtk.ScrolledWindow) {
337 | return parent as Gtk.ScrolledWindow;
338 | }
339 | parent = parent.get_parent();
340 | }
341 | return null;
342 | }
343 |
344 | double get_scroll_position(Gtk.ScrolledWindow scrolled_window) {
345 | var vadjustment = scrolled_window.get_vadjustment();
346 | return vadjustment.get_value();
347 | }
348 |
349 | void restore_scroll_position(Gtk.ScrolledWindow scrolled_window, double value) {
350 | var vadjustment = scrolled_window.get_vadjustment();
351 | Idle.add(() => {
352 | vadjustment.set_value(value);
353 | return false;
354 | });
355 | }
356 |
357 | void save_config_to_file (ListBox list_box) {
358 | try {
359 | var output_stream = config_file.replace (
360 | null,
361 | false,
362 | FileCreateFlags.NONE,
363 | null
364 | );
365 | var data_stream = new DataOutputStream (output_stream);
366 |
367 | data_stream.put_string ("# PRO MangoJuice #\n");
368 |
369 | var child = list_box.get_first_child ();
370 | while (child != null) {
371 | var action_row = child as Adw.ActionRow;
372 | if (action_row != null) {
373 | data_stream.put_string (action_row.subtitle + "\n", null);
374 | }
375 | child = child.get_next_sibling ();
376 | }
377 |
378 | foreach (var config_line in all_config_lines) {
379 | if (filtered_config_lines.find_custom (config_line, strcmp) == null) {
380 | data_stream.put_string (config_line + "\n", null);
381 | }
382 | }
383 |
384 | output_stream.close ();
385 | } catch (Error e) {
386 | print (_("Error writing to the file: %s\n"), e.message);
387 | }
388 | }
389 |
390 | string get_localized_title (string key) {
391 | switch (key) {
392 | case "custom_text_center":
393 | return _("Your text");
394 | case "custom_text":
395 | return _("Your text");
396 | case "gpu_stats":
397 | return _("Load GPU");
398 | case "vulkan_driver":
399 | return _("Vulkan Driver");
400 | case "vram":
401 | return _("VRAM");
402 | case "cpu_stats":
403 | return _("Load CPU");
404 | case "core_load":
405 | return _("Load per core");
406 | case "ram":
407 | return _("RAM");
408 | case "io_read":
409 | return _("Disk");
410 | case "io_write":
411 | return _("Disk");
412 | case "procmem":
413 | return _("Resident memory");
414 | case "swap":
415 | return _("Swap");
416 | case "fan":
417 | return _("Fan");
418 | case "fps":
419 | return _("FPS");
420 | case "fps_metrics=avg,0.01":
421 | return _("Lowest 0.1%");
422 | case "fps_metrics=avg,0.1":
423 | return _("Lowest 1%");
424 | case "version":
425 | return _("Version");
426 | case "engine_version":
427 | return _("Engine version");
428 | case "gamemode":
429 | return _("Gamemode");
430 | case "vkbasalt":
431 | return _("vkBasalt");
432 | case "exec_name":
433 | return _("Exe name");
434 | case "fsr":
435 | return _("FSR");
436 | case "hdr":
437 | return _("HDR");
438 | case "refresh_rate":
439 | return _("Refresh rate");
440 | case "resolution":
441 | return _("Resolution");
442 | case "arch":
443 | return _("Architecture");
444 | case "present_mode":
445 | return _("VPS");
446 | case "display_server":
447 | return _("Session type");
448 | case "show_fps_limit":
449 | return _("Frame limit");
450 | case "frame_timing":
451 | return _("Frame graph");
452 | case "frame_count":
453 | return _("Frame");
454 | case "battery":
455 | return _("Battery charge");
456 | case "battery_watt":
457 | return _("Battery power");
458 | case "battery_time":
459 | return _("Time remain");
460 | case "device_battery_icon":
461 | return _("Battery icon");
462 | case "device_battery=gamepad,mouse":
463 | return _("Other batteries");
464 | case "network":
465 | return _("Network");
466 | case "media_player":
467 | return _("Media");
468 | case "wine":
469 | return _("Version");
470 | case "winesync":
471 | return _("Winesync");
472 | default:
473 | return _("Other");
474 | }
475 | }
476 | }
477 |
--------------------------------------------------------------------------------
/src/config.vapi:
--------------------------------------------------------------------------------
1 | /* config.vapi // Licence: GPL-v3.0 */
2 | [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "config.h")]
3 | namespace Config {
4 | public const string GETTEXT_PACKAGE;
5 | public const string GNOMELOCALEDIR;
6 | public const string VERSION;
7 | public const bool IS_DEVEL;
8 | }
--------------------------------------------------------------------------------
/src/dialog.vala:
--------------------------------------------------------------------------------
1 | /* dialog // Licence: GPL-v3.0 */
2 |
3 | using Gtk;
4 | using Adw;
5 |
6 | namespace AboutDialog {
7 |
8 | public void show_about_dialog (Gtk.Window parent_window) {
9 |
10 | const string[] developers = {
11 | "Radiolamp https://github.com/radiolamp",
12 | "Rirusha https://rirusha.space",
13 | "Boria138 https://github.com/Boria138",
14 | "SpikedPaladin https://github.com/SpikedPaladin",
15 | "slserg https://github.com/slserg",
16 | "Samueru-sama https://github.com/Samueru-sama",
17 | "x1z53 https://gitverse.ru/x1z53"
18 | };
19 |
20 | var dialog = new Adw.AboutDialog.from_appdata (
21 | "/io/github/radiolamp/mangojuice/io.github.radiolamp.mangojuice.metainfo.xml",
22 | null
23 | );
24 |
25 | dialog.application_icon = "io.github.radiolamp.mangojuice";
26 | dialog.version = Config.VERSION;
27 | dialog.translator_credits = _("translator-credits");
28 | dialog.set_developers(developers);
29 | dialog.add_link (_("Financial support") + " (Donation Alerts)", "https://www.donationalerts.com/r/radiolamp");
30 | dialog.add_link (_("Financial support") + " (Tinkoff)", "https://www.tbank.ru/cf/3PPTstulqEq");
31 | dialog.add_link (_("Financial support") + " (Boosty)", "https://boosty.to/radiolamp");
32 |
33 | dialog.present (parent_window);
34 | }
35 |
36 | int profile_count = 0;
37 |
38 | delegate void DeleteCallback();
39 |
40 | void update_group_state(Adw.PreferencesGroup group, Adw.StatusPage status_page) {
41 | if (profile_count == 0 && status_page.get_parent() == null) {
42 | group.add(status_page);
43 | } else if (profile_count > 0 && status_page.get_parent() != null) {
44 | group.remove(status_page);
45 | }
46 | }
47 |
48 | public void preset_dialog(Gtk.Window parent_window, MangoJuice app) {
49 | var dialog = new Adw.Dialog();
50 | dialog.set_content_width(800);
51 | dialog.set_content_height(600);
52 | dialog.set_size_request(320, 240);
53 |
54 | var breakpoint_450px = new Adw.Breakpoint(Adw.BreakpointCondition.parse("max-width: 450px"));
55 | dialog.add_breakpoint(breakpoint_450px);
56 |
57 | var toast_overlay = new Adw.ToastOverlay();
58 | dialog.set_child(toast_overlay);
59 |
60 | var main_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
61 | toast_overlay.set_child(main_box);
62 |
63 | var window_handle = new Gtk.WindowHandle();
64 | main_box.append(window_handle);
65 |
66 | var header_bar = new Adw.HeaderBar();
67 | header_bar.set_show_start_title_buttons(true);
68 | header_bar.set_show_end_title_buttons(true);
69 | header_bar.add_css_class("flat");
70 | main_box.append(header_bar);
71 |
72 | var info_button = new Gtk.Button();
73 | info_button.set_icon_name("dialog-information-symbolic");
74 | info_button.add_css_class("circular");
75 | info_button.set_tooltip_text(_("To get ready presets, click on the title."));
76 | header_bar.pack_start(info_button);
77 |
78 | var presets_button = new Gtk.Button();
79 | presets_button.set_hexpand(true);
80 | presets_button.add_css_class("flat");
81 | var button_content = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
82 | button_content.set_halign(Gtk.Align.CENTER);
83 | var presets_label = new Gtk.Label(_("Presets"));
84 | var arrow_icon = new Gtk.Image.from_icon_name("go-next-symbolic");
85 | button_content.append(presets_label);
86 | button_content.append(arrow_icon);
87 | presets_button.set_child(button_content);
88 | header_bar.set_title_widget(presets_button);
89 |
90 | var content_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
91 | content_box.set_hexpand(true);
92 | content_box.set_vexpand(true);
93 | main_box.append(content_box);
94 |
95 | var clamp = new Adw.Clamp() {
96 | maximum_size = 800,
97 | tightening_threshold = 450,
98 | margin_top = 12,
99 | margin_bottom = 12
100 | };
101 | content_box.append(clamp);
102 |
103 | var clamped_content = new Gtk.Box(Gtk.Orientation.VERTICAL, 12);
104 | clamped_content.set_margin_start(24);
105 | clamped_content.set_margin_end(24);
106 | clamp.set_child(clamped_content);
107 |
108 | var group = new Adw.PreferencesGroup();
109 | var status_page = new Adw.StatusPage() {
110 | title = _("No profiles yet"),
111 | icon_name = "emoji-symbols-symbolic"
112 | };
113 | status_page.add_css_class("dim-label");
114 | status_page.set_vexpand(true);
115 |
116 | var add_button = new Gtk.Button.with_label(_("Add Profile"));
117 | add_button.set_size_request(-1, 40);
118 |
119 | add_button.clicked.connect(() => {
120 | var row = add_option_button(group, app, toast_overlay, () => {
121 | profile_count--;
122 | update_group_state(group, status_page);
123 | });
124 | group.add(row);
125 | profile_count++;
126 | update_group_state(group, status_page);
127 | });
128 |
129 | try {
130 | var config_dir = File.new_for_path(Environment.get_home_dir())
131 | .get_child(".config")
132 | .get_child("MangoHud");
133 |
134 | if (config_dir.query_exists()) {
135 | var enumerator = config_dir.enumerate_children(FileAttribute.STANDARD_NAME, 0);
136 | FileInfo info;
137 | var profiles = new GLib.List();
138 |
139 | while ((info = enumerator.next_file()) != null) {
140 | string name = info.get_name();
141 | if (name.has_suffix(".conf") && name != "MangoHud.conf" && name != ".MangoHud.backup") {
142 | string profile_name = name[0:-5].replace("-", " ");
143 | profiles.append(profile_name);
144 | }
145 | }
146 |
147 | profiles.sort((a, b) => {
148 | return a.collate(b);
149 | });
150 |
151 | foreach (string profile_name in profiles) {
152 | var row = add_option_button(group, app, toast_overlay, () => {
153 | profile_count--;
154 | update_group_state(group, status_page);
155 | }, profile_name, true);
156 | group.add(row);
157 | profile_count++;
158 | }
159 | }
160 | } catch (Error e) {
161 | warning("Error loading profiles: %s", e.message);
162 | }
163 |
164 | update_group_state(group, status_page);
165 |
166 | var scrolled = new Gtk.ScrolledWindow();
167 | scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
168 |
169 | var profile_container = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
170 | profile_container.set_margin_top(2);
171 | profile_container.set_margin_bottom(2);
172 | profile_container.set_margin_start(2);
173 | profile_container.set_margin_end(2);
174 | profile_container.append(group);
175 |
176 | scrolled.set_child(profile_container);
177 | scrolled.set_vexpand(true);
178 | clamped_content.append(scrolled);
179 | clamped_content.append(add_button);
180 |
181 | presets_button.clicked.connect(() => {
182 | show_presets_carousel_dialog((Gtk.Window)dialog, app);
183 | });
184 |
185 | dialog.closed.connect(() => {
186 | try {
187 | Process.spawn_command_line_async("pkill vkcube");
188 | Process.spawn_command_line_async("pkill glxgears");
189 | } catch (Error e) {
190 | stderr.printf(_("Error when executing the command: %s\n"), e.message);
191 | }
192 | });
193 |
194 | dialog.present(parent_window);
195 | }
196 |
197 | Adw.ActionRow add_option_button(Adw.PreferencesGroup group, MangoJuice app, Adw.ToastOverlay toast_overlay, owned DeleteCallback on_delete, string initial_name = _("Profile"), bool is_existing_profile = false) {
198 | string profile_name = initial_name;
199 |
200 | if (!is_existing_profile) {
201 | if (profile_name.has_suffix(".exe")) {
202 | profile_name = "wine-" + profile_name.substring(0, profile_name.length - 4);
203 | } else if (initial_name == _("Profile")) {
204 | profile_name = generate_unique_profile_name(initial_name);
205 | }
206 | create_profile_config(profile_name);
207 | }
208 |
209 | var row = new Adw.ActionRow();
210 | row.set_title(profile_name);
211 | row.set_activatable(true);
212 | row.set_selectable(false);
213 | row.set_tooltip_text(_("Profile preview"));
214 |
215 | var edit_btn = new Gtk.Button();
216 | edit_btn.set_icon_name("document-edit-symbolic");
217 | edit_btn.set_focusable(false);
218 | edit_btn.add_css_class("flat");
219 | edit_btn.add_css_class("circular");
220 | edit_btn.set_tooltip_text(_("Renaming. Name the name of the game, or name.exe for Wine games, e.g. DOOM.exe. Attention case is important!"));
221 | edit_btn.set_valign(Gtk.Align.CENTER);
222 |
223 | var reset_btn = new Gtk.Button();
224 | reset_btn.set_icon_name("view-refresh-symbolic");
225 | reset_btn.set_focusable(false);
226 | reset_btn.add_css_class("flat");
227 | reset_btn.add_css_class("circular");
228 | reset_btn.set_tooltip_text(_("Overwrite profile"));
229 | reset_btn.set_valign(Gtk.Align.CENTER);
230 |
231 | var close_btn = new Gtk.Button();
232 | close_btn.set_icon_name("edit-delete-symbolic");
233 | close_btn.set_focusable(false);
234 | close_btn.add_css_class("flat");
235 | close_btn.set_tooltip_text(_("Delete profile"));
236 | close_btn.set_valign(Gtk.Align.CENTER);
237 | close_btn.add_css_class("circular");
238 |
239 | var button_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 2);
240 | button_box.append(edit_btn);
241 | button_box.append(reset_btn);
242 | button_box.append(close_btn);
243 | row.add_suffix(button_box);
244 |
245 | var entry = new Gtk.Entry();
246 | entry.set_text(profile_name);
247 | entry.set_visible(false);
248 | entry.set_hexpand(true);
249 | entry.set_valign(Gtk.Align.CENTER);
250 | row.add_prefix(entry);
251 |
252 | edit_btn.clicked.connect(() => {
253 | entry.set_text(profile_name);
254 | row.set_title("");
255 | entry.set_visible(true);
256 | entry.grab_focus();
257 | });
258 |
259 | reset_btn.clicked.connect(() => {
260 | try {
261 | var config_dir = File.new_for_path(Environment.get_home_dir())
262 | .get_child(".config")
263 | .get_child("MangoHud");
264 |
265 | var original_config = config_dir.get_child("MangoHud.conf");
266 | var profile_config = config_dir.get_child(
267 | profile_name.replace(" ", "-") + ".conf"
268 | );
269 |
270 | if (original_config.query_exists()) {
271 | original_config.copy(profile_config, FileCopyFlags.OVERWRITE);
272 | }
273 |
274 | var toast = new Adw.Toast(_("Changed"));
275 | toast.set_timeout(3);
276 | toast_overlay.add_toast(toast);
277 | } catch (Error e) {
278 | warning("Failed to reset profile: %s", e.message);
279 | }
280 | });
281 |
282 | entry.activate.connect(() => {
283 | string new_name = entry.get_text().strip();
284 |
285 | if (new_name.has_suffix(".exe")) {
286 | new_name = "wine " + new_name.substring(0, new_name.length - 4);
287 | }
288 |
289 | if (new_name != "" && new_name != profile_name) {
290 | rename_profile_config(profile_name, new_name);
291 | profile_name = new_name;
292 | }
293 |
294 | entry.set_visible(false);
295 | row.set_title(profile_name);
296 | });
297 |
298 | var play_btn = new Gtk.Button.from_icon_name("media-playback-start-symbolic");
299 | play_btn.add_css_class("flat");
300 | play_btn.set_tooltip_text(_("Apply the profile to the entire system"));
301 | play_btn.set_valign(Gtk.Align.CENTER);
302 | play_btn.add_css_class("circular");
303 | play_btn.clicked.connect(() => {
304 | app.run_test();
305 | apply_profile_config(profile_name);
306 | LoadStates.load_states_from_file.begin(app);
307 | app.reset_manager.reset_all_widgets();
308 |
309 | var toast = new Adw.Toast(_("Applied"));
310 | toast.set_timeout(3);
311 | toast_overlay.add_toast(toast);
312 | });
313 | row.add_prefix(play_btn);
314 |
315 | var focus_controller = new Gtk.EventControllerFocus();
316 | focus_controller.leave.connect(() => {
317 | if (entry.get_visible()) {
318 | entry.activate();
319 | }
320 | });
321 | entry.add_controller(focus_controller);
322 |
323 | close_btn.clicked.connect(() => {
324 | delete_profile_config(profile_name);
325 | group.remove(row);
326 | on_delete();
327 | var toast = new Adw.Toast(_("Deleted"));
328 | toast.set_timeout(3);
329 | toast_overlay.add_toast(toast);
330 | });
331 |
332 | string? wayland_display = Environment.get_variable("WAYLAND_DISPLAY");
333 | bool is_wayland = (wayland_display != null && wayland_display != "");
334 |
335 | row.activated.connect(() => {
336 | try {
337 | Process.spawn_command_line_async("pkill vkcube");
338 | Process.spawn_command_line_async("pkill glxgears");
339 |
340 | string config_path = Path.build_filename(
341 | Environment.get_home_dir(),
342 | ".config",
343 | "MangoHud",
344 | profile_name.replace(" ", "-") + ".conf"
345 | );
346 |
347 | string base_cmd = @"env MANGOHUD_CONFIGFILE='$config_path' mangohud";
348 |
349 | if (app.is_flatpak ()) {
350 | Process.spawn_command_line_sync ("pkill vkcube");
351 | if (is_wayland) {
352 | Process.spawn_command_line_async (base_cmd + " mangohud vkcube-wayland");
353 | } else {
354 | Process.spawn_command_line_async (base_cmd + " mangohud vkcube");
355 | }
356 | } else if (app.is_vkcube_available ()) {
357 | Process.spawn_command_line_sync ("pkill vkcube");
358 | Process.spawn_command_line_async (base_cmd + " mangohud vkcube");
359 | } else if (app.is_glxgears_available ()) {
360 | Process.spawn_command_line_sync ("pkill glxgears");
361 | Process.spawn_command_line_async (base_cmd + " mangohud glxgears");
362 | }
363 | } catch (Error e) {
364 | warning("%s", e.message);
365 | }
366 | });
367 |
368 | return row;
369 | }
370 |
371 | void show_presets_carousel_dialog(Gtk.Window parent_dialog, MangoJuice app) {
372 | var dialog = new Adw.Dialog();
373 | dialog.set_content_width(800);
374 | dialog.set_content_height(600);
375 | dialog.set_size_request(320, 240);
376 |
377 | var breakpoint_mobile = new Adw.Breakpoint(Adw.BreakpointCondition.parse("max-width: 450px"));
378 | var breakpoint_desktop = new Adw.Breakpoint(Adw.BreakpointCondition.parse("min-width: 451px"));
379 | dialog.add_breakpoint(breakpoint_mobile);
380 | dialog.add_breakpoint(breakpoint_desktop);
381 |
382 | var main_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
383 | dialog.set_child(main_box);
384 |
385 | var header = new Adw.HeaderBar();
386 | header.set_show_start_title_buttons(true);
387 | header.set_show_end_title_buttons(true);
388 | header.add_css_class("flat");
389 | main_box.append(header);
390 |
391 | var header_center_box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6);
392 | header_center_box.set_halign(Gtk.Align.CENTER);
393 | header_center_box.set_valign(Gtk.Align.CENTER);
394 | header_center_box.set_hexpand(true);
395 | header_center_box.set_vexpand(false);
396 | header.set_title_widget(header_center_box);
397 |
398 | var carousel = new Adw.Carousel();
399 | carousel.set_hexpand(true);
400 | carousel.set_vexpand(true);
401 |
402 | var header_indicators = new Adw.CarouselIndicatorDots();
403 | header_indicators.set_carousel(carousel);
404 | header_indicators.set_valign(Gtk.Align.CENTER);
405 | header_indicators.set_halign(Gtk.Align.CENTER);
406 |
407 | header_center_box.append(header_indicators);
408 |
409 | var restore_button = new Gtk.Button.with_label(_("Restore"));
410 | ((Gtk.Label)restore_button.get_child()).set_ellipsize(Pango.EllipsizeMode.END);
411 | restore_button.clicked.connect(() => {
412 | try {
413 | var backup_file = File.new_for_path(Environment.get_home_dir())
414 | .get_child(".config")
415 | .get_child("MangoHud")
416 | .get_child(".MangoHud.backup");
417 | app.restore_config_from_file(backup_file.get_path());
418 | backup_file.delete();
419 | } catch (Error e) {
420 | stderr.printf("Error: %s\n", e.message);
421 | }
422 | });
423 | header.pack_start(restore_button);
424 |
425 | var apply_button = new Gtk.Button.with_label(_("Apply"));
426 | ((Gtk.Label)apply_button.get_child()).set_ellipsize(Pango.EllipsizeMode.END);
427 | apply_button.add_css_class("suggested-action");
428 | apply_button.clicked.connect(() => {
429 | apply_preset(carousel, app);
430 | });
431 | header.pack_end(apply_button);
432 |
433 | var content_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 12);
434 | content_box.set_margin_top(12);
435 | content_box.set_margin_bottom(12);
436 | content_box.set_margin_start(12);
437 | content_box.set_margin_end(12);
438 | content_box.set_hexpand(true);
439 | content_box.set_vexpand(true);
440 | main_box.append(content_box);
441 |
442 | content_box.append(carousel);
443 |
444 | var bottom_indicators = new Adw.CarouselIndicatorDots();
445 | bottom_indicators.set_carousel(carousel);
446 | bottom_indicators.set_valign(Gtk.Align.CENTER);
447 | bottom_indicators.set_halign(Gtk.Align.CENTER);
448 | bottom_indicators.set_margin_top(10);
449 | bottom_indicators.set_visible(false);
450 | content_box.append(bottom_indicators);
451 |
452 | breakpoint_mobile.add_setter(header_indicators, "visible", false);
453 | breakpoint_mobile.add_setter(bottom_indicators, "visible", true);
454 | breakpoint_desktop.add_setter(header_indicators, "visible", true);
455 | breakpoint_desktop.add_setter(bottom_indicators, "visible", false);
456 |
457 | string[] titles = { _("Minimal"), _("Default"), _("Advanced"), _("Full"), _("Only FPS") };
458 | string[] icons = { "minimal", "default", "advanced", "full", "fps" };
459 |
460 | for (int i = 0; i < titles.length; i++) {
461 | var page = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
462 | page.set_hexpand(true);
463 | page.set_vexpand(true);
464 |
465 | var center = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
466 | center.set_hexpand(true);
467 | center.set_vexpand(true);
468 |
469 | var picture = new Gtk.Picture();
470 | picture.set_resource("/io/github/radiolamp/mangojuice/images/" + icons[i] + ".png");
471 | picture.set_hexpand(true);
472 | picture.set_vexpand(true);
473 | picture.set_can_shrink(false);
474 |
475 | var label = new Gtk.Label(titles[i]);
476 | label.add_css_class("title-2");
477 | label.set_margin_top(10);
478 | label.set_margin_bottom(10);
479 |
480 | center.append(picture);
481 | center.append(label);
482 | page.append(center);
483 |
484 | carousel.append(page);
485 | }
486 |
487 | dialog.present(parent_dialog);
488 | }
489 |
490 |
491 | void apply_preset(Adw.Carousel carousel, MangoJuice app) {
492 | int current_page = (int)carousel.get_position();
493 | string[] page_names = { _("Minimal"), _("Default"), _("Advanced"), _("Full"), _("Only FPS") };
494 | stdout.printf(_("Applying %s layout\n"), page_names[current_page]);
495 |
496 | switch (current_page) {
497 | case 0:
498 | string[] profile1_vars = { "background_alpha=0.4", "round_corners=0", "background_color=000000", "text_color=FFFFFF", "position=top-left",
499 | "table_columns=2", "cpu_stats", "gpu_stats", "ram", "vram", "hud_compact", "fps", "hud_no_margin" };
500 | set_preset(profile1_vars);
501 | break;
502 | case 1:
503 | string[] profile2_vars = { "background_alpha=0.4", "round_corners=10", "cpu_stats", "gpu_load_change", "gpu_load_value=30,60",
504 | "gpu_load_color=FFFFFF,FFAA7F,CC0000", "gpu_temp", "gpu_fan", "gpu_power", "gpu_stats", "cpu_load_change", "cpu_load_value=30,60",
505 | "cpu_load_color=FFFFFF,FFAA7F,CC0000", "cpu_mhz", "cpu_temp", "cpu_color=2E97CB", "vram", "vram_color=AD64C1", "ram", "ram_color=C26693",
506 | "wine_color=EB4B4B", "fps", "frametime_color=00e4ff", "toggle_fps_limit=Shift_L+F1", "fps_limit=0,30,60", "fps_color_change",
507 | "fps_color=ff0000,FDFD09,ffffff", "fps_value=30,60", "engine_short_names", "frame_timing" };
508 | set_preset(profile2_vars);
509 | break;
510 | case 2:
511 | string[] profile3_vars = { "background_alpha=0.4", "round_corners=10", "gpu_text=GPU", "gpu_stats", "gpu_load_change", "gpu_load_value=30,60",
512 | "gpu_load_color=ffffff,ffaa7f,cc0000", "gpu_temp", "gpu_fan", "gpu_power", "gpu_color=2E9762", "cpu_text=CPU", "cpu_stats", "cpu_load_change",
513 | "cpu_load_value=30,60", "cpu_load_color=ffffff,ffaa7f,cc0000", "cpu_mhz", "cpu_temp", "cpu_color=2E97CB", "vram", "vram_color=AD64C1", "ram",
514 | "ram_color=C26693", "fps", "engine_short_names", "gpu_name", "wine", "wine_color=eb4b4b", "frame_timing", "frametime_color=00edff",
515 | "toggle_fps_limit=Shift_L+F1", "show_fps_limit", "fps_limit=0,30,60", "resolution", "fsr", "hdr", "refresh_rate", "fps_color_change",
516 | "fps_color=ff0000,fdfd09,ffffff", "fps_value=30,60", "media_player", "media_player_color=FFFFFF" };
517 | set_preset(profile3_vars);
518 | break;
519 | case 3:
520 | string[] profile4_vars = { "background_alpha=0.4", "round_corners=10", "table_columns=4", "gpu_stats", "gpu_load_change", "gpu_load_value=30,60",
521 | "gpu_load_color=FFFFFF,FFAA7F,CC0000", "gpu_temp", "gpu_fan", "gpu_power", "gpu_color=2E9762", "cpu_stats", "cpu_load_change", "cpu_load_value=30,60",
522 | "cpu_load_color=FFFFFF,FFAA7F,CC0000", "cpu_mhz", "cpu_temp", "cpu_color=2E97CB", "vram", "vram_color=AD64C1", "ram", "procmem", "io_read", "io_write",
523 | "ram_color=C26693", "fps", "engine_short_names", "gpu_name", "wine_color=EB4B4B", "frame_timing", "frame_count", "frametime_color=00FF00", "show_fps_limit",
524 | "fps_limit=0,120,240", "resolution", "fsr", "hdr", "refresh_rate", "fps_color_change", "fps_color=ff0000,FDFD09,ffffff", "fps_value=80,140", "media_player",
525 | "media_player_color=FFFFFF", "cpu_power", "gpu_junction_temp", "gpu_core_clock", "gpu_mem_temp", "gpu_mem_clock", "gpu_voltage", "procmem_shared", "procmem_virt",
526 | "battery", "battery_icon", "device_battery_icon", "battery_watt", "battery_time", "exec_name", "throttling_status_graph", "arch", "full" };
527 | set_preset(profile4_vars);
528 | break;
529 | case 4:
530 | string[] profile5_vars = { "fps_only", "background_alpha=0" };
531 | set_preset(profile5_vars);
532 | break;
533 | }
534 | LoadStates.load_states_from_file.begin(app);
535 | app.reset_manager.reset_all_widgets();
536 | }
537 |
538 | string generate_unique_profile_name(string base_name) {
539 | string name = base_name;
540 | int counter = 1;
541 |
542 | while (true) {
543 | string config_path = Path.build_filename(
544 | Environment.get_home_dir(),
545 | ".config",
546 | "MangoHud",
547 | name.replace(" ", "-") + ".conf"
548 | );
549 |
550 | if (!File.new_for_path(config_path).query_exists()) {
551 | break;
552 | }
553 |
554 | name = @"$base_name $counter";
555 | counter++;
556 | }
557 |
558 | return name;
559 | }
560 |
561 | void create_profile_config(string profile_name) {
562 | try {
563 | var config_dir = File.new_for_path(Environment.get_home_dir())
564 | .get_child(".config")
565 | .get_child("MangoHud");
566 |
567 | var original_config = config_dir.get_child("MangoHud.conf");
568 | var new_config = config_dir.get_child(
569 | profile_name.replace(" ", "-") + ".conf"
570 | );
571 | if (original_config.query_exists()) {
572 | original_config.copy(new_config, FileCopyFlags.OVERWRITE);
573 | }
574 | } catch (Error e) {
575 | warning("Failed to create profile: %s", e.message);
576 | }
577 | }
578 |
579 | void rename_profile_config(string old_name, string new_name) {
580 | try {
581 | string old_path = Path.build_filename(
582 | Environment.get_home_dir(),
583 | ".config",
584 | "MangoHud",
585 | old_name.replace(" ", "-") + ".conf"
586 | );
587 | string new_path = Path.build_filename(
588 | Environment.get_home_dir(),
589 | ".config",
590 | "MangoHud",
591 | new_name.replace(" ", "-") + ".conf"
592 | );
593 |
594 | var old_file = File.new_for_path(old_path);
595 | if (old_file.query_exists()) {
596 | old_file.move(File.new_for_path(new_path), FileCopyFlags.OVERWRITE);
597 | }
598 | } catch (Error e) {
599 | warning("Failed to rename profile: %s", e.message);
600 | }
601 | }
602 |
603 | void delete_profile_config(string profile_name) {
604 | try {
605 | string path = Path.build_filename(
606 | Environment.get_home_dir(),
607 | ".config",
608 | "MangoHud",
609 | profile_name.replace(" ", "-") + ".conf"
610 | );
611 |
612 | var file = File.new_for_path(path);
613 | if (file.query_exists()) {
614 | file.delete();
615 | }
616 | } catch (Error e) {
617 | warning("Failed to delete profile: %s", e.message);
618 | }
619 | }
620 |
621 | void apply_profile_config(string profile_name) {
622 | try {
623 | string profile_path = Path.build_filename(
624 | Environment.get_home_dir(),
625 | ".config",
626 | "MangoHud",
627 | profile_name.replace(" ", "-") + ".conf"
628 | );
629 |
630 | string target_path = Path.build_filename(
631 | Environment.get_home_dir(),
632 | ".config",
633 | "MangoHud",
634 | "MangoHud.conf"
635 | );
636 |
637 | var profile_file = File.new_for_path(profile_path);
638 | if (profile_file.query_exists()) {
639 | profile_file.copy(File.new_for_path(target_path), FileCopyFlags.OVERWRITE);
640 | }
641 | } catch (Error e) {
642 | warning("Failed to apply profile: %s", e.message);
643 | }
644 | }
645 |
646 | void set_preset (string[] preset_values) {
647 | var file = File.new_for_path (Environment.get_home_dir ()).get_child (".config").get_child("MangoHud").get_child ("MangoHud.conf");
648 | var backup_file = File.new_for_path (Environment.get_home_dir ()).get_child (".config").get_child ("MangoHud").get_child (".MangoHud.backup");
649 | try {
650 | if (file.query_exists () && !backup_file.query_exists ()) {
651 | file.copy (backup_file, FileCopyFlags.OVERWRITE);
652 | }
653 | var output_stream = new DataOutputStream (file.replace(null, false, FileCreateFlags.NONE));
654 | output_stream.put_string ("#Preset config by MangoJuice #\n");
655 | output_stream.put_string ("legacy_layout=false\n");
656 | foreach (string value in preset_values) {
657 | output_stream.put_string ("%s\n".printf (value));
658 | }
659 | } catch (Error e) {
660 | stderr.printf ("Error: %s\n", e.message);
661 | }
662 | }
663 | }
664 |
--------------------------------------------------------------------------------
/src/intel_power_fix_handler.vala:
--------------------------------------------------------------------------------
1 | using Gtk;
2 | using GLib;
3 | using Adw;
4 |
5 | public async void on_intel_power_fix_button_clicked(Button button) {
6 | try {
7 | bool is_service_active = false;
8 | try {
9 | int exit_status;
10 | Process.spawn_command_line_sync("systemctl is-active --quiet powercap-permissions.service", null, null, out exit_status);
11 | is_service_active = (exit_status == 0);
12 | } catch (Error e) {
13 | stderr.printf("Service check failed: %s\n", e.message);
14 | }
15 |
16 | var dialog = new Adw.AlertDialog(_("Warning"), _("You are changing the rights to intel energy_uj, which could potentially lead to security issues."));
17 |
18 | dialog.add_response("cancel", _("Cancel"));
19 | dialog.add_response("temporary", _("Until Reboot"));
20 | dialog.add_response("permanent", _("Permanently"));
21 | dialog.set_default_response("cancel");
22 | dialog.set_close_response("cancel");
23 |
24 | if (is_service_active) {
25 | dialog.set_response_appearance("permanent", Adw.ResponseAppearance.SUGGESTED);
26 | }
27 |
28 | var window = (Gtk.Window) button.get_root();
29 | string response = yield dialog.choose(window, null);
30 |
31 | if (response == "cancel") {
32 | return;
33 | }
34 |
35 | var file = File.new_for_path("/sys/class/powercap/intel-rapl:0/energy_uj");
36 | var info = yield file.query_info_async("*", FileQueryInfoFlags.NONE);
37 | var current_mode = info.get_attribute_uint32(FileAttribute.UNIX_MODE);
38 |
39 | string new_mode = ((current_mode & 0777) == 0644) ? "0600" : "0644";
40 |
41 | if (response == "temporary") {
42 | Process.spawn_command_line_sync("pkexec chmod " + new_mode + " /sys/class/powercap/intel-rapl\\:0/energy_uj");
43 | } else if (response == "permanent") {
44 | bool service_exists = FileUtils.test("/etc/systemd/system/powercap-permissions.service", FileTest.EXISTS);
45 |
46 | if (service_exists) {
47 | Process.spawn_command_line_sync("pkexec sh -c 'systemctl stop powercap-permissions.service && " +
48 | "systemctl disable powercap-permissions.service && " +
49 | "rm /etc/systemd/system/powercap-permissions.service && " +
50 | "pkexec chmod 0600 /sys/class/powercap/intel-rapl\\:0/energy_uj && " +
51 | "systemctl daemon-reload'");
52 | } else {
53 | string service_content = "[Unit]\n" +
54 | "Description=Change permissions of intel-rapl energy_uj file\n" +
55 | "After=sysinit.target\n\n" +
56 | "[Service]\n" +
57 | "Type=oneshot\n" +
58 | "ExecStart=/bin/chmod 0644 /sys/class/powercap/intel-rapl:0/energy_uj\n" +
59 | "RemainAfterExit=yes\n\n" +
60 | "[Install]\n" +
61 | "WantedBy=multi-user.target";
62 |
63 | Process.spawn_command_line_sync("pkexec sh -c 'echo \"" + service_content + "\" > /etc/systemd/system/powercap-permissions.service && " +
64 | "systemctl daemon-reload && " +
65 | "systemctl enable powercap-permissions.service && " +
66 | "systemctl start powercap-permissions.service'");
67 |
68 | var reboot_dialog = new Adw.AlertDialog(
69 | _("Warning"),
70 | _("For the permanent changes to take full effect, a reboot is recommended. Would you like to reboot now?")
71 | );
72 | reboot_dialog.add_response("no", _("Later"));
73 | reboot_dialog.add_response("yes", _("Reboot Now"));
74 | reboot_dialog.set_response_appearance("yes", Adw.ResponseAppearance.DESTRUCTIVE);
75 |
76 | string reboot_response = yield reboot_dialog.choose(window, null);
77 | if (reboot_response == "yes") {
78 | Process.spawn_command_line_async("pkexec reboot");
79 | }
80 | }
81 | }
82 |
83 | yield check_file_permissions_async(button);
84 |
85 | } catch (Error e) {
86 | stderr.printf("Error: %s\n", e.message);
87 |
88 | var error_dialog = new Adw.AlertDialog(
89 | _("Error"),
90 | e.message
91 | );
92 | error_dialog.add_response("ok", _("OK"));
93 |
94 | var window = (Gtk.Window) button.get_root();
95 | error_dialog.present(window);
96 | }
97 | }
98 |
99 | public async void check_file_permissions_async(Button button) {
100 | string file_path = "/sys/class/powercap/intel-rapl:0/energy_uj";
101 | bool has_permissions = false;
102 | bool permanent_solution = false;
103 | bool is_service_active = false;
104 |
105 | try {
106 | var file = File.new_for_path(file_path);
107 | var info = yield file.query_info_async("*", FileQueryInfoFlags.NONE);
108 | has_permissions = (info.get_attribute_uint32(FileAttribute.UNIX_MODE) & 0777) == 0644;
109 |
110 | permanent_solution = FileUtils.test("/etc/systemd/system/powercap-permissions.service", FileTest.EXISTS);
111 |
112 | if (permanent_solution) {
113 | int exit_status;
114 | Process.spawn_command_line_sync("systemctl is-active --quiet powercap-permissions.service", null, null, out exit_status);
115 | is_service_active = (exit_status == 0);
116 | }
117 | } catch (Error e) {
118 | stderr.printf("Permission check failed: %s\n", e.message);
119 | }
120 |
121 | Idle.add(() => {
122 | if (has_permissions) {
123 | button.add_css_class("suggested-action");
124 | button.set_tooltip_text(is_service_active ? _("Permissions set permanently (systemd service active)") :
125 | (permanent_solution ? _("Service exists but not active") : _("Permissions set until reboot")));
126 | } else {
127 | button.remove_css_class("suggested-action");
128 | button.set_tooltip_text(is_service_active ? _("Service active but permissions not set") :
129 | (permanent_solution ? _("Service exists but inactive") : _("Permissions not set")));
130 | }
131 | return false;
132 | });
133 | }
--------------------------------------------------------------------------------
/src/load_states.vala:
--------------------------------------------------------------------------------
1 | /* load_states.vala // Licence: GPL-v3.0 */
2 |
3 | using Gtk;
4 | using Gee;
5 |
6 | public class LoadStates {
7 | public static async void load_states_from_file (MangoJuice mango_juice) {
8 | var config_dir = File.new_for_path (Environment.get_home_dir ()).get_child (".config").get_child ("MangoHud");
9 | var file = config_dir.get_child ("MangoHud.conf");
10 |
11 | mango_juice.is_loading = true;
12 |
13 | if (!file.query_exists ()) {
14 | try {
15 | if (!config_dir.query_exists ()) {
16 | config_dir.make_directory_with_parents ();
17 | }
18 | file.create (FileCreateFlags.NONE);
19 | } catch (Error e) {
20 | stderr.printf ("Error creating the file: %s\n", e.message);
21 | mango_juice.is_loading = false;
22 | return;
23 | }
24 | }
25 |
26 | try {
27 | var file_stream = yield file.read_async ();
28 |
29 | var data_stream = new DataInputStream (file_stream);
30 | string line;
31 |
32 | while ((line = yield data_stream.read_line_async ()) != null) {
33 | load_switch_from_file (line, mango_juice.gpu_switches, mango_juice.gpu_config_vars);
34 | load_switch_from_file (line, mango_juice.cpu_switches, mango_juice.cpu_config_vars);
35 | load_switch_from_file (line, mango_juice.memory_switches, mango_juice.memory_config_vars);
36 | if (Config.IS_DEVEL) {
37 | load_switch_from_file (line, mango_juice.git_switches, mango_juice.git_config_vars);
38 | }
39 | load_switch_from_file (line, mango_juice.system_switches, mango_juice.system_config_vars);
40 | load_switch_from_file (line, mango_juice.wine_switches, mango_juice.wine_config_vars);
41 | load_switch_from_file (line, mango_juice.battery_switches, mango_juice.battery_config_vars);
42 | load_switch_from_file (line, mango_juice.other_extra_switches, mango_juice.other_extra_config_vars);
43 | load_switch_from_file (line, mango_juice.inform_switches, mango_juice.inform_config_vars);
44 | load_switch_from_file (line, mango_juice.options_switches, mango_juice.options_config_vars);
45 |
46 | if (line.contains("#custom_command")) {
47 | var custom_command_value = line.split(" #custom_command")[0].strip();
48 | mango_juice.custom_command_entry.text = custom_command_value;
49 | }
50 |
51 | if (line.has_prefix ("toggle_logging=")) {
52 | var logs_key = line.substring ("toggle_logging=".length);
53 | for (uint i = 0; i < mango_juice.logs_key_model.get_n_items (); i++) {
54 | var item = mango_juice.logs_key_model.get_item (i) as StringObject;
55 | if (item != null && item.get_string () == logs_key) {
56 | mango_juice.logs_key_combo.selected = i;
57 | break;
58 | }
59 | }
60 | }
61 |
62 | if (line.has_prefix ("toggle_hud_position=")) {
63 | var toggle_hud_position = line.substring ("toggle_hud_position=".length);
64 | for (uint i = 0; i < mango_juice.toggle_hud_key_model.get_n_items (); i++) {
65 | var item = mango_juice.toggle_hud_key_model.get_item (i) as StringObject;
66 | if (item != null && item.get_string () == toggle_hud_position) {
67 | mango_juice.toggle_hud_key_combo.selected = i;
68 | break;
69 | }
70 | }
71 | }
72 |
73 | if (line.has_prefix ("pci_dev=")) {
74 | if (mango_juice.gpu_dropdown != null) {
75 | string selected_pci_address = line.substring ("pci_dev=".length).strip ();
76 |
77 | selected_pci_address = selected_pci_address.replace ("0000:", "");
78 |
79 | var model = mango_juice.gpu_dropdown.model;
80 |
81 | uint index = 0;
82 | bool found = false;
83 | for (uint i = 0; i < model.get_n_items (); i++) {
84 | var item = model.get_item (i) as Gtk.StringObject;
85 | if (item != null) {
86 | string item_text = item.get_string ();
87 | if (item_text.contains (selected_pci_address)) {
88 | index = i;
89 | found = true;
90 | break;
91 | }
92 | }
93 | }
94 |
95 | if (found) {
96 | mango_juice.gpu_dropdown.selected = index;
97 | }
98 | }
99 | }
100 |
101 | if (line.has_prefix ("log_duration=")) {
102 | if (mango_juice.duracion_scale != null) {
103 | int duracion_value = int.parse (line.substring ("log_duration=".length));
104 | mango_juice.duracion_scale.set_value (duracion_value);
105 | if (mango_juice.duracion_entry != null) {
106 | mango_juice.duracion_entry.text = "%d".printf (duracion_value);
107 | }
108 | }
109 | }
110 |
111 | if (line.has_prefix ("autostart_log=")) {
112 | if (mango_juice.autostart_scale != null) {
113 | int autostart_value = int.parse (line.substring ("autostart_log=".length));
114 | mango_juice.autostart_scale.set_value (autostart_value);
115 | if (mango_juice.autostart_entry != null) {
116 | mango_juice.autostart_entry.text = "%d".printf (autostart_value);
117 | }
118 | }
119 | }
120 |
121 | if (line.has_prefix ("log_interval=")) {
122 | if (mango_juice.interval_scale != null) {
123 | int interval_value = int.parse (line.substring ("log_interval=".length));
124 | mango_juice.interval_scale.set_value (interval_value);
125 | if (mango_juice.interval_entry != null) {
126 | mango_juice.interval_entry.text = "%d".printf (interval_value);
127 | }
128 | }
129 | }
130 |
131 | if (line.has_prefix ("output_folder=")) {
132 | mango_juice.custom_logs_path_entry.text = line.substring ("output_folder=".length);
133 | }
134 |
135 | if (line.has_prefix ("fps_limit_method=")) {
136 | var fps_limit_method_value = line.substring ("fps_limit_method=".length);
137 | for (uint i = 0; i < mango_juice.fps_limit_method.model.get_n_items (); i++) {
138 | var item = mango_juice.fps_limit_method.model.get_item (i) as StringObject;
139 | if (item != null && item.get_string () == fps_limit_method_value) {
140 | mango_juice.fps_limit_method.selected = i;
141 | break;
142 | }
143 | }
144 | }
145 |
146 | if (line.has_prefix ("toggle_fps_limit=")) {
147 | var toggle_fps_limit_value = line.substring ("toggle_fps_limit=".length);
148 | for (uint i = 0; i < mango_juice.toggle_fps_limit.model.get_n_items (); i++) {
149 | var item = mango_juice.toggle_fps_limit.model.get_item (i) as StringObject;
150 | if (item != null && item.get_string () == toggle_fps_limit_value) {
151 | mango_juice.toggle_fps_limit.selected = i;
152 | break;
153 | }
154 | }
155 | }
156 |
157 | if (line.has_prefix ("fps_limit=")) {
158 | var fps_limits = line.substring ("fps_limit=".length).split (",");
159 | if (fps_limits.length == 3) {
160 | mango_juice.fps_limit_entry_1.text = fps_limits[0];
161 | mango_juice.fps_limit_entry_2.text = fps_limits[1];
162 | mango_juice.fps_limit_entry_3.text = fps_limits[2];
163 | }
164 | }
165 |
166 | if (line.has_prefix ("vsync=")) {
167 | var vulkan_config_value = line.substring ("vsync=".length);
168 | var vulkan_value = mango_juice.get_vulkan_value_from_config (vulkan_config_value);
169 | for (uint i = 0; i < mango_juice.vulkan_dropdown.model.get_n_items (); i++) {
170 | var item = mango_juice.vulkan_dropdown.model.get_item (i) as StringObject;
171 | if (item != null && item.get_string () == vulkan_value) {
172 | mango_juice.vulkan_dropdown.selected = i;
173 | break;
174 | }
175 | }
176 | }
177 |
178 | if (line.has_prefix ("gl_vsync=")) {
179 | var opengl_config_value = line.substring ("gl_vsync=".length);
180 | var opengl_value = mango_juice.get_opengl_value_from_config (opengl_config_value);
181 | for (uint i = 0; i < mango_juice.opengl_dropdown.model.get_n_items (); i++) {
182 | var item = mango_juice.opengl_dropdown.model.get_item (i) as StringObject;
183 | if (item != null && item.get_string () == opengl_value) {
184 | mango_juice.opengl_dropdown.selected = i;
185 | break;
186 | }
187 | }
188 | }
189 |
190 | if (line.contains ("#filters")) {
191 | var filter_value = line.split ("#filters")[0].strip ();
192 | for (uint i = 0; i < mango_juice.filter_dropdown.model.get_n_items (); i++) {
193 | var item = mango_juice.filter_dropdown.model.get_item (i) as StringObject;
194 | if (item != null && item.get_string () == filter_value) {
195 | mango_juice.filter_dropdown.selected = i;
196 | break;
197 | }
198 | }
199 | }
200 |
201 | if (line.has_prefix ("af=")) {
202 | if (mango_juice.af != null) {
203 | int af_value = int.parse (line.substring ("af=".length));
204 | mango_juice.af.set_value (af_value);
205 | if (mango_juice.af_entry != null) {
206 | mango_juice.af_entry.text = "%d".printf (af_value);
207 | }
208 | }
209 | }
210 |
211 | if (line.has_prefix ("picmip=")) {
212 | if (mango_juice.picmip != null) {
213 | int picmip_value = int.parse (line.substring ("picmip=".length));
214 | mango_juice.picmip.set_value (picmip_value);
215 | if (mango_juice.picmip_entry != null) {
216 | mango_juice.picmip_entry.text = "%d".printf (picmip_value);
217 | }
218 | }
219 | }
220 |
221 | if (line.has_prefix ("custom_text_center=")) {
222 | mango_juice.custom_text_center_entry.text = line.substring ("custom_text_center=".length);
223 | }
224 |
225 | if (line.has_prefix ("horizontal")) {
226 | mango_juice.custom_switch.active = true;
227 | }
228 |
229 | if (line.has_prefix ("round_corners=")) {
230 | if (mango_juice.borders_scale != null) {
231 | int borders_value = int.parse (line.substring ("round_corners=".length));
232 | mango_juice.borders_scale.set_value (borders_value);
233 | if (mango_juice.borders_entry != null) {
234 | mango_juice.borders_entry.text = "%d".printf (borders_value);
235 | }
236 | }
237 | }
238 |
239 | if (line.has_prefix ("background_alpha=")) {
240 | if (mango_juice.alpha_scale != null) {
241 | double alpha_value = double.parse (line.substring ("background_alpha=".length));
242 | mango_juice.alpha_scale.set_value (alpha_value * 100);
243 | if (mango_juice.alpha_value_label != null) {
244 | mango_juice.alpha_value_label.label = "%.1f".printf (alpha_value);
245 | }
246 | }
247 | }
248 |
249 | if (line.has_prefix ("position=")) {
250 | var position_value = line.substring ("position=".length);
251 | for (uint i = 0; i < mango_juice.position_dropdown.model.get_n_items (); i++) {
252 | var item = mango_juice.position_dropdown.model.get_item (i) as StringObject;
253 | if (item != null && item.get_string () == position_value) {
254 | mango_juice.position_dropdown.selected = i;
255 | break;
256 | }
257 | }
258 | }
259 |
260 | if (line.has_prefix ("table_columns=")) {
261 | if (mango_juice.colums_scale != null) {
262 | int colums_value = int.parse (line.substring ("table_columns=".length));
263 | mango_juice.colums_scale.set_value (colums_value);
264 | if (mango_juice.colums_entry != null) {
265 | mango_juice.colums_entry.text = "%d".printf (colums_value);
266 | }
267 | }
268 | }
269 |
270 | if (line.has_prefix ("toggle_hud=")) {
271 | var toggle_hud_value = line.substring ("toggle_hud=".length);
272 | mango_juice.toggle_hud_entry.text = toggle_hud_value;
273 | }
274 |
275 | if (line.has_prefix ("font_size=")) {
276 | if (mango_juice.font_size_scale != null) {
277 | int font_size_value = int.parse (line.substring ("font_size=".length));
278 | mango_juice.font_size_scale.set_value (font_size_value);
279 | if (mango_juice.font_size_entry != null) {
280 | mango_juice.font_size_entry.text = "%d".printf (font_size_value);
281 | }
282 | }
283 | }
284 |
285 | if (line.has_prefix ("font_file=")) {
286 | var font_file = line.substring ("font_file=".length);
287 | if (font_file.strip() == "") {
288 | mango_juice.font_button.label = _("Default");
289 | } else {
290 | var font_name = Path.get_basename (font_file);
291 | mango_juice.font_button.label = font_name;
292 | }
293 | }
294 |
295 | if (line.has_prefix ("gpu_text=")) {
296 | mango_juice.gpu_text_entry.text = line.substring ("gpu_text=".length);
297 | }
298 |
299 | if (line.has_prefix ("gpu_color=")) {
300 | var gpu_color = line.substring ("gpu_color=".length);
301 | var rgba = Gdk.RGBA ();
302 | rgba.parse ("#" + gpu_color);
303 | mango_juice.gpu_color_button.set_rgba (rgba);
304 | }
305 |
306 | if (line.has_prefix ("cpu_text=")) {
307 | mango_juice.cpu_text_entry.text = line.substring ("cpu_text=".length);
308 | }
309 |
310 | if (line.has_prefix ("cpu_color=")) {
311 | var cpu_color = line.substring ("cpu_color=".length);
312 | var rgba = Gdk.RGBA ();
313 | rgba.parse ("#" + cpu_color);
314 | mango_juice.cpu_color_button.set_rgba (rgba);
315 | }
316 |
317 | if (line.has_prefix ("fps_value=")) {
318 | var fps_values = line.substring ("fps_value=".length).split (",");
319 | if (fps_values.length == 2) {
320 | mango_juice.fps_value_entry_1.text = fps_values[0];
321 | mango_juice.fps_value_entry_2.text = fps_values[1];
322 | }
323 | }
324 |
325 | if (line.has_prefix ("fps_color=")) {
326 | var fps_colors = line.substring ("fps_color=".length).split (",");
327 | if (fps_colors.length == 3) {
328 | var rgba_1 = Gdk.RGBA ();
329 | rgba_1.parse ("#" + fps_colors[0]);
330 | mango_juice.fps_color_button_1.set_rgba (rgba_1);
331 |
332 | var rgba_2 = Gdk.RGBA ();
333 | rgba_2.parse ("#" + fps_colors[1]);
334 | mango_juice.fps_color_button_2.set_rgba (rgba_2);
335 |
336 | var rgba_3 = Gdk.RGBA ();
337 | rgba_3.parse ("#" + fps_colors[2]);
338 | mango_juice.fps_color_button_3.set_rgba (rgba_3);
339 | }
340 | }
341 |
342 | if (line.has_prefix ("gpu_load_value=")) {
343 | var gpu_load_values = line.substring ("gpu_load_value=".length).split (",");
344 | if (gpu_load_values.length == 2) {
345 | mango_juice.gpu_load_value_entry_1.text = gpu_load_values[0];
346 | mango_juice.gpu_load_value_entry_2.text = gpu_load_values[1];
347 | }
348 | }
349 |
350 | if (line.has_prefix ("gpu_load_color=")) {
351 | var gpu_load_colors = line.substring ("gpu_load_color=".length).split (",");
352 | if (gpu_load_colors.length == 3) {
353 | var rgba_1 = Gdk.RGBA ();
354 | rgba_1.parse ("#" + gpu_load_colors[0]);
355 | mango_juice.gpu_load_color_button_1.set_rgba (rgba_1);
356 |
357 | var rgba_2 = Gdk.RGBA ();
358 | rgba_2.parse ("#" + gpu_load_colors[1]);
359 | mango_juice.gpu_load_color_button_2.set_rgba (rgba_2);
360 |
361 | var rgba_3 = Gdk.RGBA ();
362 | rgba_3.parse ("#" + gpu_load_colors[2]);
363 | mango_juice.gpu_load_color_button_3.set_rgba (rgba_3);
364 | }
365 | }
366 |
367 | if (line.has_prefix ("cpu_load_value=")) {
368 | var cpu_load_values = line.substring ("cpu_load_value=".length).split (",");
369 | if (cpu_load_values.length == 2) {
370 | mango_juice.cpu_load_value_entry_1.text = cpu_load_values[0];
371 | mango_juice.cpu_load_value_entry_2.text = cpu_load_values[1];
372 | }
373 | }
374 |
375 | if (line.has_prefix ("cpu_load_color=")) {
376 | var cpu_load_colors = line.substring ("cpu_load_color=".length).split (",");
377 | if (cpu_load_colors.length == 3) {
378 | var rgba_1 = Gdk.RGBA ();
379 | rgba_1.parse ("#" + cpu_load_colors[0]);
380 | mango_juice.cpu_load_color_button_1.set_rgba (rgba_1);
381 |
382 | var rgba_2 = Gdk.RGBA ();
383 | rgba_2.parse ("#" + cpu_load_colors[1]);
384 | mango_juice.cpu_load_color_button_2.set_rgba (rgba_2);
385 |
386 | var rgba_3 = Gdk.RGBA ();
387 | rgba_3.parse ("#" + cpu_load_colors[2]);
388 | mango_juice.cpu_load_color_button_3.set_rgba (rgba_3);
389 | }
390 | }
391 |
392 | if (line.has_prefix ("background_color=")) {
393 | var background_color = line.substring ("background_color=".length);
394 | var rgba = Gdk.RGBA ();
395 | rgba.parse ("#" + background_color);
396 | mango_juice.background_color_button.set_rgba (rgba);
397 | }
398 |
399 | if (line.has_prefix ("frametime_color=")) {
400 | var frametime_color = line.substring ("frametime_color=".length);
401 | var rgba = Gdk.RGBA ();
402 | rgba.parse ("#" + frametime_color);
403 | mango_juice.frametime_color_button.set_rgba (rgba);
404 | }
405 |
406 | if (line.has_prefix ("vram_color=")) {
407 | var vram_color = line.substring ("vram_color=".length);
408 | var rgba = Gdk.RGBA ();
409 | rgba.parse ("#" + vram_color);
410 | mango_juice.vram_color_button.set_rgba (rgba);
411 | }
412 |
413 | if (line.has_prefix ("ram_color=")) {
414 | var ram_color = line.substring ("ram_color=".length);
415 | var rgba = Gdk.RGBA ();
416 | rgba.parse ("#" + ram_color);
417 | mango_juice.ram_color_button.set_rgba (rgba);
418 | }
419 |
420 | if (line.has_prefix ("wine_color=")) {
421 | var wine_color = line.substring ("wine_color=".length);
422 | var rgba = Gdk.RGBA ();
423 | rgba.parse ("#" + wine_color);
424 | mango_juice.wine_color_button.set_rgba (rgba);
425 | }
426 |
427 | if (line.has_prefix ("engine_color=")) {
428 | var engine_color = line.substring ("engine_color=".length);
429 | var rgba = Gdk.RGBA ();
430 | rgba.parse ("#" + engine_color);
431 | mango_juice.engine_color_button.set_rgba (rgba);
432 | }
433 |
434 | if (line.has_prefix ("text_color=")) {
435 | var text_color = line.substring ("text_color=".length);
436 | var rgba = Gdk.RGBA ();
437 | rgba.parse ("#" + text_color);
438 | mango_juice.text_color_button.set_rgba (rgba);
439 | }
440 |
441 | if (line.has_prefix ("media_player_color=")) {
442 | var media_player_color = line.substring ("media_player_color=".length);
443 | var rgba = Gdk.RGBA ();
444 | rgba.parse ("#" + media_player_color);
445 | mango_juice.media_player_color_button.set_rgba (rgba);
446 | }
447 |
448 | if (line.has_prefix ("network_color=")) {
449 | var network_color = line.substring ("network_color=".length);
450 | var rgba = Gdk.RGBA ();
451 | rgba.parse ("#" + network_color);
452 | mango_juice.network_color_button.set_rgba (rgba);
453 | }
454 |
455 | if (line.has_prefix ("battery_color=")) {
456 | var battery_color = line.substring ("battery_color=".length);
457 | var rgba = Gdk.RGBA ();
458 | rgba.parse ("#" + battery_color);
459 | mango_juice.battery_color_button.set_rgba (rgba);
460 | }
461 |
462 | if (line.has_prefix ("offset_x=")) {
463 | if (mango_juice.offset_x_scale != null) {
464 | mango_juice.offset_x_scale.set_value (int.parse (line.substring ("offset_x=".length)));
465 | if (mango_juice.offset_x_value_label != null) {
466 | mango_juice.offset_x_value_label.label = "%d".printf ((int)mango_juice.offset_x_scale.get_value ());
467 | }
468 | }
469 | }
470 |
471 | if (line.has_prefix ("offset_y=")) {
472 | if (mango_juice.offset_y_scale != null) {
473 | mango_juice.offset_y_scale.set_value (int.parse (line.substring ("offset_y=".length)));
474 | if (mango_juice.offset_y_value_label != null) {
475 | mango_juice.offset_y_value_label.label = "%d".printf ((int)mango_juice.offset_y_scale.get_value ());
476 | }
477 | }
478 | }
479 |
480 | if (line.has_prefix ("fps_sampling_period=")) {
481 | if (mango_juice.fps_sampling_period_scale != null) {
482 | mango_juice.fps_sampling_period_scale.set_value (int.parse (line.substring ("fps_sampling_period=".length)));
483 | if (mango_juice.fps_sampling_period_value_label != null) {
484 | mango_juice.fps_sampling_period_value_label.label = "%d ms".printf ((int)mango_juice.fps_sampling_period_scale.get_value ());
485 | }
486 | }
487 | }
488 |
489 | if (line.has_prefix ("blacklist=")) {
490 | mango_juice.blacklist_entry.text = line.substring ("blacklist=".length);
491 | }
492 |
493 | if (line.has_prefix ("gpu_list=")) {
494 | mango_juice.gpu_entry.text = line.substring ("gpu_list=".length);
495 | }
496 |
497 | if (line.has_prefix("media_player_format=")) {
498 | var format_str = line.substring("media_player_format=".length).strip();
499 |
500 | if (format_str.has_prefix("{") && format_str.has_suffix("}")) {
501 | format_str = format_str.substring(1, format_str.length-2);
502 | }
503 |
504 | string[] format_parts = format_str.split("};{");
505 |
506 | for (int i = 0; i < 3; i++) {
507 | string part = "none";
508 | if (i < format_parts.length) {
509 | part = format_parts[i].strip();
510 | }
511 |
512 | if (i < mango_juice.media_format_dropdowns.size) {
513 | var dropdown = mango_juice.media_format_dropdowns.get(i);
514 | var model = dropdown.model as Gtk.StringList;
515 |
516 | bool found = false;
517 | for (uint j = 0; j < model.get_n_items(); j++) {
518 | var item = model.get_item(j) as StringObject;
519 | if (item != null && item.get_string() == part) {
520 | dropdown.selected = j;
521 | found = true;
522 | break;
523 | }
524 | }
525 |
526 | if (!found && part == "none") {
527 | for (uint j = 0; j < model.get_n_items(); j++) {
528 | var item = model.get_item(j) as StringObject;
529 | if (item != null && item.get_string() == "none") {
530 | dropdown.selected = j;
531 | break;
532 | }
533 | }
534 | }
535 | }
536 | }
537 | }
538 | }
539 | } catch (Error e) {
540 | stderr.printf ("Error reading the file: %s\n", e.message);
541 | }
542 | mango_juice.is_loading = false;
543 | }
544 | public static void load_switch_from_file (string line, Switch[] switches, string[] config_vars) {
545 | for (int i = 0; i < config_vars.length; i++) {
546 | string config_var = config_vars[i];
547 | if (config_var == "io_read \n io_write") {
548 | if (line == "io_read" || line == "io_write") {
549 | switches[i].active = true;
550 | }
551 | } else if (line == config_var) {
552 | switches[i].active = true;
553 | }
554 | }
555 | }
556 | }
557 |
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | deps = [
2 | dependency('libadwaita-1'),
3 | dependency('gee-0.8')
4 | ]
5 |
6 | vapi_sources = files('config.vapi')
7 |
8 | sources = files(
9 | 'dialog.vala',
10 | 'mangojuice.vala',
11 | 'save_states.vala',
12 | 'other/OtherBox.vala',
13 | 'other/other_save.vala',
14 | 'other/other_load.vala',
15 | 'load_states.vala',
16 | 'reset_manager.vala',
17 | 'intel_power_fix_handler.vala',
18 | 'advanced.vala'
19 | )
20 |
21 | configure_file(output: 'config.h', configuration: conf)
22 | #config_h_dir = include_directories('.')
23 |
24 | executable(
25 | 'mangojuice',
26 |
27 | resources,
28 | vapi_sources,
29 | sources,
30 | vala_args: ['--vapidir', meson.current_source_dir()],
31 | dependencies: deps,
32 | install: true
33 | )
--------------------------------------------------------------------------------
/src/other/OtherBox.vala:
--------------------------------------------------------------------------------
1 | /* OtherBox.vala // Licence: GPL-v3.0 */
2 | using Gtk;
3 | using Gee;
4 |
5 | public class OtherBox : Box {
6 |
7 | const int MAX_WIDTH_CHARS = 6;
8 | const int WIDTH_CHARS = 4;
9 | const int FLOW_BOX_MARGIN = 12;
10 | const int FLOW_BOX_ROW_SPACING = 6;
11 | const int FLOW_BOX_COLUMN_SPACING = 6;
12 | const int MAIN_BOX_SPACING = 6;
13 |
14 | public ArrayList scales { get; set; }
15 | public ArrayList entries { get; set; }
16 | public ArrayList scale_labels { get; set; }
17 | public ArrayList switches { get; set; }
18 | public ArrayList labels { get; set; }
19 | public Button vkbasalt_global_button { get; set; }
20 | public bool vkbasalt_global_enabled { get; set; }
21 |
22 | HashMap> switch_scale_map;
23 | HashMap> switch_entry_map;
24 | HashMap> switch_reset_map;
25 |
26 | public OtherBox () {
27 | Object (orientation: Orientation.VERTICAL, spacing: 12);
28 |
29 | scales = new ArrayList ();
30 | entries = new ArrayList ();
31 | scale_labels = new ArrayList ();
32 | switches = new ArrayList ();
33 | labels = new ArrayList ();
34 |
35 | switch_scale_map = new HashMap> ();
36 | switch_entry_map = new HashMap> ();
37 | switch_reset_map = new HashMap> ();
38 |
39 | string[] config_vars = { "cas", "dls", "fxaa", "smaa", "lut" };
40 | string[] label_texts = { "CAS", "DLS", "FXAA", "SMAA", "LUT" };
41 | string[] label_texts_2 = {
42 | _("Contrast Adaptive Sharpening"),
43 | _("Denoised Luma Sharpening"),
44 | _("Fast Approximate Anti-Aliasing"),
45 | _("Subpixel Morphological Antialiasing"),
46 | _("Color LookUp Table")
47 | };
48 |
49 | create_switches_and_labels (this, "VkBasalt", switches, labels, config_vars, label_texts, label_texts_2);
50 |
51 | foreach (var switch_widget in switches) {
52 | switch_widget.state_set.connect ((state) => {
53 | OtherSave.save_states (this);
54 | update_scale_entry_reset_state (switch_widget);
55 | return false;
56 | });
57 | }
58 |
59 | var flow_box = new FlowBox ();
60 | flow_box.set_homogeneous (true);
61 | flow_box.set_row_spacing (FLOW_BOX_ROW_SPACING);
62 | flow_box.set_column_spacing (FLOW_BOX_COLUMN_SPACING);
63 | flow_box.set_margin_top (FLOW_BOX_MARGIN);
64 | flow_box.set_margin_bottom (FLOW_BOX_MARGIN);
65 | flow_box.set_margin_start (FLOW_BOX_MARGIN);
66 | flow_box.set_margin_end (FLOW_BOX_MARGIN);
67 | flow_box.set_selection_mode (SelectionMode.NONE);
68 | flow_box.set_max_children_per_line (2);
69 | this.append (flow_box);
70 |
71 | create_scale_with_entry (flow_box, "CAS Sharpness", -1.0, 1.0, 0.01, 0.0, "%.2f", "cas");
72 | create_scale_with_entry (flow_box, "DLS Sharpness", 0.0, 1.0, 0.01, 0.5, "%.2f", "dls");
73 | create_scale_with_entry (flow_box, "FXAA Quality Subpix", 0.0, 1.0, 0.01, 0.75, "%.2f", "fxaa");
74 | create_scale_with_entry (flow_box, "DLS Denoise", 0.0, 1.0, 0.01, 0.17, "%.2f", "dls");
75 | create_scale_with_entry (flow_box, "FXAA Edge Threshold", 0.0, 0.333, 0.01, 0.125, "%.3f", "fxaa");
76 | create_scale_with_entry (flow_box, "FXAA Threshold Min", 0.0, 0.0833, 0.001, 0.0833, "%.4f", "fxaa");
77 | create_scale_with_entry (flow_box, "SMAA Threshold", 0.0, 0.5, 0.01, 0.05, "%.2f", "smaa");
78 | create_scale_with_entry (flow_box, "SMAA Max Search Steps", 0, 112, 1, 8, "%d", "smaa");
79 | create_scale_with_entry (flow_box, "SMAA Max Steps Diag", 0, 20, 1, 0, "%d", "smaa");
80 | create_scale_with_entry (flow_box, "SMAA Corner Rounding", 0, 100, 1, 25, "%d", "smaa");
81 |
82 | vkbasalt_global_button = new Button.with_label ("Global VkBasalt");
83 | vkbasalt_global_button.set_margin_top (FLOW_BOX_MARGIN);
84 | vkbasalt_global_button.set_margin_end (FLOW_BOX_MARGIN);
85 | vkbasalt_global_button.set_margin_start (FLOW_BOX_MARGIN);
86 | vkbasalt_global_button.set_margin_bottom (FLOW_BOX_MARGIN);
87 | vkbasalt_global_button.clicked.connect (on_vkbasalt_global_button_clicked);
88 | this.append (vkbasalt_global_button);
89 |
90 | check_vkbasalt_global_status ();
91 | OtherLoad.load_states (this);
92 |
93 | foreach (var switch_widget in switches) {
94 | update_scale_entry_reset_state (switch_widget);
95 | }
96 | }
97 |
98 | public bool is_switch_active (string switch_name) {
99 | foreach (var switch_widget in switches) {
100 | if (switch_widget.get_name () == switch_name) {
101 | return switch_widget.get_active ();
102 | }
103 | }
104 | return false;
105 | }
106 |
107 | public bool is_scale_active (Scale scale, string switch_name) {
108 | return is_switch_active (switch_name);
109 | }
110 |
111 | void create_scale_with_entry (FlowBox flow_box, string label_text, double min, double max, double step, double initial_value, string format, string switch_name) {
112 | var main_box = new Box (Orientation.VERTICAL, 6);
113 |
114 | var label = new Label (label_text);
115 | label.set_halign (Align.START);
116 | label.set_hexpand (true);
117 | label.add_css_class ("title-4");
118 | label.set_margin_start (16);
119 | label.set_valign (Align.START);
120 |
121 | var scale_entry_button_box = new Box (Orientation.HORIZONTAL, 12);
122 | scale_entry_button_box.set_hexpand (true);
123 |
124 | var adjustment = new Adjustment (initial_value, min, max, step, step, 0.0);
125 | var scale = new Scale (Orientation.HORIZONTAL, adjustment);
126 | scale.set_hexpand (true);
127 | scale.set_valign (Align.CENTER);
128 |
129 | var entry = new Entry ();
130 | entry.set_max_width_chars (MAX_WIDTH_CHARS);
131 | entry.set_width_chars (WIDTH_CHARS);
132 | entry.set_halign (Align.END);
133 | entry.set_hexpand (false);
134 | entry.set_valign (Align.CENTER);
135 | entry.set_text (format.printf (initial_value).replace (",", "."));
136 |
137 | var reset_button = new Button.from_icon_name ("view-refresh-symbolic");
138 | reset_button.set_halign (Align.END);
139 | reset_button.set_valign (Align.CENTER);
140 | reset_button.set_tooltip_text ("Сбросить значение по умолчанию");
141 | reset_button.set_margin_end (16);
142 |
143 | scale.value_changed.connect (() => {
144 | update_entry_from_scale (scale, entry, format);
145 | OtherSave.save_states (this);
146 | });
147 |
148 | entry.activate.connect (() => {
149 | update_scale_from_entry (scale, entry, min, max, format);
150 | });
151 |
152 | reset_button.clicked.connect (() => {
153 | scale.set_value (initial_value);
154 | update_entry_from_scale (scale, entry, format);
155 | OtherSave.save_states (this);
156 | });
157 |
158 | scale_entry_button_box.append (scale);
159 | scale_entry_button_box.append (entry);
160 | scale_entry_button_box.append (reset_button);
161 |
162 | main_box.append (label);
163 | main_box.append (scale_entry_button_box);
164 |
165 | scales.add (scale);
166 | entries.add (entry);
167 | scale_labels.add (label);
168 |
169 | if (!switch_scale_map.has_key (switch_name)) {
170 | switch_scale_map[switch_name] = new ArrayList ();
171 | switch_entry_map[switch_name] = new ArrayList ();
172 | switch_reset_map[switch_name] = new ArrayList ();
173 | }
174 | switch_scale_map[switch_name].add (scale);
175 | switch_entry_map[switch_name].add (entry);
176 | switch_reset_map[switch_name].add (reset_button);
177 |
178 | flow_box.insert (main_box, -1);
179 | }
180 |
181 | void update_scale_entry_reset_state (Switch switch_widget) {
182 | string switch_name = switch_widget.get_name ();
183 | if (switch_scale_map.has_key (switch_name)) {
184 | var scales = switch_scale_map[switch_name];
185 | var entries = switch_entry_map[switch_name];
186 | var reset_buttons = switch_reset_map[switch_name];
187 |
188 | bool is_active = switch_widget.get_active ();
189 | foreach (var scale in scales) {
190 | scale.set_sensitive (is_active);
191 | }
192 | foreach (var entry in entries) {
193 | entry.set_sensitive (is_active);
194 | }
195 | foreach (var reset_button in reset_buttons) {
196 | reset_button.set_sensitive (is_active);
197 | }
198 | }
199 | }
200 |
201 | void update_entry_from_scale (Scale scale, Entry entry, string format) {
202 | double value = scale.get_value ();
203 | if (format == "%d") {
204 | entry.set_text ("%d".printf ((int) value));
205 | } else {
206 | entry.set_text (format.printf (value).replace (",", "."));
207 | }
208 | }
209 |
210 | void update_scale_from_entry (Scale scale, Entry entry, double min, double max, string format) {
211 | string text = entry.get_text ();
212 | double value = 0;
213 |
214 | if (double.try_parse (text, out value)) {
215 | if (value >= min && value <= max) {
216 | scale.set_value (value);
217 | } else {
218 | entry.set_text (format == "%d" ? "%d".printf ((int) scale.get_value ()) : format.printf (scale.get_value ()).replace (",", "."));
219 | }
220 | } else {
221 | entry.set_text (format == "%d" ? "%d".printf ((int) scale.get_value ()) : format.printf (scale.get_value ()).replace (",", "."));
222 | }
223 | }
224 |
225 | void create_switches_and_labels (Box parent_box, string title, ArrayList switches, ArrayList labels, string[] config_vars, string[] label_texts, string[] label_texts_2) {
226 | var label = new Label (title);
227 | label.add_css_class("title-3");
228 | label.set_margin_top (FLOW_BOX_MARGIN);
229 | label.set_margin_start (FLOW_BOX_MARGIN);
230 | label.set_margin_end (FLOW_BOX_MARGIN);
231 | label.set_halign (Align.START);
232 | label.set_markup ("%s".printf (title));
233 | parent_box.append (label);
234 |
235 | var flow_box = new FlowBox ();
236 | flow_box.set_homogeneous (true);
237 | flow_box.set_row_spacing (FLOW_BOX_ROW_SPACING);
238 | flow_box.set_column_spacing (FLOW_BOX_COLUMN_SPACING);
239 | flow_box.set_margin_top (FLOW_BOX_MARGIN);
240 | flow_box.set_margin_bottom (FLOW_BOX_MARGIN);
241 | flow_box.set_margin_start (FLOW_BOX_MARGIN);
242 | flow_box.set_margin_end (FLOW_BOX_MARGIN);
243 | flow_box.set_selection_mode (SelectionMode.NONE);
244 |
245 | for (int i = 0; i < config_vars.length; i++) {
246 | var row_box = new Box (Orientation.HORIZONTAL, MAIN_BOX_SPACING);
247 | row_box.set_hexpand (true);
248 | row_box.set_valign (Align.CENTER);
249 |
250 | var switch_widget = new Switch ();
251 | switch_widget.set_valign (Align.CENTER);
252 | switch_widget.set_name (config_vars[i]);
253 | switches.add (switch_widget);
254 |
255 | var text_box = new Box (Orientation.VERTICAL, 0);
256 | text_box.set_valign (Align.CENTER);
257 | text_box.set_halign (Align.START);
258 | text_box.set_size_request (160, -1);
259 |
260 | var label1 = new Label (null);
261 | label1.set_markup ("%s ".printf (label_texts[i]));
262 | label1.set_halign (Align.START);
263 | label1.set_hexpand (false);
264 | label1.set_ellipsize (Pango.EllipsizeMode.END);
265 |
266 | var label2 = new Label (label_texts_2[i]);
267 | label2.set_halign (Align.START);
268 | label2.set_hexpand (false);
269 | label2.add_css_class ("dim-label");
270 | label2.set_ellipsize (Pango.EllipsizeMode.END);
271 |
272 | label1.set_markup ("%s ".printf (label_texts[i]));
273 | label2.set_markup ("%s ".printf (label_texts_2[i]));
274 |
275 | text_box.append (label1);
276 | text_box.append (label2);
277 |
278 | row_box.append (switch_widget);
279 | row_box.append (text_box);
280 | flow_box.insert (row_box, -1);
281 | }
282 |
283 | parent_box.append (flow_box);
284 | }
285 |
286 | void on_vkbasalt_global_button_clicked () {
287 | bool success = false;
288 |
289 | if (vkbasalt_global_enabled) {
290 | try {
291 | Process.spawn_command_line_sync ("pkexec sed -i '/ENABLE_VKBASALT=1/d' /etc/environment");
292 | string file_contents;
293 | FileUtils.get_contents ("/etc/environment", out file_contents);
294 | if (!file_contents.contains ("ENABLE_VKBASALT=1")) {
295 | success = true;
296 | vkbasalt_global_enabled = false;
297 | vkbasalt_global_button.remove_css_class ("suggested-action");
298 | }
299 | } catch (Error e) {
300 | stderr.printf ("Error deleting ENABLE_VKBASALT from /etc/environment: %s\n", e.message);
301 | }
302 | } else {
303 | try {
304 | Process.spawn_command_line_sync ("pkexec sh -c 'echo \"ENABLE_VKBASALT=1\" >> /etc/environment'");
305 | string file_contents;
306 | FileUtils.get_contents ("/etc/environment", out file_contents);
307 | if (file_contents.contains ("ENABLE_VKBASALT=1")) {
308 | success = true;
309 | vkbasalt_global_enabled = true;
310 | vkbasalt_global_button.add_css_class ("suggested-action");
311 | }
312 | } catch (Error e) {
313 | stderr.printf ("Error adding ENABLE_VKBASALT to /etc/environment: %s\n", e.message);
314 | }
315 | }
316 |
317 | if (success) {
318 | check_vkbasalt_global_status ();
319 | show_restart_warning ();
320 | } else {
321 | stderr.printf ("Failed to modify /etc/environment.\n");
322 | }
323 | }
324 |
325 | void check_vkbasalt_global_status () {
326 | try {
327 | string[] argv = { "grep", "ENABLE_VKBASALT=1", "/etc/environment" };
328 | int exit_status;
329 | string standard_output;
330 | string standard_error;
331 | Process.spawn_sync (null, argv, null, SpawnFlags.SEARCH_PATH, null, out standard_output, out standard_error, out exit_status);
332 |
333 | if (exit_status == 0) {
334 | vkbasalt_global_enabled = true;
335 | vkbasalt_global_button.add_css_class ("suggested-action");
336 | } else {
337 | vkbasalt_global_enabled = false;
338 | vkbasalt_global_button.remove_css_class ("suggested-action");
339 | }
340 | } catch (Error e) {
341 | stderr.printf ("Error checking the ENABLE_VKBASALT status: %s\n", e.message);
342 | }
343 | }
344 |
345 | void show_restart_warning () {
346 | var dialog = new Adw.AlertDialog ("Warning", "The changes will take effect only after the system is restarted.");
347 | dialog.add_response ("ok", "OK");
348 | dialog.add_response ("restart", "Restart");
349 | dialog.set_default_response ("ok");
350 | dialog.set_response_appearance ("restart", Adw.ResponseAppearance.SUGGESTED);
351 |
352 | dialog.present (this.get_root () as Gtk.Window);
353 |
354 | dialog.response.connect ((response) => {
355 | if (response == "restart") {
356 | try {
357 | Process.spawn_command_line_sync ("reboot");
358 | } catch (Error e) {
359 | stderr.printf ("Error when restarting the system: %s\n", e.message);
360 | }
361 | }
362 | dialog.destroy ();
363 | });
364 | }
365 | }
366 |
--------------------------------------------------------------------------------
/src/other/other_load.vala:
--------------------------------------------------------------------------------
1 | /* other_load // Licence: GPL-v3.0 */
2 | using Gtk;
3 | using Gee;
4 |
5 | public class OtherLoad {
6 |
7 | private static bool contains_string (string[] array, string target) {
8 | foreach (string item in array) {
9 | if (item == target) {
10 | return true;
11 | }
12 | }
13 | return false;
14 | }
15 |
16 | public static void load_states (OtherBox other_box) {
17 | var config_dir = File.new_for_path (Environment.get_home_dir ())
18 | .get_child (".config")
19 | .get_child ("vkBasalt");
20 | var config_file = config_dir.get_child ("vkBasalt.conf");
21 |
22 | // Если директория или файл конфигурации не существуют, создаем их с настройками по умолчанию
23 | if (!config_dir.query_exists () || !config_file.query_exists ()) {
24 | create_default_config (config_dir, config_file);
25 | }
26 |
27 | try {
28 | var file_stream = new DataInputStream (config_file.read ());
29 | string line;
30 | bool[] found = new bool[10]; // Массив для отслеживания найденных параметров
31 | bool effectsFound = false;
32 |
33 | string[] config_vars = { "cas", "dls", "fxaa", "smaa", "lut" };
34 |
35 | while ((line = file_stream.read_line ()) != null) {
36 | if (line.has_prefix ("casSharpness=")) {
37 | load_scale_value (line, other_box.scales[0], other_box.entries[0], "%.2f");
38 | found[0] = true;
39 | } else if (line.has_prefix ("dlsSharpness=")) {
40 | load_scale_value (line, other_box.scales[1], other_box.entries[1], "%.2f");
41 | found[1] = true;
42 | } else if (line.has_prefix ("dlsDenoise=")) {
43 | load_scale_value (line, other_box.scales[2], other_box.entries[2], "%.2f");
44 | found[2] = true;
45 | } else if (line.has_prefix ("fxaaQualitySubpix=")) {
46 | load_scale_value (line, other_box.scales[3], other_box.entries[3], "%.2f");
47 | found[3] = true;
48 | } else if (line.has_prefix ("fxaaEdgeThreshold=")) {
49 | load_scale_value (line, other_box.scales[4], other_box.entries[4], "%.3f");
50 | found[4] = true;
51 | } else if (line.has_prefix ("fxaaEdgeThresholdMin=")) {
52 | load_scale_value (line, other_box.scales[5], other_box.entries[5], "%.4f");
53 | found[5] = true;
54 | } else if (line.has_prefix ("smaaThreshold=")) {
55 | load_scale_value (line, other_box.scales[6], other_box.entries[6], "%.2f");
56 | found[6] = true;
57 | } else if (line.has_prefix ("smaaMaxSearchSteps=")) {
58 | load_int_scale_value (line, other_box.scales[7], other_box.entries[7]);
59 | found[7] = true;
60 | } else if (line.has_prefix ("smaaMaxSearchStepsDiag=")) {
61 | load_int_scale_value (line, other_box.scales[8], other_box.entries[8]);
62 | found[8] = true;
63 | } else if (line.has_prefix ("smaaCornerRounding=")) {
64 | load_int_scale_value (line, other_box.scales[9], other_box.entries[9]);
65 | found[9] = true;
66 | } else if (line.has_prefix ("effects = ")) {
67 | string[] effects = line.split (" = ")[1].split (":");
68 | for (int i = 0; i < other_box.switches.size; i++) {
69 | if (contains_string (effects, config_vars[i])) {
70 | if (i < other_box.switches.size) {
71 | other_box.switches[i].set_active (true);
72 | }
73 | }
74 | }
75 | effectsFound = true;
76 | }
77 | }
78 |
79 | // Устанавливаем значения по умолчанию, если параметры не найдены
80 | if (!found[0]) set_default_scale_value (other_box.scales[0], other_box.entries[0], 0, "%.2f");
81 | if (!found[1]) set_default_scale_value (other_box.scales[1], other_box.entries[1], 0, "%.2f");
82 | if (!found[2]) set_default_scale_value (other_box.scales[2], other_box.entries[2], 0, "%.2f");
83 | if (!found[3]) set_default_scale_value (other_box.scales[3], other_box.entries[3], 0.75, "%.2f");
84 | if (!found[4]) set_default_scale_value (other_box.scales[4], other_box.entries[4], 0.125, "%.3f");
85 | if (!found[5]) set_default_scale_value (other_box.scales[5], other_box.entries[5], 0.0833, "%.4f");
86 | if (!found[6]) set_default_scale_value (other_box.scales[6], other_box.entries[6], 0.05, "%.2f");
87 | if (!found[7]) set_default_int_scale_value (other_box.scales[7], other_box.entries[7], 8);
88 | if (!found[8]) set_default_int_scale_value (other_box.scales[8], other_box.entries[8], 0);
89 | if (!found[9]) set_default_int_scale_value (other_box.scales[9], other_box.entries[9], 25);
90 |
91 | // Если эффекты не найдены, отключаем все переключатели
92 | if (!effectsFound) {
93 | for (int i = 0; i < other_box.switches.size; i++) {
94 | other_box.switches[i].set_active (false);
95 | }
96 | }
97 | } catch (Error e) {
98 | stderr.printf ("Ошибка при чтении файла: %s\n", e.message);
99 | }
100 | }
101 |
102 | // Метод для создания конфигурационного файла с настройками по умолчанию
103 | private static void create_default_config (File config_dir, File config_file) {
104 | try {
105 | // Создаем директорию, если она не существует
106 | if (!config_dir.query_exists ()) {
107 | config_dir.make_directory_with_parents ();
108 | }
109 |
110 | // Создаем файл и записываем настройки по умолчанию
111 | var file_stream = new DataOutputStream (config_file.create (FileCreateFlags.REPLACE_DESTINATION));
112 |
113 | // Записываем значения по умолчанию
114 | file_stream.put_string ("# Config Generated by MangoJuice #\n");
115 | file_stream.put_string ("casSharpness=0.00\n");
116 | file_stream.put_string ("dlsSharpness=0.50\n");
117 | file_stream.put_string ("dlsDenoise=0.17\n");
118 | file_stream.put_string ("fxaaQualitySubpix=0.75\n");
119 | file_stream.put_string ("fxaaEdgeThreshold=0.125\n");
120 | file_stream.put_string ("fxaaEdgeThresholdMin=0.0000\n");
121 | file_stream.put_string ("smaaThreshold=0.05\n");
122 | file_stream.put_string ("smaaMaxSearchSteps=8\n");
123 | file_stream.put_string ("smaaMaxSearchStepsDiag=0\n");
124 | file_stream.put_string ("smaaCornerRounding=25\n");
125 |
126 | file_stream.close ();
127 | } catch (Error e) {
128 | stderr.printf ("Ошибка при создании конфигурационного файла: %s\n", e.message);
129 | }
130 | }
131 |
132 | // Вспомогательный метод для загрузки дробных значений
133 | private static void load_scale_value (string line, Scale scale, Entry entry, string format) {
134 | string value_str = line.split ("=")[1].replace (",", ".");
135 | double value = double.parse (value_str);
136 | if (scale != null) {
137 | scale.set_value (value);
138 | if (entry != null) {
139 | entry.set_text (format.printf (value).replace (",", "."));
140 | }
141 | }
142 | }
143 |
144 | // Вспомогательный метод для загрузки целочисленных значений
145 | private static void load_int_scale_value (string line, Scale scale, Entry entry) {
146 | string value_str = line.split ("=")[1].replace (",", ".");
147 | // Убираем дробную часть, если она есть
148 | if (value_str.contains (".")) {
149 | value_str = value_str.split (".")[0];
150 | }
151 | int value = int.parse (value_str);
152 | if (scale != null) {
153 | scale.set_value (value);
154 | if (entry != null) {
155 | entry.set_text ("%d".printf (value));
156 | }
157 | }
158 | }
159 |
160 | // Вспомогательный метод для установки значений по умолчанию для дробных значений
161 | private static void set_default_scale_value (Scale scale, Entry entry, double default_value, string format) {
162 | if (scale != null) {
163 | scale.set_value (default_value);
164 | if (entry != null) {
165 | entry.set_text (format.printf (default_value).replace (",", "."));
166 | }
167 | }
168 | }
169 |
170 | // Вспомогательный метод для установки значений по умолчанию для целочисленных значений
171 | private static void set_default_int_scale_value (Scale scale, Entry entry, int default_value) {
172 | if (scale != null) {
173 | scale.set_value (default_value);
174 | if (entry != null) {
175 | entry.set_text ("%d".printf (default_value));
176 | }
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/other/other_save.vala:
--------------------------------------------------------------------------------
1 | /* other_save // Licence: GPL-v3.0 */
2 | using Gtk;
3 | using Gee;
4 |
5 | public class OtherSave {
6 |
7 | public static void save_states (OtherBox other_box) {
8 | var config_dir = File.new_for_path (Environment.get_home_dir ())
9 | .get_child (".config")
10 | .get_child ("vkBasalt");
11 | var config_file = config_dir.get_child ("vkBasalt.conf");
12 |
13 | if (!config_dir.query_exists ()) {
14 | try {
15 | config_dir.make_directory_with_parents ();
16 | } catch (Error e) {
17 | stderr.printf ("Ошибка при создании директории: %s\n", e.message);
18 | return;
19 | }
20 | }
21 |
22 | DataOutputStream file_stream_write = null;
23 | try {
24 | file_stream_write = new DataOutputStream (config_file.replace (null, false, FileCreateFlags.NONE));
25 |
26 | // Сохраняем значения Scale и Entry, если они активны
27 | save_scale_value_if_active (file_stream_write, "casSharpness", other_box.scales[0], other_box.entries[0], "%.2f", other_box, "cas");
28 | save_scale_value_if_active (file_stream_write, "dlsSharpness", other_box.scales[1], other_box.entries[1], "%.2f", other_box, "dls");
29 | save_scale_value_if_active (file_stream_write, "dlsDenoise", other_box.scales[2], other_box.entries[2], "%.2f", other_box, "dls");
30 | save_scale_value_if_active (file_stream_write, "fxaaQualitySubpix", other_box.scales[3], other_box.entries[3], "%.2f", other_box, "fxaa");
31 | save_scale_value_if_active (file_stream_write, "fxaaEdgeThreshold", other_box.scales[4], other_box.entries[4], "%.3f", other_box, "fxaa");
32 | save_scale_value_if_active (file_stream_write, "fxaaEdgeThresholdMin", other_box.scales[5], other_box.entries[5], "%.4f", other_box, "fxaa");
33 | save_scale_value_if_active (file_stream_write, "smaaThreshold", other_box.scales[6], other_box.entries[6], "%.2f", other_box, "smaa");
34 |
35 | // Сохраняем целочисленные значения, если они активны
36 | save_int_scale_value_if_active (file_stream_write, "smaaMaxSearchSteps", other_box.scales[7], other_box.entries[7], other_box, "smaa");
37 | save_int_scale_value_if_active (file_stream_write, "smaaMaxSearchStepsDiag", other_box.scales[8], other_box.entries[8], other_box, "smaa");
38 | save_int_scale_value_if_active (file_stream_write, "smaaCornerRounding", other_box.scales[9], other_box.entries[9], other_box, "smaa");
39 |
40 | // Сохраняем активные эффекты
41 | var active_effects = new Gee.ArrayList ();
42 | string[] config_vars = { "cas", "dls", "fxaa", "smaa", "lut" };
43 | for (int i = 0; i < other_box.switches.size; i++) {
44 | if (other_box.switches[i].get_active ()) {
45 | active_effects.add (config_vars[i]);
46 | }
47 | }
48 |
49 | if (!active_effects.is_empty) {
50 | string effects_line = "effects = " + string.joinv (":", (string[]) active_effects.to_array ()) + "\n";
51 | file_stream_write.put_string (effects_line);
52 | }
53 |
54 | } catch (Error e) {
55 | stderr.printf ("Ошибка при записи в файл: %s\n", e.message);
56 | } finally {
57 | if (file_stream_write != null) {
58 | try {
59 | file_stream_write.close ();
60 | } catch (Error e) {
61 | stderr.printf ("Ошибка при закрытии файла: %s\n", e.message);
62 | }
63 | }
64 | }
65 | }
66 |
67 | // Вспомогательный метод для сохранения дробных значений, если Scale активен
68 | private static void save_scale_value_if_active (DataOutputStream file_stream_write, string key, Scale scale, Entry entry, string format, OtherBox other_box, string switch_name) throws Error {
69 | if (other_box.is_scale_active (scale, switch_name)) {
70 | double value = scale.get_value ();
71 | string line = "%s=%s\n".printf (key, format.printf (value).replace (",", "."));
72 | file_stream_write.put_string (line);
73 | }
74 | }
75 |
76 | // Вспомогательный метод для сохранения целочисленных значений, если Scale активен
77 | private static void save_int_scale_value_if_active (DataOutputStream file_stream_write, string key, Scale scale, Entry entry, OtherBox other_box, string switch_name) throws Error {
78 | if (other_box.is_scale_active (scale, switch_name)) {
79 | int value = (int) scale.get_value ();
80 | string line = "%s=%d\n".printf (key, value);
81 | file_stream_write.put_string (line);
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/src/reset_manager.vala:
--------------------------------------------------------------------------------
1 | /* reset_manager.vala // Licence: GPL-v3.0 */
2 | using Gtk;
3 | using Adw;
4 | using Gee;
5 |
6 | public class ResetManager {
7 | MangoJuice app;
8 |
9 | public ResetManager (MangoJuice app) {
10 | this.app = app;
11 | }
12 |
13 | public void reset_all_widgets () {
14 | reset_switches (app.gpu_switches);
15 | reset_switches (app.cpu_switches);
16 | reset_switches (app.memory_switches);
17 | reset_switches (app.git_switches);
18 | reset_switches (app.system_switches);
19 | reset_switches (app.wine_switches);
20 | reset_switches (app.options_switches);
21 | reset_switches (app.battery_switches);
22 | reset_switches (app.other_extra_switches);
23 | reset_switches (app.inform_switches);
24 | reset_media_format_dropdowns();
25 | reset_entries ();
26 | reset_dropdowns ();
27 | reset_scales ();
28 | reset_color_buttons ();
29 | reset_custom_switch ();
30 | }
31 |
32 | void reset_switches (Switch[] switches) {
33 | foreach (var sw in switches) {
34 | sw.active = false;
35 | }
36 | }
37 |
38 | void reset_entries () {
39 | app.custom_command_entry.text = "";
40 | app.custom_logs_path_entry.text = "";
41 | app.blacklist_entry.text = "";
42 | app.custom_text_center_entry.text = "";
43 | app.fps_value_entry_1.text = "";
44 | app.fps_value_entry_2.text = "";
45 | app.gpu_load_value_entry_1.text = "";
46 | app.gpu_load_value_entry_2.text = "";
47 | app.cpu_load_value_entry_1.text = "";
48 | app.cpu_load_value_entry_2.text = "";
49 | app.fps_limit_entry_1.text = "";
50 | app.fps_limit_entry_2.text = "";
51 | app.fps_limit_entry_3.text = "";
52 | app.toggle_hud_entry.text = "";
53 | }
54 |
55 | void reset_media_format_dropdowns() {
56 | if (app.media_format_dropdowns != null && app.media_format_dropdowns.size >= 3) {
57 | app.media_format_dropdowns[0].selected = 0;
58 | app.media_format_dropdowns[1].selected = 1;
59 | app.media_format_dropdowns[2].selected = 2;
60 | }
61 | }
62 |
63 | void reset_custom_switch () {
64 | app.custom_switch.active = false;
65 | }
66 |
67 | void reset_dropdowns () {
68 | app.logs_key_combo.selected = 0;
69 | app.fps_limit_method.selected = 0;
70 | app.toggle_fps_limit.selected = 0;
71 | app.vulkan_dropdown.selected = 0;
72 | app.opengl_dropdown.selected = 0;
73 | app.filter_dropdown.selected = 0;
74 | app.position_dropdown.selected = 0;
75 | app.font_button.label = _("Default");
76 | }
77 |
78 | void reset_scales () {
79 | app.duracion_scale.set_value (30);
80 | app.autostart_scale.set_value (0);
81 | app.interval_scale.set_value (100);
82 | app.af.set_value (0);
83 | app.picmip.set_value (0);
84 | app.borders_scale.set_value (0);
85 | app.alpha_scale.set_value (50);
86 | app.colums_scale.set_value (3);
87 | app.font_size_scale.set_value (24);
88 | app.offset_x_scale.set_value (0);
89 | app.offset_y_scale.set_value (0);
90 | app.fps_sampling_period_scale.set_value (500);
91 | }
92 |
93 | void reset_color_buttons () {
94 | var default_gpu_color = Gdk.RGBA ();
95 | default_gpu_color.parse ("#2e9762");
96 | app.gpu_color_button.set_rgba (default_gpu_color);
97 |
98 | var default_cpu_color = Gdk.RGBA ();
99 | default_cpu_color.parse ("#2e97cb");
100 | app.cpu_color_button.set_rgba (default_cpu_color);
101 |
102 | var default_fps_color_1 = Gdk.RGBA ();
103 | default_fps_color_1.parse ("#cc0000");
104 | app.fps_color_button_1.set_rgba (default_fps_color_1);
105 |
106 | var default_fps_color_2 = Gdk.RGBA ();
107 | default_fps_color_2.parse ("#ffaa7f");
108 | app.fps_color_button_2.set_rgba (default_fps_color_2);
109 |
110 | var default_fps_color_3 = Gdk.RGBA ();
111 | default_fps_color_3.parse ("#92e79a");
112 | app.fps_color_button_3.set_rgba (default_fps_color_3);
113 |
114 | var default_gpu_load_color_1 = Gdk.RGBA ();
115 | default_gpu_load_color_1.parse ("#92e79a");
116 | app.gpu_load_color_button_1.set_rgba (default_gpu_load_color_1);
117 |
118 | var default_gpu_load_color_2 = Gdk.RGBA ();
119 | default_gpu_load_color_2.parse ("#ffaa7f");
120 | app.gpu_load_color_button_2.set_rgba (default_gpu_load_color_2);
121 |
122 | var default_gpu_load_color_3 = Gdk.RGBA ();
123 | default_gpu_load_color_3.parse ("#cc0000");
124 | app.gpu_load_color_button_3.set_rgba (default_gpu_load_color_3);
125 |
126 | var default_cpu_load_color_1 = Gdk.RGBA ();
127 | default_cpu_load_color_1.parse ("#92e79a");
128 | app.cpu_load_color_button_1.set_rgba (default_cpu_load_color_1);
129 |
130 | var default_cpu_load_color_2 = Gdk.RGBA ();
131 | default_cpu_load_color_2.parse ("#ffaa7f");
132 | app.cpu_load_color_button_2.set_rgba (default_cpu_load_color_2);
133 |
134 | var default_cpu_load_color_3 = Gdk.RGBA ();
135 | default_cpu_load_color_3.parse ("#cc0000");
136 | app.cpu_load_color_button_3.set_rgba (default_cpu_load_color_3);
137 |
138 | var default_background_color = Gdk.RGBA ();
139 | default_background_color.parse ("#000000");
140 | app.background_color_button.set_rgba (default_background_color);
141 |
142 | var default_frametime_color = Gdk.RGBA ();
143 | default_frametime_color.parse ("#00ff00");
144 | app.frametime_color_button.set_rgba (default_frametime_color);
145 |
146 | var default_vram_color = Gdk.RGBA ();
147 | default_vram_color.parse ("#ad64c1");
148 | app.vram_color_button.set_rgba (default_vram_color);
149 |
150 | var default_ram_color = Gdk.RGBA ();
151 | default_ram_color.parse ("#c26693");
152 | app.ram_color_button.set_rgba (default_ram_color);
153 |
154 | var default_wine_color = Gdk.RGBA ();
155 | default_wine_color.parse ("#eb5b5b");
156 | app.wine_color_button.set_rgba (default_wine_color);
157 |
158 | var default_engine_color = Gdk.RGBA ();
159 | default_engine_color.parse ("#eb5b5b");
160 | app.engine_color_button.set_rgba (default_engine_color);
161 |
162 | var default_text_color = Gdk.RGBA ();
163 | default_text_color.parse ("#FFFFFF");
164 | app.text_color_button.set_rgba (default_text_color);
165 |
166 | var default_media_player_color = Gdk.RGBA ();
167 | default_media_player_color.parse ("#FFFFFF");
168 | app.media_player_color_button.set_rgba (default_media_player_color);
169 |
170 | var default_network_color = Gdk.RGBA ();
171 | default_network_color.parse ("#e07b85");
172 | app.network_color_button.set_rgba (default_network_color);
173 |
174 | var default_battery_color = Gdk.RGBA ();
175 | default_battery_color.parse ("#92e79a");
176 | app.battery_color_button.set_rgba (default_battery_color);
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/save_states.vala:
--------------------------------------------------------------------------------
1 | /* save_states.vala // Licence: GPL-v3.0 */
2 | using Gtk;
3 | using Gee;
4 |
5 | public class SaveStates {
6 | public static void update_parameter (DataOutputStream data_stream, string parameter_name, string parameter_value) throws Error {
7 | if (
8 | parameter_value == "" ||
9 | (parameter_name == "round_corners" && parameter_value == "0") ||
10 | (parameter_name == "font_size" && parameter_value == "24") ||
11 | (parameter_name == "log_duration" && parameter_value == "30") ||
12 | (parameter_name == "log_interval" && parameter_value == "100") ||
13 | (parameter_name == "table_columns" && parameter_value == "3") ||
14 | (parameter_name == "fps_sampling_period" && parameter_value == "500") ||
15 | (parameter_name == "offset_x" && parameter_value == "0") ||
16 | (parameter_name == "offset_y" && parameter_value == "0")
17 | ) {
18 | return;
19 | }
20 | data_stream.put_string ("%s=%s\n".printf (parameter_name, parameter_value));
21 | }
22 |
23 | public static void update_pci_dev_in_file (string pci_dev_value) {
24 | update_file ("pci_dev=", pci_dev_value);
25 | }
26 |
27 | public static void update_fps_limit_in_file (string fps_limit_1, string fps_limit_2, string fps_limit_3) {
28 | update_file ("fps_limit=", "%s,%s,%s".printf (fps_limit_1, fps_limit_2, fps_limit_3));
29 | }
30 |
31 | public static void update_fps_sampling_period_in_file (string fps_sampling_period_value) {
32 | update_file ("fps_sampling_period=", fps_sampling_period_value);
33 | }
34 |
35 | public static void update_logs_key_in_file (string logs_key) {
36 | update_file ("toggle_logging=", logs_key);
37 | }
38 |
39 | public static void update_toggle_hud_key_in_file (string toggle_hud_position) {
40 | update_file ("toggle_hud_position=", toggle_hud_position);
41 | }
42 |
43 | public static void update_blacklist_in_file (string blacklist_value) {
44 | update_file ("blacklist=", blacklist_value);
45 | }
46 |
47 | public static void update_gpu_in_file (string gpu_value) {
48 | update_file ("gpu_list=", gpu_value);
49 | }
50 |
51 | public static void update_position_in_file (string position_value) {
52 | update_file ("position=", position_value);
53 | }
54 |
55 | public static void update_toggle_hud_in_file (string toggle_hud_value) {
56 | update_file ("toggle_hud=", toggle_hud_value);
57 | }
58 |
59 | public static void update_offset_x_in_file (string offset_x_value) {
60 | update_file ("offset_x=", offset_x_value);
61 | }
62 |
63 | public static void update_offset_y_in_file (string offset_y_value) {
64 | update_file ("offset_y=", offset_y_value);
65 | }
66 |
67 | public static void update_gpu_color_in_file (string gpu_color) {
68 | update_file ("gpu_color=", gpu_color);
69 | }
70 |
71 | public static void update_cpu_color_in_file (string cpu_color) {
72 | update_file ("cpu_color=", cpu_color);
73 | }
74 |
75 | public static void update_gpu_text_in_file (string gpu_text) {
76 | update_file ("gpu_text=", gpu_text);
77 | }
78 |
79 | public static void update_cpu_text_in_file (string cpu_text) {
80 | update_file ("cpu_text=", cpu_text);
81 | }
82 |
83 | public static void update_fps_value_in_file (string fps_value_1, string fps_value_2) {
84 | if ( fps_value_1 == "" || fps_value_2 == "") {
85 | return;
86 | }
87 | update_file ("fps_value=", "%s,%s".printf (fps_value_1, fps_value_2));
88 | }
89 |
90 | public static void update_fps_color_in_file (string fps_color_1, string fps_color_2, string fps_color_3) {
91 | update_file ("fps_color=", "%s,%s,%s".printf (fps_color_1, fps_color_2, fps_color_3));
92 | }
93 |
94 | public static void update_gpu_load_value_in_file(string gpu_load_value_1, string gpu_load_value_2) {
95 | if (gpu_load_value_1 == "" || gpu_load_value_2 == "") {
96 | return;
97 | }
98 | update_file ("gpu_load_value=", "%s,%s".printf(gpu_load_value_1, gpu_load_value_2));
99 | }
100 |
101 | public static void update_gpu_load_color_in_file (string gpu_load_color_1, string gpu_load_color_2, string gpu_load_color_3) {
102 | update_file ("gpu_load_color=", "%s,%s,%s".printf (gpu_load_color_1, gpu_load_color_2, gpu_load_color_3));
103 | }
104 |
105 | public static void update_font_file_in_file (string font_path) {
106 | update_file ("font_file=", font_path);
107 | }
108 |
109 | public static void update_cpu_load_value_in_file(string cpu_load_value_1, string cpu_load_value_2) {
110 | if (cpu_load_value_1 == "" || cpu_load_value_2 == "") {
111 | return;
112 | }
113 | update_file ("cpu_load_value=", "%s,%s".printf(cpu_load_value_1, cpu_load_value_2));
114 | }
115 |
116 | public static void update_cpu_load_color_in_file (string cpu_load_color_1, string cpu_load_color_2, string cpu_load_color_3) {
117 | update_file ("cpu_load_color=", "%s,%s,%s".printf (cpu_load_color_1, cpu_load_color_2, cpu_load_color_3));
118 | }
119 |
120 | public static void update_background_color_in_file (string background_color) {
121 | update_file ("background_color=", background_color);
122 | }
123 |
124 | public static void update_frametime_color_in_file (string frametime_color) {
125 | update_file ("frametime_color=", frametime_color);
126 | }
127 |
128 | public static void update_vram_color_in_file (string vram_color) {
129 | update_file ("vram_color=", vram_color);
130 | }
131 |
132 | public static void update_ram_color_in_file (string ram_color) {
133 | update_file ("ram_color=", ram_color);
134 | }
135 |
136 | public static void update_wine_color_in_file (string wine_color) {
137 | update_file ("wine_color=", wine_color);
138 | }
139 |
140 | public static void update_engine_color_in_file (string engine_color) {
141 | update_file ("engine_color=", engine_color);
142 | }
143 |
144 | public static void update_text_color_in_file (string text_color) {
145 | update_file ("text_color=", text_color);
146 | }
147 |
148 | public static void update_media_player_color_in_file (string media_player_color) {
149 | update_file ("media_player_color=", media_player_color);
150 | }
151 |
152 | public static void update_network_color_in_file (string network_color) {
153 | update_file ("network_color=", network_color);
154 | }
155 |
156 | public static void update_battery_color_in_file (string battery_color) {
157 | update_file ("battery_color=", battery_color);
158 | }
159 |
160 | public static void update_media_player_format_in_file (string format_value) {
161 | update_file ("media_player_format=", format_value);
162 | }
163 |
164 | static void update_file (string prefix, string value) {
165 | var config_dir = File.new_for_path (Environment.get_home_dir ()).get_child (".config").get_child ("MangoHud");
166 | var file = config_dir.get_child ("MangoHud.conf");
167 | if (!file.query_exists ()) {
168 | return;
169 | }
170 |
171 | try {
172 | var lines = new ArrayList ();
173 | var file_stream = new DataInputStream (file.read ());
174 | string line;
175 | while ((line = file_stream.read_line ()) != null) {
176 | if (line.has_prefix (prefix)) {
177 | line = "%s%s".printf (prefix, value);
178 | }
179 | lines.add (line);
180 | }
181 |
182 | var file_stream_write = new DataOutputStream (file.replace (null, false, FileCreateFlags.NONE));
183 | foreach (var l in lines) {
184 | file_stream_write.put_string (l + "\n");
185 | }
186 | file_stream_write.close ();
187 | } catch (Error e) {
188 | stderr.printf ("Error writing to the file: %s\n", e.message);
189 | }
190 | }
191 |
192 | public static void save_states_to_file (MangoJuice mango_juice) {
193 | var config_dir = File.new_for_path (Environment.get_home_dir ()).get_child (".config").get_child ("MangoHud");
194 | var file = config_dir.get_child ("MangoHud.conf");
195 | bool is_horizontal = mango_juice.custom_switch.active;
196 |
197 | try {
198 | if (!config_dir.query_exists ()) {
199 | config_dir.make_directory_with_parents ();
200 | }
201 |
202 | var data_stream = new DataOutputStream (file.replace (null, false, FileCreateFlags.NONE));
203 | data_stream.put_string ("# Config Generated by MangoJuice #\n");
204 | data_stream.put_string ("legacy_layout=false\n");
205 |
206 | update_parameter (data_stream, "blacklist", mango_juice.blacklist_entry.text);
207 |
208 | update_parameter (data_stream, "gpu_list", mango_juice.gpu_entry.text);
209 |
210 | if (mango_juice.gpu_dropdown.selected_item != null) {
211 | var selected_pci_address = (mango_juice.gpu_dropdown.selected_item as StringObject)?.get_string () ?? "";
212 | if (selected_pci_address != _("All video cards")) {
213 | data_stream.put_string ("pci_dev=%s\n".printf (selected_pci_address));
214 | }
215 | }
216 |
217 | var custom_command = mango_juice.custom_command_entry.text;
218 | if (custom_command != "") {
219 | data_stream.put_string ("%s #custom_command\n".printf (custom_command));
220 | }
221 |
222 | if (mango_juice.offset_x_scale != null) {
223 | update_parameter (data_stream, "offset_x", ((int)mango_juice.offset_x_scale.get_value ()).to_string ());
224 | }
225 |
226 | if (mango_juice.offset_y_scale != null) {
227 | update_parameter (data_stream, "offset_y", ((int)mango_juice.offset_y_scale.get_value ()).to_string ());
228 | }
229 |
230 | if (is_horizontal) {
231 | update_parameter (data_stream, "custom_text", mango_juice.custom_text_center_entry.text);
232 | } else {
233 | update_parameter (data_stream, "custom_text_center", mango_juice.custom_text_center_entry.text);
234 | }
235 |
236 | var order_map = new HashMap> ();
237 |
238 | var inform_start = new ArrayList ();
239 | for (int i = 0; i < 5; i++) {
240 | inform_start.add (i);
241 | }
242 | order_map.set ("inform_start", inform_start);
243 |
244 | var inform_end = new ArrayList ();
245 | inform_end.add (11);
246 | for (int i = 5; i < 11; i++) {
247 | inform_end.add (i);
248 | }
249 | order_map.set ("inform_end", inform_end);
250 |
251 | var gpu_start = new ArrayList ();
252 | gpu_start.add (0);
253 | gpu_start.add (1);
254 | gpu_start.add (2);
255 | gpu_start.add (3);
256 | gpu_start.add (4);
257 | gpu_start.add (5);
258 | gpu_start.add (6);
259 | gpu_start.add (7);
260 | gpu_start.add (8);
261 | gpu_start.add (10);
262 | gpu_start.add (11);
263 | gpu_start.add (12);
264 | gpu_start.add (13);
265 | order_map.set ("gpu_start", gpu_start);
266 |
267 | var gpu_end = new ArrayList ();
268 | gpu_end.add (9);
269 | gpu_end.add (14);
270 | gpu_end.add (15);
271 | order_map.set ("gpu_end", gpu_end);
272 |
273 | var system_start = new ArrayList ();
274 | system_start.add (0);
275 | system_start.add (1);
276 | system_start.add (2);
277 | system_start.add (3);
278 | system_start.add (4);
279 | system_start.add (6);
280 | order_map.set ("system_start", system_start);
281 |
282 | var system_end = new ArrayList ();
283 | system_end.add (7);
284 | system_end.add (5);
285 | order_map.set ("system_end", system_end);
286 |
287 | save_switches_to_file (data_stream, mango_juice.gpu_switches, mango_juice.gpu_config_vars, (int[]) order_map.get ("gpu_start").to_array ());
288 |
289 | int[] cpu_order = {0, 1, 2, 3, 4, 5, 6, 7, 8};
290 | save_switches_to_file (data_stream, mango_juice.cpu_switches, mango_juice.cpu_config_vars, cpu_order);
291 |
292 | int[] memory_order = {0, 1, 2, 3, 4, 5, 6};
293 | save_switches_to_file (data_stream, mango_juice.memory_switches, mango_juice.memory_config_vars, memory_order);
294 |
295 | if (Config.IS_DEVEL) {
296 | int[] git_order = {0, 1, 2};
297 | save_switches_to_file (data_stream, mango_juice.git_switches, mango_juice.git_config_vars, git_order);
298 | }
299 |
300 | save_switches_to_file (data_stream, mango_juice.inform_switches, mango_juice.inform_config_vars, (int[]) order_map.get ("inform_start").to_array ());
301 |
302 | save_switches_to_file (data_stream, mango_juice.system_switches, mango_juice.system_config_vars, (int[]) order_map.get ("system_end").to_array ());
303 |
304 | int[] options_order = {0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10, 11};
305 | save_switches_to_file (data_stream, mango_juice.options_switches, mango_juice.options_config_vars, options_order);
306 |
307 | save_switches_to_file (data_stream, mango_juice.gpu_switches, mango_juice.gpu_config_vars, (int[]) order_map.get ("gpu_end").to_array ());
308 |
309 | save_switches_to_file (data_stream, mango_juice.system_switches, mango_juice.system_config_vars, (int[]) order_map.get ("system_start").to_array ());
310 |
311 | save_switches_to_file (data_stream, mango_juice.inform_switches, mango_juice.inform_config_vars, (int[]) order_map.get ("inform_end").to_array ());
312 |
313 | int[] battery_order = {0, 1, 2, 3, 4, 5};
314 | save_switches_to_file (data_stream, mango_juice.battery_switches, mango_juice.battery_config_vars, battery_order);
315 |
316 | int[] other_extra_order = {1, 2, 0, 3};
317 | save_switches_to_file (data_stream, mango_juice.other_extra_switches, mango_juice.other_extra_config_vars, other_extra_order);
318 |
319 | int[] wine_order = {0, 1};
320 | save_switches_to_file (data_stream, mango_juice.wine_switches, mango_juice.wine_config_vars, wine_order);
321 |
322 | if (mango_juice.logs_key_combo.selected_item != null) {
323 | var logs_key = (mango_juice.logs_key_combo.selected_item as StringObject)?.get_string () ?? "";
324 | update_parameter (data_stream, "toggle_logging", logs_key);
325 | }
326 |
327 | if (mango_juice.toggle_hud_key_combo.selected_item != null) {
328 | var toggle_hud_position = (mango_juice.toggle_hud_key_combo.selected_item as StringObject)?.get_string () ?? "";
329 | update_parameter (data_stream, "toggle_hud_position", toggle_hud_position);
330 | }
331 |
332 | if (mango_juice.duracion_scale != null && (int)mango_juice.duracion_scale.get_value () != 0) {
333 | update_parameter (data_stream, "log_duration", ((int)mango_juice.duracion_scale.get_value ()).to_string ());
334 | }
335 |
336 | if (mango_juice.autostart_scale != null && (int)mango_juice.autostart_scale.get_value () != 0) {
337 | update_parameter (data_stream, "autostart_log", ((int)mango_juice.autostart_scale.get_value ()).to_string ());
338 | }
339 |
340 | if (mango_juice.interval_scale != null && (int)mango_juice.interval_scale.get_value () != 0) {
341 | update_parameter (data_stream, "log_interval", ((int)mango_juice.interval_scale.get_value ()).to_string ());
342 | }
343 |
344 | update_parameter (data_stream, "output_folder", mango_juice.custom_logs_path_entry.text);
345 |
346 | if (mango_juice.fps_limit_method.selected_item != null) {
347 | var fps_limit_method_value = (mango_juice.fps_limit_method.selected_item as StringObject)?.get_string () ?? "";
348 | update_parameter (data_stream, "fps_limit_method", fps_limit_method_value);
349 | }
350 |
351 | if (mango_juice.toggle_fps_limit.selected_item != null) {
352 | var toggle_fps_limit_value = (mango_juice.toggle_fps_limit.selected_item as StringObject)?.get_string () ?? "";
353 | update_parameter (data_stream, "toggle_fps_limit", toggle_fps_limit_value);
354 | }
355 |
356 | var fps_limit_1 = mango_juice.fps_limit_entry_1.text;
357 | var fps_limit_2 = mango_juice.fps_limit_entry_2.text;
358 | var fps_limit_3 = mango_juice.fps_limit_entry_3.text;
359 | if (fps_limit_1 != "" || fps_limit_2 != "" || fps_limit_3 != "") {
360 | update_parameter (data_stream, "fps_limit", "%s,%s,%s".printf (fps_limit_1, fps_limit_2, fps_limit_3));
361 | }
362 |
363 | if (mango_juice.vulkan_dropdown.selected_item != null) {
364 | var vulkan_value = (mango_juice.vulkan_dropdown.selected_item as StringObject)?.get_string () ?? "";
365 | var vulkan_config_value = mango_juice.get_vulkan_config_value (vulkan_value);
366 | update_parameter (data_stream, "vsync", vulkan_config_value);
367 | }
368 |
369 | if (mango_juice.opengl_dropdown.selected_item != null) {
370 | var opengl_value = (mango_juice.opengl_dropdown.selected_item as StringObject)?.get_string () ?? "";
371 | var opengl_config_value = mango_juice.get_opengl_config_value (opengl_value);
372 | update_parameter (data_stream, "gl_vsync", opengl_config_value);
373 | }
374 |
375 | if (mango_juice.filter_dropdown.selected_item != null) {
376 | var filter_value = (mango_juice.filter_dropdown.selected_item as StringObject)?.get_string () ?? "";
377 | if (filter_value != "none") {
378 | data_stream.put_string ("%s #filters\n".printf (filter_value));
379 | }
380 | }
381 |
382 | if (mango_juice.af != null && (int)mango_juice.af.get_value () != 0) {
383 | update_parameter (data_stream, "af", ((int)mango_juice.af.get_value ()).to_string ());
384 | }
385 |
386 | if (mango_juice.picmip != null && (int)mango_juice.picmip.get_value () != 0) {
387 | update_parameter (data_stream, "picmip", ((int)mango_juice.picmip.get_value ()).to_string ());
388 | }
389 |
390 | if (mango_juice.custom_switch.active) {
391 | try {
392 | data_stream.put_string ("horizontal\nhorizontal_stretch=0\n");
393 | } catch (Error e) {
394 | stderr.printf ("Error writing to the file: %s\n", e.message);
395 | }
396 | }
397 |
398 | if (mango_juice.borders_scale != null) {
399 | update_parameter (data_stream, "round_corners", ((int)mango_juice.borders_scale.get_value ()).to_string ());
400 | }
401 |
402 | if (mango_juice.alpha_scale != null) {
403 | double alpha_value = mango_juice.alpha_scale.get_value () / 100.0;
404 | string alpha_value_str = "%.1f".printf (alpha_value).replace (",", ".");
405 | update_parameter (data_stream, "background_alpha", alpha_value_str);
406 | }
407 |
408 | if (mango_juice.position_dropdown.selected_item != null) {
409 | var position_value = (mango_juice.position_dropdown.selected_item as StringObject)?.get_string () ?? "";
410 | update_parameter (data_stream, "position", position_value);
411 | }
412 |
413 | if (mango_juice.colums_scale != null) {
414 | update_parameter (data_stream, "table_columns", ((int)mango_juice.colums_scale.get_value ()).to_string ());
415 | }
416 |
417 | update_parameter (data_stream, "toggle_hud", mango_juice.toggle_hud_entry.text);
418 |
419 | if (mango_juice.font_size_scale != null) {
420 | update_parameter (data_stream, "font_size", ((int)mango_juice.font_size_scale.get_value ()).to_string ());
421 | }
422 |
423 | if (mango_juice.font_button != null) {
424 | var font_name = mango_juice.font_button.label;
425 | if (font_name != _("Default") && font_name != _("Select Font")) {
426 | var font_path = mango_juice.find_font_path_by_name(font_name, mango_juice.find_fonts());
427 | if (font_path != "") {
428 | update_parameter(data_stream, "font_file", font_path);
429 | data_stream.put_string("font_glyph_ranges=korean, chinese, chinese_simplified, japanese, cyrillic, thai, vietnamese, latin_ext_a, latin_ext_b\n");
430 | }
431 | }
432 | }
433 |
434 | if (mango_juice.fps_sampling_period_scale != null) {
435 | update_parameter (data_stream, "fps_sampling_period", ((int)mango_juice.fps_sampling_period_scale.get_value ()).to_string ());
436 | }
437 |
438 | update_parameter (data_stream, "gpu_text", mango_juice.gpu_text_entry.text);
439 |
440 | if (mango_juice.gpu_color_button != null) {
441 | var gpu_color = mango_juice.rgba_to_hex (mango_juice.gpu_color_button.get_rgba ());
442 | update_parameter (data_stream, "gpu_color", gpu_color);
443 | }
444 |
445 | update_parameter (data_stream, "cpu_text", mango_juice.cpu_text_entry.text);
446 |
447 | if (mango_juice.cpu_color_button != null) {
448 | var cpu_color = mango_juice.rgba_to_hex (mango_juice.cpu_color_button.get_rgba ());
449 | update_parameter (data_stream, "cpu_color", cpu_color);
450 | }
451 |
452 | if (mango_juice.fps_value_entry_1 != null && mango_juice.fps_value_entry_2 != null) {
453 | var fps_value_1 = mango_juice.fps_value_entry_1.text;
454 | var fps_value_2 = mango_juice.fps_value_entry_2.text;
455 | if (fps_value_1 != "" && fps_value_2 != "") {
456 | update_parameter (data_stream, "fps_value", "%s,%s".printf (fps_value_1, fps_value_2));
457 | }
458 | }
459 |
460 | if (mango_juice.fps_color_button_1 != null && mango_juice.fps_color_button_2 != null && mango_juice.fps_color_button_3 != null) {
461 | var fps_color_1 = mango_juice.rgba_to_hex (mango_juice.fps_color_button_1.get_rgba ());
462 | var fps_color_2 = mango_juice.rgba_to_hex (mango_juice.fps_color_button_2.get_rgba ());
463 | var fps_color_3 = mango_juice.rgba_to_hex (mango_juice.fps_color_button_3.get_rgba ());
464 | if (fps_color_1 != "" && fps_color_2 != "" && fps_color_3 != "") {
465 | update_parameter (data_stream, "fps_color", "%s,%s,%s".printf (fps_color_1, fps_color_2, fps_color_3));
466 | }
467 | }
468 |
469 | if (mango_juice.gpu_load_value_entry_1 != null && mango_juice.gpu_load_value_entry_2 != null) {
470 | var gpu_load_value_1 = mango_juice.gpu_load_value_entry_1.text;
471 | var gpu_load_value_2 = mango_juice.gpu_load_value_entry_2.text;
472 | if (gpu_load_value_1 != "" && gpu_load_value_2 != "") {
473 | update_parameter (data_stream, "gpu_load_value", "%s,%s".printf (gpu_load_value_1, gpu_load_value_2));
474 | }
475 | }
476 |
477 | if (mango_juice.gpu_load_color_button_1 != null && mango_juice.gpu_load_color_button_2 != null && mango_juice.gpu_load_color_button_3 != null) {
478 | var gpu_load_color_1 = mango_juice.rgba_to_hex (mango_juice.gpu_load_color_button_1.get_rgba ());
479 | var gpu_load_color_2 = mango_juice.rgba_to_hex (mango_juice.gpu_load_color_button_2.get_rgba ());
480 | var gpu_load_color_3 = mango_juice.rgba_to_hex (mango_juice.gpu_load_color_button_3.get_rgba ());
481 | if (gpu_load_color_1 != "" && gpu_load_color_2 != "" && gpu_load_color_3 != "") {
482 | update_parameter (data_stream, "gpu_load_color", "%s,%s,%s".printf (gpu_load_color_1, gpu_load_color_2, gpu_load_color_3));
483 | }
484 | }
485 |
486 | if (mango_juice.cpu_load_value_entry_1 != null && mango_juice.cpu_load_value_entry_2 != null) {
487 | var cpu_load_value_1 = mango_juice.cpu_load_value_entry_1.text;
488 | var cpu_load_value_2 = mango_juice.cpu_load_value_entry_2.text;
489 | if (cpu_load_value_1 != "" && cpu_load_value_2 != "") {
490 | update_parameter (data_stream, "cpu_load_value", "%s,%s".printf (cpu_load_value_1, cpu_load_value_2));
491 | }
492 | }
493 |
494 | if (mango_juice.cpu_load_color_button_1 != null && mango_juice.cpu_load_color_button_2 != null && mango_juice.cpu_load_color_button_3 != null) {
495 | var cpu_load_color_1 = mango_juice.rgba_to_hex (mango_juice.cpu_load_color_button_1.get_rgba ());
496 | var cpu_load_color_2 = mango_juice.rgba_to_hex (mango_juice.cpu_load_color_button_2.get_rgba ());
497 | var cpu_load_color_3 = mango_juice.rgba_to_hex (mango_juice.cpu_load_color_button_3.get_rgba ());
498 | if (cpu_load_color_1 != "" && cpu_load_color_2 != "" && cpu_load_color_3 != "") {
499 | update_parameter (data_stream, "cpu_load_color", "%s,%s,%s".printf (cpu_load_color_1, cpu_load_color_2, cpu_load_color_3));
500 | }
501 | }
502 |
503 | if (mango_juice.background_color_button != null) {
504 | var background_color = mango_juice.rgba_to_hex (mango_juice.background_color_button.get_rgba ());
505 | update_parameter (data_stream, "background_color", background_color);
506 | }
507 |
508 | if (mango_juice.frametime_color_button != null) {
509 | var frametime_color = mango_juice.rgba_to_hex (mango_juice.frametime_color_button.get_rgba ());
510 | update_parameter (data_stream, "frametime_color", frametime_color);
511 | }
512 |
513 | if (mango_juice.vram_color_button != null) {
514 | var vram_color = mango_juice.rgba_to_hex (mango_juice.vram_color_button.get_rgba ());
515 | update_parameter (data_stream, "vram_color", vram_color);
516 | }
517 |
518 | if (mango_juice.ram_color_button != null) {
519 | var ram_color = mango_juice.rgba_to_hex (mango_juice.ram_color_button.get_rgba ());
520 | update_parameter (data_stream, "ram_color", ram_color);
521 | }
522 |
523 | if (mango_juice.wine_color_button != null) {
524 | var wine_color = mango_juice.rgba_to_hex (mango_juice.wine_color_button.get_rgba ());
525 | update_parameter (data_stream, "wine_color", wine_color);
526 | }
527 |
528 | if (mango_juice.engine_color_button != null) {
529 | var engine_color = mango_juice.rgba_to_hex (mango_juice.engine_color_button.get_rgba ());
530 | update_parameter (data_stream, "engine_color", engine_color);
531 | }
532 |
533 | if (mango_juice.text_color_button != null) {
534 | var text_color = mango_juice.rgba_to_hex (mango_juice.text_color_button.get_rgba ());
535 | update_parameter (data_stream, "text_color", text_color);
536 | }
537 |
538 | if (mango_juice.media_player_color_button != null) {
539 | var media_player_color = mango_juice.rgba_to_hex (mango_juice.media_player_color_button.get_rgba ());
540 | update_parameter (data_stream, "media_player_color", media_player_color);
541 | }
542 |
543 | if (mango_juice.network_color_button != null) {
544 | var network_color = mango_juice.rgba_to_hex (mango_juice.network_color_button.get_rgba ());
545 | update_parameter (data_stream, "network_color", network_color);
546 | }
547 |
548 | if (mango_juice.battery_color_button != null) {
549 | var battery_color = mango_juice.rgba_to_hex (mango_juice.battery_color_button.get_rgba ());
550 | update_parameter (data_stream, "battery_color", battery_color);
551 | }
552 |
553 | if (mango_juice.media_format_dropdowns != null) {
554 | var active_values = new Gee.ArrayList();
555 |
556 | foreach (var dropdown in mango_juice.media_format_dropdowns) {
557 | var selected_item = dropdown.selected_item as StringObject;
558 | string? value = selected_item?.get_string();
559 | if (value != null && value != "" && value != "none") {
560 | active_values.add(value);
561 | }
562 | }
563 |
564 | string media_format = "";
565 | if (active_values.size > 0) {
566 | var sb = new StringBuilder();
567 | sb.append("{");
568 | bool first = true;
569 | foreach (string val in active_values) {
570 | if (!first) sb.append("};{");
571 | sb.append(val);
572 | first = false;
573 | }
574 | sb.append("}");
575 | media_format = sb.str;
576 | }
577 | update_parameter(data_stream, "media_player_format", media_format);
578 | }
579 |
580 | data_stream.close ();
581 | } catch (Error e) {
582 | stderr.printf ("Error writing to the file: %s\n", e.message);
583 | }
584 | }
585 |
586 | // Метод для сохранения состояний переключателей в файл
587 | public static void save_switches_to_file (DataOutputStream data_stream, Switch[] switches, string[] config_vars, int[] order) {
588 | for (int i = 0; i < order.length; i++) {
589 | int index = order[i];
590 | if (switches[index].active) {
591 | try {
592 | string config_var = config_vars[index];
593 | data_stream.put_string ("%s\n".printf (config_var));
594 | } catch (Error e) {
595 | stderr.printf ("Error writing to the file: %s\n", e.message);
596 | }
597 | }
598 | }
599 | }
600 | }
601 |
--------------------------------------------------------------------------------