Initial ThinkPad Hyprland dotfiles
This commit is contained in:
211
config/hypr/Scripts/power-menu.py
Executable file
211
config/hypr/Scripts/power-menu.py
Executable file
@@ -0,0 +1,211 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import gi
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version("Gdk", "3.0")
|
||||
from gi.repository import Gdk, Gtk # noqa: E402
|
||||
|
||||
|
||||
HYPR_DIR = Path.home() / ".config" / "hypr"
|
||||
THEME_DIR = HYPR_DIR / "Themes"
|
||||
CURRENT_WALLPAPER = HYPR_DIR / "current-wallpaper"
|
||||
|
||||
|
||||
DEFAULT_THEME = {
|
||||
"NAME": "Power",
|
||||
"ACCENT": "#f38ba8",
|
||||
"ACCENT_2": "#cba6f7",
|
||||
"BACKGROUND_HEX": "#18141f",
|
||||
"PANEL_HEX": "#313244",
|
||||
"FOREGROUND": "#f5e0dc",
|
||||
"MUTED": "#a6adc8",
|
||||
"SELECTED_TEXT": "#11111b",
|
||||
}
|
||||
|
||||
|
||||
def parse_theme_file(path):
|
||||
theme = {}
|
||||
|
||||
for line in path.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||
line = line.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
|
||||
key, value = line.split("=", 1)
|
||||
key = key.strip()
|
||||
value = value.strip()
|
||||
|
||||
try:
|
||||
parsed = shlex.split(value)
|
||||
theme[key] = parsed[0] if parsed else ""
|
||||
except ValueError:
|
||||
theme[key] = value.strip("\"'")
|
||||
|
||||
return theme
|
||||
|
||||
|
||||
def load_current_theme():
|
||||
current_wallpaper = ""
|
||||
if CURRENT_WALLPAPER.exists():
|
||||
current_wallpaper = CURRENT_WALLPAPER.read_text(encoding="utf-8", errors="ignore").strip()
|
||||
|
||||
for theme_file in sorted(THEME_DIR.glob("*.theme")):
|
||||
theme = parse_theme_file(theme_file)
|
||||
if theme.get("WALLPAPER") == current_wallpaper:
|
||||
return {**DEFAULT_THEME, **theme}
|
||||
|
||||
rose = THEME_DIR / "rose-night.theme"
|
||||
if rose.exists():
|
||||
return {**DEFAULT_THEME, **parse_theme_file(rose)}
|
||||
|
||||
return DEFAULT_THEME
|
||||
|
||||
|
||||
def run(command):
|
||||
subprocess.Popen(command, start_new_session=True)
|
||||
Gtk.main_quit()
|
||||
|
||||
|
||||
class PowerMenu(Gtk.Window):
|
||||
def __init__(self):
|
||||
super().__init__(title="Power")
|
||||
|
||||
self.theme = load_current_theme()
|
||||
self.set_decorated(False)
|
||||
self.set_resizable(False)
|
||||
self.set_keep_above(True)
|
||||
self.set_position(Gtk.WindowPosition.CENTER)
|
||||
self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
|
||||
self.set_skip_taskbar_hint(True)
|
||||
self.set_skip_pager_hint(True)
|
||||
self.set_app_paintable(True)
|
||||
self.connect("key-press-event", self.on_key_press)
|
||||
self.connect("focus-out-event", lambda *_: Gtk.main_quit())
|
||||
|
||||
overlay = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=18)
|
||||
overlay.get_style_context().add_class("power-shell")
|
||||
|
||||
title = Gtk.Label(label=self.theme.get("NAME", "Power"))
|
||||
title.get_style_context().add_class("power-title")
|
||||
overlay.pack_start(title, False, False, 0)
|
||||
|
||||
grid = Gtk.Grid()
|
||||
grid.set_column_spacing(14)
|
||||
grid.set_row_spacing(14)
|
||||
grid.set_halign(Gtk.Align.CENTER)
|
||||
|
||||
actions = [
|
||||
("", "Sperren", ["hyprlock"]),
|
||||
("", "Ruhezustand", ["systemctl", "suspend"]),
|
||||
("", "Abmelden", ["hyprctl", "dispatch", "exit"]),
|
||||
("", "Neustart", ["systemctl", "reboot"]),
|
||||
("⏻", "Ausschalten", ["systemctl", "poweroff"]),
|
||||
("", "Abbrechen", None),
|
||||
]
|
||||
|
||||
for index, (icon, label, command) in enumerate(actions):
|
||||
button = self.make_button(icon, label, command)
|
||||
grid.attach(button, index % 3, index // 3, 1, 1)
|
||||
|
||||
overlay.pack_start(grid, False, False, 0)
|
||||
self.add(overlay)
|
||||
self.apply_css()
|
||||
|
||||
def make_button(self, icon, label, command):
|
||||
button = Gtk.Button()
|
||||
button.get_style_context().add_class("power-button")
|
||||
button.set_size_request(150, 118)
|
||||
button.set_relief(Gtk.ReliefStyle.NONE)
|
||||
|
||||
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
|
||||
box.set_halign(Gtk.Align.CENTER)
|
||||
box.set_valign(Gtk.Align.CENTER)
|
||||
|
||||
icon_label = Gtk.Label(label=icon)
|
||||
icon_label.get_style_context().add_class("power-icon")
|
||||
text_label = Gtk.Label(label=label)
|
||||
text_label.get_style_context().add_class("power-label")
|
||||
|
||||
box.pack_start(icon_label, False, False, 0)
|
||||
box.pack_start(text_label, False, False, 0)
|
||||
button.add(box)
|
||||
|
||||
if command:
|
||||
button.connect("clicked", lambda *_: run(command))
|
||||
else:
|
||||
button.connect("clicked", lambda *_: Gtk.main_quit())
|
||||
|
||||
return button
|
||||
|
||||
def apply_css(self):
|
||||
css = f"""
|
||||
window {{
|
||||
background: transparent;
|
||||
}}
|
||||
|
||||
.power-shell {{
|
||||
margin: 0;
|
||||
padding: 24px;
|
||||
border-radius: 26px;
|
||||
border: 1px solid {self.theme["ACCENT"]};
|
||||
background: alpha({self.theme["BACKGROUND_HEX"]}, 0.94);
|
||||
box-shadow: 0 22px 70px alpha(#000000, 0.55);
|
||||
}}
|
||||
|
||||
.power-title {{
|
||||
color: {self.theme["FOREGROUND"]};
|
||||
font-family: "JetBrainsMono Nerd Font", "JetBrains Mono", sans-serif;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
}}
|
||||
|
||||
.power-button {{
|
||||
color: {self.theme["FOREGROUND"]};
|
||||
background: alpha({self.theme["PANEL_HEX"]}, 0.82);
|
||||
border: 1px solid alpha({self.theme["ACCENT_2"]}, 0.42);
|
||||
border-radius: 18px;
|
||||
transition: 160ms ease;
|
||||
}}
|
||||
|
||||
.power-button:hover,
|
||||
.power-button:focus {{
|
||||
color: {self.theme["SELECTED_TEXT"]};
|
||||
background: linear-gradient(135deg, {self.theme["ACCENT"]}, {self.theme["ACCENT_2"]});
|
||||
border-color: {self.theme["ACCENT"]};
|
||||
}}
|
||||
|
||||
.power-icon {{
|
||||
font-family: "JetBrainsMono Nerd Font", "JetBrains Mono", sans-serif;
|
||||
font-size: 34px;
|
||||
font-weight: 800;
|
||||
}}
|
||||
|
||||
.power-label {{
|
||||
font-family: "JetBrainsMono Nerd Font", "JetBrains Mono", sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}}
|
||||
"""
|
||||
|
||||
provider = Gtk.CssProvider()
|
||||
provider.load_from_data(css.encode("utf-8"))
|
||||
Gtk.StyleContext.add_provider_for_screen(
|
||||
Gdk.Screen.get_default(),
|
||||
provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
)
|
||||
|
||||
def on_key_press(self, _widget, event):
|
||||
if event.keyval in (Gdk.KEY_Escape, Gdk.KEY_q):
|
||||
Gtk.main_quit()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
window = PowerMenu()
|
||||
window.show_all()
|
||||
Gtk.main()
|
||||
Reference in New Issue
Block a user