#!/usr/bin/env python
# Module     : winDesktop.py
# Synopsis   : Windows desktop utils.
# Programmer : Simon Brunning - simon@brunningonline.net
# Date       : 13 Nov 2003
# Copyright  : Released to the public domain. Provided as-is, with no warranty.
# Notes      : Various functions for working with Windows desktop settings.
'''Various functions for working with Windows desktop settings.'''

import Image
import ctypes
import os
import shutil
import struct
import win32api
import win32con
import win32gui
import win32ui

def setScreenSaverEnabled(state):
    """Enable or disable the Windows screensaver.
    Note that enabling the screen save isn't the same as running it. It just
    means that the saver *will* run after the screen saver wait time has elapsed
    the PC is unused during that time."""
    ctypes.windll.user32.SystemParametersInfoA(win32con.SPI_SETSCREENSAVEACTIVE,
                                               state,
                                               None,
                                               0)
    
def getScreenSaverEnabled():
    state = ctypes.c_int()
    ctypes.windll.user32.SystemParametersInfoA(win32con.SPI_GETSCREENSAVEACTIVE,
                                               0,
                                               ctypes.byref(state),
                                               0)
    return bool(state.value)

def setScreenSaverWait(wait):
    """Set screen saver wait time, in seconds."""
    ctypes.windll.user32.SystemParametersInfoA(win32con.SPI_SETSCREENSAVETIMEOUT,
                                               wait,
                                               None,
                                               0)

def getScreenSaverWait():
    """Get screen saver wait time, in seconds."""
    wait = ctypes.c_int()
    ctypes.windll.user32.SystemParametersInfoA(win32con.SPI_GETSCREENSAVETIMEOUT,
                                               0,
                                               ctypes.byref(wait),
                                               0)
    return wait.value
    
def getWallpaper():
    SPI_GETDESKWALLPAPER = 0x0000073
#    try:
#        win32con.SPI_GETDESKWALLPAPER 
#    except AttributeError, attributeError:
#        raise WinDesktopError, "getWallpaper() not supported on this OS"
    wallpaper = ctypes.c_buffer("\000" * 256)
    ctypes.windll.user32.SystemParametersInfoA(SPI_GETDESKWALLPAPER,
                                               len(wallpaper),
                                               ctypes.byref(wallpaper),
                                               0)
    return wallpaper.value
    
def setWallpaper(wallpaperPath, conversionPath=None):
    
    # Convert to bitmap if necessary
    wallpaperImage = Image.open(wallpaperPath)
    if wallpaperImage.format != 'BMP':
        conversionPath = conversionPath or os.getenv('SystemRoot')
        wallpaperPath = os.path.join(conversionPath,
                                     os.path.splitext(os.path.split(wallpaperPath)[-1])[0] + '.bmp')
        wallpaperImage.save(wallpaperPath)
        
    # Set wallpaper
    wallpaperPath = ctypes.c_buffer(wallpaperPath)
    ctypes.windll.user32.SystemParametersInfoA(win32con.SPI_SETDESKWALLPAPER,
                                               0,
                                               wallpaperPath,
                                               0)

def setScreenSaver(saver):
    '''Copy screensaver to %SystemRoot%, & make it the current saver.'''
    
    # copy selected saver to windows directory
    systemRoot = os.getenv('SystemRoot')
    saver_in_systemroot = os.path.join(systemRoot, os.path.basename(saver))
    if saver != saver_in_systemroot:
        shutil.copy(saver, systemRoot)
    saverInstalled = saver_in_systemroot

    # Convert to 8.3 format filename
    saverInstalled = win32api.GetShortPathName(saverInstalled)

    # set user section of registry.
    keyHandle = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,
                                      'Control Panel\Desktop',
                                      0,
                                      win32con.KEY_WRITE)
    win32api.RegSetValueEx(keyHandle,
                           'SCRNSAVE.EXE',
                           0, win32con.REG_SZ,
                           saverInstalled)
    
def getScreenSaver():
    keyHandle = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,
                                      'Control Panel\Desktop',
                                      0,
                                      win32con.KEY_READ)
    return win32api.RegQueryValueEx(keyHandle, 'SCRNSAVE.EXE')[0]
    
def triggerScreenSaver():
    '''
    
    From Darryl Dixon's Cookbook recipe at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/106624'''
    win32api.SendMessage(win32con.HWND_TOPMOST,
                         win32con.WM_SYSCOMMAND,
                         win32con.SC_SCREENSAVE,
                         0)
    
