3 import commands
, sys
, os
, os
.path
, subprocess
, time
4 from GregDebug
import debug
, setDebugLevel
, DEBUG_LEVEL_DEBUG
, DEBUG_LEVEL_LOW
, DEBUG_LEVEL_MEDIUM
, DEBUG_LEVEL_HIGH
, DEBUG_INCREMENT
6 import python24_adapter
# NB: Must be imported before collections
9 """This is a cross platform/cross window manager way to change your current
12 __all__
= ('RandomBG')
14 def RandomBG(*args
, **kwargs
):
15 """Desktop Changer factory"""
19 debug("Testing for OSX (NonX11)", DEBUG_LEVEL_LOW
)
20 if commands
.getstatusoutput("ps ax -o command -c|grep -q WindowServer")[0] == 0:
21 ret
= __OSXChanger(*args
, **kwargs
)
23 if 'DISPLAY' not in os
.environ
or os
.environ
['DISPLAY'].startswith('/tmp/launch'):
27 if os
.uname()[0] == 'Darwin':
28 # Try to detect if the X11 server is running on OSX
29 if commands
.getstatusoutput("ps ax -o command|grep -q '/.*X11 .* %s'" % os
.environ
['DISPLAY'])[0] != 0:
30 # X11 is not running for this display
33 debug("Testing for KDE", DEBUG_LEVEL_LOW
)
34 if commands
.getstatusoutput("xwininfo -name 'KDE Desktop'")[0] == 0:
36 ret
.nextChanger
= __KDEChanger(*args
, **kwargs
)
38 ret
= __KDEChanger(*args
, **kwargs
)
40 debug("Testing for Gnome", DEBUG_LEVEL_LOW
)
41 if commands
.getstatusoutput("xwininfo -name 'gnome-session'")[0] == 0:
43 ret
.nextChanger
= __GnomeChanger(*args
, **kwargs
)
45 ret
= __GnomeChanger(*args
, **kwargs
)
47 debug("Testing for WMaker", DEBUG_LEVEL_LOW
)
48 if commands
.getstatusoutput("xlsclients | grep -qi wmaker")[0] == 0:
50 ret
.nextChanger
= __WMakerChanger(*args
, **kwargs
)
52 ret
= __WMakerChanger(*args
, **kwargs
)
55 raise Exception("Unknown window manager")
59 class __BaseChanger(object):
60 def __init__(self
, backgroundColour
='black', permanent
=False):
61 debug('Determined the window manager is "%s"' % self
.__class
__.__name
__, DEBUG_LEVEL_MEDIUM
)
62 self
.backgroundColour
= backgroundColour
63 self
.permanent
= permanent
64 # Used to 'chain' background changers
65 self
.nextChanger
= None
67 def setImage(self
, filename
):
68 self
._setImage
(filename
)
69 if self
.nextChanger
is not None:
70 self
.nextChange
.changeTo(filename
)
72 class __WMakerChanger(__BaseChanger
):
73 _ConvertedWallpaperLocation
= '/tmp/wallpapers_wmaker/'
74 def _removeOldImageCache(self
):
75 """Cleans up any old temp images"""
76 if not os
.path
.isdir(self
._ConvertedWallpaperLocation
):
77 os
.mkdir(self
._ConvertedWallpaperLocation
)
78 for fullpath
, filenames
, dirnames
in os
.walk(self
._ConvertedWallpaperLocation
, topdown
=False):
79 for filename
in filenames
:
80 os
.unlink(os
.path
.join(fullpath
, filename
))
81 for dirname
in dirnames
:
82 os
.unlink(os
.path
.join(fullpath
, dirname
))
84 def _convertImageFormat(self
, file):
85 """Convert the image to a png, and store it in a local place"""
86 self
._removeOldImageCache
()
87 output_name
= os
.path
.join(self
._ConvertedWallpaperLocation
, '%s.png' % time
.time())
88 cmd
= ["convert", '-resize', '1280', '-gravity', 'Center', '-crop', '1280x800+0+0', file, output_name
]
89 debug("""Convert command: '"%s"'""" % '" "'.join(cmd
), DEBUG_LEVEL_DEBUG
)
90 return output_name
, subprocess
.Popen(cmd
, stdout
=sys
.stdout
, stderr
=sys
.stderr
, stdin
=None).wait()
92 def _setImage(self
, file):
93 file, convert_status
= self
._convertImageFormat
(file)
95 debug('Convert failed')
97 "-b", self
.backgroundColour
, # Sets the background colour to be what the user specified
98 "-S", # 'Smooth' (WTF?)
99 "-e", # Center the image on the screen (only affects when the image in no the in the correct aspect ratio
100 ### "-a", # scale the image, keeping the aspect ratio
101 "-u", # Force this to be the default background
105 cmd
+= ["-u"] # update the wmaker database
107 debug('''WMaker bgset command: "'%s'"''' % "' '".join(cmd
), DEBUG_LEVEL_DEBUG
)
108 return not subprocess
.Popen(cmd
, stdout
=sys
.stdout
, stderr
=sys
.stderr
, stdin
=None).wait()
110 class __OSXChanger(__BaseChanger
):
111 _ConvertedWallpaperLocation
= '/tmp/wallpapers/'
112 _DesktopPlistLocation
= os
.path
.expanduser('~/Library/Preferences/com.apple.desktop.plist')
114 def _removeOldImageCache(self
):
115 """Cleans up any old temp images"""
116 if not os
.path
.isdir(self
._ConvertedWallpaperLocation
):
117 os
.mkdir(self
._ConvertedWallpaperLocation
)
118 for fullpath
, filenames
, dirnames
in os
.walk(self
._ConvertedWallpaperLocation
, topdown
=False):
119 for filename
in filenames
:
120 os
.unlink(os
.path
.join(fullpath
, filename
))
121 for dirname
in dirnames
:
122 os
.unlink(os
.path
.join(fullpath
, dirname
))
124 def _convertImageFormat(self
, file):
125 """Convert the image to a png, and store it in a local place"""
126 self
._removeOldImageCache
()
127 output_name
= os
.path
.join(self
._ConvertedWallpaperLocation
, '%s.png' % time
.time())
129 import PIL
, PIL
.Image
130 img
= PIL
.Image
.open(file)
131 img
.save(output_name
, "PNG")
132 return output_name
, True
134 debug('Could not load PIL, going to try just copying the image')
136 output_name
= os
.path
.join(self
._ConvertedWallpaperLocation
, os
.path
.basename(file))
137 shutil
.copyfile(file, output_name
)
138 return output_name
, True
140 def _fixDesktopPList(self
):
141 """Removes the entry in the desktop plist file that specifies the wallpaper for each monitor"""
144 desktopPList
= Foundation
.NSMutableDictionary
.dictionaryWithContentsOfFile_(self
._DesktopPlistLocation
)
145 # Remove all but the 'default' entry
146 for k
in desktopPList
['Background'].keys():
149 desktopPList
['Background'].removeObjectForKey_(k
)
150 # Store the plist again (Make sure we write it out atomically -- Don't want to break finder)
151 desktopPList
.writeToFile_atomically_(self
._DesktopPlistLocation
, True)
153 debug('Could not import the Foundation module, you may have problems with dual screens', DEBUG_LEVEL_MEDIUM
)
155 def _setImage(self
, file):
156 output_name
, ret
= self
._convertImageFormat
(file)
158 debug("Convert failed")
160 self
._fixDesktopPList
()
161 cmd
= """osascript -e 'tell application "finder" to set desktop picture to posix file "%s"'""" % output_name
162 debug(cmd
, DEBUG_LEVEL_DEBUG
)
163 return not commands
.getstatusoutput(cmd
)[0]
165 class __GnomeChanger(__BaseChanger
):
166 def _setImage(self
, file):
167 cmd
= ['gconftool-2', '--type', 'string', '--set', '/desktop/gnome/background/picture_filename', file]
168 debug(cmd
, DEBUG_LEVEL_DEBUG
)
169 return subprocess
.Popen(cmd
, stdout
=sys
.stdout
, stderr
=sys
.stderr
, stdin
=None).wait()
171 class __KDEChanger(__BaseChanger
):
172 def _setImage(self
, file):
174 for group
in ('Desktop0', 'Desktop0Screen0'):
175 base
= ['kwriteconfig', '--file', 'kdesktoprc', '--group', group
, '--key']
176 cmds
.append(base
+ ['Wallpaper', file])
177 cmds
.append(base
+ ['UseSHM', '--type', 'bool', 'true'])
178 cmds
.append(base
+ ['WallpaperMode', 'ScaleAndCrop'])
179 cmds
.append(base
+ ['MultiWallpaperMode', 'NoMulti'])
181 cmds
.append(['dcop', 'kdesktop', 'KBackgroundIface', 'configure'])
183 debug(cmd
, DEBUG_LEVEL_DEBUG
)
184 if subprocess
.Popen(cmd
, stdout
=sys
.stdout
, stderr
=sys
.stderr
, stdin
=None).wait() != 0: