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