mirror of
https://github.com/rywng/dotfiles.git
synced 2024-11-22 19:01:50 +08:00
Compare commits
No commits in common. "018da3a582fe750444f5f60fbb167bdc562989f3" and "99a5fe023a499f9d466f496808b5be6c8b9e5a7c" have entirely different histories.
018da3a582
...
99a5fe023a
@ -1,6 +1,6 @@
|
|||||||
# output=<not set>
|
# output=<not set>
|
||||||
font=sans:size=14
|
font=sans:size=14
|
||||||
dpi-aware=auto
|
dpi-aware=yes
|
||||||
prompt="> "
|
prompt="> "
|
||||||
# icon-theme=hicolor
|
# icon-theme=hicolor
|
||||||
# icons-enabled=yes
|
# icons-enabled=yes
|
||||||
@ -9,7 +9,7 @@ fields=name
|
|||||||
filter-desktop=yes
|
filter-desktop=yes
|
||||||
# fuzzy=yes
|
# fuzzy=yes
|
||||||
show-actions=true
|
show-actions=true
|
||||||
terminal=/bin/kitty -e
|
# terminal=$TERMINAL -e # Note: you cannot actually use environment variables here
|
||||||
# launch-prefix=<not set>
|
# launch-prefix=<not set>
|
||||||
|
|
||||||
# lines=15
|
# lines=15
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# output=<not set>
|
# output=<not set>
|
||||||
font=sans:size=14
|
font=sans:size=14
|
||||||
dpi-aware=auto
|
dpi-aware=yes
|
||||||
prompt="> "
|
prompt="> "
|
||||||
# icon-theme=hicolor
|
# icon-theme=hicolor
|
||||||
# icons-enabled=yes
|
# icons-enabled=yes
|
||||||
@ -9,7 +9,7 @@ fields=name
|
|||||||
filter-desktop=yes
|
filter-desktop=yes
|
||||||
# fuzzy=yes
|
# fuzzy=yes
|
||||||
show-actions=true
|
show-actions=true
|
||||||
terminal=/bin/kitty -e
|
# terminal=$TERMINAL -e # Note: you cannot actually use environment variables here
|
||||||
# launch-prefix=<not set>
|
# launch-prefix=<not set>
|
||||||
|
|
||||||
# lines=15
|
# lines=15
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit fa5aa0c57609254ce23d7479e344d0c3e292efd9
|
Subproject commit 4fd5fd0e0ceef326f1b569354449187c9323014e
|
@ -11,29 +11,6 @@ bindswitch --reload --locked lid:off output $laptop enable
|
|||||||
force_display_urgency_hint 500 ms
|
force_display_urgency_hint 500 ms
|
||||||
smart_borders no_gaps
|
smart_borders no_gaps
|
||||||
|
|
||||||
# floating window
|
|
||||||
for_window [window_role = "pop-up"] floating enable
|
|
||||||
for_window [window_role = "bubble"] floating enable
|
|
||||||
for_window [window_role = "dialog"] floating enable
|
|
||||||
for_window [window_type = "dialog"] floating enable
|
|
||||||
for_window [window_role = "task_dialog"] floating enable
|
|
||||||
for_window [window_type = "menu"] floating enable
|
|
||||||
for_window [app_id = "floating"] floating enable
|
|
||||||
for_window [app_id = "floating_update"] floating enable, resize set width 1024px height 768px
|
|
||||||
for_window [class = "(?i)pinentry"] floating enable
|
|
||||||
for_window [title = "Administrator privileges required"] floating enable
|
|
||||||
|
|
||||||
for_window [class="^Steam$" title="^Friends$"] floating enable
|
|
||||||
for_window [class="^Steam$" title="Steam - News"] floating enable
|
|
||||||
for_window [class="^Steam$" title=".* - Chat"] floating enable
|
|
||||||
for_window [class="^Steam$" title="^Settings$"] floating enable
|
|
||||||
for_window [class="^Steam$" title=".* - event started"] floating enable
|
|
||||||
for_window [class="^Steam$" title=".* CD key"] floating enable
|
|
||||||
for_window [class="^Steam$" title="^Steam - Self Updater$"] floating enable
|
|
||||||
for_window [class="^Steam$" title="^Screenshot Uploader$"] floating enable
|
|
||||||
for_window [class="^Steam$" title="^Steam Guard - Computer Authorization Required$"] floating enable
|
|
||||||
for_window [title="^Steam Keyboard$"] floating enable
|
|
||||||
|
|
||||||
seat * xcursor_theme Adwaita
|
seat * xcursor_theme Adwaita
|
||||||
|
|
||||||
seat * hide_cursor 10000
|
seat * hide_cursor 10000
|
||||||
|
@ -19,14 +19,14 @@ if test "$choice" = lock; then
|
|||||||
sleep_time=10
|
sleep_time=10
|
||||||
fi
|
fi
|
||||||
sleep 0.3
|
sleep 0.3
|
||||||
# playerctl stop
|
playerctl stop
|
||||||
|
|
||||||
bright=$(xbacklight -get)
|
bright=$(light)
|
||||||
|
|
||||||
swayidle -w \
|
swayidle -w \
|
||||||
timeout 5 "xbacklight -set 0" resume "xbacklight -set $bright" \
|
timeout 5 "light -S 1" resume "light -S $bright" \
|
||||||
|
timeout $sleep_time 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
|
||||||
&
|
&
|
||||||
# timeout $sleep_time 'swaymsg "output * power off"' resume 'swaymsg "output * power on"' \
|
|
||||||
idlepid=$!
|
idlepid=$!
|
||||||
|
|
||||||
# swaylock -e -c 282828 --inside-color 00000003
|
# swaylock -e -c 282828 --inside-color 00000003
|
||||||
@ -35,7 +35,7 @@ if test "$choice" = lock; then
|
|||||||
|
|
||||||
kill $idlepid
|
kill $idlepid
|
||||||
swaymsg "output * power on"
|
swaymsg "output * power on"
|
||||||
xbacklight -set $bright
|
light -S $bright
|
||||||
elif test -n "$choice"; then
|
elif test -n "$choice"; then
|
||||||
systemctl $choice
|
systemctl $choice
|
||||||
fi
|
fi
|
||||||
|
@ -1,290 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
"""
|
|
||||||
Automatically assign a dedicated systemd scope to the GUI applications
|
|
||||||
launched in the same cgroup as the compositor. This could be helpful for
|
|
||||||
implementing cgroup-based resource management and would be necessary when
|
|
||||||
`systemd-oomd` is in use.
|
|
||||||
|
|
||||||
Limitations: The script is using i3ipc window:new event to detect application
|
|
||||||
launches and would fail to detect background apps or special surfaces.
|
|
||||||
Therefore it's recommended to supplement the script with use of systemd user
|
|
||||||
services for such background apps.
|
|
||||||
|
|
||||||
Dependencies: dbus-next, i3ipc, psutil, tenacity, python-xlib
|
|
||||||
"""
|
|
||||||
import argparse
|
|
||||||
import asyncio
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import socket
|
|
||||||
import struct
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from dbus_next import Variant
|
|
||||||
from dbus_next.aio import MessageBus
|
|
||||||
from dbus_next.errors import DBusError
|
|
||||||
from i3ipc import Event
|
|
||||||
from i3ipc.aio import Con, Connection
|
|
||||||
from psutil import Process
|
|
||||||
from tenacity import retry, retry_if_exception_type, stop_after_attempt
|
|
||||||
from Xlib import X
|
|
||||||
from Xlib.display import Display
|
|
||||||
|
|
||||||
try:
|
|
||||||
# requires python-xlib >= 0.30
|
|
||||||
from Xlib.ext import res as XRes
|
|
||||||
except ImportError:
|
|
||||||
XRes = None
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger("assign-cgroups")
|
|
||||||
SD_BUS_NAME = "org.freedesktop.systemd1"
|
|
||||||
SD_OBJECT_PATH = "/org/freedesktop/systemd1"
|
|
||||||
SD_SLICE_FORMAT = "app-{app_id}.slice"
|
|
||||||
SD_UNIT_FORMAT = "app-{app_id}-{unique}.scope"
|
|
||||||
# Ids of known launcher applications that are not special surfaces. When the app is
|
|
||||||
# started using one of those, it should be moved to a new cgroup.
|
|
||||||
# Launcher should only be listed here if it creates cgroup of its own.
|
|
||||||
LAUNCHER_APPS = ["nwgbar", "nwgdmenu", "nwggrid"]
|
|
||||||
|
|
||||||
SD_UNIT_ESCAPE_RE = re.compile(r"[^\w:.\\]", re.ASCII)
|
|
||||||
|
|
||||||
|
|
||||||
def escape_app_id(app_id: str) -> str:
|
|
||||||
"""Escape app_id for systemd APIs.
|
|
||||||
|
|
||||||
The "unit prefix" must consist of one or more valid characters (ASCII letters,
|
|
||||||
digits, ":", "-", "_", ".", and "\"). The total length of the unit name including
|
|
||||||
the suffix must not exceed 256 characters. [systemd.unit(5)]
|
|
||||||
|
|
||||||
We also want to escape "-" to avoid creating extra slices.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def repl(match):
|
|
||||||
return "".join([f"\\x{x:02x}" for x in match.group().encode()])
|
|
||||||
|
|
||||||
return SD_UNIT_ESCAPE_RE.sub(repl, app_id)
|
|
||||||
|
|
||||||
|
|
||||||
LAUNCHER_APP_CGROUPS = [
|
|
||||||
SD_SLICE_FORMAT.format(app_id=escape_app_id(app)) for app in LAUNCHER_APPS
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def get_cgroup(pid: int) -> Optional[str]:
|
|
||||||
"""
|
|
||||||
Get cgroup identifier for the process specified by pid.
|
|
||||||
Assumes cgroups v2 unified hierarchy.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
with open(f"/proc/{pid}/cgroup", "r") as file:
|
|
||||||
cgroup = file.read()
|
|
||||||
return cgroup.strip().split(":")[-1]
|
|
||||||
except OSError:
|
|
||||||
LOG.exception("Error geting cgroup info")
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_pid_by_socket(sockpath: str) -> int:
|
|
||||||
"""
|
|
||||||
getsockopt (..., SO_PEERCRED, ...) returns the following structure
|
|
||||||
struct ucred
|
|
||||||
{
|
|
||||||
pid_t pid; /* s32: PID of sending process. */
|
|
||||||
uid_t uid; /* u32: UID of sending process. */
|
|
||||||
gid_t gid; /* u32: GID of sending process. */
|
|
||||||
};
|
|
||||||
See also: socket(7), unix(7)
|
|
||||||
"""
|
|
||||||
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
|
|
||||||
sock.connect(sockpath)
|
|
||||||
ucred = sock.getsockopt(
|
|
||||||
socket.SOL_SOCKET, socket.SO_PEERCRED, struct.calcsize("iII")
|
|
||||||
)
|
|
||||||
pid, _, _ = struct.unpack("iII", ucred)
|
|
||||||
return pid
|
|
||||||
|
|
||||||
|
|
||||||
class XlibHelper:
|
|
||||||
"""Utility class for some X11-specific logic"""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.display = Display()
|
|
||||||
self.use_xres = self._try_init_xres()
|
|
||||||
|
|
||||||
def _try_init_xres(self) -> bool:
|
|
||||||
if XRes is None or self.display.query_extension(XRes.extname) is None:
|
|
||||||
LOG.warning(
|
|
||||||
"X-Resource extension is not supported. "
|
|
||||||
"Process identification for X11 applications will be less reliable."
|
|
||||||
)
|
|
||||||
return False
|
|
||||||
ver = self.display.res_query_version()
|
|
||||||
LOG.info(
|
|
||||||
"X-Resource version %d.%d",
|
|
||||||
ver.server_major,
|
|
||||||
ver.server_minor,
|
|
||||||
)
|
|
||||||
return (ver.server_major, ver.server_minor) >= (1, 2)
|
|
||||||
|
|
||||||
def get_net_wm_pid(self, wid: int) -> int:
|
|
||||||
"""Get PID from _NET_WM_PID property of X11 window"""
|
|
||||||
window = self.display.create_resource_object("window", wid)
|
|
||||||
net_wm_pid = self.display.get_atom("_NET_WM_PID")
|
|
||||||
pid = window.get_full_property(net_wm_pid, X.AnyPropertyType)
|
|
||||||
|
|
||||||
if pid is None:
|
|
||||||
raise Exception("Failed to get PID from _NET_WM_PID")
|
|
||||||
return int(pid.value.tolist()[0])
|
|
||||||
|
|
||||||
def get_xres_client_id(self, wid: int) -> int:
|
|
||||||
"""Get PID from X server via X-Resource extension"""
|
|
||||||
res = self.display.res_query_client_ids(
|
|
||||||
[{"client": wid, "mask": XRes.LocalClientPIDMask}]
|
|
||||||
)
|
|
||||||
for cid in res.ids:
|
|
||||||
if cid.spec.client > 0 and cid.spec.mask == XRes.LocalClientPIDMask:
|
|
||||||
for value in cid.value:
|
|
||||||
return value
|
|
||||||
raise Exception("Failed to get PID via X-Resource extension")
|
|
||||||
|
|
||||||
def get_window_pid(self, wid: int) -> Optional[int]:
|
|
||||||
"""Get PID of X11 window"""
|
|
||||||
if self.use_xres:
|
|
||||||
return self.get_xres_client_id(wid)
|
|
||||||
|
|
||||||
return self.get_net_wm_pid(wid)
|
|
||||||
|
|
||||||
|
|
||||||
class CGroupHandler:
|
|
||||||
"""Main logic: handle i3/sway IPC events and start systemd transient units."""
|
|
||||||
|
|
||||||
def __init__(self, bus: MessageBus, conn: Connection):
|
|
||||||
self._bus = bus
|
|
||||||
self._conn = conn
|
|
||||||
self._xhelper: Optional[XlibHelper] = None
|
|
||||||
try:
|
|
||||||
self._xhelper = XlibHelper()
|
|
||||||
# pylint: disable=broad-except
|
|
||||||
except Exception as exc:
|
|
||||||
LOG.warning("Failed to connect to X11 display: %s", exc)
|
|
||||||
|
|
||||||
async def connect(self):
|
|
||||||
"""asynchronous initialization code"""
|
|
||||||
# pylint: disable=attribute-defined-outside-init
|
|
||||||
introspection = await self._bus.introspect(SD_BUS_NAME, SD_OBJECT_PATH)
|
|
||||||
self._sd_proxy = self._bus.get_proxy_object(
|
|
||||||
SD_BUS_NAME, SD_OBJECT_PATH, introspection
|
|
||||||
)
|
|
||||||
self._sd_manager = self._sd_proxy.get_interface(f"{SD_BUS_NAME}.Manager")
|
|
||||||
|
|
||||||
self._compositor_pid = get_pid_by_socket(self._conn.socket_path)
|
|
||||||
self._compositor_cgroup = get_cgroup(self._compositor_pid)
|
|
||||||
assert self._compositor_cgroup is not None
|
|
||||||
LOG.info("compositor:%s %s", self._compositor_pid, self._compositor_cgroup)
|
|
||||||
|
|
||||||
self._conn.on(Event.WINDOW_NEW, self._on_new_window)
|
|
||||||
return self
|
|
||||||
|
|
||||||
def get_pid(self, con: Con) -> Optional[int]:
|
|
||||||
"""Get PID from IPC response (sway), X-Resource or _NET_WM_PID (i3)"""
|
|
||||||
if isinstance(con.pid, int) and con.pid > 0:
|
|
||||||
return con.pid
|
|
||||||
|
|
||||||
if con.window is not None and self._xhelper is not None:
|
|
||||||
return self._xhelper.get_window_pid(con.window)
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
def cgroup_change_needed(self, cgroup: Optional[str]) -> bool:
|
|
||||||
"""Check criteria for assigning current app into an isolated cgroup"""
|
|
||||||
if cgroup is None:
|
|
||||||
return False
|
|
||||||
for launcher in LAUNCHER_APP_CGROUPS:
|
|
||||||
if launcher in cgroup:
|
|
||||||
return True
|
|
||||||
return cgroup == self._compositor_cgroup
|
|
||||||
|
|
||||||
@retry(
|
|
||||||
reraise=True,
|
|
||||||
retry=retry_if_exception_type(DBusError),
|
|
||||||
stop=stop_after_attempt(3),
|
|
||||||
)
|
|
||||||
async def assign_scope(self, app_id: str, proc: Process):
|
|
||||||
"""
|
|
||||||
Assign process (and all unassigned children) to the
|
|
||||||
app-{app_id}.slice/app{app_id}-{pid}.scope cgroup
|
|
||||||
"""
|
|
||||||
app_id = escape_app_id(app_id)
|
|
||||||
sd_slice = SD_SLICE_FORMAT.format(app_id=app_id)
|
|
||||||
sd_unit = SD_UNIT_FORMAT.format(app_id=app_id, unique=proc.pid)
|
|
||||||
# Collect child processes as systemd assigns a scope only to explicitly
|
|
||||||
# specified PIDs.
|
|
||||||
# There's a risk of race as the child processes may exit by the time dbus call
|
|
||||||
# reaches systemd, hence the @retry decorator is applied to the method.
|
|
||||||
pids = [proc.pid] + [
|
|
||||||
x.pid
|
|
||||||
for x in proc.children(recursive=True)
|
|
||||||
if self.cgroup_change_needed(get_cgroup(x.pid))
|
|
||||||
]
|
|
||||||
|
|
||||||
await self._sd_manager.call_start_transient_unit(
|
|
||||||
sd_unit,
|
|
||||||
"fail",
|
|
||||||
[["PIDs", Variant("au", pids)], ["Slice", Variant("s", sd_slice)]],
|
|
||||||
[],
|
|
||||||
)
|
|
||||||
LOG.debug(
|
|
||||||
"window %s successfully assigned to cgroup %s/%s", app_id, sd_slice, sd_unit
|
|
||||||
)
|
|
||||||
|
|
||||||
async def _on_new_window(self, _: Connection, event: Event):
|
|
||||||
"""window:new IPC event handler"""
|
|
||||||
con = event.container
|
|
||||||
app_id = con.app_id if con.app_id else con.window_class
|
|
||||||
try:
|
|
||||||
pid = self.get_pid(con)
|
|
||||||
if pid is None:
|
|
||||||
LOG.warning("Failed to get pid for %s", app_id)
|
|
||||||
return
|
|
||||||
proc = Process(pid)
|
|
||||||
cgroup = get_cgroup(proc.pid)
|
|
||||||
# some X11 apps don't set WM_CLASS. fallback to process name
|
|
||||||
if app_id is None:
|
|
||||||
app_id = proc.name()
|
|
||||||
LOG.debug("window %s(%s) cgroup %s", app_id, proc.pid, cgroup)
|
|
||||||
if self.cgroup_change_needed(cgroup):
|
|
||||||
await self.assign_scope(app_id, proc)
|
|
||||||
# pylint: disable=broad-except
|
|
||||||
except Exception as exc:
|
|
||||||
LOG.error("Failed to modify cgroup for %s: %s", app_id, exc)
|
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
"""Async entrypoint"""
|
|
||||||
try:
|
|
||||||
bus = await MessageBus().connect()
|
|
||||||
conn = await Connection(auto_reconnect=False).connect()
|
|
||||||
await CGroupHandler(bus, conn).connect()
|
|
||||||
await conn.main()
|
|
||||||
except DBusError as exc:
|
|
||||||
LOG.error("DBus connection error: %s", exc)
|
|
||||||
except (ConnectionError, EOFError) as exc:
|
|
||||||
LOG.error("Sway IPC connection error: %s", exc)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="Assign CGroups to apps in compositors with i3 IPC protocol support"
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-l",
|
|
||||||
"--loglevel",
|
|
||||||
choices=["critical", "error", "warning", "info", "debug"],
|
|
||||||
default="info",
|
|
||||||
dest="loglevel",
|
|
||||||
help="set logging level",
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
|
||||||
logging.basicConfig(level=args.loglevel.upper())
|
|
||||||
asyncio.run(main())
|
|
@ -1,136 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
#
|
|
||||||
# Address several issues with DBus activation and systemd user sessions
|
|
||||||
#
|
|
||||||
# 1. DBus-activated and systemd services do not share the environment with user
|
|
||||||
# login session. In order to make the applications that have GUI or interact
|
|
||||||
# with the compositor work as a systemd user service, certain variables must
|
|
||||||
# be propagated to the systemd and dbus.
|
|
||||||
# Possible (but not exhaustive) list of variables:
|
|
||||||
# - DISPLAY - for X11 applications that are started as user session services
|
|
||||||
# - WAYLAND_DISPLAY - similarly, this is needed for wayland-native services
|
|
||||||
# - I3SOCK/SWAYSOCK - allow services to talk with sway using i3 IPC protocol
|
|
||||||
#
|
|
||||||
# 2. `xdg-desktop-portal` requires XDG_CURRENT_DESKTOP to be set in order to
|
|
||||||
# select the right implementation for screenshot and screencast portals.
|
|
||||||
# With all the numerous ways to start sway, it's not possible to rely on the
|
|
||||||
# right value of the XDG_CURRENT_DESKTOP variable within the login session,
|
|
||||||
# therefore the script will ensure that it is always set to `sway`.
|
|
||||||
#
|
|
||||||
# 3. GUI applications started as a systemd service (or via xdg-autostart-generator)
|
|
||||||
# may rely on the XDG_SESSION_TYPE variable to select the backend.
|
|
||||||
# Ensure that it is always set to `wayland`.
|
|
||||||
#
|
|
||||||
# 4. The common way to autostart a systemd service along with the desktop
|
|
||||||
# environment is to add it to a `graphical-session.target`. However, systemd
|
|
||||||
# forbids starting the graphical session target directly and encourages use
|
|
||||||
# of an environment-specific target units. Therefore, the integration
|
|
||||||
# package here provides and uses `sway-session.target` which would bind to
|
|
||||||
# the `graphical-session.target`.
|
|
||||||
#
|
|
||||||
# 5. Stop the target and unset the variables when the compositor exits.
|
|
||||||
#
|
|
||||||
# References:
|
|
||||||
# - https://github.com/swaywm/sway/wiki#gtk-applications-take-20-seconds-to-start
|
|
||||||
# - https://github.com/emersion/xdg-desktop-portal-wlr/wiki/systemd-user-services,-pam,-and-environment-variables
|
|
||||||
# - https://www.freedesktop.org/software/systemd/man/systemd.special.html#graphical-session.target
|
|
||||||
# - https://systemd.io/DESKTOP_ENVIRONMENTS/
|
|
||||||
#
|
|
||||||
export XDG_CURRENT_DESKTOP=sway
|
|
||||||
export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:-sway}"
|
|
||||||
export XDG_SESSION_TYPE=wayland
|
|
||||||
VARIABLES="DESKTOP_SESSION XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE"
|
|
||||||
VARIABLES="${VARIABLES} DISPLAY I3SOCK SWAYSOCK WAYLAND_DISPLAY"
|
|
||||||
SESSION_TARGET="sway-session.target"
|
|
||||||
SESSION_SHUTDOWN_TARGET="sway-session-shutdown.target"
|
|
||||||
WITH_CLEANUP=1
|
|
||||||
|
|
||||||
print_usage() {
|
|
||||||
cat <<EOH
|
|
||||||
Usage:
|
|
||||||
--help Show this help message and exit.
|
|
||||||
--add-env NAME, -E NAME
|
|
||||||
Add a variable name to the subset of environment passed
|
|
||||||
to the user session. Can be specified multiple times.
|
|
||||||
--no-cleanup Skip cleanup code at compositor exit.
|
|
||||||
EOH
|
|
||||||
}
|
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
--help)
|
|
||||||
print_usage
|
|
||||||
exit 0 ;;
|
|
||||||
# The following flag is intentionally not exposed in the usage info:
|
|
||||||
# - I don't believe that's the right or safe thing to do;
|
|
||||||
# - systemd upstream is of the same opinion and has already deprecated
|
|
||||||
# the ability to import the full environment (systemd/systemd#18137)
|
|
||||||
--all-environment)
|
|
||||||
VARIABLES="" ;;
|
|
||||||
--add-env=?*)
|
|
||||||
VARIABLES="${VARIABLES} ${1#*=}" ;;
|
|
||||||
--add-env | -E)
|
|
||||||
shift
|
|
||||||
VARIABLES="${VARIABLES} ${1}" ;;
|
|
||||||
--with-cleanup)
|
|
||||||
;; # ignore (enabled by default)
|
|
||||||
--no-cleanup)
|
|
||||||
unset WITH_CLEANUP ;;
|
|
||||||
-*)
|
|
||||||
echo "Unexpected option: $1" 1>&2
|
|
||||||
print_usage
|
|
||||||
exit 1 ;;
|
|
||||||
*)
|
|
||||||
break ;;
|
|
||||||
esac
|
|
||||||
shift
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check if another Sway session is already active.
|
|
||||||
#
|
|
||||||
# Ignores all other kinds of parallel or nested sessions
|
|
||||||
# (Sway on Gnome/KDE/X11/etc.), as the only way to detect these is to check
|
|
||||||
# for (WAYLAND_)?DISPLAY and that is know to be broken on Arch.
|
|
||||||
if systemctl --user -q is-active "$SESSION_TARGET"; then
|
|
||||||
echo "Another session found; refusing to overwrite the variables"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# DBus activation environment is independent from systemd. While most of
|
|
||||||
# dbus-activated services are already using `SystemdService` directive, some
|
|
||||||
# still don't and thus we should set the dbus environment with a separate
|
|
||||||
# command.
|
|
||||||
if hash dbus-update-activation-environment 2>/dev/null; then
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
dbus-update-activation-environment --systemd ${VARIABLES:- --all}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# reset failed state of all user units
|
|
||||||
systemctl --user reset-failed
|
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
systemctl --user import-environment $VARIABLES
|
|
||||||
systemctl --user start "$SESSION_TARGET"
|
|
||||||
|
|
||||||
# Optionally, wait until the compositor exits and cleanup variables and services.
|
|
||||||
if [ -z "$WITH_CLEANUP" ] ||
|
|
||||||
[ -z "$SWAYSOCK" ] ||
|
|
||||||
! hash swaymsg 2>/dev/null
|
|
||||||
then
|
|
||||||
exit 0;
|
|
||||||
fi
|
|
||||||
|
|
||||||
# declare cleanup handler and run it on script termination via kill or Ctrl-C
|
|
||||||
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
|
|
||||||
}
|
|
||||||
trap session_cleanup INT TERM
|
|
||||||
# wait until the compositor exits
|
|
||||||
swaymsg -t subscribe '["shutdown"]'
|
|
||||||
# run cleanup handler on normal exit
|
|
||||||
session_cleanup
|
|
@ -1,6 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=Sway session
|
|
||||||
Documentation=man:systemd.special(7)
|
|
||||||
BindsTo=graphical-session.target
|
|
||||||
Wants=graphical-session-pre.target
|
|
||||||
After=graphical-session-pre.target
|
|
@ -25,7 +25,7 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// "layer": "top",
|
"layer": "top",
|
||||||
"name": "alt",
|
"name": "alt",
|
||||||
"output": "XMI Redmi 27 NU 3948622WH08F4",
|
"output": "XMI Redmi 27 NU 3948622WH08F4",
|
||||||
"modules-left": [
|
"modules-left": [
|
||||||
|
5
.zshrc
5
.zshrc
@ -1,3 +1,8 @@
|
|||||||
|
cat ~/.config/splash 2> /dev/null || true
|
||||||
|
echo
|
||||||
|
echo '\033[0;35m /w '$(awk -F "=" '/^NAME/ {print $2}' 2> /dev/null < /etc/os-release || uname -o)
|
||||||
|
echo '\033[0;34m @ '$HOST
|
||||||
|
|
||||||
# Install zinit if no zinit is present
|
# Install zinit if no zinit is present
|
||||||
ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
|
ZINIT_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}/zinit/zinit.git"
|
||||||
if [[ ! -f $ZINIT_HOME/zinit.zsh ]]; then
|
if [[ ! -f $ZINIT_HOME/zinit.zsh ]]; then
|
||||||
|
Loading…
Reference in New Issue
Block a user