9ea03fdf058e418bdad00ea3e546db4a2071f8a7
[mikachu/openbox.git] / tools / xdg-autostart / xdg-autostart
1 #!/usr/bin/env python
2
3 # xdg-autostart runs things based on the XDG autostart specification
4 # Copyright (C) 2008       Dana Jansens
5 #
6 # XDG autostart specification can be found here:
7 # http://standards.freedesktop.org/autostart-spec/
8 #
9 #
10 #
11 # LICENSE:
12 #   This program is free software; you can redistribute it and/or modify
13 #   it under the terms of the GNU General Public License as published by
14 #   the Free Software Foundation; either version 2 of the License, or
15 #   (at your option) any later version.
16 #
17 #   This program is distributed in the hope that it will be useful,
18 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
19 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 #   GNU General Public License for more details.
21
22 ME="xdg-autostart"
23 VERSION="1.0"
24
25 import os, glob, sys
26 try:
27     from xdg import BaseDirectory
28     from xdg.DesktopEntry import DesktopEntry
29     from xdg.Exceptions import ParsingError
30 except ImportError:
31     print
32     print "ERROR:", ME, "requires PyXDG to be installed"
33     print
34     sys.exit(1)
35
36 def main(argv=sys.argv):
37     if "--help" in argv[1:]:
38         show_help()
39         return 0
40     if "--version" in argv[1:]:
41         show_version()
42         return 0
43
44     # get the autostart directories
45     autodirs = BaseDirectory.load_config_paths("autostart")
46
47     # find all the autostart files
48     files = []
49     for dir in autodirs:
50         for path in glob.glob(os.path.join(dir, '*.desktop')):
51             try:
52                 autofile = AutostartFile(path)
53             except ParsingError:
54                 print "Invalid .desktop file: " + path
55             else:
56                 if not autofile in files:
57                     files.append(autofile)
58
59     list = False
60     if "--list" in argv[1:]:
61         list = True
62         argv.remove("--list")
63
64     # run them !
65     environments = argv[1:]
66     for autofile in files:
67         if list: autofile.display(environments)
68         else: autofile.run(environments)
69
70 class AutostartFile:
71     def __init__(self, path):
72         self.path = path
73         self.filename = os.path.basename(path)
74         self.dirname = os.path.dirname(path)
75         self.de = DesktopEntry(path)
76
77     def __eq__(self, other):
78         return self.filename == other.filename
79
80     def __str__(self):
81         return self.path + " : " + self.de.getName()
82
83     def _isexecfile(path):
84         return os.access(path, os.X_OK)
85
86     def _findFile(self, path, search, match_func):
87         # check empty path
88         if not path: return None
89         # check absolute path
90         if path[0] == '/':
91             if match_func(path): return path
92             else: return None
93         else:
94             # check relative path
95             for dirname in search.split(os.pathsep):
96                 if dirname != "":
97                     candidate = os.path.join(dirname, path)
98                     if (match_func(candidate)): return candidate
99
100     def _alert(self, str, info=False):
101         if info:
102             print "\t ", str
103         else:
104             print "\t*", str
105
106     def _showInEnvironment(self, envs, verbose=False):
107         default = not self.de.getOnlyShowIn()
108         noshow = False
109         force = False
110         for i in self.de.getOnlyShowIn():
111             if i in envs: force = True
112         for i in self.de.getNotShowIn():
113             if i in envs: noshow = True
114
115         if verbose:
116             if not default and not force:
117                 s = ""
118                 for i in self.de.getOnlyShowIn():
119                     if s: s += ", "
120                     s += i
121                 self._alert("Excluded by: OnlyShowIn (" + s + ")")
122             if default and noshow and not force:
123                 s = ""
124                 for i in self.de.getOnlyShowIn():
125                     if s: s += ", "
126                     s += i
127                 self._alert("Excluded by: NotShowIn (" + s + ")")
128         return (default and not noshow) or force
129
130     def _shouldRun(self, envs, verbose=False):
131         if not self.de.getExec():
132             if verbose: self._alert("Excluded by: Missing Exec field")
133             return False
134         if self.de.getHidden():
135             if verbose: self._alert("Excluded by: Hidden")
136             return False
137         if self.de.getTryExec():
138             if not self._findFile(self.de.getTryExec(), os.getenv("PATH"),
139                                   self._isexecfile):
140                 if verbose: self._alert("Excluded by: TryExec (" +
141                                         self.de.getTryExec() + ")")
142                 return False
143         if not self._showInEnvironment(envs, verbose):
144             return False
145         return True
146
147     def display(self, envs):
148         if self._shouldRun(envs):
149             print "[*] " + self.de.getName()
150         else:
151             print "[ ] " + self.de.getName()
152         self._alert("File: " + self.path, info=True)
153         if self.de.getExec():
154             self._alert("Executes: " + self.de.getExec(), info=True)
155         self._shouldRun(envs, True)
156         print
157
158     def run(self, envs):
159         here = os.getcwd()
160         if self.de.getPath():
161             os.chdir(self.de.getPath())
162         if self._shouldRun(envs):
163             args = ["/bin/sh", "-c", "exec " + self.de.getExec()]
164             os.spawnv(os.P_NOWAIT, args[0], args);
165         os.chdir(here)
166
167 def show_help():
168     print "Usage:", ME, "[OPTION]... [ENVIRONMENT]..."
169     print
170     print "This tool will run xdg autostart .desktop files"
171     print
172     print "OPTIONS"
173     print "  --list        Show a list of the files which would be run"
174     print "                Files which would be run are marked with an asterix"
175     print "                symbol [*].  For files which would not be run,"
176     print "                information is given for why they are excluded"
177     print "  --help        Show this help and exit"
178     print "  --version     Show version and copyright information"
179     print
180     print "ENVIRONMENT specifies a list of environments for which to run autostart"
181     print "applications.  If none are specified, only applications which do not "
182     print "limit themselves to certain environments will be run."
183     print
184     print "ENVIRONMENT can be one or more of:"
185     print "  GNOME         Gnome Desktop"
186     print "  KDE           KDE Desktop"
187     print "  ROX           ROX Desktop"
188     print "  XFCE          XFCE Desktop"
189     print "  Old           Legacy systems"
190     print
191
192 def show_version():
193     print ME, VERSION
194     print "Copyright (c) 2008        Dana Jansens"
195     print
196
197 if __name__ == "__main__":
198         sys.exit(main())