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:
@@ -28,9 +28,9 @@ if [[ "$1" == "--toggle" ]]; then
|
|||||||
BRIGHT=$(_bright_for "$NEXT")
|
BRIGHT=$(_bright_for "$NEXT")
|
||||||
brightnessctl set "${BRIGHT}%" -q
|
brightnessctl set "${BRIGHT}%" -q
|
||||||
|
|
||||||
# Feedback wob
|
# Feedback overlay
|
||||||
if [[ -p /tmp/wob.fifo ]]; then
|
if [[ -p /tmp/wob.fifo ]]; then
|
||||||
echo "$BRIGHT" > /tmp/wob.fifo 2>/dev/null || true
|
echo "b:${BRIGHT}" > /tmp/wob.fifo 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Rafraîchir le module waybar
|
# Rafraîchir le module waybar
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ def get_node_name(target):
|
|||||||
|
|
||||||
def set_sink_vol(v):
|
def set_sink_vol(v):
|
||||||
run(['wpctl', 'set-volume', '-l', '1.0', '@DEFAULT_AUDIO_SINK@', f'{v}%'])
|
run(['wpctl', 'set-volume', '-l', '1.0', '@DEFAULT_AUDIO_SINK@', f'{v}%'])
|
||||||
_wob(v)
|
_wob(f'v:{v}')
|
||||||
|
|
||||||
def set_source_vol(v):
|
def set_source_vol(v):
|
||||||
run(['wpctl', 'set-volume', '@DEFAULT_AUDIO_SOURCE@', f'{v}%'])
|
run(['wpctl', 'set-volume', '@DEFAULT_AUDIO_SOURCE@', f'{v}%'])
|
||||||
@@ -216,14 +216,14 @@ def get_brightness():
|
|||||||
def set_brightness(v):
|
def set_brightness(v):
|
||||||
v = max(1, v)
|
v = max(1, v)
|
||||||
run(['brightnessctl', 'set', f'{v}%', '-q'])
|
run(['brightnessctl', 'set', f'{v}%', '-q'])
|
||||||
_wob(v)
|
_wob(f'b:{v}')
|
||||||
|
|
||||||
def _wob(v):
|
def _wob(msg):
|
||||||
fifo = '/tmp/wob.fifo'
|
fifo = '/tmp/wob.fifo'
|
||||||
if os.path.exists(fifo):
|
if os.path.exists(fifo):
|
||||||
try:
|
try:
|
||||||
fd = os.open(fifo, os.O_WRONLY | os.O_NONBLOCK)
|
fd = os.open(fifo, os.O_WRONLY | os.O_NONBLOCK)
|
||||||
os.write(fd, f'{v}\n'.encode())
|
os.write(fd, f'{msg}\n'.encode())
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ case "$1" in
|
|||||||
down) brightnessctl set "${STEP}%-" -q ;;
|
down) brightnessctl set "${STEP}%-" -q ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Feedback wob si le daemon tourne
|
# Feedback overlay
|
||||||
if [[ -p "$FIFO" ]] && pgrep -x wob >/dev/null 2>&1; then
|
if [[ -p "$FIFO" ]]; then
|
||||||
BRIGHT=$(brightnessctl -m 2>/dev/null | awk -F, '{gsub(/%/,"",$4); print int($4)}')
|
BRIGHT=$(brightnessctl -m 2>/dev/null | awk -F, '{gsub(/%/,"",$4); print int($4)}')
|
||||||
echo "$BRIGHT" > "$FIFO"
|
echo "b:${BRIGHT}" > "$FIFO"
|
||||||
fi
|
fi
|
||||||
|
|||||||
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()
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# wob-start.sh — lance le daemon wob via FIFO
|
# wob-start.sh — lance l'overlay violet-chaton via FIFO
|
||||||
# Appelé au démarrage de session (autostart)
|
# Appelé au démarrage de session (autostart)
|
||||||
|
|
||||||
FIFO="/tmp/wob.fifo"
|
FIFO="/tmp/wob.fifo"
|
||||||
|
|
||||||
pkill wob 2>/dev/null
|
pkill -f wob-overlay.py 2>/dev/null
|
||||||
rm -f "$FIFO"
|
rm -f "$FIFO"
|
||||||
mkfifo "$FIFO"
|
mkfifo "$FIFO"
|
||||||
|
|
||||||
# Ouvrir le FIFO en lecture+écriture sur fd3 :
|
# Ouvrir le FIFO en lecture+écriture sur fd3 :
|
||||||
# - empêche wob de recevoir EOF entre deux écritures
|
# empêche l'overlay de recevoir EOF entre deux écritures
|
||||||
# - wob hérite du fd et reste vivant même après la fin de ce script
|
|
||||||
exec 3<> "$FIFO"
|
exec 3<> "$FIFO"
|
||||||
wob --config "$HOME/.config/wob.ini" <&3 &
|
python3 "$HOME/.config/waybar/scripts/wob-overlay.py" &
|
||||||
disown $!
|
disown $!
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ case "$1" in
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# Feedback wob si le daemon tourne
|
# Feedback overlay
|
||||||
if [[ -p "$FIFO" ]] && pgrep -x wob >/dev/null 2>&1; then
|
if [[ -p "$FIFO" ]]; then
|
||||||
echo "$(get_vol)" > "$FIFO"
|
echo "v:$(get_vol)" > "$FIFO"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user