def setDisplaySettings(xres=None, yres=None, cdepth=None):
    """Changes the display resolution and bit depth on Windows.
    
    From Shane Holloway's post http://aspn.activestate.com/ASPN/Mail/Message/wxPython-users/1684800"""

    DM_ORIENTATION     = 0x00000001
    DM_PAPERSIZE       = 0x00000002
    DM_PAPERLENGTH     = 0x00000004
    DM_PAPERWIDTH      = 0x00000008
    DM_SCALE           = 0x00000010
    DM_POSITION        = 0x00000020
    DM_COPIES          = 0x00000100
    DM_DEFAULTSOURCE   = 0x00000200
    DM_PRINTQUALITY    = 0x00000400
    DM_COLOR           = 0x00000800
    DM_DUPLEX          = 0x00001000
    DM_YRESOLUTION     = 0x00002000
    DM_TTOPTION        = 0x00004000
    DM_COLLATE         = 0x00008000
    DM_FORMNAME        = 0x00010000
    DM_LOGPIXELS       = 0x00020000
    DM_BITSPERPEL      = 0x00040000
    DM_PELSWIDTH       = 0x00080000
    DM_PELSHEIGHT      = 0x00100000
    DM_DISPLAYFLAGS    = 0x00200000
    DM_DISPLAYFREQUENCY= 0x00400000
    DM_ICMMETHOD       = 0x00800000
    DM_ICMINTENT       = 0x01000000
    DM_MEDIATYPE       = 0x02000000
    DM_DITHERTYPE      = 0x04000000
    DM_PANNINGWIDTH    = 0x08000000
    DM_PANNINGHEIGHT   = 0x10000000
    CDS_UPDATEREGISTRY = 0x00000001
    CDS_TEST           = 0x00000002
    CDS_FULLSCREEN     = 0x00000004
    CDS_GLOBAL         = 0x00000008
    CDS_SET_PRIMARY    = 0x00000010
    CDS_RESET          = 0x40000000
    CDS_SETRECT        = 0x20000000
    CDS_NORESET        = 0x10000000
    SIZEOF_DEVMODE     = 148

    DevModeData = struct.calcsize("32BHH") * '\x00'
    DevModeData += struct.pack("H", SIZEOF_DEVMODE)
    DevModeData += struct.calcsize("H") * '\x00'
    dwFields = (xres and DM_PELSWIDTH or 0) | (yres and DM_PELSHEIGHT or 0) | (cdepth and DM_BITSPERPEL or 0)
    DevModeData += struct.pack("L", dwFields)
    DevModeData += struct.calcsize("l9h32BHL") * '\x00'
    DevModeData += struct.pack("LLL", cdepth or 0, xres or 0, yres or 0)
    DevModeData += struct.calcsize("8L") * '\x00'
    result = ctypes.windll.user32.ChangeDisplaySettingsA(DevModeData, CDS_FULLSCREEN | CDS_UPDATEREGISTRY)
    if result != 0: # success if zero, some failure otherwise
        raise WinDesktopError, "setDisplaySettings() died, call to ChangeDisplaySettingsA returned" + repr(result)
    
def getDisplaySettings():
    '''returns x_resolution, y_resolution, colour_depth'''
    return win32api.GetSystemMetrics(win32con.SM_CXSCREEN),\
           win32api.GetSystemMetrics(win32con.SM_CYSCREEN),\
           win32ui.GetDeviceCaps(win32gui.GetDC(0), win32con.BITSPIXEL)
    
class WinDesktopError(StandardError):
    pass

if __name__ == '__main__':
    import glob, random, sys, time
    
    script_dir = os.path.dirname(sys.argv[0])
    
    # Set screen saver wait
    setScreenSaverWait(random.randrange(60, 1800))
    print "getScreenSaverWait()", getScreenSaverWait()
    time.sleep(1)
    
    # Set wallpaper
    jpeg = random.choice(glob.glob(os.path.join(script_dir, '*.jpeg')))
    print 'Setting wallpaper to', jpeg
    setWallpaper(jpeg, conversionPath=r"C:\temp")
    try:
        print "getWallpaper():", getWallpaper()
    except Exception, exception:
        print exception
    time.sleep(1)
    bitmap = random.choice(glob.glob(os.path.join(script_dir, '*.bmp')))
    print 'Setting wallpaper to', bitmap
    setWallpaper(bitmap)
    try:
        print "getWallpaper():", getWallpaper()
    except Exception, exception:
        print exception
    time.sleep(1)
    
    # Query and set display settings
    print "Starting display settings:", getDisplaySettings()
    oldx, oldy, oldd = getDisplaySettings()
    print "Setting display to 640x480x8"
    setDisplaySettings(xres=640, yres=480, cdepth=8)
    print "Display settings now:", getDisplaySettings()
    time.sleep(1)
    print "Restoring"
    setDisplaySettings(xres=oldx, yres=oldy, cdepth=oldd)
    print "Display settings now:", getDisplaySettings()
    time.sleep(1)
    
    # Enable and disable
    setScreenSaverEnabled(False)
    print "getScreenSaverEnabled()", getScreenSaverEnabled()
    setScreenSaverEnabled(True)
    print "getScreenSaverEnabled()", getScreenSaverEnabled()
    time.sleep(1)
    
    # Pick randon screensaver
    print "getScreenSaver()", getScreenSaver()
    setScreenSaver(random.choice(glob.glob(os.path.join(os.getenv('SystemRoot'), '*.scr'))))
    print "getScreenSaver()", getScreenSaver()
    triggerScreenSaver()