168 lines
5.9 KiB
Python
Executable file
168 lines
5.9 KiB
Python
Executable file
#!/usr/bin/python
|
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"""
|
|
mac_desktop_image.py
|
|
|
|
Mac-specific utility to get/set the desktop background image or check that
|
|
the current background image path matches a provided path.
|
|
|
|
Depends on Objective-C python binding imports which are in the python import
|
|
paths by default when using macOS's /usr/bin/python.
|
|
|
|
Includes generous amount of logging to aid debugging for use in automated tests.
|
|
"""
|
|
|
|
import argparse
|
|
import logging
|
|
import os
|
|
import sys
|
|
|
|
#
|
|
# These Objective-C bindings imports are included in the import path by default
|
|
# for the Mac-bundled python installed in /usr/bin/python. They're needed to
|
|
# call the Objective-C API's to set and retrieve the current desktop background
|
|
# image.
|
|
#
|
|
from AppKit import NSScreen, NSWorkspace
|
|
from Cocoa import NSURL
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Utility to print, set, or "
|
|
+ "check the path to image being used as "
|
|
+ "the desktop background image. By "
|
|
+ "default, prints the path to the "
|
|
+ "current desktop background image."
|
|
)
|
|
parser.add_argument(
|
|
"-v",
|
|
"--verbose",
|
|
action="store_true",
|
|
help="print verbose debugging information",
|
|
default=False,
|
|
)
|
|
group = parser.add_mutually_exclusive_group()
|
|
group.add_argument(
|
|
"-s",
|
|
"--set-background-image",
|
|
dest="newBackgroundImagePath",
|
|
required=False,
|
|
help="path to the new background image to set. A zero "
|
|
+ "exit code indicates no errors occurred.",
|
|
default=None,
|
|
)
|
|
group.add_argument(
|
|
"-c",
|
|
"--check-background-image",
|
|
dest="checkBackgroundImagePath",
|
|
required=False,
|
|
help="check if the provided background image path "
|
|
+ "matches the provided path. A zero exit code "
|
|
+ "indicates the paths match.",
|
|
default=None,
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
# Using logging for verbose output
|
|
if args.verbose:
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
else:
|
|
logging.basicConfig(level=logging.CRITICAL)
|
|
logger = logging.getLogger("desktopImage")
|
|
|
|
# Print what we're going to do
|
|
if args.checkBackgroundImagePath is not None:
|
|
logger.debug(
|
|
"checking provided desktop image %s matches current "
|
|
"image" % args.checkBackgroundImagePath
|
|
)
|
|
elif args.newBackgroundImagePath is not None:
|
|
logger.debug("setting image to %s " % args.newBackgroundImagePath)
|
|
else:
|
|
logger.debug("retrieving desktop image path")
|
|
|
|
focussedScreen = NSScreen.mainScreen()
|
|
if not focussedScreen:
|
|
raise RuntimeError("mainScreen error")
|
|
|
|
ws = NSWorkspace.sharedWorkspace()
|
|
if not ws:
|
|
raise RuntimeError("sharedWorkspace error")
|
|
|
|
# If we're just checking the image path, check it and then return.
|
|
# A successful exit code (0) indicates the paths match.
|
|
if args.checkBackgroundImagePath is not None:
|
|
# Get existing desktop image path and resolve it
|
|
existingImageURL = getCurrentDesktopImageURL(focussedScreen, ws, logger)
|
|
existingImagePath = existingImageURL.path()
|
|
existingImagePathReal = os.path.realpath(existingImagePath)
|
|
logger.debug("existing desktop image: %s" % existingImagePath)
|
|
logger.debug("existing desktop image realpath: %s" % existingImagePath)
|
|
|
|
# Resolve the path we're going to check
|
|
checkImagePathReal = os.path.realpath(args.checkBackgroundImagePath)
|
|
logger.debug("check desktop image: %s" % args.checkBackgroundImagePath)
|
|
logger.debug("check desktop image realpath: %s" % checkImagePathReal)
|
|
|
|
if existingImagePathReal == checkImagePathReal:
|
|
print("desktop image path matches provided path")
|
|
return True
|
|
|
|
print("desktop image path does NOT match provided path")
|
|
return False
|
|
|
|
# Log the current desktop image
|
|
if args.verbose:
|
|
existingImageURL = getCurrentDesktopImageURL(focussedScreen, ws, logger)
|
|
logger.debug("existing desktop image: %s" % existingImageURL.path())
|
|
|
|
# Set the desktop image
|
|
if args.newBackgroundImagePath is not None:
|
|
newImagePath = args.newBackgroundImagePath
|
|
if not os.path.exists(newImagePath):
|
|
logger.critical("%s does not exist" % newImagePath)
|
|
return False
|
|
if not os.access(newImagePath, os.R_OK):
|
|
logger.critical("%s is not readable" % newImagePath)
|
|
return False
|
|
|
|
logger.debug("new desktop image to set: %s" % newImagePath)
|
|
newImageURL = NSURL.fileURLWithPath_(newImagePath)
|
|
logger.debug("new desktop image URL to set: %s" % newImageURL)
|
|
|
|
status = False
|
|
(status, error) = ws.setDesktopImageURL_forScreen_options_error_(
|
|
newImageURL, focussedScreen, None, None
|
|
)
|
|
if not status:
|
|
raise RuntimeError("setDesktopImageURL error")
|
|
|
|
# Print the current desktop image
|
|
imageURL = getCurrentDesktopImageURL(focussedScreen, ws, logger)
|
|
imagePath = imageURL.path()
|
|
imagePathReal = os.path.realpath(imagePath)
|
|
logger.debug("updated desktop image URL: %s" % imageURL)
|
|
logger.debug("updated desktop image path: %s" % imagePath)
|
|
logger.debug("updated desktop image path (resolved): %s" % imagePathReal)
|
|
print(imagePathReal)
|
|
return True
|
|
|
|
|
|
def getCurrentDesktopImageURL(focussedScreen, workspace, logger):
|
|
imageURL = workspace.desktopImageURLForScreen_(focussedScreen)
|
|
if not imageURL:
|
|
raise RuntimeError("desktopImageURLForScreen returned invalid URL")
|
|
if not imageURL.isFileURL():
|
|
logger.warning("desktop image URL is not a file URL")
|
|
return imageURL
|
|
|
|
|
|
if __name__ == "__main__":
|
|
if not main():
|
|
sys.exit(1)
|
|
else:
|
|
sys.exit(0)
|