Compare commits

..
14 Commits
24 changed files with 231 additions and 154 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ pacman -S dunst rofi hyprland
Зависимости для `eww`:
```Bash
pacman -S xorg-xrand jq xdg-desktop-portal-gtk hyprpolkitagent python-dbus python-evdev python-gobject libnotify wl-clipboard cliphist socat
pacman -S xorg-xrand jq xdg-desktop-portal-gtk hyprpolkitagent hyprlock hypridle python-dbus python-evdev python-gobject libnotify wl-clipboard cliphist socat
```
Для корректной работы `python-evdev` добавляет своего пользователя в группу `input`:
+2 -1
View File
@@ -138,12 +138,13 @@
(statswidget :reveal_state s_rev :reveal_var s_var)
(volumewidget :reveal_state v_rev :reveal_var v_var))))
;; дополнительный бар (без трея)
;; дополнительный бар
(defwidget side_bar [mon_key t_rev t_var s_rev s_var v_rev v_var]
(centerbox :class "bar-inner"
(box :halign "start" (workspaces :ws_data {ws_data[mon_key]}))
(box :halign "center" (timewidget :reveal_state t_rev :reveal_var t_var))
(box :halign "end" :space-evenly false
(tray_dynamic)
(kb_widget)
(statswidget :reveal_state s_rev :reveal_var s_var)
(volumewidget :reveal_state v_rev :reveal_var v_var))))
+55 -59
View File
@@ -1,10 +1,9 @@
#!/usr/bin/env python3
import asyncio
import json
import subprocess
import os
import sys
import socket
import threading
import time
class UnifiedWorkspaceManager:
def __init__(self):
@@ -16,11 +15,8 @@ class UnifiedWorkspaceManager:
self.monitors_cache = {}
self.load_icon_configuration()
self.clients_refresh()
self.monitors_refresh()
def load_icon_configuration(self):
# тянем иконки из конфига
config_path = os.path.join(self.script_directory, "workspaces_map.json")
try:
with open(config_path, 'r') as file:
@@ -28,11 +24,16 @@ class UnifiedWorkspaceManager:
except:
self.icon_map = {"default": "", "no-icon": ""}
def monitors_refresh(self):
# обновляем инфу по мониторам
async def monitors_refresh(self):
try:
raw = subprocess.check_output(["hyprctl", "-j", "monitors"], stderr=subprocess.DEVNULL)
monitors = json.loads(raw)
proc = await asyncio.create_subprocess_exec(
"hyprctl", "-j", "monitors",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL
)
stdout, _ = await proc.communicate()
if proc.returncode == 0:
monitors = json.loads(stdout.decode())
self.monitors_cache = {
m['name']: {
"id": m['id'],
@@ -43,11 +44,16 @@ class UnifiedWorkspaceManager:
except:
self.monitors_cache = {}
def clients_refresh(self):
# полный сброс и пересборка кэша окон
async def clients_refresh(self):
try:
raw = subprocess.check_output(["hyprctl", "-j", "clients"], stderr=subprocess.DEVNULL)
clients = json.loads(raw)
proc = await asyncio.create_subprocess_exec(
"hyprctl", "-j", "clients",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL
)
stdout, _ = await proc.communicate()
if proc.returncode == 0:
clients = json.loads(stdout.decode())
self.clients_cache = {
c['address'].strip().replace('0x', ''): {
"class": c['class'],
@@ -59,22 +65,18 @@ class UnifiedWorkspaceManager:
self.clients_cache = {}
def get_current_state_json(self):
# собираем финальный json
try:
output = {}
for mon_name, mon_data in self.monitors_cache.items():
m_id = mon_data["id"]
active_id = mon_data["active_workspace_id"]
focused = mon_data["focused"]
# готовим 10 слотов
workspaces = {
str(i): {"exists": False, "active": False, "focused": False, "urgent": False, "icons": []}
for i in range(1, 11)
}
# раскидываем окна по воркспейсам
for addr, client in self.clients_cache.items():
if client['monitor_id'] == m_id:
ws_id = str(client['workspace_id'])
@@ -88,12 +90,10 @@ class UnifiedWorkspaceManager:
if icon not in slot["icons"]:
slot["icons"].append(icon)
# помечаем текущий активный воркспейс
curr_ws = str(active_id)
if curr_ws in workspaces:
workspaces[curr_ws].update({"active": True, "focused": focused, "exists": True})
# рисуем no-icon
for ws in workspaces.values():
if ws["exists"] and not ws["icons"]:
ws["icons"] = [self.icon_map.get("no-icon", "")]
@@ -105,22 +105,26 @@ class UnifiedWorkspaceManager:
return "{}"
def push_update(self):
# отдаём json в stdout при изменении
current = self.get_current_state_json()
if current != self.last_sent_json:
self.last_sent_json = current
sys.stdout.write(current + '\n')
sys.stdout.flush()
def update_client(self, window_address):
# обновляем окно
async def update_client(self, window_address):
try:
clean_addr = window_address.replace('0x', '')
search_addr = f"0x{clean_addr}"
raw = subprocess.check_output(["hyprctl", "-j", "clients"], stderr=subprocess.DEVNULL)
clients = json.loads(raw)
proc = await asyncio.create_subprocess_exec(
"hyprctl", "-j", "clients",
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.DEVNULL
)
stdout, _ = await proc.communicate()
if proc.returncode == 0:
clients = json.loads(stdout.decode())
target = next((c for c in clients if c['address'] == search_addr), None)
if target:
@@ -129,44 +133,39 @@ class UnifiedWorkspaceManager:
"workspace_id": target['workspace']['id'],
"monitor_id": target['monitor']
}
else:
return
self.clients_cache.pop(clean_addr, None)
except:
# если что-то отвалилось, то просто пересобираем всё
self.clients_refresh()
await self.clients_refresh()
def run(self):
async def run(self):
await self.clients_refresh()
await self.monitors_refresh()
self.push_update()
def event_socket_listener():
# слушаем сокет хайпера
signature = os.environ.get('HYPRLAND_INSTANCE_SIGNATURE')
socket_path = f"/run/user/{os.getuid()}/hypr/{signature}/.socket2.sock"
while True:
try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
sock.connect(socket_path)
buf = ""
reader, writer = await asyncio.open_unix_connection(socket_path)
while True:
data = sock.recv(4096).decode('utf-8', errors='ignore')
if not data: break
buf += data
line_bytes = await reader.readline()
if not line_bytes:
break
if '\n' in buf:
lines = buf.split('\n')
buf = lines.pop()
line = line_bytes.decode('utf-8', errors='ignore').strip()
if ">>" not in line:
continue
trigger = False
for line in lines:
if ">>" not in line: continue
event, args = line.split('>>')
trigger = False
# ивенты с окнами
if event in ["openwindow", "movewindow"]:
addr = args.split(',')[0].replace('0x', '')
self.update_client(addr)
await self.update_client(addr)
trigger = True
elif event == "closewindow":
@@ -175,9 +174,8 @@ class UnifiedWorkspaceManager:
self.urgent_window_addresses.discard(addr)
trigger = True
# ивенты с мониторами
elif event in ["workspace", "workspacev2", "monitoradded", "monitorremoved"]:
self.monitors_refresh()
await self.monitors_refresh()
trigger = True
elif event in ["focusedmon", "focusedmonv2"]:
@@ -186,7 +184,6 @@ class UnifiedWorkspaceManager:
self.monitors_cache[name]["focused"] = (name == mon_name)
trigger = True
# алерты
elif event == "urgent":
self.urgent_window_addresses.add(args.replace('0x', ''))
trigger = True
@@ -199,15 +196,14 @@ class UnifiedWorkspaceManager:
if trigger:
self.push_update()
except:
time.sleep(2) # реконнект, если хайпер отвалился
# слушаем поток в фоне
threading.Thread(target=event_socket_listener, daemon=True).start()
try:
while True: time.sleep(100)
except KeyboardInterrupt: sys.exit(0)
except (asyncio.CancelledError, KeyboardInterrupt):
break
except Exception as e:
await asyncio.sleep(2)
if __name__ == "__main__":
UnifiedWorkspaceManager().run()
try:
asyncio.run(UnifiedWorkspaceManager().run())
except KeyboardInterrupt:
sys.exit(0)
+1 -1
View File
@@ -4,7 +4,7 @@
"firefox": "",
"code-oss": "󰨞",
"org.telegram.desktop": "",
"kitty": "",
"foot": "",
"steam": "",
"Spotify": "",
"discord": "󰙯",
+5 -3
View File
@@ -70,7 +70,7 @@ bindl = $mainMod, F11, exec, playerctl play-pause
bindl = $mainMod, F12, exec, playerctl next
# resize mode
bind = $mainMod, R, exec, hyprctl keyword general:col.active_border "rgb(e3a1d2)"
bind = $mainMod, R, exec, hyprctl keyword general:col.active_border "rgb(e3a1d2)" ; hyprctl keyword general:border_size 5
bind = $mainMod, R, submap, resize
submap = resize
@@ -78,8 +78,10 @@ submap = resize
binde = , left, resizeactive, -20 0
binde = , up, resizeactive, 0 -20
binde = , down, resizeactive, 0 20
bind = , escape, exec, hyprctl keyword general:col.active_border "rgb(a8afe1)"
bind = , escape, exec, hyprctl keyword general:col.active_border "rgb(a8afe1)" ; hyprctl keyword general:border_size 1
bind = , escape, submap, reset
bind = , return, exec, hyprctl keyword general:col.active_border "rgb(a8afe1)"
bind = , return, exec, hyprctl keyword general:col.active_border "rgb(a8afe1)" ; hyprctl keyword general:border_size 1
bind = , return, submap, reset
submap = reset
bind = $mainMod, L, exec, loginctl lock-session
+3 -1
View File
@@ -4,4 +4,6 @@ exec-once = wl-paste --type image --watch cliphist store
exec-once = systemctl --user start hyprpolkitagent
exec-once = gsettings set org.gnome.desktop.interface gtk-theme "Adwaita-dark"
exec-once = gsettings set org.gnome.desktop.interface color-scheme "prefer-dark"
exec-once = eww daemon && eww open-many bar_0 bar_1 wallpaper_0 wallpaper_1
exec-once = eww daemon && sleep 1 && eww open-many bar_0 bar_1 wallpaper_0 wallpaper_1
exec-once = hypridle --grace 15
exec-once = python3 /home/pyrschtjag/Documents/.ntfy-notify/ntfy-notify.py
@@ -6,4 +6,5 @@ input {
kb_rules =
follow_mouse = 1
sensitivity = 0
force_no_accel = true
}
+2
View File
@@ -0,0 +1,2 @@
monitor = HDMI-A-1, 1920x1080@60, 0x0, 1
monitor = DVI-I-1, 1600x900@60, 1920x120, 1
+4
View File
@@ -0,0 +1,4 @@
$mainMod = SUPER
$terminal = foot
//$fileManager = kitty mc
$menu = rofi -show drun
@@ -50,3 +50,11 @@ windowrule {
opacity = 1.0 override 1.0 override 1.0 override
float = true
}
windowrule {
name = steam-app
match:class = ^(steam_app_)(.*)
fullscreen = on
fullscreen_state = 2
monitor = HDMI-A-1
}
+24
View File
@@ -0,0 +1,24 @@
general {
lock_cmd = pidof hyprlock || hyprlock
before_sleep_cmd = loginctl lock-session
after_sleep_cmd = hyprctl dispatch dpms on
ignore_dbus_inhibit = false
ignore_wayland_inhibit = false
ignore_systemd_inhibit = false
}
listener {
timeout = 300
on-timeout = loginctl lock-session
}
listener {
timeout = 360
on-timeout = hyprctl dispatch dpms off
on-resume = hyprctl dispatch dpms on
}
listener {
timeout = 600
on-timeout = systemctl suspend
}
+14 -14
View File
@@ -1,14 +1,14 @@
source = ~/.config/hypr/monitors.conf
source = ~/.config/hypr/workspaces.conf
source = ~/.config/hypr/programs.conf
source = ~/.config/hypr/exec.conf
source = ~/.config/hypr/env.conf
source = ~/.config/hypr/general.conf
source = ~/.config/hypr/decoration.conf
source = ~/.config/hypr/animations.conf
source = ~/.config/hypr/dwindle.conf
source = ~/.config/hypr/master.conf
source = ~/.config/hypr/misc.conf
source = ~/.config/hypr/input.conf
source = ~/.config/hypr/bind.conf
source = ~/.config/hypr/windowrule.conf
source = ~/.config/hypr/config/monitors.conf
source = ~/.config/hypr/config/workspaces.conf
source = ~/.config/hypr/config/programs.conf
source = ~/.config/hypr/config/exec.conf
source = ~/.config/hypr/config/env.conf
source = ~/.config/hypr/config/general.conf
source = ~/.config/hypr/config/decoration.conf
source = ~/.config/hypr/config/animations.conf
//source = ~/.config/hypr/config/dwindle.conf
source = ~/.config/hypr/config/master.conf
source = ~/.config/hypr/config/misc.conf
source = ~/.config/hypr/config/input.conf
source = ~/.config/hypr/config/bind.conf
source = ~/.config/hypr/config/windowrule.conf
+40
View File
@@ -0,0 +1,40 @@
general {
hide_cursor = true
ignore_empty_input = true
}
background {
monitor =
path = screenshot
blur_passes = 2
blur_size = 5
}
input-field {
monitor =
size = 250, 60
outline_thickness = 2
dots_size = 0.2
dots_spacing = 0.2
dots_center = true
outer_color = rgba(168, 175, 225, 0.5)
inner_color = rgba(30, 30, 46, 0.5)
font_color = rgb(202, 211, 245)
fade_on_empty = true
placeholder_text = <i>Password...</i>
hide_input = false
position = 0, -154
halign = center
valign = center
}
label {
monitor =
text = $TIME
color = rgba(202, 211, 245, 0.8)
font_size = 94
font_family = Noto Sans Bold
position = 0, 0
halign = center
valign = center
}
-2
View File
@@ -1,2 +0,0 @@
monitor = HDMI-A-1, 1920x1080@60, 0x0, 1
monitor = DVI-I-1, 1600x900@60, -1600x140, 1
-4
View File
@@ -1,4 +0,0 @@
$mainMod = SUPER
$terminal = kitty
$fileManager = kitty mc
$menu = rofi -show drun
+7 -4
View File
@@ -1,9 +1,12 @@
#!/bin/bash
MONITOR_NAME="DVI-I-1"
WIDTH=1920
HEIGHT=120
WIDHT_FIXED=$((WIDTH+10))
hyprctl keyword monitor "$MONITOR_NAME, 1600x900@60, 0x-2000, 1" && eww reload
notify-send -t 1500 "$MONITOR_NAME: Game Mode" "Monitor moved to 0x-2000"
hyprctl keyword monitor "$MONITOR_NAME, 1600x900@60, ${WIDHT_FIXED}x${HEIGHT}, 1" && eww reload
notify-send -t 1500 "$MONITOR_NAME: Game Mode" "Monitor moved to ${WIDHT_FIXED}x${HEIGHT}"
if [[ "$1" == *"="* ]]; then
VAR=$1
@@ -13,5 +16,5 @@ else
"$@"
fi
hyprctl -- keyword monitor "$MONITOR_NAME, 1600x900@60, -1600x0, 1" && eww reload
notify-send -t 1500 "$MONITOR_NAME: Desktop Mode" "Monitor returned to -1600x0"
hyprctl -- keyword monitor "$MONITOR_NAME, 1600x900@60, ${WIDTH}x${HEIGHT}, 1" && eww reload
notify-send -t 1500 "$MONITOR_NAME: Desktop Mode" "Monitor returned to ${WIDTH}x${HEIGHT}"