Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple desktops and spaces #7

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 40 additions & 42 deletions set-desktop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
# Ensure 'restore_sqliterc' is executed every time the script exits regardless of exit status
trap restore_sqliterc EXIT

# If the path to an image file contains 'com_apple_MobileAsset_DesktopPicture', check that it exists having previously been downloaded via System Preferences. This function is called regardless of the installed version of macOS, but is currently only relevant for macOS 12 Monterey.
# If the path to an image file contains 'com_apple_MobileAsset_DesktopPicture', check that it exists having previously been downloaded via System Preferences. This function is called regardless of the installed version of macOS, but is currently only relevant for macOS 12 Monterey.
function check_file_downloaded {
# The function is passed the value of the $value variable which is received as $1
if [[ "$1" == *"com_apple_MobileAsset_DesktopPicture"* ]]; then
Expand All @@ -47,27 +47,27 @@
# $1 : String representing the full path to the Desktop image passed to this function. e.g `'~/Library/Application Support/com.apple.mobileAssetDesktop/Big Sur.heic'`
# asset_count : Total number of Desktop images contained in the `assets` file. [Count of the `DesktopPictureID` key in the `assets` file]
# assets : Full path to the Apple-supplied XML file containing data on downloadable Desktop images.
# baseurl : Base URL for ZIP files containing Desktop images. [`__BaseURL` key from the `assets` file]
# desktop_image : Name of the Desktop image. [Derived from `filename` and correlates to the the `DesktopPictureID` key in the `assets` file]
# baseurl : Base URL for ZIP files containing Desktop images. [`__BaseURL` key from the `assets` file]
# desktop_image : Name of the Desktop image. [Derived from `filename` and correlates to the the `DesktopPictureID` key in the `assets` file]
# filename : Filename and extension of the Desktop image. [Derived from `$1`]
# i :
# relativepath : Location and unique filename of the individual ZIP file [`__RelativePath` key from the `assets` file]
# i :
# relativepath : Location and unique filename of the individual ZIP file [`__RelativePath` key from the `assets` file]
# temp : Full path to the temporary directory where ZIP files are downloaded. Deleted on completion.
# zipfile : Unique filename of the individual ZIP file [Derived from `relativepath`]

# Only continue if `$1` contains 'com.apple.mobileAssetDesktop'
if [[ "$1" == *"com.apple.mobileAssetDesktop"* ]]; then
if [[ "$1" == *"com.apple.mobileAssetDesktop"* ]]; then
# Only continue if `$1` doesn't already exist
if [ ! -f "$(echo "$1" | sed "s|~/|$HOME/|" | tr -d "'")" ]; then
filename=$(echo "$(basename "$1")" | tr -d "'") # >>> Big Sur.heic
desktop_image=$(echo ${filename%.*}) # >>> Big Sur

if [ -f "/System/Library/AssetsV2/com_apple_MobileAsset_DesktopPicture/com_apple_MobileAsset_DesktopPicture.xml" ]; then
# This file only exists if any image has previously been downloaded through System Preferences / System Settings
assets="/System/Library/AssetsV2/com_apple_MobileAsset_DesktopPicture/com_apple_MobileAsset_DesktopPicture.xml"
else
assets="./com_apple_MobileAsset_DesktopPicture.xml"
fi
fi

asset_count=$(/usr/libexec/PlistBuddy -x -c "Print Assets" "$assets" | grep DesktopPictureID | wc -l)
temp=$(mktemp -d)
Expand Down Expand Up @@ -116,12 +116,12 @@

# backup = location for backups when re-setting 'desktoppicture.db' to the default
# category = how the image is categorised in System Preferences (populated from match in the 'option_config' file)
# data_id = the 'data' table row id to be used in the 'preferences' table
# data_id = the 'data' table row id to be used in the 'preferences' table
# db = database name including path
# is_file = only set if the argument passed to the script is a filename
# key = value of the 'key' column for new rows in the 'preferences' table (populated from match in the 'option_config' file unless a filename was passed to the script)
# lastrow[0] = highest row id in the 'data' table
# lastrow[1] = highest row id in the 'preferences' table
# lastrow[0] = highest row id in the 'data' table
# lastrow[1] = highest row id in the 'preferences' table
# major = the major version number of the installed release of macOS i.e. 10 (Catalina), 11 (Big Sur), 12 (Monterey)
# minor = the minor version number of the installed release of macOS. Only used for Catalina and earlier i.e. .14, (10.14), .15 (10.15) etc
# name = the title or filename of the Desktop image (populated from match in the 'option_config' file unless a filename was passed to the script)
Expand All @@ -131,7 +131,7 @@
# option_data = string representing JSON-encoded data for a given option ($option_arg)
# row_count = the number of rows to be added to the 'data' table (populated from match in the 'option_config' file)
# rows = an array where each element represents the values of the 'value' column for new rows in the 'data' table and the value of the 'key' column for new rows in the 'preferences' table (populated from match in the 'option_config' file unless a filename was passed to the script in which case it is populated using the filename for the 'value' and '1' for the 'key')
# timestamp = temporary filename suffix added to '.sqliterc'
# timestamp = temporary filename suffix added to '.sqliterc'
# value = value of the 'value' column for new rows in the 'data' table (populated from match in the 'option_config' file unless a filename was passed to the script)
# version = the installed version of macOS (variable needs to be exported so its value is available to the Python code)

Expand All @@ -140,8 +140,8 @@
db="$HOME/Library/Application Support/Dock/desktoppicture.db"
backup="$HOME/Library/Application Support/Dock/backup"

# The version numbering convention has changed with the release of Big Sur where only the major version number is significant for
# determining if Big Sur is installed i.e. 11.0, 11.1, 11.2 etc are all versions of Big Sur. This is in contrast to earlier macOS
# The version numbering convention has changed with the release of Big Sur where only the major version number is significant for
# determining if Big Sur is installed i.e. 11.0, 11.1, 11.2 etc are all versions of Big Sur. This is in contrast to earlier macOS
# versions where both the major and minor version numbers are significant i.e 10.15 Catalina, 10.14 Mojave etc.
major=$(system_profiler SPSoftwareDataType | awk '/System Version/ {print $4}' | cut -d . -f 1)
minor=$(system_profiler SPSoftwareDataType | awk '/System Version/ {print $4}'| cut -d . -f 2)
Expand Down Expand Up @@ -182,7 +182,7 @@

# Exit with error if configuration file doesn't exist
if [ ! -f "$option_config" ]; then
printf "ERROR: Can't find configuration file '%s'.\n" "$option_config"
printf "ERROR: Can't find configuration file '%s'.\n" "$option_config"
exit 1
fi

Expand All @@ -203,7 +203,7 @@

if [ "$option_arg" != "default" ]; then

# Look in the configuration file for the value of the 'option' argument that was passed to the script.
# Look in the configuration file for the value of the 'option' argument that was passed to the script.
option_data=$(python -c $'from __future__ import print_function\nimport os,sys,json\nwith open(os.environ["option_config"],"r") as f:\n\tdata = json.load(f)\nfor _version in data["versions"]:\n\tif _version["version"]==os.environ["version"]:\n\t\tfor _option in _version["options"]:\n\t\t\tif _option["option"]==os.environ["option_arg"]:print(json.dumps(_option))')

if [ -z "$option_data" ]; then # the option that was passed to the script was not found in the configuration file
Expand All @@ -215,24 +215,24 @@
exit 1
fi
fi
else # 5. ...an invalid option
else # 5. ...an invalid option
printf "ERROR: '%s' is not a valid option.\n" "$option_arg"
exit 1
fi
fi
fi

# Exit with error if this is a multi-monitor environment (the 'spdisplays_ndrvs' array will have 2 or more objects).
if [ $(system_profiler SPDisplaysDataType -json | python -c $'import os,sys,json\ndata=json.loads(sys.stdin.read())\nprint(len(data["SPDisplaysDataType"][0]["spdisplays_ndrvs"]))') -ge 2 ]; then
echo "ERROR: This script should not be used in a multi-monitor environment."
exit 1
fi
# if [ $(system_profiler SPDisplaysDataType -json | python -c $'import os,sys,json\ndata=json.loads(sys.stdin.read())\nprint(len(data["SPDisplaysDataType"][0]["spdisplays_ndrvs"]))') -ge 2 ]; then
# echo "ERROR: This script should not be used in a multi-monitor environment."
# exit 1
# fi

# Exit with error if multiple Desktops are configured (the 'spaces' table will have 2 or more rows).
if [ $(sqlite3 "$db" "SELECT COUNT() FROM spaces;") -ge 2 ]; then
echo "ERROR: This script should not be used when multiple Desktops (Spaces) are configured."
exit 1
fi
# if [ $(sqlite3 "$db" "SELECT COUNT() FROM spaces;") -ge 2 ]; then
# echo "ERROR: This script should not be used when multiple Desktops (Spaces) are configured."
# exit 1
# fi



Expand Down Expand Up @@ -268,7 +268,7 @@
name="$option_arg"
key=1

# If the image file path contains 'com_apple_MobileAsset_DesktopPicture', check it has been downloaded via System Preferences
# If the image file path contains 'com_apple_MobileAsset_DesktopPicture', check it has been downloaded via System Preferences
# if ! check_file_downloaded "$value"; then
# exit 1
# fi
Expand All @@ -282,21 +282,21 @@
unset value key

fi
else # 3. ...a valid option
else # 3. ...a valid option
option=$(echo $option_data | python -c $'from __future__ import print_function\nimport sys, json; data=json.loads(sys.stdin.read())\nprint(data["option"])')
name=$(echo $option_data | python -c $'from __future__ import print_function\nimport sys, json; data=json.loads(sys.stdin.read())\nprint(data["name"])')
category=$(echo $option_data | python -c $'from __future__ import print_function\nimport sys, json; data=json.loads(sys.stdin.read())\nprint(data["category"])')

# The row_count variable stores the number of Python dictionaries (JSON objects) in the Python list (JSON array) whose key is "rows". This is a minimum of 1 and a maximum of 2.
# The row_count variable stores the number of Python dictionaries (JSON objects) in the Python list (JSON array) whose key is "rows". This is a minimum of 1 and a maximum of 2.
row_count=$(echo $option_data | python -c $'from __future__ import print_function\nimport sys, json; data=json.loads(sys.stdin.read())\nprint(len(data["rows"]))')

stop=$(expr $row_count - 1)
for i in $(seq 0 $stop); do
export i
for i in $(seq 0 $stop); do
export i
value=$(echo $option_data | python -c $'from __future__ import print_function\nimport os, sys, json; data=json.loads(sys.stdin.read())\ne=int(os.environ["i"])\nprint(data["rows"][int(os.environ["i"])]["value"])')
key=$(echo $option_data | python -c $'from __future__ import print_function\nimport os, sys, json; data=json.loads(sys.stdin.read())\ne=int(os.environ["i"])\nprint(data["rows"][int(os.environ["i"])]["key"])')

# If the image file path contains 'com_apple_MobileAsset_DesktopPicture', check it has been downloaded via System Preferences
# If the image file path contains 'com_apple_MobileAsset_DesktopPicture', check it has been downloaded via System Preferences
# if ! check_file_downloaded "$value"; then
# exit 1
# fi
Expand Down Expand Up @@ -348,25 +348,23 @@
# INSERT NEW ROWS
#

# Images typically require 1 row in the 'data' table and 4 corresponding rows in the 'preferences' table. Most images categorised by
# System Preferences as 'Dynamic Desktop' or 'Light and Dark Desktop' and a few categorised as 'Desktop Pictures' require a total of 2 rows
# in the 'data' table and 8 corresponding rows in the 'preferences' table.
# Images typically require 1 row in the 'data' table and 4 corresponding rows in the 'preferences' table (one per row in the 'pictures' table).
# Most images categorised by System Preferences as 'Dynamic Desktop' or 'Light and Dark Desktop' and a few categorised as 'Desktop Pictures' require
# a total of 2 rows in the 'data' table and 8 corresponding rows in the 'preferences' table.

for i in "${rows[@]}"; do

value=$(echo $i | cut -d ':' -f1)
key=$(echo $i | cut -d ':' -f2)

# Insert a new row into the 'data' table.
sqlite3 "$db" "INSERT INTO data(rowid,value) VALUES( $((++lastrow[0])), $value );"
# Insert a new row into the 'data' table. This automatically sets the (hidden) column rowid to a correct value.
sqlite3 "$db" "INSERT INTO data(value) VALUES( $value );"

# Insert new rows into the 'preferences' table.
data_id=$(sqlite3 "$db" "SELECT rowid FROM data WHERE value=$value;")
# Insert new rows into the 'preferences' table. This automatically sets the (hidden) column rowid to a correct values.
data_id=$(sqlite3 "$db" "SELECT rowid FROM data ORDER BY rowid DESC LIMIT 1;")

sqlite3 "$db" "INSERT INTO preferences(rowid,key,data_id,picture_id) VALUES( $((++lastrow[1])),$key,${data_id},3);"
sqlite3 "$db" "INSERT INTO preferences(rowid,key,data_id,picture_id) VALUES( $((++lastrow[1])),$key,${data_id},4);"
sqlite3 "$db" "INSERT INTO preferences(rowid,key,data_id,picture_id) VALUES( $((++lastrow[1])),$key,${data_id},2);"
sqlite3 "$db" "INSERT INTO preferences(rowid,key,data_id,picture_id) VALUES( $((++lastrow[1])),$key,${data_id},1);"
#sqlite3 "$db" "INSERT INTO preferences SELECT $key AS key, (SELECT ROWID FROM data ORDER BY ROWID DESC LIMIT 1) AS data_id, ROWID AS picture_id FROM pictures;"
sqlite3 "$db" "INSERT INTO preferences SELECT $key AS key, $data_id AS data_id, ROWID AS picture_id FROM pictures;"

unset value key

Expand Down