X-Git-Url: https://code.delx.au/bg-scripts/blobdiff_plain/f9c37d3e9223c407abe5775490b258fb8ad5bdac..1ad2850b8c0ec352f1d096882d961325604afd71:/wallchanger.py diff --git a/wallchanger.py b/wallchanger.py new file mode 100755 index 0000000..b20c068 --- /dev/null +++ b/wallchanger.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# Copyright 2008 Greg Darke +# Copyright 2008 James Bunton +# Licensed for distribution under the GPL version 2, check COPYING for details +# This is a cross platform/cross window manager way to change your wallpaper + +import commands, sys, os, os.path, subprocess, time +from logging import debug, info, warning + +__all__ = ("init", "set_image") + + +changers = [] + +def set_image(filename): + info("Setting image: %s" % filename) + for changer in changers: + if not changer.set_image(filename): + warning("Failed to set background: wallchanger.set_image(%s), changer=%s" % (filename, changer)) + +def init(*args, **kwargs): + """Desktop Changer factory""" + + debug("Testing for OSX (NonX11)") + if commands.getstatusoutput("ps ax -o command -c|grep -q WindowServer")[0] == 0: + changers.append(OSXChanger(*args, **kwargs)) + + if 'DISPLAY' not in os.environ or os.environ['DISPLAY'].startswith('/tmp/launch'): + # X11 is not running + return + else: + if os.uname()[0] == 'Darwin': + # Try to detect if the X11 server is running on OSX + if commands.getstatusoutput("ps ax -o command|grep -q '/.*X11 .* %s'" % os.environ['DISPLAY'])[0] != 0: + # X11 is not running for this display + return + + debug("Testing for KDE") + if commands.getstatusoutput("xwininfo -name 'KDE Desktop'")[0] == 0: + changers.append(KDEChanger(*args, **kwargs)) + + debug("Testing for Gnome") + if commands.getstatusoutput("xwininfo -name 'gnome-session'")[0] == 0: + changers.append(GnomeChanger(*args, **kwargs)) + + debug("Testing for WMaker") + if commands.getstatusoutput("xlsclients | grep -qi wmaker")[0] == 0: + changers.append(WMakerChanger(*args, **kwargs)) + + if len(changers) == 0: + raise Exception("Unknown window manager") + + +class BaseChanger(object): + name = "undefined" + def __init__(self, background_color='black', permanent=False, convert=False): + info('Determined the window manager is "%s"' % self.name) + self.background_color = background_color + self.permanent = permanent + self.convert = convert + + def set_image(self, filename): + raise NotImplementedError() + +class WMakerChanger(BaseChanger): + name = "WindowMaker" + _ConvertedWallpaperLocation = '/tmp/wallpapers_wmaker/' + def remove_old_image_cache(self): + """Cleans up any old temp images""" + if not os.path.isdir(self._ConvertedWallpaperLocation): + os.mkdir(self._ConvertedWallpaperLocation) + for fullpath, filenames, dirnames in os.walk(self._ConvertedWallpaperLocation, topdown=False): + for filename in filenames: + os.unlink(os.path.join(fullpath, filename)) + for dirname in dirnames: + os.unlink(os.path.join(fullpath, dirname)) + + def convert_image_format(self, file): + """Convert the image to a png, and store it in a local place""" + self.remove_old_image_cache() + output_name = os.path.join(self._ConvertedWallpaperLocation, '%s.png' % time.time()) + cmd = ["convert", '-resize', '1280', '-gravity', 'Center', '-crop', '1280x800+0+0', file, output_name] + debug("""Convert command: '"%s"'""" % '" "'.join(cmd)) + return output_name, subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=None).wait() + + def set_image(self, file): + if self.convert: + file, convert_status = self.convert_image_format(file) + if convert_status: + debug('Convert failed') + cmd = ["wmsetbg", + "-b", self.background_color, # 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 +### "-a", # scale the image, keeping the aspect ratio + "-u", # Force this to be the default background + "-d" # dither + ] + if self.permanent: + cmd += ["-u"] # update the wmaker database + cmd += [file] + debug('''WMaker bgset command: "'%s'"''' % "' '".join(cmd)) + return not subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=None).wait() + +class OSXChanger(BaseChanger): + name = "Mac OS X" + _ConvertedWallpaperLocation = '/tmp/wallpapers/' + _DesktopPlistLocation = os.path.expanduser('~/Library/Preferences/com.apple.desktop.plist') + + def __init__(self, *args, **kwargs): + BaseChanger.__init__(self, *args, **kwargs) + self.fix_desktop_plist() + + def remove_old_image_cache(self): + """Cleans up any old temp images""" + if not os.path.isdir(self._ConvertedWallpaperLocation): + os.mkdir(self._ConvertedWallpaperLocation) + for fullpath, filenames, dirnames in os.walk(self._ConvertedWallpaperLocation, topdown=False): + for filename in filenames: + os.unlink(os.path.join(fullpath, filename)) + for dirname in dirnames: + os.unlink(os.path.join(fullpath, dirname)) + + def convert_image_format(self, file): + """Convert the image to a png, and store it in a local place""" + self.remove_old_image_cache() + output_name = os.path.join(self._ConvertedWallpaperLocation, '%s.png' % time.time()) + try: + import PIL, PIL.Image + img = PIL.Image.open(file) + img.save(output_name, "PNG") + return output_name, True + except ImportError: + debug('Could not load PIL, going to try just copying the image') + import shutil + output_name = os.path.join(self._ConvertedWallpaperLocation, os.path.basename(file)) + shutil.copyfile(file, output_name) + return output_name, True + + def fix_desktop_plist(self): + """Removes the entry in the desktop plist file that specifies the wallpaper for each monitor""" + try: + import Foundation + desktop_plist = Foundation.NSMutableDictionary.dictionaryWithContentsOfFile_(self._DesktopPlistLocation) + # Remove all but the 'default' entry + for k in desktop_plist['Background'].keys(): + if k == 'default': + continue + desktop_plist['Background'].removeObjectForKey_(k) + # Store the plist again (Make sure we write it out atomically -- Don't want to break finder) + desktop_plist.writeToFile_atomically_(self._DesktopPlistLocation, True) + except ImportError: + debug('Could not import the Foundation module, you may have problems with dual screens') + + def set_image(self, filename): + if self.convert: + filename, ret = self.convert_image_format(filename) + if not ret: + debug("Convert failed") + return False + cmd = """osascript -e 'tell application "finder" to set desktop picture to posix file "%s"'""" % filename + debug(cmd) + return not commands.getstatusoutput(cmd)[0] + +class GnomeChanger(BaseChanger): + name = "Gnome" + def set_image(self, file): + cmd = ['gconftool-2', '--type', 'string', '--set', '/desktop/gnome/background/picture_filename', file] + debug(cmd) + return not subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=None).wait() + +class KDEChanger(BaseChanger): + name = "KDE" + def set_image(self, file): + cmds = [] + for group in ('Desktop0', 'Desktop0Screen0'): + base = ['kwriteconfig', '--file', 'kdesktoprc', '--group', group, '--key'] + cmds.append(base + ['Wallpaper', file]) + cmds.append(base + ['UseSHM', '--type', 'bool', 'true']) + cmds.append(base + ['WallpaperMode', 'ScaleAndCrop']) + cmds.append(base + ['MultiWallpaperMode', 'NoMulti']) + + cmds.append(['dcop', 'kdesktop', 'KBackgroundIface', 'configure']) + for cmd in cmds: + debug(cmd) + if subprocess.Popen(cmd, stdout=sys.stdout, stderr=sys.stderr, stdin=None).wait() != 0: + return False + + return True + + +def main(filename): + import logging + logging.basicConfig(level=logging.DEBUG, format="%(levelname)s: %(message)s") + init() + set_image(filename) + +if __name__ == "__main__": + try: + filename = sys.argv[1] + except: + print >>sys.stderr, "Usage: %s filename" % sys.argv[0] + sys.exit(1) + + main(filename) + +