Integrate with systemd, add custom idle-inhibitor, fix configs

This commit is contained in:
Aleksey Samoilov 2024-07-20 19:42:39 +04:00
parent 13f80dd784
commit 239d0ae2f0
14 changed files with 239 additions and 24 deletions

2
debian/control vendored
View file

@ -9,6 +9,6 @@ Rules-Requires-Root: no
Package: tileos-settings-qtile Package: tileos-settings-qtile
Architecture: all Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends} Depends: ${shlibs:Depends}, ${misc:Depends}, python3-tenacity, python3-dbus-next
Conflicts: tileos-settings-river, tileos-settings-sway Conflicts: tileos-settings-river, tileos-settings-sway
Description: default settings for Qtile on TileOS Description: default settings for Qtile on TileOS

View file

@ -1,12 +1,12 @@
[ [
{ {
"label": "Lock", "label": "Lock",
"exec": "~/.config/swaylock/lock.sh", "exec": "bash -c ~/.config/swaylock/lock.sh",
"icon": "system-lock-screen" "icon": "system-lock-screen"
}, },
{ {
"label": "Logout", "label": "Logout",
"exec": "qtile cmd-obj -o cmd -f shutdown", "exec": "bash -c /usr/share/qtile/scripts/qtile-exit.sh",
"icon": "system-log-out" "icon": "system-log-out"
}, },
{ {

View file

@ -1,13 +1,27 @@
#!/usr/bin/env bash #!/bin/bash
export XDG_CURRENT_DESKTOP=wlroots export XDG_CURRENT_DESKTOP=wlroots
export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-wlroots}" export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-wlroots}"
export XDG_SESSION_TYPE=wayland export XDG_SESSION_TYPE=wayland
VARIABLES="DESKTOP_SESSION XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE" VARIABLES="DESKTOP_SESSION XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE"
VARIABLES="${VARIABLES} DISPLAY WAYLAND_DISPLAY" VARIABLES="${VARIABLES} DISPLAY WAYLAND_DISPLAY"
SESSION_TARGET="qtile-session.target"
SESSION_XDG_AUTOSTART_TARGET="qtile-xdg-autostart.target"
SNI_CHECK="/usr/share/qtile/scripts/wait-sni-ready"
# shellcheck disable=SC2086
dbus-update-activation-environment --systemd ${VARIABLES:- --all} & dbus-update-activation-environment --systemd ${VARIABLES:- --all} &
# reset failed state of all user units
systemctl --user reset-failed
# shellcheck disable=SC2086
systemctl --user import-environment $VARIABLES
systemctl --user start "$SESSION_TARGET"
# Wait for StatusNotifierWatcher is available and start XDG Autostart target
"$SNI_CHECK" && systemctl --user start "$SESSION_XDG_AUTOSTART_TARGET"
# PolicyKit Agent # PolicyKit Agent
/usr/bin/mate-polkit /usr/bin/mate-polkit
@ -25,7 +39,3 @@ pcmanfm-qt -d &
# Clipboard daemon # Clipboard daemon
pkill wl-paste pkill wl-paste
wl-paste --watch cliphist store & wl-paste --watch cliphist store &
# Power daemon
pkill poweralertd
poweralertd &

View file

@ -1,6 +1,6 @@
timeout 240 'light -G > /tmp/brightness && light -S 10' resume 'light -S $([ -f /tmp/brightness ] && cat /tmp/brightness || echo 100%)' timeout 240 'light -G > /tmp/brightness && light -S 10' resume 'light -S $([ -f /tmp/brightness ] && cat /tmp/brightness || echo 100%)'
timeout 300 ~/.config/swaylock/lock.sh timeout 300 ~/.config/swaylock/lock.sh
timeout 600 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' timeout 600 'wlopm --off \*' resume 'wlopm --on \*'
before-sleep 'playerctl pause' before-sleep 'playerctl pause'
before-sleep ~/.config/swaylock/lock.sh before-sleep ~/.config/swaylock/lock.sh
lock ~/.config/swaylock/lock.sh lock ~/.config/swaylock/lock.sh

View file

@ -0,0 +1,81 @@
#!/usr/bin/env python3
import sys
from dataclasses import dataclass
from signal import SIGINT, SIGTERM, signal
from threading import Event
from pywayland.client.display import Display
from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import (
ZwpIdleInhibitManagerV1,
)
from pywayland.protocol.wayland.wl_compositor import WlCompositor
from pywayland.protocol.wayland.wl_registry import WlRegistryProxy
from pywayland.protocol.wayland.wl_surface import WlSurface
@dataclass
class GlobalRegistry:
surface: WlSurface | None = None
inhibit_manager: ZwpIdleInhibitManagerV1 | None = None
def handle_registry_global(
wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int
) -> None:
global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry()
if iface_name == "wl_compositor":
compositor = wl_registry.bind(id_num, WlCompositor, version)
global_registry.surface = compositor.create_surface() # type: ignore
elif iface_name == "zwp_idle_inhibit_manager_v1":
global_registry.inhibit_manager = wl_registry.bind(
id_num, ZwpIdleInhibitManagerV1, version
)
def main() -> None:
done = Event()
signal(SIGINT, lambda _, __: done.set())
signal(SIGTERM, lambda _, __: done.set())
global_registry = GlobalRegistry()
display = Display()
display.connect()
registry = display.get_registry() # type: ignore
registry.user_data = global_registry
registry.dispatcher["global"] = handle_registry_global
def shutdown() -> None:
display.dispatch()
display.roundtrip()
display.disconnect()
display.dispatch()
display.roundtrip()
if global_registry.surface is None or global_registry.inhibit_manager is None:
print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.")
shutdown()
sys.exit(1)
inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore
global_registry.surface
)
display.dispatch()
display.roundtrip()
print("Inhibiting idle...")
done.wait()
print("Shutting down...")
inhibitor.destroy()
shutdown()
if __name__ == "__main__":
main()

View file

@ -0,0 +1,10 @@
[Unit]
Description=Shutdown running Qtile session
DefaultDependencies=no
StopWhenUnneeded=true
Conflicts=graphical-session.target graphical-session-pre.target
After=graphical-session.target graphical-session-pre.target
Conflicts=qtile-session.target
After=qtile-session.target

View file

@ -0,0 +1,6 @@
[Unit]
Description=Qtile session
Documentation=man:systemd.special(7)
BindsTo=graphical-session.target
Wants=graphical-session-pre.target
After=graphical-session-pre.target

View file

@ -0,0 +1,10 @@
# Systemd provides xdg-desktop-autostart.target as a way to process XDG autostart
# desktop files. The target sets RefuseManualStart though, and thus cannot be
# used from scripts.
#
[Unit]
Description=XDG autostart for Qtile session
Documentation=man:systemd.special(7) man:systemd-xdg-autostart-generator(8)
BindsTo=xdg-desktop-autostart.target
PartOf=qtile-session.target
After=qtile-session.target

View file

@ -0,0 +1,10 @@
[Unit]
Description=Automatically restart the swayidle when its configuration changes
PartOf=swayidle.service
After=swayidle.service
[Path]
PathChanged=%h/.config/swayidle/config
[Install]
WantedBy=qtile-session.target

View file

@ -0,0 +1,6 @@
[Service]
ExecStart=systemctl --user restart swayidle.service
Type=oneshot
[Install]
WantedBy=graphical-session.target

View file

@ -0,0 +1,12 @@
[Unit]
Description=Idle manager for Wayland
Documentation=man:swayidle(1)
PartOf=graphical-session.target
ConditionPathExists=/usr/bin/swayidle
[Service]
Type=simple
ExecStart=/usr/bin/swayidle -w
[Install]
WantedBy=qtile-session.target

View file

@ -1,22 +1,13 @@
#!/bin/bash #!/bin/bash
# Qtile swayidle toggle # Qtile idle-inhibitor toggle
function toggle { function toggle {
if pgrep "swayidle" > /dev/null if pgrep -f "wayland-idle-inhibitor" > /dev/null
then then
pkill swayidle pkill -f wayland-idle-inhibitor
notify-send -r 5556 -u normal " Screensaver Disabled" notify-send -r 5556 -u normal " Screensaver Disabled"
else else
cd /tmp /usr/bin/wayland-idle-inhibitor.py &
grim screen.png
# Delete existing image
rm screen-out.png
#Adds a blur and vignette
ffmpeg -i screen.png -vf "gblur=sigma=10, vignette=PI/5" -c:a copy screen-out.png
swayidle \
timeout 5 'qtile cmd-obj -o core -f hide_cursor' resume 'qtile cmd-obj -o core -f unhide_cursor' \
timeout 300 'swaylock -f -i screen-out.png' \
timeout 600 'wlopm --off \*' resume 'wlopm --on \*' &
notify-send -r 5556 -u normal " Screensaver Enabled" notify-send -r 5556 -u normal " Screensaver Enabled"
fi fi
} }
@ -26,7 +17,7 @@ case $1 in
toggle toggle
;; ;;
*) *)
if pgrep "swayidle" > /dev/null if pgrep -f "wayland-idle-inhibitor" > /dev/null
then then
icon="" icon=""
else else

