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