File: wait-tray.sh

package info (click to toggle)
uwsm 0.26.4%2Bds-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 724 kB
  • sloc: python: 4,354; sh: 1,485; makefile: 11
file content (137 lines) | stat: -rw-r--r-- 2,962 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/bin/sh

# Bundled with UWSM, but is independent of it.
# https://github.com/Vladimir-csp/uwsm
# https://gitlab.freedesktop.org/Vladimir-csp/uwsm

# NOTE: this is a hack to locally prop up applications that do not properly
# wait for tray themselves, but should.
#
# Put it into `ExecStartPre=-` of the autostart unit or make it a part of a
# wrapper to delay application startup until tray is available or timeout is
# reached. Positional arguments: [TIMEOUT_SECONDS [DELAY_SECONDS]]
#
# This is not a part of any standard mechanism nor it should be, because there
# is no standard. Other custom mechanisms exist, i.e NixOS's `tray.target`, but
# nothing of sorts should be encouraged.
#
# If you find yourself in need of putting this script to use, consider filing a
# bug report for the culprit app.

set -e

wait_tray() {
	# Run busctl monitor in background, save pid to $MON_PID.
	# It will exit when any of tray dbus services' owner changes from
	# nothing to something.

	# wrap tray service names with dbus match args
	set --
	for arg in $TRAY_NAMES; do
		# shellcheck disable=SC2089
		set -- "$@" --match "type='signal',member='NameOwnerChanged',path='/org/freedesktop/DBus',arg0='${arg}',arg1=''"
	done

	# watch for message
	busctl --user monitor \
		--json=short \
		--no-pager \
		--no-legend \
		"$@" \
		--limit-messages 1 \
		--timeout "${TIMEOUT}s" \
		> /dev/null 2>&1 &
	MON_PID=$!
}

check_tray() {
	# return 0 if any of tray serivces is active
	for service in $TRAY_NAMES; do
		if busctl --user status "$service" --no-pager --no-legend > /dev/null 2>&1; then
			return 0
		fi
	done
	return 1
}

# shellcheck disable=SC2329
trapterm() {
	# cancel trap to make it single-use
	trap - INT TERM HUP EXIT

	# suppress stderr, including "Terminated" message
	exec 2> /dev/null

	kill "$MON_PID" || true
	wait "$MON_PID" || true
}

delay() {
	if [ "$DELAY" -gt "0" ]; then
		printf '%s\n' "Delaying for $DELAY seconds"
		sleep "$DELAY"
	fi
}

usage() {
	printf '%s\n' "Usage: ${0##*/} [TIMEOUT_SECONDS [DELAY_SECONDS]]"
}

########

TRAY_NAMES="org.kde.StatusNotifierWatcher org.freedesktop.StatusNotifierWatcher"

TIMEOUT=${1:-30}
DELAY=${2:-0}

case " $* " in
*' -h '* | *' --help '*)
	usage
	exit 0
	;;
esac
case "$TIMEOUT" in
*[!0-9]*)
	{
		printf '%s\n' "Expected number of seconds as timeout, got: $TIMEOUT"
		usage
	} >&2
	exit 1
	;;
esac
case "$DELAY" in
*[!0-9]*)
	{
		printf '%s\n' "Expected number of seconds as delay, got: $DELAY"
		usage
	} >&2
	exit 1
	;;
esac

## start busctl monitor in background
wait_tray

## set cleanup trap
trap trapterm INT TERM HUP EXIT

## check current state and exit on success
if check_tray; then
	printf '%s\n' "Tray is active"
	delay
	exit 0
fi

printf '%s\n' "Waiting $TIMEOUT seconds for Tray to activate..."
wait "$MON_PID" || true

# recheck current status
if check_tray; then
	printf '%s\n' "Tray is active"
	delay
	exit 0
else
	RC=$?
	printf '%s\n' "Tray failed to activate!" >&2
	exit "$RC"
fi