I often work on my computer at night and sometimes the screen is just too bright so I like to invert the colors to have a darker display. When I’m only reading text this seems to be a great way to work. I’ve seen other scripts which invert your screen but none of them properly restored my desktop back to original settings when I re-inverted the screen back to normal. Mostly this was because I have 2 displays connected to my computer and the other scripts didn’t take that into account. This one does. It works for any number of displays you have attached to your computer. It even works if your desktop is set to change its picture periodically.
Any improvements or comments are welcome.
(*This is a "toggle" script... it will toggle between inverted screen colors and not-inverted screen colors on successive runs. It will work with any number of displays you have connected to your computer.*)
(* When your screens are inverted, the script will store the state of your current desktops for each display you have connected to your computer. It will set the desktop picture of each display to a white image so that when inverted your desktops will appear black. When the screen is returned to normal it will restore the stored desktop settings so your desktops appears like they were before you inverted them.*)
property prefFile : (path to preferences as string) & "com.apple.desktop.plist"
property invertPic : "/Library/Desktop Pictures/Solid Colors/Solid White.png"
property desktopPics : {}
property changeStates : {}
property displayIDs : {}
property is_inverted : false
if not my prefFile_check(prefFile) then return -- check for the needed pref file and stop if it doesn't exist
if is_inverted then -- screens are inverted so set them back to normal with persistent values of previous normal state
tell application "System Events"
repeat with i from 1 to (count of displayIDs)
try
set value of property list item "ImageFilePath" of property list item (item i of displayIDs) of property list item "Background" of property list file prefFile to (item i of desktopPics)
set value of property list item "Change" of property list item (item i of displayIDs) of property list item "Background" of property list file prefFile to (item i of changeStates)
end try
end repeat
end tell
my invert_screen()
set is_inverted to false
else -- screens are normal so store current desktop values and set screens to an inverted state
set {desktopPics, changeStates, displayIDs} to {{}, {}, {}}
set displayIDs to my get_displayIDs() -- get display ids for currently connected displays
if displayIDs is false then return
tell application "System Events"
repeat with i from 1 to (count of displayIDs)
try -- store current normal values for currently connected displays
set end of desktopPics to value of property list item "ImageFilePath" of property list item (item i of displayIDs) of property list item "Background" of property list file prefFile
on error
tell me to display alert "Error. A needed setting is missing!" message "Please open the \"Desktop & Screensaver\" preference pane and change your desktop picture for each of your displays because this action will create the missing setting." & return & return & "Note: you only have to do this once. You can change your desktop picture to anything you want and then change it right back to its original setting if you wish." as warning
return
end try
try -- prepare for inverted state by setting desktop pics to invertPic and change states to "Never"
set value of property list item "ImageFilePath" of property list item (item i of displayIDs) of property list item "Background" of property list file prefFile to invertPic
set end of changeStates to value of property list item "Change" of property list item (item i of displayIDs) of property list item "Background" of property list file prefFile
set value of property list item "Change" of property list item (item i of displayIDs) of property list item "Background" of property list file prefFile to "Never"
end try
end repeat
end tell
my invert_screen()
set is_inverted to true
end if
(*================== SUBROUTINES ====================*)
on get_displayIDs()
-- this returns a list of the id numbers for each display connected to your computer
-- this needs the number_to_text subroutine to work
try
set plistFolderPath to (path to preferences folder as string) & "ByHost:"
tell application "Finder" to set plistName to (name of files of folder plistFolderPath whose name contains "com.apple.windowserver") as string
set plistPath to plistFolderPath & plistName
tell application "Image Events" to set count_of_displays to count of displays
set j to 1
repeat
set displayIDs to {}
tell application "System Events" to set displaySet to value of property list item j of property list item "DisplaySets" of property list file plistPath
try
repeat with i from 1 to count_of_displays
set expID to |DisplayID| of (item i of displaySet)
set stringID to my number_to_text(expID)
set end of displayIDs to stringID
end repeat
exit repeat
on error
set j to j + 1
end try
end repeat
return displayIDs
on error
set frontApp to displayed name of (info for (path to frontmost application))
tell application frontApp to display alert "Error. A needed file is missing!" message "Please make some changes to the settings in the \"Displays\" preference pane because this action will create the missing file." & return & return & "Note: you only have to do this once. You can make any change in the preference pane (which will create the needed file) and then you can change the setting right back if you wish." as warning
return false
end try
end get_displayIDs
on number_to_text(this_number)
(*This subroutine will convert any number to a string of numeric characters. This is a modified version of a subroutine found at http://www.apple.com/applescript/guidebook/sbrt/pgs/sbrt.08.htm. Apple's original version deleted all the decimal places from the number, this one keeps them.*)
set this_number to this_number as text
if this_number contains "E+" then
set x to the offset of "." in this_number
set y to the offset of "+" in this_number
set z to the offset of "E" in this_number
set the decimal_adjust to characters (y - (length of this_number)) thru ¬
-1 of this_number as string as number
if x is not 0 then
set the first_part to characters 1 thru (x - 1) of this_number as string
else
set the first_part to ""
end if
set the second_part to characters (x + 1) thru (z - 1) of this_number as string
set the converted_number to the first_part
set decimal_added to false
repeat with i from 1 to the (length of second_part)
try
set the converted_number to ¬
the converted_number & character i of the second_part
on error
set the converted_number to the converted_number & "0"
end try
if decimal_added is false and (i mod decimal_adjust) is 0 and (i is not (length of second_part)) then
set the converted_number to the converted_number & "."
set decimal_added to true
end if
end repeat
return the converted_number
else
return this_number
end if
end number_to_text
on prefFile_check(prefFile)
try
set test_for_prefFile to alias prefFile
return true
on error
set frontApp to displayed name of (info for (path to frontmost application))
tell application frontApp to display alert "Error. A needed file is missing!" message "Please open the \"Desktop & Screensaver\" preference pane and change the desktop picture for each of your displays because this action will create the missing file." & return & return & "Note: you only have to do this once. You can change your desktop picture to anything you want and then change it right back to its original setting if you wish." as warning
return false
end try
end prefFile_check
on invert_screen()
tell application "System Events" to key code 28 using {command down, control down, option down}
end invert_screen