Compare commits
17 Commits
4769b48328
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
aef3ccc5c6
|
|||
|
0215834891
|
|||
|
4d5ebe465e
|
|||
|
5c35e4dfdc
|
|||
|
618cb4869b
|
|||
|
304be63652
|
|||
|
12741f4f7a
|
|||
|
df69a5b1ea
|
|||
|
44145ecfde
|
|||
|
833e4b51b0
|
|||
|
58156a116b
|
|||
|
8a9b87a036
|
|||
|
5703308149
|
|||
|
bfe2a50523
|
|||
|
ca724cc40a
|
|||
|
b8ea34d2a3
|
|||
|
02a2b37406
|
@@ -15,4 +15,4 @@ local datetime="$(date +'d%d-%m-%Y_t%H-%M-%S')"
|
|||||||
local filename="keepassxc-db-backup-${datetime}.tar.gz"
|
local filename="keepassxc-db-backup-${datetime}.tar.gz"
|
||||||
tar -caf \
|
tar -caf \
|
||||||
"${devdir}/${filename}" \
|
"${devdir}/${filename}" \
|
||||||
"${HOME}/.keepassxc"
|
"${HOME}/nextcloud/KeePassXC/working/"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ fi
|
|||||||
bin_name="$(basename "$1" .lisp)"
|
bin_name="$(basename "$1" .lisp)"
|
||||||
|
|
||||||
sbcl --load "$1" \
|
sbcl --load "$1" \
|
||||||
|
--eval "(sb-ext:disable-debugger)" \
|
||||||
--eval "(sb-ext:save-lisp-and-die \"$bin_name\"
|
--eval "(sb-ext:save-lisp-and-die \"$bin_name\"
|
||||||
:executable t
|
:executable t
|
||||||
:save-runtime-options t
|
:save-runtime-options t
|
||||||
|
|||||||
185
cl/list-manual-sleep-locks.lisp
Normal file
185
cl/list-manual-sleep-locks.lisp
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
(defpackage list-manual-sleep-locks
|
||||||
|
(:use :cl)
|
||||||
|
(:export #:toplevel))
|
||||||
|
|
||||||
|
(in-package :list-manual-sleep-locks)
|
||||||
|
|
||||||
|
(defclass running-lock ()
|
||||||
|
((start-time :type integer
|
||||||
|
:accessor running-lock-start-time
|
||||||
|
:initarg :start-time
|
||||||
|
:initform 0
|
||||||
|
:documentation "The start time of the lock in microseconds. This
|
||||||
|
is relative to the CLOCK_MONOTONIC clock id.")
|
||||||
|
(length :type (or integer null)
|
||||||
|
:accessor running-lock-length
|
||||||
|
:initarg :length
|
||||||
|
:initform 0
|
||||||
|
:documentation "The length of the lock in microseconds. A value of
|
||||||
|
nil means forever."))
|
||||||
|
(:documentation "An object representing a running lock."))
|
||||||
|
|
||||||
|
(defun monotonic-microseconds ()
|
||||||
|
"Return the value of the CLOCK_MONOTONIC clock in microseconds."
|
||||||
|
(multiple-value-bind (sec nanosec)
|
||||||
|
(sb-unix:clock-gettime sb-unix:clock-monotonic)
|
||||||
|
(+ (* sec 1000 1000)
|
||||||
|
(floor (/ nanosec 1000)))))
|
||||||
|
|
||||||
|
(defun lock-microseconds-left (lock &key (from (monotonic-microseconds)))
|
||||||
|
"Return the number of microseconds left in LOCK. FROM is the point in time
|
||||||
|
from which to calculate."
|
||||||
|
(with-slots (start-time length) lock
|
||||||
|
(when length
|
||||||
|
(- (+ start-time length) from))))
|
||||||
|
|
||||||
|
(defun format-seconds (seconds)
|
||||||
|
"Return a string representing SECONDS in a human readable way."
|
||||||
|
(if (zerop seconds)
|
||||||
|
"0s"
|
||||||
|
(let* ((days (floor (/ (abs seconds) 24 60 60)))
|
||||||
|
(hours (floor (/ (- (abs seconds) (* days 24 60 60)) 60 60)))
|
||||||
|
(mins (floor (/ (- (abs seconds)
|
||||||
|
(* hours 60 60)
|
||||||
|
(* days 24 60 60))
|
||||||
|
60)))
|
||||||
|
(secs (- (abs seconds) (* mins 60)
|
||||||
|
(* hours 60 60) (* days 24 60 60))))
|
||||||
|
(format nil
|
||||||
|
"~@[~*-~]~[~:;~:*~Sd~]~[~:;~:*~Sh~]~[~:;~:*~Sm~]~[~:;~:*~Ss~]"
|
||||||
|
(minusp seconds) days hours mins secs))))
|
||||||
|
|
||||||
|
(defun split-key-value-line (line)
|
||||||
|
"Split LINE, in the form of key=vale, into a list of (key value)."
|
||||||
|
(let ((index (position #\= line :test #'eql)))
|
||||||
|
(list (subseq line 0 index)
|
||||||
|
(subseq line (1+ index)))))
|
||||||
|
|
||||||
|
(defun systemd-unescape (str &key (start 0) (end (length str)))
|
||||||
|
"Act as sytemd-escape --unescape (for non-path strings) for STR."
|
||||||
|
(with-output-to-string (stream)
|
||||||
|
(let ((copy-start start))
|
||||||
|
(flet ((copy-to-output (i skip)
|
||||||
|
(when (<= copy-start end)
|
||||||
|
(write-string str stream :start copy-start :end i)
|
||||||
|
(setq copy-start (+ i skip)))))
|
||||||
|
(loop for i upfrom start below end
|
||||||
|
for c = (aref str i)
|
||||||
|
when (and (eql c #\\) (>= (- end i) 4)
|
||||||
|
(eql (aref str (1+ i)) #\x))
|
||||||
|
do (copy-to-output i 4)
|
||||||
|
and do (write-char (code-char (parse-integer str
|
||||||
|
:start (+ i 2)
|
||||||
|
:end (+ i 4)
|
||||||
|
:radix 16))
|
||||||
|
stream))
|
||||||
|
(copy-to-output end 0)))))
|
||||||
|
|
||||||
|
(defun extract-lock-length-string-from-service-name (name)
|
||||||
|
"Extract the lock length string from a service name NAME of the form
|
||||||
|
\"NAME@TIME.service\"."
|
||||||
|
(let ((start-idx (1+ (position #\@ name)))
|
||||||
|
(end-idx (when (uiop:string-suffix-p name ".service")
|
||||||
|
(- (length name) (length ".service")))))
|
||||||
|
(systemd-unescape name :start start-idx :end end-idx)))
|
||||||
|
|
||||||
|
(defparameter *lock-length-string-units*
|
||||||
|
`((#\d . ,(* 24 60 60 1000 1000))
|
||||||
|
(#\h . ,(* 60 60 1000 1000))
|
||||||
|
(#\m . ,(* 60 1000 1000))
|
||||||
|
(#\s . ,(* 1000 1000)))
|
||||||
|
"Table mapping units (as characters) to microsecond lengths.")
|
||||||
|
|
||||||
|
(defun lock-length-string-to-usecs (str)
|
||||||
|
"Convert the lock length string STR to microseconds (usec). Return nil if the
|
||||||
|
string means infinite length."
|
||||||
|
(unless (equal str "infinity")
|
||||||
|
(loop with sum = 0
|
||||||
|
for i below (length str)
|
||||||
|
for c = (aref str i)
|
||||||
|
unless (eql c #\Space)
|
||||||
|
do (multiple-value-bind (num chars)
|
||||||
|
(parse-integer str :start i :junk-allowed t)
|
||||||
|
(unless num
|
||||||
|
(error "Invalid time interval!"))
|
||||||
|
(setq i chars)
|
||||||
|
(let ((scale (assoc (if (< i (length str))
|
||||||
|
(aref str i)
|
||||||
|
#\s)
|
||||||
|
*lock-length-string-units*)))
|
||||||
|
(unless scale
|
||||||
|
(error "Invalid time interval!"))
|
||||||
|
(incf sum (* num (cdr scale))))
|
||||||
|
;; (incf i) implied
|
||||||
|
)
|
||||||
|
finally (return sum))))
|
||||||
|
|
||||||
|
(defun list-locks-from-systemctl-show-output (stream)
|
||||||
|
"List all running locks in STREAM, which contains the output from systemctl's
|
||||||
|
show command."
|
||||||
|
(let ((cur-params (cons nil nil))
|
||||||
|
(cur-params-count 0)
|
||||||
|
output)
|
||||||
|
(loop
|
||||||
|
for line = (read-line stream nil)
|
||||||
|
while line
|
||||||
|
do (if (zerop (length line))
|
||||||
|
(progn
|
||||||
|
(when (= cur-params-count 2)
|
||||||
|
(push (make-instance 'running-lock
|
||||||
|
:start-time (cdr cur-params)
|
||||||
|
:length (car cur-params))
|
||||||
|
output))
|
||||||
|
(setq cur-params-count 0))
|
||||||
|
(destructuring-bind (key value)
|
||||||
|
(split-key-value-line line)
|
||||||
|
(cond
|
||||||
|
((equal key "Id")
|
||||||
|
(ignore-errors
|
||||||
|
(setf (car cur-params)
|
||||||
|
(lock-length-string-to-usecs
|
||||||
|
(extract-lock-length-string-from-service-name value)))
|
||||||
|
(incf cur-params-count)))
|
||||||
|
((equal key "ExecMainStartTimestampMonotonic")
|
||||||
|
(setf (cdr cur-params) (parse-integer value))
|
||||||
|
(incf cur-params-count))))))
|
||||||
|
(when (= cur-params-count 2)
|
||||||
|
(push (make-instance 'running-lock
|
||||||
|
:start-time (cdr cur-params)
|
||||||
|
:length (car cur-params))
|
||||||
|
output))
|
||||||
|
output))
|
||||||
|
|
||||||
|
(defun list-running-locks ()
|
||||||
|
"Return a list of running locks."
|
||||||
|
(with-input-from-string
|
||||||
|
(stream (uiop:run-program '("systemctl" "--user" "--no-pager" "--full"
|
||||||
|
"--state=activating,active" "show"
|
||||||
|
"manual-inhibit-sleep@*.service")
|
||||||
|
:output :string
|
||||||
|
:error-output :interactive
|
||||||
|
:input nil))
|
||||||
|
(list-locks-from-systemctl-show-output stream)))
|
||||||
|
|
||||||
|
(defun sort-running-locks (locks &optional (start-usecs (monotonic-microseconds)))
|
||||||
|
"Sort a list of running locks with one's ending sooner sorting after."
|
||||||
|
(sort locks (lambda (lock1 lock2)
|
||||||
|
(let ((usec1 (lock-microseconds-left
|
||||||
|
lock1 :from start-usecs))
|
||||||
|
(usec2 (lock-microseconds-left
|
||||||
|
lock2 :from start-usecs)))
|
||||||
|
(or (not usec1)
|
||||||
|
(and usec2 (> usec1 usec2)))))))
|
||||||
|
|
||||||
|
(defun toplevel ()
|
||||||
|
"Main program entry point."
|
||||||
|
(loop with start-usecs = (monotonic-microseconds)
|
||||||
|
for lock in (sort-running-locks (list-running-locks) start-usecs)
|
||||||
|
for rem-usec = (lock-microseconds-left lock :from start-usecs)
|
||||||
|
when (not rem-usec)
|
||||||
|
do (format t "infinity infinity~%")
|
||||||
|
else when (plusp rem-usec)
|
||||||
|
do (format t "~A ~A~%"
|
||||||
|
(format-seconds
|
||||||
|
(floor (/ (running-lock-length lock) 1000 1000)))
|
||||||
|
(floor (/ rem-usec 1000 1000)))))
|
||||||
43
emacs-server-import-environment.el
Executable file
43
emacs-server-import-environment.el
Executable file
@@ -0,0 +1,43 @@
|
|||||||
|
#!/usr/bin/env -S emacs -Q --script
|
||||||
|
;;; -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
(require 'cl-lib)
|
||||||
|
(require 'server)
|
||||||
|
|
||||||
|
(defun append-to-path (value)
|
||||||
|
"Split VALUE and append to PATH."
|
||||||
|
(let ((to-add (split-string value ":" t nil)))
|
||||||
|
(server-eval-at "server"
|
||||||
|
`(dolist (file ',to-add)
|
||||||
|
(add-to-list 'exec-path file)))))
|
||||||
|
|
||||||
|
(dolist (var argv)
|
||||||
|
(let ((sep (cl-position ?= var :test #'eql)))
|
||||||
|
(cond
|
||||||
|
((string-prefix-p "-" var)
|
||||||
|
;; unset
|
||||||
|
(when (equal var "-PATH")
|
||||||
|
(message "Refusing to unset PATH")
|
||||||
|
(kill-emacs 1))
|
||||||
|
(server-eval-at "server"
|
||||||
|
`(setenv ,(substring var 1) nil)))
|
||||||
|
(sep
|
||||||
|
(let ((name (substring var 0 sep))
|
||||||
|
(value (substring var (1+ sep))))
|
||||||
|
(if (equal name "PATH")
|
||||||
|
(append-to-path value)
|
||||||
|
;; append to PATH, not set
|
||||||
|
;; set to passed value
|
||||||
|
(server-eval-at "server"
|
||||||
|
`(setenv ,name ,value)))))
|
||||||
|
(t
|
||||||
|
(if (equal var "PATH")
|
||||||
|
;; copy form and append to path
|
||||||
|
(append-to-path (getenv var))
|
||||||
|
;; copy from our evnironment
|
||||||
|
(server-eval-at "server"
|
||||||
|
`(setenv ,var ,(getenv var))))))))
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; flycheck-disabled-checkers: (emacs-lisp-checkdoc)
|
||||||
|
;; End:
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env zsh
|
|
||||||
|
|
||||||
setopt rcquotes
|
|
||||||
|
|
||||||
printf '%s' "${WAYLAND_DISPLAY}" |
|
|
||||||
/usr/bin/emacs --batch --insert=/dev/fd/0 \
|
|
||||||
--eval \
|
|
||||||
'(let ((wayland-display (buffer-string)))
|
|
||||||
(require ''server)
|
|
||||||
(server-eval-at
|
|
||||||
"server"
|
|
||||||
`(setenv "WAYLAND_DISPLAY" ,wayland-display)))'
|
|
||||||
28
old/pulse/select-sound-output-pulse.sh
Executable file
28
old/pulse/select-sound-output-pulse.sh
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env zsh
|
||||||
|
local info="$(pactl list sinks)"
|
||||||
|
local default_name="$(pactl info | grep -Po '(?<=Default Sink: ).+')"
|
||||||
|
local ids=(${(@f)"$(echo "${info}" | grep -Po '(?<=Sink #).+')"})
|
||||||
|
local names=(${(@f)"$(echo "${info}" | grep -Po '(?<=Name: ).+')"})
|
||||||
|
local descs=(${(@f)"$(echo "${info}" | grep -Po '(?<=Description: ).+')"})
|
||||||
|
local default_id=""
|
||||||
|
local query_string=""
|
||||||
|
for ((i = 1; i <= "${#ids}"; ++i)); do
|
||||||
|
if [[ "${names[${i}]}" == "${default_name}" ]]; then
|
||||||
|
default_id="${ids[${i}]}"
|
||||||
|
fi
|
||||||
|
query_string+="${ids[${i}]}: ${descs[${i}]} (${names[${i}]})\n"
|
||||||
|
done
|
||||||
|
[[ -v WAYLAND_DISPLAY ]] \
|
||||||
|
&& prompt_cmd=("fuzzel" "-dp" "${default_id}> ") \
|
||||||
|
|| prompt_cmd=("dmenu" "-p" "${default_id}:")
|
||||||
|
local choice
|
||||||
|
choice="$(echo "${query_string%"\n"}" | ${prompt_cmd})"
|
||||||
|
if (( "${?}" != 0 )); then
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
local selected_id="$(echo "${choice}" | grep -Eo '^[0-9]+')"
|
||||||
|
pactl set-default-sink "${selected_id}"
|
||||||
|
local selected_name="$(echo "${choice}" \
|
||||||
|
| cut -c "$(("${#selected_id}" + 3))-" \
|
||||||
|
| grep -Po '^.+(?= \()')"
|
||||||
|
notify-send 'Output Device' "${selected_name} (${selected_id})"
|
||||||
@@ -21,7 +21,7 @@ fi
|
|||||||
|
|
||||||
get_current_profile() {
|
get_current_profile() {
|
||||||
local profile
|
local profile
|
||||||
profile="$(kanshictl status | jq -er '.current_profile')"
|
profile="${$(kanshictl status):17}"
|
||||||
(( $? )) && return 1
|
(( $? )) && return 1
|
||||||
: ${(P)1::="${profile}"}
|
: ${(P)1::="${profile}"}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,15 @@ printf 'Using interface: %s\n' "${iface}"
|
|||||||
# <-A|-D> <ex_ip> <in_ip>
|
# <-A|-D> <ex_ip> <in_ip>
|
||||||
function do_rules {
|
function do_rules {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
function handle_error {
|
||||||
|
setopt noxtrace
|
||||||
|
echo Failed to add iptables rules
|
||||||
|
rm -f "${save_file}"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[[ "${1}" = -A ]] && trap handle_error INT ZERR
|
||||||
PS4='Run: '
|
PS4='Run: '
|
||||||
setopt errexit xtrace
|
setopt xtrace
|
||||||
doas iptables -t filter "${1}" FORWARD -i "${iface}" -o wg0-mullvad -j ACCEPT
|
doas iptables -t filter "${1}" FORWARD -i "${iface}" -o wg0-mullvad -j ACCEPT
|
||||||
|
|
||||||
doas iptables -t nat "${1}" PREROUTING -d "${2}"/32 -p tcp -m tcp --dport 62000 \
|
doas iptables -t nat "${1}" PREROUTING -d "${2}"/32 -p tcp -m tcp --dport 62000 \
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ PID can be a string or a number."
|
|||||||
(cfg-dir (current-eww-config-dir)))
|
(cfg-dir (current-eww-config-dir)))
|
||||||
(when cfg-dir
|
(when cfg-dir
|
||||||
(setq args (nconc (list "-c" cfg-dir) args)))
|
(setq args (nconc (list "-c" cfg-dir) args)))
|
||||||
(apply 'call-process "eww" nil 0 nil args)))
|
(ignore-errors
|
||||||
|
(apply 'call-process "eww" nil 0 nil args))))
|
||||||
|
|
||||||
(defun update-waybar ()
|
(defun update-waybar ()
|
||||||
(call-process "pkill" nil 0 nil "-RTMIN+1" "waybar"))
|
(call-process "pkill" nil 0 nil "-RTMIN+1" "waybar"))
|
||||||
|
|||||||
76
status-bar/sb-manual-sleep-locks
Executable file
76
status-bar/sb-manual-sleep-locks
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env -S emacs -Q --script
|
||||||
|
;; -*- lexical-binding: t -*-
|
||||||
|
|
||||||
|
(require 'cl-lib)
|
||||||
|
(require 'json)
|
||||||
|
|
||||||
|
(defconst list-sleep-locks-bin
|
||||||
|
(expand-file-name "~/scripts/cl/bin/list-manual-sleep-locks"))
|
||||||
|
|
||||||
|
(defun make-pretty-timestamp (offset)
|
||||||
|
"Return a pretty-printed string timestamp of UTC + offset (in seconds)."
|
||||||
|
(format-time-string "%H:%M:%S %b %-e"
|
||||||
|
(+ (time-convert nil 'integer) offset)))
|
||||||
|
|
||||||
|
(defun list-running-locks ()
|
||||||
|
"List all running manual sleep locks."
|
||||||
|
(with-temp-buffer
|
||||||
|
(when-let ((rval (call-process list-sleep-locks-bin nil t))
|
||||||
|
((eql rval 0)))
|
||||||
|
(goto-char (point-min))
|
||||||
|
(cl-loop
|
||||||
|
while (not (eobp))
|
||||||
|
for (length sec-str) = (split-string
|
||||||
|
(buffer-substring (point) (pos-eol)) " ")
|
||||||
|
when (equal length "infinity")
|
||||||
|
collect (cons "infinity" "next restart")
|
||||||
|
else
|
||||||
|
collect (cons length (make-pretty-timestamp (cl-parse-integer sec-str)))
|
||||||
|
do (forward-line)))))
|
||||||
|
|
||||||
|
(defun format-tooltip (locks)
|
||||||
|
"Format a tooltip for a list of LOCKS."
|
||||||
|
(cond
|
||||||
|
((null locks) "No manual sleep locks")
|
||||||
|
((length= locks 1)
|
||||||
|
(format "Sleep manually locked until %s" (cdar locks)))
|
||||||
|
(t
|
||||||
|
(with-temp-buffer
|
||||||
|
(insert "<tt>\n")
|
||||||
|
(cl-loop
|
||||||
|
for lock in locks
|
||||||
|
maximize (length (car lock)) into first-col-len
|
||||||
|
maximize (length (cdr lock)) into second-col-len
|
||||||
|
finally
|
||||||
|
(progn
|
||||||
|
(setq first-col-len (max first-col-len (length "Length"))
|
||||||
|
second-col-len (max second-col-len (length "Until")))
|
||||||
|
(insert (string-pad "Length" first-col-len) " Until\n")
|
||||||
|
(insert (make-string (+ first-col-len 2 second-col-len) ?-) "\n")
|
||||||
|
(dolist (lock locks)
|
||||||
|
(cl-destructuring-bind (length . end) lock
|
||||||
|
(insert (string-pad length first-col-len) " " end "\n")))))
|
||||||
|
(insert "</tt>")
|
||||||
|
(buffer-substring-no-properties (point-min) (point-max))))))
|
||||||
|
|
||||||
|
(defun format-output-line (locks)
|
||||||
|
"Format a line of output for LOCKS."
|
||||||
|
(json-encode `(:text ,(if locks " " "")
|
||||||
|
:tooltip ,(format-tooltip locks))))
|
||||||
|
|
||||||
|
(defun print-running-locks ()
|
||||||
|
"Print running locks in JSON."
|
||||||
|
(interactive)
|
||||||
|
(princ (format-output-line (list-running-locks)))
|
||||||
|
(terpri)
|
||||||
|
(flush-standard-output))
|
||||||
|
|
||||||
|
(define-key special-event-map '[sigusr1] #'print-running-locks)
|
||||||
|
|
||||||
|
(print-running-locks)
|
||||||
|
(while t
|
||||||
|
(read-event))
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; flycheck-disabled-checkers: (emacs-lisp-checkdoc)
|
||||||
|
;; End:
|
||||||
@@ -14,12 +14,21 @@ function has-rootful-xwayland-p {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function safeeyes-running-p {
|
||||||
|
[[ "$(safeeyes --status)" = Next* ]]
|
||||||
|
}
|
||||||
|
|
||||||
function run {
|
function run {
|
||||||
# ensure multiple instances do not run
|
# ensure multiple instances do not run
|
||||||
mkdir -p "${LOCKFILE:h}"
|
mkdir -p "${LOCKFILE:h}"
|
||||||
exec 4<>"${LOCKFILE}"
|
exec 4<>"${LOCKFILE}"
|
||||||
flock -n 4 || exit 0
|
flock -n 4 || exit 0
|
||||||
dunstctl set-paused true
|
dunstctl set-paused true
|
||||||
|
let need_restore_safeeyes=0
|
||||||
|
if safeeyes-running-p; then
|
||||||
|
safeeyes --disable
|
||||||
|
need_restore_safeeyes=1
|
||||||
|
fi
|
||||||
if [[ "${XDG_CURRENT_DESKTOP}" == 'river' ]] && has-rootful-xwayland-p; then
|
if [[ "${XDG_CURRENT_DESKTOP}" == 'river' ]] && has-rootful-xwayland-p; then
|
||||||
swaylock ${empty_flag} --color '#000000'
|
swaylock ${empty_flag} --color '#000000'
|
||||||
else
|
else
|
||||||
@@ -33,19 +42,18 @@ function run {
|
|||||||
ignored_args+=(-i "${(q)name}")
|
ignored_args+=(-i "${(q)name}")
|
||||||
done
|
done
|
||||||
swayidle -w -C /dev/null \
|
swayidle -w -C /dev/null \
|
||||||
before-sleep "${(q)RESET_SAFEEYES}" \
|
|
||||||
timeout 15 "${(q)ENABLE_DISPLAYS} -d ${ignored_args}" \
|
timeout 15 "${(q)ENABLE_DISPLAYS} -d ${ignored_args}" \
|
||||||
resume "${(q)ENABLE_DISPLAYS} {$ignored_args}" &
|
resume "${(q)ENABLE_DISPLAYS} {$ignored_args}" &
|
||||||
swayidle_pid="${!}"
|
swayidle_pid="${!}"
|
||||||
else
|
else
|
||||||
swayidle -w -C /dev/null \
|
swayidle -w -C /dev/null \
|
||||||
before-sleep "${(q)RESET_SAFEEYES}" \
|
|
||||||
timeout 15 "systemctl sleep" &
|
timeout 15 "systemctl sleep" &
|
||||||
swayidle_pid="${!}"
|
swayidle_pid="${!}"
|
||||||
fi
|
fi
|
||||||
swaylock ${empty_flag} ${img_flags}
|
swaylock ${empty_flag} ${img_flags}
|
||||||
kill "${swayidle_pid}"
|
kill "${swayidle_pid}"
|
||||||
fi
|
fi
|
||||||
|
(( need_restore_safeeyes )) && safeeyes --enable
|
||||||
dunstctl set-paused false
|
dunstctl set-paused false
|
||||||
fix_eww
|
fix_eww
|
||||||
flock -u 4
|
flock -u 4
|
||||||
|
|||||||
@@ -1,28 +1,78 @@
|
|||||||
#!/usr/bin/env zsh
|
#!/usr/bin/env zsh
|
||||||
local info="$(pactl list sinks)"
|
|
||||||
local default_name="$(pactl info | grep -Po '(?<=Default Sink: ).+')"
|
setopt pipefail typeset_silent
|
||||||
local ids=(${(@f)"$(echo "${info}" | grep -Po '(?<=Sink #).+')"})
|
|
||||||
local names=(${(@f)"$(echo "${info}" | grep -Po '(?<=Name: ).+')"})
|
get_default_sink() {
|
||||||
local descs=(${(@f)"$(echo "${info}" | grep -Po '(?<=Description: ).+')"})
|
local -a first_line
|
||||||
local default_id=""
|
first_line=${${(f)"$(wpctl inspect @DEFAULT_AUDIO_SINK@)"}[1]}
|
||||||
local query_string=""
|
if (( ${?} )); then
|
||||||
for ((i = 1; i <= "${#ids}"; ++i)); do
|
echo "error: getting default sink with wpctl failed with error code ${?}" >&2
|
||||||
if [[ "${names[${i}]}" == "${default_name}" ]]; then
|
exit 1
|
||||||
default_id="${ids[${i}]}"
|
elif [[ ${first_line} =~ '^id ([0-9]+), ' ]]; then
|
||||||
|
printf '%s' "${match}"
|
||||||
|
else
|
||||||
|
echo "error: getting default sink with wpctl failed" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
query_string+="${ids[${i}]}: ${descs[${i}]} (${names[${i}]})\n"
|
}
|
||||||
done
|
|
||||||
[[ -v WAYLAND_DISPLAY ]] \
|
let current_sink="$(get_default_sink)"
|
||||||
&& prompt_cmd=("fuzzel" "-dp" "${default_id}> ") \
|
|
||||||
|| prompt_cmd=("dmenu" "-p" "${default_id}:")
|
local JQ_SCRIPT=$(<<'EOF'
|
||||||
local choice
|
.[] | select(.type == "PipeWire:Interface:Node"
|
||||||
choice="$(echo "${query_string%"\n"}" | ${prompt_cmd})"
|
and .info.props.["media.class"] == "Audio/Sink")
|
||||||
if (( "${?}" != 0 )); then
|
| "\(.id)\u0000\(.info.props.["node.nick"]) - \(.info.props.["node.description"]) (\(.id))\u0000\(.info.props.["device.icon-name"])\u0000"
|
||||||
exit
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
local -a id_desc_pairs
|
||||||
|
|
||||||
|
id_desc_pairs=(${(0)"$(pw-dump | jq -rj "${JQ_SCRIPT}")"})
|
||||||
|
if (( ${?} )); then
|
||||||
|
echo "error: pw-dump or jq failed with error code ${?}" >&2
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
local selected_id="$(echo "${choice}" | grep -Eo '^[0-9]+')"
|
|
||||||
pactl set-default-sink "${selected_id}"
|
generate_icon_names() {
|
||||||
local selected_name="$(echo "${choice}" \
|
# I got this idea from the pavucontrol source
|
||||||
| cut -c "$(("${#selected_id}" + 3))-" \
|
# - First try the icon name as is
|
||||||
| grep -Po '^.+(?= \()')"
|
# - Then concatenate "-symbolic"
|
||||||
notify-send 'Output Device' "${selected_name} (${selected_id})"
|
# - Then remove the last dash (-) character and everything after it
|
||||||
|
# - Then again try that with "-symbolic"
|
||||||
|
local nonl="${1//%'\n'/}"
|
||||||
|
printf '%s,%s' "${nonl}" "${nonl}-symbolic"
|
||||||
|
if [[ ${1} = *-* ]]; then
|
||||||
|
printf ',%s,%s' "${nonl%-*}" "${nonl%-*}-symbolic"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
local -a ids descs fuzzel_ents
|
||||||
|
|
||||||
|
for id desc icon in ${id_desc_pairs}; do
|
||||||
|
ids+=("${id}")
|
||||||
|
descs+=("${desc}")
|
||||||
|
fuzzel_ents+=("${desc//$'\n'/}" "$(generate_icon_names "${icon}")")
|
||||||
|
done
|
||||||
|
|
||||||
|
local fuzzel_index
|
||||||
|
|
||||||
|
fuzzel_index="$(printf '%s\0icon\x1f%s\n' ${fuzzel_ents} \
|
||||||
|
| fuzzel -p "Cur: ${current_sink}> " --dmenu --index)"
|
||||||
|
if (( ${?} )); then
|
||||||
|
echo "Canceled by user" >&2
|
||||||
|
exit 0
|
||||||
|
elif [[ ${fuzzel_res} = -1 ]]; then
|
||||||
|
echo "User selected non-existant entry" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
let new_id=$(( ids[fuzzel_index + 1] ))
|
||||||
|
|
||||||
|
wpctl set-default ${new_id}
|
||||||
|
if (( ${?} )); then
|
||||||
|
echo 'error: wpctl failed with exit code ${?}' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
notify-send -t 5000 'Default audio sink changed' \
|
||||||
|
"${descs[${fuzzel_index} + 1]}"
|
||||||
|
|||||||
@@ -8,25 +8,19 @@ function is-desktop-p {
|
|||||||
! is-laptop-p
|
! is-laptop-p
|
||||||
}
|
}
|
||||||
|
|
||||||
systemctl --user --quiet is-active swayidle.service \
|
|
||||||
&& swayidle_state="Enabled" || swayidle_state="Disabled"
|
|
||||||
|
|
||||||
# Format: label action condition
|
# Format: label action condition
|
||||||
local entries=('Select system sound output' 'select-sound-output.sh' 'true'
|
local entries=('Select system sound output' 'select-sound-output.sh' 'true'
|
||||||
"Enable or disable system sleep (Current: ${swayidle_state})" 'system-sleep-menu.sh' 'true'
|
"Enable or disable system sleep" 'system-sleep-menu.sh' 'true'
|
||||||
'Enable or disable TV' 'tv-power-menu.sh' 'is-desktop-p'
|
'Enable or disable TV' 'tv-power-menu.sh' 'is-desktop-p'
|
||||||
'Configure USB device access' 'usbguard-menu.py' 'pgrep usbguard-daemon'
|
'Configure USB device access' 'usbguard-menu.py' 'pgrep usbguard-daemon'
|
||||||
'Power settings (restart and shutdown)' 'system-power-menu.sh' 'true'
|
'Power settings (restart and shutdown)' 'system-power-menu.sh' 'true'
|
||||||
'Login to captive portal protected WiFi' 'login-to-wifi.sh' 'is-laptop-p'
|
'Login to captive portal protected WiFi' 'login-to-wifi.sh' 'is-laptop-p')
|
||||||
# I'm not using eww right now
|
|
||||||
# 'Restart top bar' 'river-restart-eww.sh' '[[ "${XDG_CURRENT_DESKTOP}" == river ]]'
|
|
||||||
)
|
|
||||||
|
|
||||||
local entry_array=()
|
local entry_array=()
|
||||||
local enabled_entries=()
|
local enabled_entries=()
|
||||||
for ((i = 1; i <= ${#entries}; i+=3)); do
|
for ((i = 1; i <= ${#entries}; i+=3)); do
|
||||||
if eval "${entries[${i} + 2]}" >/dev/null 2>&1; then
|
if eval "${entries[${i} + 2]}" >/dev/null 2>&1; then
|
||||||
entry_array[$((${i} / 3 + 1))]="${entries[${i}]}"
|
entry_array[$((i / 3 + 1))]="${entries[i]}"
|
||||||
enabled_entries+=(${entries[@]:${i} - 1:3})
|
enabled_entries+=(${entries[@]:${i} - 1:3})
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -1,31 +1,63 @@
|
|||||||
#!/usr/bin/env zsh
|
#!/usr/bin/env zsh
|
||||||
|
|
||||||
let is_active=0
|
zmodload zsh/datetime
|
||||||
systemctl --user --quiet is-active swayidle.service && is_active=1
|
zmodload zsh/mathfunc
|
||||||
|
setopt typeset_silent
|
||||||
|
|
||||||
local swayidle_state
|
local TIMES=(forever 1m 5m 10m 15m 30m 1h 2h 4h 1d)
|
||||||
(( is_active )) && swayidle_state='Enabled' || swayidle_state='Disabled'
|
|
||||||
|
|
||||||
choice="$(fuzzel --index -d -p "Cur: ${swayidle_state} > " <<'EOF'
|
local -a running_locks
|
||||||
Enable
|
|
||||||
Disable
|
|
||||||
EOF
|
|
||||||
)"
|
|
||||||
|
|
||||||
(( ${?} != 0 )) && exit
|
() {
|
||||||
|
local IFS=$'\n '
|
||||||
|
running_locks=(${="$("${HOME}/scripts/cl/bin/list-manual-sleep-locks")"})
|
||||||
|
}
|
||||||
|
|
||||||
case "${choice}" in
|
let base_time=${EPOCHSECONDS}
|
||||||
0)
|
for ((i = 2; i <= ${#running_locks}; i+=2)); do
|
||||||
systemctl --user start swayidle.service
|
local nsecs="${running_locks[i]}"
|
||||||
;;
|
if [[ "${nsecs}" == infinity ]]; then
|
||||||
1)
|
running_locks[i]="next reboot"
|
||||||
systemctl --user stop swayidle.service
|
else
|
||||||
;;
|
running_locks[i]=$(strftime -n '%H:%M:%S %b %-e' \
|
||||||
esac
|
$(( base_time + nsecs )))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
if [[ "${XDG_CURRENT_DESKTOP}" == 'river' ]]; then
|
function is_valid_sleep_time() {
|
||||||
eww -c "${HOME}/.config/river/config/" update swayidle="$(( ! ${choice} ))"
|
[[ "${1}" = forever ]] \
|
||||||
pkill -RTMIN+3 waybar
|
|| [[ "${1}" = infinity ]] \
|
||||||
elif [[ "${XDG_CURRENT_DESKTOP}" == 'Hyprland' ]]; then
|
|| [[ "${1}" =~ ' *([0-9]+[smhd]? *)+' ]]
|
||||||
pkill -SIGRTMIN+1 waybar
|
}
|
||||||
|
|
||||||
|
if (( ${#running_locks} )); then
|
||||||
|
# We have existing locks
|
||||||
|
local prompt plural_s
|
||||||
|
if (( ${#running_locks} > 2 )); then
|
||||||
|
let count_locks=$(( int(${#running_locks} / 2) ))
|
||||||
|
prompt="Locked by ${count_locks} locks until ${running_locks[2]}> "
|
||||||
|
plural_s='s'
|
||||||
|
else
|
||||||
|
prompt="Locked until ${running_locks[2]}> "
|
||||||
|
fi
|
||||||
|
local choice
|
||||||
|
choice="$(printf "Cancel lock${plural_s}\n" \
|
||||||
|
| fuzzel --dmenu --only-match --index -p "${prompt}")"
|
||||||
|
if (( ${?} == 0 )) && (( ${choice} == 0 )); then
|
||||||
|
systemctl --user stop 'manual-inhibit-sleep@*.service'
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# No locks
|
||||||
|
local choice
|
||||||
|
choice="$(printf '%s\n' ${TIMES} | fuzzel -d -p "Inhibit sleep for> ")"
|
||||||
|
if (( ${?} )); then
|
||||||
|
exit
|
||||||
|
elif is_valid_sleep_time "${choice}"; then
|
||||||
|
[[ "${choice}" == forever ]] && choice=infinity
|
||||||
|
local unit="$(systemd-escape --template=manual-inhibit-sleep@.service \
|
||||||
|
"${choice}")"
|
||||||
|
systemctl --user start "${unit}"
|
||||||
|
else
|
||||||
|
printf 'Invalid sleep time: %s\n' "${choice}" 1>&2
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
12
systemd/manual-inhibit-sleep@.service
Normal file
12
systemd/manual-inhibit-sleep@.service
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Inhibit sleep for some period of time
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=exec
|
||||||
|
Environment=TIME=%I
|
||||||
|
ExecStartPre=-pkill -f -SIGUSR1 '^(.*/)?emacs +-Q +--script +(.*/)?sb-manual-sleep-locks( +.+)?$'
|
||||||
|
ExecStart=systemd-inhibit --what=sleep:idle "--who=manual-inhibit-sleep@%I.service" --mode=block "--why=User manually inhibited sleep" sleep $TIME
|
||||||
|
ExecStopPost=-pkill -f -SIGUSR1 '^(.*/)?emacs +-Q +--script +(.*/)?sb-manual-sleep-locks( +.+)?$'
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -4,22 +4,22 @@ import shutil
|
|||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
from subprocess import Popen, run, DEVNULL, PIPE
|
from subprocess import Popen, run, DEVNULL, PIPE
|
||||||
|
import sys
|
||||||
|
|
||||||
USBGUARD_EXEC_NAME = shutil.which("usbguard")
|
USBGUARD_EXEC_NAME = shutil.which("usbguard")
|
||||||
DUNSTIFY_EXEC_NAME = shutil.which("dunstify")
|
DUNSTIFY_EXEC_NAME = shutil.which("dunstify")
|
||||||
open_notifications = {}
|
open_notifications = {}
|
||||||
|
|
||||||
|
|
||||||
def parse_event_type_and_id(stream):
|
def parse_event_type_and_id(line):
|
||||||
line = stream.readline()
|
|
||||||
if not line.startswith("[device] "):
|
if not line.startswith("[device] "):
|
||||||
return None
|
return None, False
|
||||||
event_type = re.findall("(?<=\\[device\\] )[a-zA-Z]+", line)
|
event_type = re.findall("(?<=\\[device\\] )[a-zA-Z]+", line)
|
||||||
if len(event_type) == 0:
|
if len(event_type) == 0:
|
||||||
return None
|
return None, False
|
||||||
event_id = re.findall("(?<=id=)[0-9]+", line)
|
event_id = re.findall("(?<=id=)[0-9]+", line)
|
||||||
if len(event_id) == 0:
|
if len(event_id) == 0:
|
||||||
return None
|
return None, False
|
||||||
return event_type[0], int(event_id[0])
|
return event_type[0], int(event_id[0])
|
||||||
|
|
||||||
|
|
||||||
@@ -101,9 +101,11 @@ with Popen(
|
|||||||
bufsize=0,
|
bufsize=0,
|
||||||
) as usbguard_proc:
|
) as usbguard_proc:
|
||||||
new_devices = set()
|
new_devices = set()
|
||||||
usbguard_proc.stdout.readline() # get rid of initial connection message
|
first_line = (
|
||||||
while True:
|
usbguard_proc.stdout.readline()
|
||||||
event_type_result = parse_event_type_and_id(usbguard_proc.stdout)
|
) # get rid of initial connection message
|
||||||
|
for line in usbguard_proc.stdout:
|
||||||
|
event_type_result = parse_event_type_and_id(line)
|
||||||
if event_type_result is None:
|
if event_type_result is None:
|
||||||
continue
|
continue
|
||||||
event_type, dev_id = event_type_result
|
event_type, dev_id = event_type_result
|
||||||
|
|||||||
Reference in New Issue
Block a user