#!/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)