Created
November 13, 2016 04:23
-
-
Save jdah/d3d7a4ec4b12bdf74bdd0de4bc12a2e2 to your computer and use it in GitHub Desktop.
Python script that sets the desktop background Windows 10 spotlight wallpapers. Works with any number and size of monitors.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Run with python .\spotlight.py | |
from functools import reduce | |
import ctypes, os, winreg, glob, time | |
from PIL import Image | |
SPOTLIGHT_PATH = r"{0}\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets" | |
# >>>> CONFIGURATION VARIABLES <<<< | |
CHANGE_TIME_MINUTES = 2.5 | |
MONITOR_COUNT = 2 | |
MONITOR_SIZE = [(1920, 1080), (1920, 1080)] | |
SPI_SETDESKWALLPAPER = 0x0014 | |
SPI_SETDESKPATTERN = 0x0015 | |
SPIF_UPDATEINIFILE = 0x01 | |
SPIF_SENDWININICHANGE = 0x02 | |
# Map of wallpaper filenames to the number of times that they have been used | |
wallpapers = {} | |
# Next wallpaper in the sequence to be changed | |
next_change = 0 | |
# Names of the current wallpapers | |
current_wallpapers = [None] * MONITOR_COUNT | |
def get_spotlight_path(): | |
return SPOTLIGHT_PATH.format(os.getenv("APPDATA") + "\\..") | |
def set_wallpapers(paths): | |
# Load all images | |
images = list() | |
for i, p in enumerate(paths): | |
images.append(Image.open(p).resize(MONITOR_SIZE[i], Image.BILINEAR)) | |
# Concatenate the images end-to-end | |
final_image = Image.new("RGB", (reduce(lambda x, y: x + y.width, images, 0), max([x.height for x in images]))) | |
width = 0 | |
for i, image in enumerate(images): | |
final_image.paste(image, (width, 0)) | |
width += image.width | |
final_image.save(".\\wp.jpg", "JPEG") | |
for k, v in {("TileWallpaper", "1"), ("WallpaperStyle", "0")}: | |
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Control Panel\\Desktop", 0, winreg.KEY_WOW64_32KEY | winreg.KEY_WRITE) | |
winreg.SetValueEx(key, k, 0, winreg.REG_SZ, v) | |
ctypes.windll.user32.SystemParametersInfoW(SPI_SETDESKWALLPAPER, 0, os.path.abspath(".\\wp.jpg"), SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE) | |
def change(): | |
global wallpapers, next_change, current_wallpapers | |
def setw(): | |
sp = get_spotlight_path() + "\\" | |
set_wallpapers([sp + p for p in current_wallpapers]) | |
lowest = lambda w: sorted(w.items(), key=lambda x: x[1])[0][0] | |
# If no wallpapers have been set yet, then set up the initial wallpapers | |
if current_wallpapers[0] is None: | |
for x in range(0, MONITOR_COUNT): | |
l = lowest(wallpapers) | |
wallpapers[l] += 1 | |
current_wallpapers[x] = l | |
setw() | |
return | |
# Set the current wallpaper for the next monitor to be changed to the | |
# wallpaper least used out of the list | |
l = lowest(wallpapers) | |
wallpapers[l] += 1 | |
current_wallpapers[next_change] = l | |
next_change += 1 | |
if next_change == MONITOR_COUNT: | |
next_change = 0 | |
setw() | |
# Poll for new wallpapers and update the wallpaper table | |
def update(): | |
size_max = (max([x[0] for x in MONITOR_SIZE]), max([x[1] for x in MONITOR_SIZE])) | |
for wp in glob.glob(get_spotlight_path() + "\\*"): | |
name = os.path.basename(wp) | |
if not name in wallpapers: | |
try: | |
with Image.open(wp) as image: | |
if image.width < size_max[0] or image.height < size_max[1]: | |
continue | |
except: | |
continue | |
wallpapers[name] = 0 | |
if __name__ == "__main__": | |
while True: | |
update() | |
change() | |
time.sleep(CHANGE_TIME_MINUTES * 60) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@pcarver Windows 8 allowed setting unique wallpaper for each monitor. This was removed in Windows 10 and the workaround is to make a single image that covers the "virtual space" all of the monitors cover. "Tiling" the single image is required to make it work correctly, otherwise a mangled version will be used and duplicated on each monitor. It may take you a few tries with an image editor. "Tiling" the single image is required to make it work correctly, otherwise a mangled version will be used and duplicated on each monitor.
In my case I had a laptop screen for a primary monitor and a larger secondary monitor that wasn't always connected (though this fortunately didn't break anything). I made a composite image that was the combined width of my two screens and the maximum height between them. The primary screen wallpaper had to be top-aligned even though the screens were bottom-aligned in the display settings.
Hopefully that helps!