mini-eq 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mini_eq-0.3.0 → mini_eq-0.3.2}/CHANGELOG.md +13 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/PKG-INFO +1 -1
- {mini_eq-0.3.0 → mini_eq-0.3.2}/data/io.github.bhack.mini-eq.metainfo.xml +20 -2
- {mini_eq-0.3.0 → mini_eq-0.3.2}/docs/flathub.md +8 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/docs/release.md +28 -0
- mini_eq-0.3.2/docs/screenshots/mini-eq-dark.png +0 -0
- mini_eq-0.3.2/docs/screenshots/mini-eq.png +0 -0
- mini_eq-0.3.2/docs/social-preview.png +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/pyproject.toml +1 -1
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/style.css +24 -64
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window.py +6 -1
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_layout.py +21 -23
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/wireplumber_backend.py +16 -2
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/wireplumber_stream_router.py +12 -4
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq.egg-info/PKG-INFO +1 -1
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq.egg-info/SOURCES.txt +1 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_window.py +33 -2
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_wireplumber_backend.py +130 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_wireplumber_stream_router.py +46 -0
- mini_eq-0.3.2/tools/check_flatpak_runtime.py +290 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/check_wireplumber_gi.py +1 -0
- mini_eq-0.3.0/docs/screenshots/mini-eq-dark.png +0 -0
- mini_eq-0.3.0/docs/screenshots/mini-eq.png +0 -0
- mini_eq-0.3.0/docs/social-preview.png +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/AGENTS.md +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/LICENSE +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/MANIFEST.in +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/README.md +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/SECURITY.md +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/data/io.github.bhack.mini-eq.desktop +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/docker/ubuntu-24.04-wp04.Dockerfile +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/docs/performance.md +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/docs/screenshots/README.md +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/extensions/gnome-shell/README.md +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/extensions/gnome-shell/mini-eq@bhack.github.io/extension.js +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/extensions/gnome-shell/mini-eq@bhack.github.io/metadata.json +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/extensions/gnome-shell/mini-eq@bhack.github.io/mini-eq-symbolic.svg +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/flatpak/patches/wireplumber-0.5.14-tools-disabled-po.patch +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/io.github.bhack.mini-eq.yaml +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/python3-dependencies.yaml +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/setup.cfg +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/__init__.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/__main__.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/analyzer.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/analyzer_widget.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/app.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/appearance.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/assets/icons/hicolor/scalable/apps/io.github.bhack.mini-eq.svg +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/assets/icons/hicolor/symbolic/apps/io.github.bhack.mini-eq-symbolic.svg +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/band_fader.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/cli.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/core.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/dbus_control.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/deps.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/desktop_integration.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/ebur128.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/filter_chain.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/glib_utils.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/gtk_utils.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/instance.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/routing.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/screenshot.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_analyzer.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_graph.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_headroom.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_presets.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_utility.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq/window_utils.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq.egg-info/dependency_links.txt +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq.egg-info/entry_points.txt +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq.egg-info/requires.txt +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/src/mini_eq.egg-info/top_level.txt +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_gnome_shell_extension.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_analyzer.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_app.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_appearance.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_cli.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_core.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_dbus_control.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_deps.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_desktop_integration.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_ebur128.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_filter_chain.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_instance.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_output_presets.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_routing.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_window_analyzer.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_mini_eq_window_graph.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tests/test_version_metadata.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/benchmark_fader_drag.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/check_flathub_manifest_drift.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/check_gnome_shell_extension.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/demo_runtime.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/gnome-shell-extension/fake_mini_eq_control.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/pack_gnome_shell_extension.sh +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/profile_live_app.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/profile_sysprof.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/release_post_publish.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/release_preflight.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/render_demo_screenshot.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/render_social_preview.py +0 -0
- {mini_eq-0.3.0 → mini_eq-0.3.2}/tools/run_gnome_extension_dev_shell.sh +0 -0
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.2 - 2026-05-04
|
|
4
|
+
|
|
5
|
+
- Fix Flatpak system-wide routing by requesting PipeWire manager access from the WirePlumber client.
|
|
6
|
+
- Restore partially routed streams when initial routing fails and reset the routing switch after failures.
|
|
7
|
+
- Avoid restarting output routing during GTK close shutdown.
|
|
8
|
+
- Add a local Flatpak runtime smoke test and an experimental manual CI job for routing checks.
|
|
9
|
+
|
|
10
|
+
## 0.3.1 - 2026-05-04
|
|
11
|
+
|
|
12
|
+
- Improve adaptive layout spacing across compact, tall, and wide windows.
|
|
13
|
+
- Remove unnecessary utility-pane scrolling at the minimum window height.
|
|
14
|
+
- Lighten the utility pane presentation so tall windows keep focus on the controls.
|
|
15
|
+
|
|
3
16
|
## 0.3.0 - 2026-05-03
|
|
4
17
|
|
|
5
18
|
- Add optional live LUFS loudness metering through libebur128 and the existing JACK monitor stream.
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
</description>
|
|
35
35
|
<screenshots>
|
|
36
36
|
<screenshot type="default">
|
|
37
|
-
<image>https://raw.githubusercontent.com/bhack/mini-eq/v0.3.
|
|
37
|
+
<image>https://raw.githubusercontent.com/bhack/mini-eq/v0.3.2/docs/screenshots/mini-eq.png</image>
|
|
38
38
|
<caption>Adjust sound output with equalizer controls</caption>
|
|
39
39
|
</screenshot>
|
|
40
40
|
<screenshot>
|
|
41
|
-
<image>https://raw.githubusercontent.com/bhack/mini-eq/v0.3.
|
|
41
|
+
<image>https://raw.githubusercontent.com/bhack/mini-eq/v0.3.2/docs/screenshots/mini-eq-dark.png</image>
|
|
42
42
|
<caption>Use the equalizer with dark style</caption>
|
|
43
43
|
</screenshot>
|
|
44
44
|
</screenshots>
|
|
@@ -46,6 +46,24 @@
|
|
|
46
46
|
<url type="bugtracker">https://github.com/bhack/mini-eq/issues</url>
|
|
47
47
|
<url type="vcs-browser">https://github.com/bhack/mini-eq</url>
|
|
48
48
|
<releases>
|
|
49
|
+
<release version="0.3.2" date="2026-05-04">
|
|
50
|
+
<description>
|
|
51
|
+
<ul>
|
|
52
|
+
<li>Fix Flatpak system-wide routing access through WirePlumber.</li>
|
|
53
|
+
<li>Restore partially routed streams when initial routing fails.</li>
|
|
54
|
+
<li>Avoid restarting routing during window-close shutdown.</li>
|
|
55
|
+
</ul>
|
|
56
|
+
</description>
|
|
57
|
+
</release>
|
|
58
|
+
<release version="0.3.1" date="2026-05-04">
|
|
59
|
+
<description>
|
|
60
|
+
<ul>
|
|
61
|
+
<li>Improve adaptive layout spacing across compact, tall, and wide windows.</li>
|
|
62
|
+
<li>Avoid unnecessary utility pane scrolling at the minimum window height.</li>
|
|
63
|
+
<li>Lighten the utility pane presentation so tall windows keep focus on the controls.</li>
|
|
64
|
+
</ul>
|
|
65
|
+
</description>
|
|
66
|
+
</release>
|
|
49
67
|
<release version="0.3.0" date="2026-05-03">
|
|
50
68
|
<description>
|
|
51
69
|
<ul>
|
|
@@ -126,6 +126,14 @@ flatpak run --command=flathub-build org.flatpak.Builder --install io.github.bhac
|
|
|
126
126
|
flatpak run io.github.bhack.mini-eq --check-deps
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
When routing, WirePlumber access, Flatpak permissions, runtime dependencies, or
|
|
130
|
+
shutdown behavior changed, also run the upstream runtime smoke test against the
|
|
131
|
+
installed local build before opening or merging the Flathub PR:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
python3 tools/check_flatpak_runtime.py --app-ref io.github.bhack.mini-eq//master
|
|
135
|
+
```
|
|
136
|
+
|
|
129
137
|
For a local source and full build check without installing the app:
|
|
130
138
|
|
|
131
139
|
```bash
|
|
@@ -94,6 +94,34 @@ If extensions.gnome.org asks for an extension screenshot, capture it from the
|
|
|
94
94
|
nested fake-control Shell documented in `extensions/gnome-shell/README.md` so no
|
|
95
95
|
real desktop, device, account, or path details are exposed.
|
|
96
96
|
|
|
97
|
+
## Flatpak Runtime Smoke
|
|
98
|
+
|
|
99
|
+
Run this after installing the local Flatpak build, and before release
|
|
100
|
+
publication or Flathub handoff, whenever PipeWire routing, WirePlumber access,
|
|
101
|
+
Flatpak permissions, runtime dependencies, or shutdown behavior changed. This
|
|
102
|
+
check temporarily routes a silent host PipeWire stream through Mini EQ and then
|
|
103
|
+
verifies that the stream is restored when the app exits, so keep it separate
|
|
104
|
+
from the generic preflight.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
|
108
|
+
flatpak install --user -y flathub org.flatpak.Builder//stable
|
|
109
|
+
flatpak run --command=flathub-build org.flatpak.Builder --install io.github.bhack.mini-eq.yaml
|
|
110
|
+
python3 tools/check_flatpak_runtime.py --app-ref io.github.bhack.mini-eq//master
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For shutdown changes, also run the installed Flatpak interactively, enable
|
|
114
|
+
system-wide EQ, close the GTK window, and confirm that the app exits without a
|
|
115
|
+
crash and streams are restored:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
flatpak run io.github.bhack.mini-eq//master --auto-route
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
There is also an experimental non-blocking GitHub Actions path for this check:
|
|
122
|
+
manually dispatch the `CI` workflow with `flatpak_runtime_smoke=true`. Treat it
|
|
123
|
+
as extra signal only until it has proven stable in the hosted runner.
|
|
124
|
+
|
|
97
125
|
## Build
|
|
98
126
|
|
|
99
127
|
```bash
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -120,8 +120,21 @@
|
|
|
120
120
|
color: alpha(var(--window-fg-color), 0.86);
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
overlay-split-view.mini-eq-workspace > widget.sidebar-pane {
|
|
124
|
+
background-color: transparent;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.mini-eq-dark overlay-split-view.mini-eq-workspace > widget.sidebar-pane {
|
|
128
|
+
background-color: transparent;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.utility-pane-scroller,
|
|
132
|
+
.utility-pane-scroller viewport {
|
|
133
|
+
background-color: transparent;
|
|
134
|
+
}
|
|
135
|
+
|
|
123
136
|
.utility-section {
|
|
124
|
-
padding:
|
|
137
|
+
padding: 7px 10px;
|
|
125
138
|
border-radius: 12px;
|
|
126
139
|
border: 1px solid var(--mini-border-soft);
|
|
127
140
|
background-color: var(--mini-utility-section-bg);
|
|
@@ -132,13 +145,13 @@
|
|
|
132
145
|
}
|
|
133
146
|
|
|
134
147
|
.utility-row {
|
|
135
|
-
padding:
|
|
148
|
+
padding: 4px 0;
|
|
136
149
|
border-radius: 0;
|
|
137
150
|
background-color: transparent;
|
|
138
151
|
}
|
|
139
152
|
|
|
140
153
|
.compare-row {
|
|
141
|
-
padding:
|
|
154
|
+
padding: 4px 0;
|
|
142
155
|
border-radius: 0;
|
|
143
156
|
background-color: transparent;
|
|
144
157
|
}
|
|
@@ -173,7 +186,7 @@
|
|
|
173
186
|
}
|
|
174
187
|
|
|
175
188
|
.preset-state-chip {
|
|
176
|
-
padding:
|
|
189
|
+
padding: 3px 10px;
|
|
177
190
|
border-radius: 999px;
|
|
178
191
|
font-size: 9pt;
|
|
179
192
|
font-weight: 800;
|
|
@@ -195,7 +208,7 @@
|
|
|
195
208
|
}
|
|
196
209
|
|
|
197
210
|
.system-state-chip {
|
|
198
|
-
padding:
|
|
211
|
+
padding: 3px 10px;
|
|
199
212
|
border-radius: 999px;
|
|
200
213
|
font-size: 9pt;
|
|
201
214
|
font-weight: 800;
|
|
@@ -222,7 +235,7 @@
|
|
|
222
235
|
}
|
|
223
236
|
|
|
224
237
|
.headroom-panel {
|
|
225
|
-
padding:
|
|
238
|
+
padding: 4px 0;
|
|
226
239
|
border-radius: 8px;
|
|
227
240
|
background-color: transparent;
|
|
228
241
|
}
|
|
@@ -240,7 +253,7 @@
|
|
|
240
253
|
}
|
|
241
254
|
|
|
242
255
|
.headroom-peak-chip {
|
|
243
|
-
padding:
|
|
256
|
+
padding: 3px 9px;
|
|
244
257
|
border-radius: 999px;
|
|
245
258
|
font-size: 9.5pt;
|
|
246
259
|
font-weight: 800;
|
|
@@ -277,13 +290,13 @@
|
|
|
277
290
|
}
|
|
278
291
|
|
|
279
292
|
.monitor-strip {
|
|
280
|
-
margin-top:
|
|
281
|
-
padding-top:
|
|
293
|
+
margin-top: 1px;
|
|
294
|
+
padding-top: 5px;
|
|
282
295
|
border-top: 1px solid var(--mini-border-subtle);
|
|
283
296
|
}
|
|
284
297
|
|
|
285
298
|
.monitor-detail-row {
|
|
286
|
-
min-height:
|
|
299
|
+
min-height: 24px;
|
|
287
300
|
}
|
|
288
301
|
|
|
289
302
|
.monitor-settings-button {
|
|
@@ -299,60 +312,7 @@
|
|
|
299
312
|
}
|
|
300
313
|
|
|
301
314
|
.loudness-meter-area {
|
|
302
|
-
min-height:
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
.utility-pane-dense .utility-section {
|
|
306
|
-
padding: 6px 8px;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
.utility-pane-dense .utility-row,
|
|
310
|
-
.utility-pane-dense .compare-row {
|
|
311
|
-
padding: 6px 8px;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
.utility-pane-dense .toolbar-button {
|
|
315
|
-
min-height: 32px;
|
|
316
|
-
padding-top: 2px;
|
|
317
|
-
padding-bottom: 2px;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
.utility-pane-dense .preset-row {
|
|
321
|
-
margin-top: 0;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
.utility-pane-dense .preset-state-chip,
|
|
325
|
-
.utility-pane-dense .system-state-chip,
|
|
326
|
-
.utility-pane-dense .compare-state-chip,
|
|
327
|
-
.utility-pane-dense .headroom-peak-chip {
|
|
328
|
-
padding-top: 2px;
|
|
329
|
-
padding-bottom: 2px;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
.utility-pane-dense .headroom-panel {
|
|
333
|
-
padding: 6px 8px;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
.utility-pane-dense .headroom-state {
|
|
337
|
-
font-size: 12pt;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
.utility-pane-dense .headroom-meter-area {
|
|
341
|
-
min-height: 10px;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
.utility-pane-dense .monitor-strip {
|
|
345
|
-
margin-top: 1px;
|
|
346
|
-
padding-top: 5px;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
.utility-pane-dense .monitor-detail-row {
|
|
350
|
-
min-height: 24px;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
.utility-pane-dense .monitor-settings-button {
|
|
354
|
-
min-width: 32px;
|
|
355
|
-
min-height: 32px;
|
|
315
|
+
min-height: 14px;
|
|
356
316
|
}
|
|
357
317
|
|
|
358
318
|
.headroom-state.headroom-safe {
|
|
@@ -352,7 +352,7 @@ class MiniEqWindow(
|
|
|
352
352
|
self.updating_ui = False
|
|
353
353
|
|
|
354
354
|
try:
|
|
355
|
-
self.controller.route_system_audio(False, announce=False)
|
|
355
|
+
self.controller.route_system_audio(False, announce=False, refresh_output=False)
|
|
356
356
|
except Exception:
|
|
357
357
|
pass
|
|
358
358
|
finally:
|
|
@@ -780,6 +780,11 @@ class MiniEqWindow(
|
|
|
780
780
|
self.controller.route_system_audio(enabled)
|
|
781
781
|
route_changed = True
|
|
782
782
|
except Exception as exc:
|
|
783
|
+
self.updating_ui = True
|
|
784
|
+
try:
|
|
785
|
+
switch.set_active(self.controller.routed)
|
|
786
|
+
finally:
|
|
787
|
+
self.updating_ui = False
|
|
783
788
|
self.set_status(str(exc))
|
|
784
789
|
finally:
|
|
785
790
|
self.update_eq_power_indicator()
|
|
@@ -34,7 +34,6 @@ from .window_utils import (
|
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
ADAPTIVE_NARROW_BREAKPOINT_SP = 1320
|
|
37
|
-
RESPONSIVE_COMFORTABLE_HEIGHT = 720
|
|
38
37
|
RESPONSIVE_ROOMY_HEIGHT = 960
|
|
39
38
|
COMPACT_BREAKPOINT_SP = 1080
|
|
40
39
|
DEFAULT_GRAPH_CONTENT_WIDTH = 900
|
|
@@ -184,6 +183,7 @@ class MiniEqWindowLayoutMixin:
|
|
|
184
183
|
root.append(toolbar_stack)
|
|
185
184
|
|
|
186
185
|
workspace = Adw.OverlaySplitView()
|
|
186
|
+
workspace.add_css_class("mini-eq-workspace")
|
|
187
187
|
workspace.set_hexpand(True)
|
|
188
188
|
workspace.set_vexpand(True)
|
|
189
189
|
workspace.set_valign(Gtk.Align.FILL)
|
|
@@ -219,6 +219,7 @@ class MiniEqWindowLayoutMixin:
|
|
|
219
219
|
right_column.add_css_class("utility-pane-shell")
|
|
220
220
|
|
|
221
221
|
right_scroller = Gtk.ScrolledWindow()
|
|
222
|
+
right_scroller.add_css_class("utility-pane-scroller")
|
|
222
223
|
right_scroller.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
|
|
223
224
|
right_scroller.set_propagate_natural_height(False)
|
|
224
225
|
right_scroller.set_size_request(310, -1)
|
|
@@ -620,32 +621,27 @@ class MiniEqWindowLayoutMixin:
|
|
|
620
621
|
ROOMY_FADER_SCROLLER_MIN_HEIGHT,
|
|
621
622
|
layout_height,
|
|
622
623
|
)
|
|
623
|
-
|
|
624
|
-
right_column.
|
|
625
|
-
right_column.
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
self.
|
|
630
|
-
|
|
631
|
-
monitor_panel.set_spacing(2 if dense else 4)
|
|
632
|
-
if dense:
|
|
633
|
-
right_column.add_css_class("utility-pane-dense")
|
|
634
|
-
else:
|
|
635
|
-
right_column.remove_css_class("utility-pane-dense")
|
|
624
|
+
right_column.set_spacing(responsive_value(6, 12, layout_height))
|
|
625
|
+
right_column.set_margin_top(responsive_value(2, 4, layout_height))
|
|
626
|
+
right_column.set_margin_bottom(responsive_value(0, 2, layout_height))
|
|
627
|
+
preset_section.set_spacing(responsive_value(5, 8, layout_height))
|
|
628
|
+
system_section.set_spacing(responsive_value(5, 8, layout_height))
|
|
629
|
+
self.headroom_panel.set_spacing(responsive_value(3, 7, layout_height))
|
|
630
|
+
self.headroom_meter_area.set_content_height(responsive_value(9, 14, layout_height))
|
|
631
|
+
monitor_panel.set_spacing(responsive_value(1, 4, layout_height))
|
|
636
632
|
|
|
637
633
|
if compact:
|
|
638
634
|
right_column.set_margin_start(18)
|
|
639
635
|
right_column.set_margin_end(12)
|
|
640
|
-
graph_shell.set_spacing(4
|
|
636
|
+
graph_shell.set_spacing(responsive_value(2, 4, layout_height))
|
|
641
637
|
self.graph_area.set_content_height(graph_height)
|
|
642
638
|
self.analyzer_area.set_content_height(analyzer_height)
|
|
643
639
|
self.graph_response_area.set_content_height(graph_height)
|
|
644
640
|
fader_section.set_spacing(COMPACT_FADER_SECTION_SPACING)
|
|
645
641
|
fader_section.set_vexpand(False)
|
|
646
642
|
fader_section.set_valign(Gtk.Align.START)
|
|
647
|
-
fader_section.set_margin_top(6
|
|
648
|
-
fader_section.set_margin_bottom(4
|
|
643
|
+
fader_section.set_margin_top(responsive_value(4, 6, layout_height))
|
|
644
|
+
fader_section.set_margin_bottom(responsive_value(3, 4, layout_height))
|
|
649
645
|
self.fader_scroller.set_vexpand(False)
|
|
650
646
|
self.fader_scroller.set_valign(Gtk.Align.START)
|
|
651
647
|
self.fader_scroller.set_min_content_height(fader_scroller_height)
|
|
@@ -679,21 +675,23 @@ class MiniEqWindowLayoutMixin:
|
|
|
679
675
|
|
|
680
676
|
right_column.set_margin_start(14)
|
|
681
677
|
right_column.set_margin_end(10)
|
|
682
|
-
graph_shell.set_spacing(2
|
|
678
|
+
graph_shell.set_spacing(responsive_value(2, 6, layout_height))
|
|
683
679
|
self.graph_area.set_content_height(graph_height)
|
|
684
680
|
self.analyzer_area.set_content_height(analyzer_height)
|
|
685
681
|
self.graph_response_area.set_content_height(graph_height)
|
|
686
|
-
fader_section.set_spacing(
|
|
682
|
+
fader_section.set_spacing(
|
|
683
|
+
responsive_value(COMPACT_FADER_SECTION_SPACING, DEFAULT_FADER_SECTION_SPACING, layout_height)
|
|
684
|
+
)
|
|
687
685
|
fader_section.set_vexpand(False)
|
|
688
686
|
fader_section.set_valign(Gtk.Align.START)
|
|
689
|
-
fader_section.set_margin_top(4
|
|
690
|
-
fader_section.set_margin_bottom(3
|
|
687
|
+
fader_section.set_margin_top(responsive_value(4, 8, layout_height))
|
|
688
|
+
fader_section.set_margin_bottom(responsive_value(3, 6, layout_height))
|
|
691
689
|
self.fader_scroller.set_vexpand(False)
|
|
692
690
|
self.fader_scroller.set_valign(Gtk.Align.START)
|
|
693
691
|
self.fader_scroller.set_min_content_height(fader_scroller_height)
|
|
694
692
|
self.fader_scroller.remove_css_class("fader-scroller-compact")
|
|
695
|
-
fader_grid.set_margin_top(2
|
|
696
|
-
fader_grid.set_margin_bottom(2
|
|
693
|
+
fader_grid.set_margin_top(responsive_value(2, 4, layout_height))
|
|
694
|
+
fader_grid.set_margin_bottom(responsive_value(2, 4, layout_height))
|
|
697
695
|
band_editor.remove_css_class("band-editor-compact-active")
|
|
698
696
|
band_editor.remove_css_class("band-editor-inline-compact")
|
|
699
697
|
band_editor.set_child_spacing(8)
|
|
@@ -12,6 +12,8 @@ SPA_ID_TYPE = "Spa:Id"
|
|
|
12
12
|
STREAM_OUTPUT_AUDIO = "Stream/Output/Audio"
|
|
13
13
|
AUDIO_SINK = "Audio/Sink"
|
|
14
14
|
FILTER_CHAIN_MODULE_NAME = "libpipewire-module-filter-chain"
|
|
15
|
+
PIPEWIRE_CLIENT_NAME = "Mini EQ"
|
|
16
|
+
PIPEWIRE_MEDIA_CATEGORY = "Manager"
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
@dataclass(frozen=True)
|
|
@@ -367,7 +369,15 @@ class WirePlumberBackend:
|
|
|
367
369
|
if not target.object_serial:
|
|
368
370
|
raise WirePlumberError(f"audio sink has no object.serial: {target_node_name}")
|
|
369
371
|
|
|
370
|
-
self.set_metadata_and_wait(stream.bound_id, TARGET_OBJECT_KEY, SPA_ID_TYPE, target.object_serial)
|
|
372
|
+
moved = self.set_metadata_and_wait(stream.bound_id, TARGET_OBJECT_KEY, SPA_ID_TYPE, target.object_serial)
|
|
373
|
+
if moved:
|
|
374
|
+
return
|
|
375
|
+
|
|
376
|
+
target_object, target_type = self.stream_target_object(stream.bound_id)
|
|
377
|
+
if target_object != target.object_serial or target_type not in {None, SPA_ID_TYPE}:
|
|
378
|
+
raise WirePlumberError(
|
|
379
|
+
f"WirePlumber did not acknowledge moving {stream.display_name} to {target_node_name}"
|
|
380
|
+
)
|
|
371
381
|
|
|
372
382
|
def stream_targets_node(self, stream_bound_id: int, target_node_name: str) -> bool:
|
|
373
383
|
target = self.audio_sink_by_name(target_node_name)
|
|
@@ -468,8 +478,12 @@ class WirePlumberBackend:
|
|
|
468
478
|
|
|
469
479
|
@staticmethod
|
|
470
480
|
def _new_core(Wp):
|
|
481
|
+
properties = Wp.Properties.new_empty()
|
|
482
|
+
properties.set("application.name", PIPEWIRE_CLIENT_NAME)
|
|
483
|
+
properties.set("media.category", PIPEWIRE_MEDIA_CATEGORY)
|
|
484
|
+
|
|
471
485
|
try:
|
|
472
|
-
return Wp.Core.new(None, None,
|
|
486
|
+
return Wp.Core.new(None, None, properties)
|
|
473
487
|
except TypeError:
|
|
474
488
|
return Wp.Core.new(None, None)
|
|
475
489
|
|
|
@@ -104,7 +104,7 @@ class WirePlumberStreamRouter:
|
|
|
104
104
|
self.routed_stream_ids.clear()
|
|
105
105
|
return restored
|
|
106
106
|
|
|
107
|
-
def refresh(self) -> bool:
|
|
107
|
+
def refresh(self, *, raise_errors: bool = False) -> bool:
|
|
108
108
|
if not self.enabled:
|
|
109
109
|
return False
|
|
110
110
|
|
|
@@ -114,6 +114,8 @@ class WirePlumberStreamRouter:
|
|
|
114
114
|
self.emit_status(f"routed {routed_now} stream(s) to {self.virtual_sink_name}")
|
|
115
115
|
except Exception as exc:
|
|
116
116
|
self.emit_status(f"routing warning: {exc}")
|
|
117
|
+
if raise_errors:
|
|
118
|
+
raise
|
|
117
119
|
|
|
118
120
|
return False
|
|
119
121
|
|
|
@@ -140,14 +142,14 @@ class WirePlumberStreamRouter:
|
|
|
140
142
|
if self.event_source_id == 0:
|
|
141
143
|
self.event_source_id = GLib.idle_add(self.on_stream_event_idle)
|
|
142
144
|
|
|
143
|
-
def start_monitoring(self) -> None:
|
|
145
|
+
def start_monitoring(self, *, require_initial_route: bool = False) -> None:
|
|
144
146
|
self.backend.connect()
|
|
145
147
|
self.accept_stream_events = True
|
|
146
148
|
|
|
147
149
|
if self.object_added_handler_id == 0:
|
|
148
150
|
self.object_added_handler_id = self.backend.connect_object_added(self.handle_object_added)
|
|
149
151
|
|
|
150
|
-
self.refresh()
|
|
152
|
+
self.refresh(raise_errors=require_initial_route)
|
|
151
153
|
|
|
152
154
|
def stop_monitoring(self) -> None:
|
|
153
155
|
self.accept_stream_events = False
|
|
@@ -162,7 +164,13 @@ class WirePlumberStreamRouter:
|
|
|
162
164
|
|
|
163
165
|
def enable(self) -> None:
|
|
164
166
|
self.enabled = True
|
|
165
|
-
|
|
167
|
+
try:
|
|
168
|
+
self.start_monitoring(require_initial_route=True)
|
|
169
|
+
except Exception:
|
|
170
|
+
self.enabled = False
|
|
171
|
+
self.stop_monitoring()
|
|
172
|
+
self.restore_output_streams()
|
|
173
|
+
raise
|
|
166
174
|
|
|
167
175
|
def disable(self, announce: bool = True) -> None:
|
|
168
176
|
if not self.enabled and not self.routed_stream_ids:
|
|
@@ -82,6 +82,7 @@ tests/test_mini_eq_wireplumber_stream_router.py
|
|
|
82
82
|
tests/test_version_metadata.py
|
|
83
83
|
tools/benchmark_fader_drag.py
|
|
84
84
|
tools/check_flathub_manifest_drift.py
|
|
85
|
+
tools/check_flatpak_runtime.py
|
|
85
86
|
tools/check_gnome_shell_extension.py
|
|
86
87
|
tools/check_wireplumber_gi.py
|
|
87
88
|
tools/demo_runtime.py
|
|
@@ -58,7 +58,9 @@ def test_begin_close_request_shutdown_restores_routing_before_delayed_quit(monke
|
|
|
58
58
|
updating_ui=False,
|
|
59
59
|
route_switch=FakeSwitch(True),
|
|
60
60
|
controller=SimpleNamespace(
|
|
61
|
-
route_system_audio=lambda enabled, announce=True: calls.append(
|
|
61
|
+
route_system_audio=lambda enabled, announce=True, refresh_output=True: calls.append(
|
|
62
|
+
("route", enabled, announce, refresh_output)
|
|
63
|
+
)
|
|
62
64
|
),
|
|
63
65
|
update_info_label=lambda: calls.append("info"),
|
|
64
66
|
update_status_summary=lambda: calls.append("summary"),
|
|
@@ -74,7 +76,7 @@ def test_begin_close_request_shutdown_restores_routing_before_delayed_quit(monke
|
|
|
74
76
|
assert fake_window.updating_ui is False
|
|
75
77
|
assert fake_window.close_finish_source_id == 321
|
|
76
78
|
assert calls == [
|
|
77
|
-
("route", False, False),
|
|
79
|
+
("route", False, False, False),
|
|
78
80
|
"info",
|
|
79
81
|
"summary",
|
|
80
82
|
("visible", False),
|
|
@@ -86,3 +88,32 @@ def test_begin_close_request_shutdown_restores_routing_before_delayed_quit(monke
|
|
|
86
88
|
|
|
87
89
|
assert fake_window.close_finish_source_id == 0
|
|
88
90
|
assert application.quit_count == 1
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def test_on_route_changed_resets_switch_when_routing_fails() -> None:
|
|
94
|
+
calls: list[object] = []
|
|
95
|
+
|
|
96
|
+
def fail_route(_enabled: bool) -> None:
|
|
97
|
+
raise RuntimeError("metadata permission denied")
|
|
98
|
+
|
|
99
|
+
fake_window = SimpleNamespace(
|
|
100
|
+
updating_ui=False,
|
|
101
|
+
controller=SimpleNamespace(
|
|
102
|
+
eq_enabled=True,
|
|
103
|
+
routed=False,
|
|
104
|
+
route_system_audio=fail_route,
|
|
105
|
+
),
|
|
106
|
+
update_eq_power_indicator=lambda: calls.append("power"),
|
|
107
|
+
update_info_label=lambda: calls.append("info"),
|
|
108
|
+
update_status_summary=lambda: calls.append("summary"),
|
|
109
|
+
update_focus_summary=lambda: calls.append("focus"),
|
|
110
|
+
set_status=lambda message: calls.append(("status", message)),
|
|
111
|
+
notify_control_state_changed=lambda: calls.append("notify"),
|
|
112
|
+
)
|
|
113
|
+
route_switch = FakeSwitch(True)
|
|
114
|
+
|
|
115
|
+
window.MiniEqWindow.on_route_changed(fake_window, route_switch, None)
|
|
116
|
+
|
|
117
|
+
assert route_switch.get_active() is False
|
|
118
|
+
assert fake_window.updating_ui is False
|
|
119
|
+
assert ("status", "metadata permission denied") in calls
|