View file

@ -0,0 +1,18 @@
#!/bin/bash
VARIABLES="DESKTOP_SESSION XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE"
VARIABLES="${VARIABLES} DISPLAY WAYLAND_DISPLAY"
SESSION_SHUTDOWN_TARGET="qtile-session-shutdown.target"
session_cleanup () {
# stop the session target and unset the variables
systemctl --user start --job-mode=replace-irreversibly "$SESSION_SHUTDOWN_TARGET"
if [ -n "$VARIABLES" ]; then
# shellcheck disable=SC2086
systemctl --user unset-environment $VARIABLES
fi
}
session_cleanup
qtile cmd-obj -o cmd -f shutdown

View file

@ -0,0 +1,61 @@
#!/usr/bin/python3
"""
A simple script for waiting until an org.kde.StatusNotifierItem host implementation
is available and ready.
Dependencies: dbus-next, tenacity
"""
import asyncio
import logging
import os
from dbus_next.aio import MessageBus
from tenacity import retry, stop_after_delay, wait_fixed
LOG = logging.getLogger("wait-sni-host")
TIMEOUT = int(os.environ.get("SNI_WAIT_TIMEOUT", default=25))
@retry(reraise=True, stop=stop_after_delay(TIMEOUT), wait=wait_fixed(0.5))
async def get_service(bus, name, object_path, interface_name):
"""Wait until the service appears on the bus"""
introspection = await bus.introspect(name, object_path)
proxy = bus.get_proxy_object(name, object_path, introspection)
return proxy.get_interface(interface_name)
async def wait_sni_host(bus: MessageBus):
"""Wait until a StatusNotifierWatcher service is available and has a
StatusNotifierHost instance"""
future = asyncio.get_event_loop().create_future()
async def on_host_registered():
value = await sni_watcher.get_is_status_notifier_host_registered()
LOG.debug("StatusNotifierHostRegistered: %s", value)
if value:
future.set_result(value)
sni_watcher = await get_service(bus, "org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher",
"org.kde.StatusNotifierWatcher")
sni_watcher.on_status_notifier_host_registered(on_host_registered)
# fetch initial value
await on_host_registered()
return await asyncio.wait_for(future, timeout=TIMEOUT)
async def main():
"""asyncio entrypoint"""
bus = await MessageBus().connect()
try:
await wait_sni_host(bus)
LOG.info("Successfully waited for org.kde.StatusNotifierHost")
# pylint: disable=broad-except
except Exception as err:
LOG.error("Failed to wait for org.kde.StatusNotifierHost: %s",
str(err))
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
asyncio.run(main())