]> code.delx.au - bg-scripts/blob - bin/randombg2
WallChanger:Removed the MacOSX dependency on imagemagick, we now depend on PIL (Pytho...
[bg-scripts] / bin / randombg2
1 #!/usr/bin/env python
2
3 import commands, sys, os, os.path, random, socket, subprocess
4 import cPickle, datetime, time
5 from optparse import OptionParser, Values
6
7 VERSION = "1.1"
8 CACHE_LOCATION = os.path.expanduser('~/.randombg2_filelist_cache')
9
10 try:
11 import GregDebug
12 from SigHandler import HUPInterrupt
13 from GregDebug import debug, setDebugLevel, DEBUG_LEVEL_DEBUG, DEBUG_LEVEL_LOW, DEBUG_LEVEL_MEDIUM, DEBUG_LEVEL_HIGH, DEBUG_INCREMENT
14 from FileLists import *
15 except ImportError:
16 print >>sys.stderr, "Missing libraries!\nExiting..."
17 sys.exit(1)
18
19 try:
20 from collections import defaultdict
21 def magicdict():
22 return defaultdict(dict)
23 except ImportError:
24 class magicdict(dict):
25 def __getitem__(self, key):
26 if not self.has_key(key):
27 self[key] = {}
28 return dict.__getitem__(self, key)
29
30 class RandomBG(object):
31 KDE_CONFIG = os.path.expanduser('~/.kde/share/config/kdesktoprc')
32 def __init__(self, filelist, backgroundColour='black', permanent=False):
33 windowManager = self._determineWindowManager()
34 debug('Determined the window manager is "%s"' % windowManager, DEBUG_LEVEL_MEDIUM)
35 self.backgroundColour = backgroundColour
36 self.permanent = permanent
37 self.filelist = filelist
38
39 if windowManager == "WMAKER":
40 self._randombg = self._randombgWMAKER
41 elif windowManager == "KDE":
42 self._randombg = self._randombgKDE
43 elif windowManager == "OSX":
44 self._randombg = self._randombgOSX
45 else:
46 raise Exception("Unknown window manager")
47
48 def _determineWindowManager(self):
49 """Searches for a some specified windows within the current X session to see
50 what window manager we are running under"""
51
52 debug("Testing for OSX (NonX)", DEBUG_LEVEL_LOW)
53 if commands.getstatusoutput("ps ax -o command -c|grep -q WindowServer")[0] == 0:
54 return "OSX"
55 debug("Testing for KDE", DEBUG_LEVEL_LOW)
56 if commands.getstatusoutput("xwininfo -name 'KDE Desktop'")[0] == 0:
57 return "KDE"
58 debug("Testing for WMaker", DEBUG_LEVEL_LOW)
59 if commands.getstatusoutput("xlsclients | grep -qi wmaker")[0] == 0:
60 return "WMAKER"
61
62 return None
63
64 def _randombgWMAKER(self, file):
65 cmd = ["wmsetbg",
66 "-b", self.backgroundColour, # Sets the background colour to be what the user specified
67 "-S", # 'Smooth' (WTF?)
68 "-e", # Center the image on the screen (only affects when the image in no the in the correct aspect ratio
69 "-d", # dither
70 "-a"] # scale the image, keeping the aspect ratio
71 if self.permanent:
72 cmd += ["-u"] # update the wmaker database
73 cmd += [file]
74 return subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=open('/dev/null', 'r')).wait()
75
76 def _randombgOSX(self, file):
77 cmd = """osascript -e 'tell application "finder" to set desktop picture to posix file "%s"'""" % file
78 debug(cmd, DEBUG_LEVEL_DEBUG)
79 return commands.getstatusoutput(cmd)[0]
80
81 def _parseKDEConfig(self, filename = KDE_CONFIG):
82 fd = open(filename, 'r')
83 result = magicdict()
84 section = None
85 for line in fd:
86 line = line.strip()
87 if not line or line.startswith('#'):
88 continue
89
90 if line.startswith('[') and line.endswith(']'):
91 section = line[1:-1]
92 result[section] = {}
93 continue
94 elif not section:
95 raise Exception('Invalid kdesktoprc file')
96
97 unpack = line.split('=', 1)
98 if len(unpack) == 2:
99 key, val = unpack
100 else:
101 key, val = unpack[0], None
102 result[section][key] = val
103
104 fd.close()
105 return result
106
107 def _writeKDEConfig(self, config, filename = KDE_CONFIG):
108 fd = open(filename, 'w')
109 for section, values in config.items():
110 print >>fd, '[%s]' % section
111 for k, v in values.items():
112 if v != None:
113 print >>fd, '%s=%s' % (k,v)
114 else:
115 print >>fd, k
116 print >>fd
117 fd.close()
118
119 def _randombgKDE(self, file):
120 kdeconfig = self._parseKDEConfig()
121 #kdeconfig['Background Common']['DrawBackgroundPerScreen_0']='true'
122 for section in ('Desktop0', 'Desktop0Screen0'):
123 kdeconfig[section]['Wallpaper'] = file
124 kdeconfig[section]['UseSHM'] = 'true'
125 kdeconfig[section]['WallpaperMode'] = 'ScaleAndCrop'
126 # Ensure that random mode is disabled...
127 if 'MultiWallpaperMode' in kdeconfig[section]:
128 del kdeconfig[section]['MultiWallpaperMode']
129
130 self._writeKDEConfig(kdeconfig)
131
132 return subprocess.Popen(['dcop', 'kdesktop', 'KBackgroundIface', 'configure'],
133 stdout=sys.stdout, stderr=sys.stderr, stdin=open('/dev/null', 'r')).wait()
134
135 def __call__(self):
136 self.cycleNext()
137
138 def cycleNext(self):
139 file = self.filelist.getNextRandomImage()
140 return self._randombg(file)
141
142 def cyclePrev(self):
143 file = self.filelist.getPrevRandomImage()
144 return self._randombg(file)
145
146 def buildparser():
147 def addfilestolist(optclass, opt, value, parser, fileList):
148 fo = open(value)
149 for line in fo:
150 fileList.list.append(line.strip())
151 fo.close()
152 fileList.allowAllRandom = False
153
154 parser = OptionParser(version="%prog " + VERSION,
155 description = "Picks a random background image",
156 usage = "%prog [options] dir [dir2 ...]")
157 parser.add_option("-p", "--permanent",
158 action="store_true", dest="permanent", default=False,
159 help="Make the background permanent. Note: This will cause all machines logged in with this account to simultaneously change background [Default: %default]")
160 parser.add_option("-q", "--quiet", "--silent",
161 action="count", dest="quiet", default=0,
162 help="Make the script quiet (good for running from a shell script)")
163 parser.add_option("-v", '-d', "--verbose", "--debug",
164 action="count", dest="verbose", default=0,
165 help="Make the louder (good for debugging, or those who are curious)")
166 parser.add_option("-b", "--background-colour",
167 action="store", type="string", dest="background_colour", default="black",
168 help="Change the default background colour that is displayed if the image is not in the correct aspect ratio [Default: %default]")
169 parser.add_option("--all-random",
170 action="store_true", dest="all_random", default=False,
171 help="Make sure that all images have been displayed before repeating an image")
172 parser.add_option("--folder-random",
173 action="store_true", dest="folder_random", default=False,
174 help="Give each folder an equal chance of having an image selected from it")
175 #parser.add_option("--file-list",
176 # action="callback", callback=addfilestolist, type="string", callback_args=(fileList,),
177 # help="Adds the list of images from the external file")
178 parser.add_option("--cycle",
179 action="store", type="int", default=0, dest="cycle_time",
180 help="Cause the image to cycle every X seconds")
181 return parser
182
183 def main():
184 parser = buildparser()
185 useroptions, paths = parser.parse_args(sys.argv[1:])
186
187 setDebugLevel(DEBUG_INCREMENT * (useroptions.quiet - useroptions.verbose))
188 debug("Just set GregDebug.DEBUG_LEVEL to %d" % GregDebug.DEBUG_LEVEL, DEBUG_LEVEL_LOW)
189
190 if useroptions.all_random:
191 filelist = AllRandomFileList()
192 elif useroptions.folder_random:
193 filelist = FolderRandomFileList()
194 else:
195 filelist = RandomFileList()
196
197 for path in paths:
198 filelist.doAddPath(path)
199
200 if filelist.attemptCacheLoad(CACHE_LOCATION):
201 debug("Loaded cache successfully", DEBUG_LEVEL_LOW)
202 else:
203 debug("Could not load cache")
204 filelist.doScanPaths()
205 try:
206
207 if not filelist.hasImages():
208 print >>sys.stderr, "No files!"
209 parser.print_help()
210 sys.exit(1)
211
212 ret = None
213 debug("Initilizing RandomBG", DEBUG_LEVEL_DEBUG)
214 randombg = RandomBG(filelist, useroptions.background_colour, useroptions.permanent)
215 if useroptions.cycle_time > 0:
216 while True:
217 try:
218 debug("Cycling wallpaper", DEBUG_LEVEL_LOW)
219 ret = randombg()
220 if ret:
221 debug('Could not set wallpaper. Returned "%s" % ret')
222 break
223 debug('About to sleep for "%d" seconds' % useroptions.cycle_time, DEBUG_LEVEL_LOW)
224 time.sleep(useroptions.cycle_time)
225 except KeyboardInterrupt, e:
226 break
227 debug("Caught KeyboardInterrupt", DEBUG_LEVEL_LOW)
228 except HUPInterrupt, e:
229 # Force a new image to be displayed before the timeout
230 debug("Caught SIGHUP: Loading new image")
231 else:
232 ret = randombg()
233
234 finally:
235 filelist.doStoreCache(CACHE_LOCATION)
236
237 sys.exit(ret)
238
239 if __name__ == "__main__":
240 main()