about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--COPYING9
-rwxr-xr-xautoshart.sh231
2 files changed, 240 insertions, 0 deletions
diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..0520203 --- /dev/null +++ b/COPYING
@@ -0,0 +1,9 @@
1Copyright (C) 2022 Case Duckworth <acdw@acdw.net>
2
3Usage of the works is permitted provided that this instrument is
4retained with the works, so that any entity that uses the works is
5notified of this instrument.
6
7DISCLAIMER: THE WORKS ARE WITHOUT WARRANTY.
8
9
diff --git a/autoshart.sh b/autoshart.sh new file mode 100755 index 0000000..4868846 --- /dev/null +++ b/autoshart.sh
@@ -0,0 +1,231 @@
1#!/bin/sh
2# AUTOSHART: autostart *.desktop files
3# Copyright (C) 2022 Case Duckworth <acdw@acdw.net>
4# Licensed under the Fair license. See COPYING for details.
5#
6# Commentary:
7#
8# Freedesktop autostart specification:
9# https://specifications.freedesktop.org/autostart-spec/latest/
10# Freedesktop desktop entry specification:
11# https://specifications.freedesktop.org/desktop-entry-spec/latest/
12#
13# Prior art:
14# - dex -- https://github.com/jceb/dex
15#
16# Code:
17
18usage() {
19 cat <<EOF
20AUTOSHART: autostart without the shit
21USAGE: autoshart -h
22 autoshart [-k] [-n]
23
24FLAGS:
25 -h Show this help and exit.
26 -k Kill all processes started by autoshart and exit.
27 -n Only print what would happen; don't execute anything.
28EOF
29}
30
31main() {
32 PID_FILE="${AUTOSHART_PID_FILE:-/tmp/autoshart.pid}"
33 FOUND_FILE="${AUTOSHART_FOUND_FILE:-/tmp/autoshart.found}"
34 RUN=true
35 QUIET=false
36 while getopts hknq opt; do
37 case "$opt" in
38 h) usage ;;
39 k) auto_kill ;;
40 n) RUN=false ;;
41 q) QUIET=true ;;
42 esac
43 done
44 shift "$((OPTIND - 1))"
45 auto_search
46}
47
48auto_kill() {
49 cat "$PID_FILE" | xargs kill
50}
51
52auto_start() { ## auto_start FILE
53 eprint "$1"
54 # When the .desktop file has the Hidden key set to true, the .desktop
55 # file MUST be ignored. When multiple .desktop files with the same name
56 # exists in multiple directories then only the Hidden key in the most
57 # important .desktop file must be considered: If it is set to true all
58 # .desktop files with the same name in the other directories MUST be
59 # ignored as well.
60 hidden="$(get Hidden "$1")"
61 test "$hidden" = true && return "$(die 1 "Stopped: Hidden: $1")"
62 # This specification defines 3 types of desktop entries: Application
63 # (type 1), Link (type 2) and Directory (type 3). To allow the addition
64 # of new types in the future, implementations should ignore desktop
65 # entries with an unknown type. (REQUIRED)
66 type="$(get Type "$1")"
67 test "$type" = Application || return "$(die 2 "Error: Bad desktop type: ${type:-[none]}")"
68 # Specific name of the application, for example "Mozilla". (REQUIRED)
69 name="$(get Name "$1" | head -n1)"
70 test -n "$name" || return "$(die 3 "Error: No application name")"
71 # Program to execute, possibly with arguments. See the Exec key for
72 # details on how this key works. The Exec key is required if
73 # DBusActivatable is not set to true. Even if DBusActivatable is true,
74 # Exec should be specified for compatibility with implementations that
75 # do not understand DBusActivatable. (Makes no sense to be omitted in an
76 # autostart context --- acdw)
77 exec="$(get Exec "$1")"
78 test -n "$exec" || return "$(die 4 "Error: No Exec key: $1")"
79 # The OnlyShowIn entry may contain a list of strings identifying
80 # the desktop environments that MUST autostart this application, all
81 # other desktop environments MUST NOT autostart this application. The
82 # NotShowIn entry may contain a list of strings identifying the desktop
83 # environments that MUST NOT autostart this application, all other
84 # desktop environments MUST autostart this application. Only one of
85 # these keys, either OnlyShowIn or NotShowIn, may appear in a single
86 # .desktop file.
87 #
88 ### The OnlyShowIn, NotShowIn keys are specified thus:
89 #
90 # A list of strings identifying the desktop environments that should
91 # display/not display a given desktop entry.
92 #
93 # By default, a desktop file should be shown, unless an OnlyShowIn key
94 # is present, in which case, the default is for the file not to be
95 # shown.
96 #
97 # If $XDG_CURRENT_DESKTOP is set then it contains a colon-separated list
98 # of strings. In order, each string is considered. If a matching entry
99 # is found in OnlyShowIn then the desktop file is shown. If an entry is
100 # found in NotShowIn then the desktop file is not shown. If none of the
101 # strings match then the default action is taken (as above).
102 #
103 # $XDG_CURRENT_DESKTOP should have been set by the login manager,
104 # according to the value of the DesktopNames found in the session
105 # file. The entry in the session file has multiple values separated in
106 # the usual way: with a semicolon.
107 #
108 # The same desktop name may not appear in both OnlyShowIn and NotShowIn
109 # of a group.
110 #
111 ### I think this "functionality" is dubious at best and pretty
112 ### ... silly. --- acdw
113 onlyshowin="$(get OnlyShowIn "$1")"
114 notshowin="$(get NotShowIn "$1")"
115 if test -n "$onlyshowin" && test -n "$notshowin"; then
116 return "$(die 5 "Error: Incompatible keys: OnlyShowIn, NotShowIn: $1")"
117 elif test -n "$onlyshowin"; then
118 start=false
119 else
120 start=true
121 fi
122
123 # This is so cursed
124 quit="$(
125 echo "$XDG_CURRENT_DESKTOP" | tr : \\n |
126 while read desktop; do
127 case "$onlyshowin;$notshowin" in
128 *$desktop*)
129 if test -n "$onlyshowin"; then
130 break
131 elif test -n "$notshowin"; then
132 echo true
133 die 6 "Stopped: NotShowIn=$notshowin"
134 fi
135 ;;
136 *)
137 if ! $start; then
138 echo true
139 die 6 "Stopped: OnlyShowIn=$onlyshowin"
140 fi
141 ;;
142 esac
143 done
144 echo false
145 )"
146 if $quit; then
147 return 6
148 fi
149
150 # A .desktop file with a non-empty TryExec field MUST NOT be autostarted
151 # if the value of the TryExec key does NOT match with an installed
152 # executable program. The value of the TryExec field may either be an
153 # absolute path or the name of an executable without any path
154 # components. If the name of an executable is specified without any path
155 # components then the $PATH environment is searched to find a matching
156 # executable program.
157 tryexec="$(get TryExec "$1")"
158 if test -n "$tryexec"; then
159 command -v "$tryexec" | grep -v ^alias | grep -q / ||
160 return "$(die 7 "Error: TryExec command not found: $tryexec")"
161 fi
162 # If all these tests pass, we're ready to go
163 # XXX: probably won't do quoting properly
164 eprint "> $exec"
165 if $RUN; then
166 $exec &
167 print $! >>"$PID_FILE"
168 fi
169 :
170}
171
172auto_search() { ## auto_search
173 # The Autostart Directories are $XDG_CONFIG_DIRS/autostart as defined
174 # in accordance with the "Referencing this specification" section in
175 # the "desktop base directory specification".
176 #
177 # If the same filename is located under multiple Autostart Directories
178 # only the file under the most important directory should be used.
179 #
180 # Example: If $XDG_CONFIG_HOME is not set the Autostart Directory in the
181 # user's home directory is ~/.config/autostart/
182 #
183 # Example: If $XDG_CONFIG_DIRS is not set the system wide Autostart
184 # Directory is /etc/xdg/autostart/
185 #
186 # Example: If $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS are not set and the
187 # two files /etc/xdg/autostart/foo.desktop and
188 # ~/.config/autostart/foo.desktop exist then only the file
189 # ~/.config/autostart/foo.desktop will be used because
190 # ~/.config/autostart/ is more important than /etc/xdg/autostart/
191 echo "${XDG_CONFIG_HOME:-$HOME/.config}:${XDG_CONFIG_DIRS:-/etc/xdg}" | tr : \\n |
192 sed 's,$,/autostart,' |
193 while read dir; do
194 if test -d "$dir"; then
195 for desktop in "$dir"/*.desktop; do
196 if ! grep "$desktop" "$FOUND_FILE"; then
197 auto_start "$desktop" &&
198 print "$desktop" >>"$FOUND_FILE"
199 else
200 eprint "Already executed: $desktop"
201 fi
202 done
203 fi
204 done
205}
206
207####################################
208
209get() { # get KEY FILE
210 grep "^$1" "${2:-}" 2>/dev/null | cut -d= -f2-
211}
212
213print() {
214 $QUIET || printf '%s\n' "$*"
215}
216
217eprint() {
218 print "$@" >&2
219}
220
221die() {
222 errcode="$1"
223 shift
224 eprint "! $@"
225 echo $errcode
226 exit $errcode
227}
228
229####################################
230
231main "$@"