+#!/usr/bin/env python
+
+import commands, sys, os, os.path, random, socket, subprocess
+import cPickle, datetime, time
+from optparse import OptionParser, Values
+
+VERSION = "1.1"
+CACHE_LOCATION = os.path.expanduser('~/.randombg2_filelist_cache')
+
+try:
+ import GregDebug
+ from SigHandler import HUPInterrupt
+ from GregDebug import debug, setDebugLevel, DEBUG_LEVEL_DEBUG, DEBUG_LEVEL_LOW, DEBUG_LEVEL_MEDIUM, DEBUG_LEVEL_HIGH, DEBUG_INCREMENT
+ from FileLists import *
+except ImportError:
+ print >>sys.stderr, "Missing libraries!\nExiting..."
+ sys.exit(1)
+
+try:
+ from collections import defaultdict
+ def magicdict():
+ return defaultdict(dict)
+except ImportError:
+ class magicdict(dict):
+ def __getitem__(self, key):
+ if not self.has_key(key):
+ self[key] = {}
+ return dict.__getitem__(self, key)
+
+class RandomBG(object):
+ KDE_CONFIG = os.path.expanduser('~/.kde/share/config/kdesktoprc')
+ def __init__(self, filelist, backgroundColour='black', permanent=False):
+ windowManager = self._determineWindowManager()
+ debug('Determined the window manager is "%s"' % windowManager, DEBUG_LEVEL_MEDIUM)
+ self.backgroundColour = backgroundColour
+ self.permanent = permanent
+ self.filelist = filelist
+
+ if windowManager == "WMAKER":
+ self._randombg = self._randombgWMAKER
+ elif windowManager == "KDE":
+ self._randombg = self._randombgKDE
+ elif windowManager == "OSX":
+ self._randombg = self._randombgOSX
+ else:
+ raise Exception("Unknown window manager")
+
+ def _determineWindowManager(self):
+ """Searches for a some specified windows within the current X session to see
+ what window manager we are running under"""
+
+ debug("Testing for OSX (NonX)", DEBUG_LEVEL_LOW)
+ if commands.getstatusoutput("ps ax -o command -c|grep -q WindowServer")[0] == 0:
+ return "OSX"
+ debug("Testing for KDE", DEBUG_LEVEL_LOW)
+ if commands.getstatusoutput("xwininfo -name 'KDE Desktop'")[0] == 0:
+ return "KDE"
+ debug("Testing for WMaker", DEBUG_LEVEL_LOW)
+ if commands.getstatusoutput("xlsclients | grep -qi wmaker")[0] == 0:
+ return "WMAKER"
+
+ return None
+
+ def _randombgWMAKER(self, file):
+ cmd = ["wmsetbg",
+ "-b", self.backgroundColour, # Sets the background colour to be what the user specified
+ "-S", # 'Smooth' (WTF?)
+ "-e", # Center the image on the screen (only affects when the image in no the in the correct aspect ratio
+ "-d", # dither
+ "-a"] # scale the image, keeping the aspect ratio
+ if self.permanent:
+ cmd += ["-u"] # update the wmaker database
+ cmd += [file]
+ return subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=open('/dev/null', 'r')).wait()
+
+ def _randombgOSX(self, file):
+ cmd = """osascript -e 'tell application "finder" to set desktop picture to posix file "%s"'""" % file
+ debug(cmd, DEBUG_LEVEL_DEBUG)
+ return commands.getstatusoutput(cmd)[0]
+
+ def _parseKDEConfig(self, filename = KDE_CONFIG):
+ fd = open(filename, 'r')
+ result = magicdict()
+ section = None
+ for line in fd:
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+
+ if line.startswith('[') and line.endswith(']'):
+ section = line[1:-1]
+ result[section] = {}
+ continue
+ elif not section:
+ raise Exception('Invalid kdesktoprc file')
+
+ unpack = line.split('=', 1)
+ if len(unpack) == 2:
+ key, val = unpack
+ else:
+ key, val = unpack[0], None
+ result[section][key] = val
+
+ fd.close()
+ return result
+
+ def _writeKDEConfig(self, config, filename = KDE_CONFIG):
+ fd = open(filename, 'w')
+ for section, values in config.items():
+ print >>fd, '[%s]' % section
+ for k, v in values.items():
+ if v != None:
+ print >>fd, '%s=%s' % (k,v)
+ else:
+ print >>fd, k
+ print >>fd
+ fd.close()
+
+ def _randombgKDE(self, file):
+ kdeconfig = self._parseKDEConfig()
+ #kdeconfig['Background Common']['DrawBackgroundPerScreen_0']='true'
+ for section in ('Desktop0', 'Desktop0Screen0'):
+ kdeconfig[section]['Wallpaper'] = file
+ kdeconfig[section]['UseSHM'] = 'true'
+ kdeconfig[section]['WallpaperMode'] = 'ScaleAndCrop'
+ # Ensure that random mode is disabled...
+ if 'MultiWallpaperMode' in kdeconfig[section]:
+ del kdeconfig[section]['MultiWallpaperMode']
+
+ self._writeKDEConfig(kdeconfig)
+
+ return subprocess.Popen(['dcop', 'kdesktop', 'KBackgroundIface', 'configure'],
+ stdout=sys.stdout, stderr=sys.stderr, stdin=open('/dev/null', 'r')).wait()
+
+ def __call__(self):
+ self.cycleNext()
+
+ def cycleNext(self):
+ file = self.filelist.getNextRandomImage()
+ return self._randombg(file)
+
+ def cyclePrev(self):
+ file = self.filelist.getPrevRandomImage()
+ return self._randombg(file)
+
+def buildparser():
+ def addfilestolist(optclass, opt, value, parser, fileList):
+ fo = open(value)
+ for line in fo:
+ fileList.list.append(line.strip())
+ fo.close()
+ fileList.allowAllRandom = False
+
+ parser = OptionParser(version="%prog " + VERSION,
+ description = "Picks a random background image",
+ usage = "%prog [options] dir [dir2 ...]")
+ parser.add_option("-p", "--permanent",
+ action="store_true", dest="permanent", default=False,
+ help="Make the background permanent. Note: This will cause all machines logged in with this account to simultaneously change background [Default: %default]")
+ parser.add_option("-q", "--quiet", "--silent",
+ action="count", dest="quiet", default=0,
+ help="Make the script quiet (good for running from a shell script)")
+ parser.add_option("-v", '-d', "--verbose", "--debug",
+ action="count", dest="verbose", default=0,
+ help="Make the louder (good for debugging, or those who are curious)")
+ parser.add_option("-b", "--background-colour",
+ action="store", type="string", dest="background_colour", default="black",
+ help="Change the default background colour that is displayed if the image is not in the correct aspect ratio [Default: %default]")
+ parser.add_option("--all-random",
+ action="store_true", dest="all_random", default=False,
+ help="Make sure that all images have been displayed before repeating an image")
+ parser.add_option("--folder-random",
+ action="store_true", dest="folder_random", default=False,
+ help="Give each folder an equal chance of having an image selected from it")
+ #parser.add_option("--file-list",
+ # action="callback", callback=addfilestolist, type="string", callback_args=(fileList,),
+ # help="Adds the list of images from the external file")
+ parser.add_option("--cycle",
+ action="store", type="int", default=0, dest="cycle_time",
+ help="Cause the image to cycle every X seconds")
+ return parser
+
+def main():
+ parser = buildparser()
+ useroptions, paths = parser.parse_args(sys.argv[1:])
+
+ setDebugLevel(DEBUG_INCREMENT * (useroptions.quiet - useroptions.verbose))
+ debug("Just set GregDebug.DEBUG_LEVEL to %d" % GregDebug.DEBUG_LEVEL, DEBUG_LEVEL_LOW)
+
+ if useroptions.all_random:
+ filelist = AllRandomFileList()
+ elif useroptions.folder_random:
+ filelist = FolderRandomFileList()
+ else:
+ filelist = RandomFileList()
+
+ for path in paths:
+ filelist.doAddPath(path)
+
+ if filelist.attemptCacheLoad(CACHE_LOCATION):
+ debug("Loaded cache successfully", DEBUG_LEVEL_LOW)
+ else:
+ debug("Could not load cache")
+ filelist.doScanPaths()
+ try:
+
+ if not filelist.hasImages():
+ print >>sys.stderr, "No files!"
+ parser.print_help()
+ sys.exit(1)
+
+ ret = None
+ debug("Initilizing RandomBG", DEBUG_LEVEL_DEBUG)
+ randombg = RandomBG(filelist, useroptions.background_colour, useroptions.permanent)
+ if useroptions.cycle_time > 0:
+ while True:
+ try:
+ debug("Cycling wallpaper", DEBUG_LEVEL_LOW)
+ ret = randombg()
+ if ret:
+ debug('Could not set wallpaper. Returned "%s" % ret')
+ break
+ debug('About to sleep for "%d" seconds' % useroptions.cycle_time, DEBUG_LEVEL_LOW)
+ time.sleep(useroptions.cycle_time)
+ except KeyboardInterrupt, e:
+ break
+ debug("Caught KeyboardInterrupt", DEBUG_LEVEL_LOW)
+ except HUPInterrupt, e:
+ # Force a new image to be displayed before the timeout
+ debug("Caught SIGHUP: Loading new image")
+ else:
+ ret = randombg()
+
+ finally:
+ filelist.doStoreCache(CACHE_LOCATION)
+
+ sys.exit(ret)
+
+if __name__ == "__main__":
+ main()