feat(wob): remplacer wob par overlay GTK arrondi violet-chaton
- Nouveau wob-overlay.py : fenêtre GTK3+GtkLayerShell transparente avec barre arrondie (border-radius 12px), couleur pink pour volume et cyan pour luminosité - Protocole FIFO typé : v:N pour volume, b:N pour luminosité - wob-start.sh lance wob-overlay.py au lieu du binaire wob - wob-volume.sh, wob-brightness.sh, vc-media-popup.py et power-profile.sh mis à jour pour envoyer les messages typés - Correction bug vc-media-popup.py : les deux sliders audio contrôlaient @DEFAULT_AUDIO_SINK@ (mauvaise capture de target)
This commit is contained in:
215
INSTALL/configs/waybar/scripts/wob-overlay.py
Normal file
215
INSTALL/configs/waybar/scripts/wob-overlay.py
Normal file
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env python3
|
||||
# wob-overlay.py — Overlay volume/luminosité violet-chaton (remplace wob)
|
||||
# Protocole FIFO : "v:N" = volume (rose), "b:N" = luminosité (cyan), "N" = volume
|
||||
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkLayerShell', '0.1')
|
||||
from gi.repository import Gtk, Gdk, GtkLayerShell, GLib
|
||||
import os
|
||||
import threading
|
||||
|
||||
FIFO = '/tmp/wob.fifo'
|
||||
POPUP_WIDTH = 280
|
||||
POPUP_HEIGHT = -1
|
||||
MARGIN_BOTTOM = 48
|
||||
HIDE_DELAY = 1200 # ms
|
||||
|
||||
CSS = """
|
||||
window {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
#wob-box {
|
||||
background-color: rgba(38, 21, 55, 0.92);
|
||||
border: 2px solid rgba(92, 73, 108, 0.80);
|
||||
border-radius: 12px;
|
||||
padding: 10px 16px;
|
||||
}
|
||||
|
||||
#wob-icon {
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 15px;
|
||||
min-width: 22px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
#wob-pct {
|
||||
color: #f8f8f2;
|
||||
font-family: "JetBrainsMono Nerd Font";
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
min-width: 36px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* ── Volume (rose) ──────────────────────────────────────────── */
|
||||
|
||||
progressbar.vol trough {
|
||||
background-color: rgba(92, 73, 108, 0.45);
|
||||
border-radius: 5px;
|
||||
min-height: 7px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
progressbar.vol progress {
|
||||
background-color: #ff79c6;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
min-height: 7px;
|
||||
}
|
||||
|
||||
/* ── Luminosité (cyan) ──────────────────────────────────────── */
|
||||
|
||||
progressbar.bright trough {
|
||||
background-color: rgba(92, 73, 108, 0.45);
|
||||
border-radius: 5px;
|
||||
min-height: 7px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
progressbar.bright progress {
|
||||
background-color: #8be9fd;
|
||||
border-radius: 5px;
|
||||
border: none;
|
||||
min-height: 7px;
|
||||
}
|
||||
"""
|
||||
|
||||
VOL_ICONS = ['', '', '']
|
||||
BRIGHT_ICONS = ['', '', '']
|
||||
|
||||
def _icon(icons, pct):
|
||||
if pct <= 0:
|
||||
return icons[0]
|
||||
if pct < 50:
|
||||
return icons[1]
|
||||
return icons[2]
|
||||
|
||||
|
||||
class WobOverlay(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._hide_timer = None
|
||||
|
||||
# ── Layer shell ──────────────────────────────────────────────────────
|
||||
GtkLayerShell.init_for_window(self)
|
||||
GtkLayerShell.set_layer(self, GtkLayerShell.Layer.OVERLAY)
|
||||
GtkLayerShell.set_anchor(self, GtkLayerShell.Edge.BOTTOM, True)
|
||||
GtkLayerShell.set_margin(self, GtkLayerShell.Edge.BOTTOM, MARGIN_BOTTOM)
|
||||
GtkLayerShell.set_exclusive_zone(self, -1)
|
||||
GtkLayerShell.set_keyboard_mode(self, GtkLayerShell.KeyboardMode.NONE)
|
||||
|
||||
self.set_decorated(False)
|
||||
self.set_resizable(False)
|
||||
self.set_app_paintable(True)
|
||||
self.set_default_size(POPUP_WIDTH, POPUP_HEIGHT)
|
||||
|
||||
# Fenêtre transparente
|
||||
screen = self.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
if visual:
|
||||
self.set_visual(visual)
|
||||
|
||||
# ── CSS ──────────────────────────────────────────────────────────────
|
||||
provider = Gtk.CssProvider()
|
||||
provider.load_from_data(CSS.encode())
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
Gdk.Screen.get_default(), provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
|
||||
)
|
||||
|
||||
# ── Layout ───────────────────────────────────────────────────────────
|
||||
outer = Gtk.Box()
|
||||
outer.set_name('wob-box')
|
||||
self.add(outer)
|
||||
|
||||
self._icon_lbl = Gtk.Label()
|
||||
self._icon_lbl.set_name('wob-icon')
|
||||
outer.pack_start(self._icon_lbl, False, False, 0)
|
||||
|
||||
self._bar = Gtk.ProgressBar()
|
||||
self._bar.set_hexpand(True)
|
||||
self._bar.set_valign(Gtk.Align.CENTER)
|
||||
outer.pack_start(self._bar, True, True, 0)
|
||||
|
||||
self._pct_lbl = Gtk.Label()
|
||||
self._pct_lbl.set_name('wob-pct')
|
||||
self._pct_lbl.set_halign(Gtk.Align.END)
|
||||
outer.pack_end(self._pct_lbl, False, False, 0)
|
||||
|
||||
self.show_all()
|
||||
self.hide()
|
||||
|
||||
def show_value(self, val, kind='v'):
|
||||
"""Appelé depuis le thread FIFO via GLib.idle_add."""
|
||||
val = max(0, min(100, val))
|
||||
fraction = val / 100.0
|
||||
|
||||
# Icône + couleur selon le type
|
||||
if kind == 'b':
|
||||
icon = _icon(BRIGHT_ICONS, val)
|
||||
css_class = 'bright'
|
||||
else:
|
||||
icon = _icon(VOL_ICONS, val)
|
||||
css_class = 'vol'
|
||||
|
||||
sc = self._bar.get_style_context()
|
||||
for c in ['vol', 'bright']:
|
||||
sc.remove_class(c)
|
||||
sc.add_class(css_class)
|
||||
|
||||
self._icon_lbl.set_label(icon)
|
||||
self._icon_lbl.set_markup(
|
||||
f'<span foreground="{"#8be9fd" if kind == "b" else "#ff79c6"}">{icon}</span>'
|
||||
)
|
||||
self._bar.set_fraction(fraction)
|
||||
self._pct_lbl.set_label(f'{val}%')
|
||||
|
||||
self.show()
|
||||
|
||||
# Reset timer
|
||||
if self._hide_timer:
|
||||
GLib.source_remove(self._hide_timer)
|
||||
self._hide_timer = GLib.timeout_add(HIDE_DELAY, self._do_hide)
|
||||
|
||||
def _do_hide(self):
|
||||
self.hide()
|
||||
self._hide_timer = None
|
||||
return False
|
||||
|
||||
|
||||
def _fifo_reader(overlay):
|
||||
"""Thread : lit le FIFO en boucle et schedule les mises à jour UI."""
|
||||
while True:
|
||||
try:
|
||||
if not os.path.exists(FIFO):
|
||||
os.mkfifo(FIFO)
|
||||
with open(FIFO, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
# Protocole : "v:N", "b:N" ou plain "N"
|
||||
if ':' in line:
|
||||
kind, _, raw = line.partition(':')
|
||||
else:
|
||||
kind, raw = 'v', line
|
||||
try:
|
||||
val = int(raw)
|
||||
GLib.idle_add(overlay.show_value, val, kind)
|
||||
except ValueError:
|
||||
pass
|
||||
except OSError:
|
||||
import time
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
win = WobOverlay()
|
||||
win.connect('destroy', Gtk.main_quit)
|
||||
|
||||
t = threading.Thread(target=_fifo_reader, args=(win,), daemon=True)
|
||||
t.start()
|
||||
|
||||
Gtk.main()
|
||||
Reference in New Issue
Block a user