getScreenResolution() updated for 10.5

Well I finally moved to 10.5 ( yippie! ) and found my trusty old method for getting the screen resolution was broken by Apple moving the plist to the ByHost folder. So, here’s my trusty new method for Tiger.

set {screenWidth, screenHeight} to getScreenDimensions()

on getScreenDimensions()
	--paulskinner Monday, March 10, 2008 6:31:52 PM
	set {monitor_width, monitor_height} to {(word 3 of (do shell script "defaults -currentHost read com.apple.windowserver | grep -w Width")) as number, (word 3 of (do shell script "defaults -currentHost read com.apple.windowserver | grep -w Height")) as number}
end getScreenDimensions


If you have dual screens, this script (sorry I can’t remember whose it is) finds both the screen dimensions and the origin of the second one (the one without the menu bar).

set f to (path to preferences from local domain as Unicode text) & "com.apple.windowserver.plist"
tell application "System Events"
	set {{|Width|:w1, |Height|:h1, |OriginX|:OX1, |OriginY|:OY1}, {|Width|:w2, |Height|:h2, |OriginX|:OX2, |OriginY|:OY2}} to value of property list items of property list item 1 of property list item "DisplaySets" of property list file f
end tell
{{w1, h1, OX1, OY1}, {w2, h2, OX2, OY2}}

Your posted script is looking for the windowserver preference file in the old location.

“System Events got an error: Can’t get property list item “DisplaySets” of property list file “mac:Library:Preferences:com.apple.windowserver.plist”.”

This isn’t as easily fixed as just adding “ByHost” either, because the plist now has a hash in the name. You need to acquire the hash and append it. That’s why I use -currenthost, and the Defaults read command. It simplifies pulling the data and is likely speedier than having sys events do it. Too busy to actually test it.

You make a good point though, I’ll mod this to get all display’s dimensions if there are more than one. The real problem with all of this hackery is that without an Apple suplied method, we’re still screwed if someone plugs in a second display. The plists aren’t updated unless you modify the displays in some way (arrangement or resolution).

This version will return a list of the dimensions of each monitor. needs to be modified to return them Main monitor first and to include layout info. I did like your method of using Sys Events though. Records are so much easier! And it’s quite fast enough for any purpose.

Lingering issue is that the plist doesn’t get updated when you simply plug another monitor in.


set windowserverPrefFilePath to do shell script "find " & (POSIX path of ((path to preferences from user domain as Unicode text) & "ByHost:")) & " -name 'com.apple.windowserver*'"

tell application "System Events"
	set wsp to item 1 of (item 1 of (get value of property list items of property list file windowserverPrefFilePath))
end tell

set MonDimensions to {}
repeat with mon from 1 to length of wsp
	set monData to item mon of wsp
	set the end of MonDimensions to {|Height| of monData, |Width| of monData}
end repeat

This seems to work well.



set dp to monitorProperties()
set h to Height of monitor1 of monitorProperties()
set {w, h} to {Width, Height} of monitor1 of monitorProperties()
set n to monitorCount of monitorProperties()



on monitorProperties()
	--paulskinner Tuesday, March 11, 2008 1:19:41 PM
	set {monitor1, monitor2} to {{}, {}}
 	 set windowserverPrefFilePath to do shell script "find " & (POSIX path of ((path to preferences from user domain as Unicode text) & "ByHost:")) & " -name 'com.apple.windowserver*'"
	tell application "System Events"
		set wsp to item 1 of (item 1 of (get value of property list items of property list file windowserverPrefFilePath))
	end tell
	
	repeat with mon from 1 to length of wsp
		set monData to item mon of wsp
		if (|OriginX| of monData is 0) and (|OriginY| of monData is 0) then
			set monitor1 to {Height:|Height| of monData, Width:|Width| of monData, OriginX:|OriginX| of monData, OriginY:|OriginY| of monData}
		else
			set monitor2 to {Height:|Height| of monData, Width:|Width| of monData, OriginX:|OriginX| of monData, OriginY:|OriginY| of monData}
		end if
	end repeat
	return {monitor1:monitor1, monitor2:monitor2, monitorCount:(length of wsp) as integer}
end monitorProperties


Hi,

if only the resolution is required, this might be sufficient and works in Tiger and Leopard


set d to paragraphs of (do shell script "system_profiler SPDisplaysDataType | awk '/Resolution/ {print $2, $4}'")
set monitor to {}
repeat with i in d
	set end of monitor to {Width:word 1 of i, Height:word 2 of i}
end repeat
monitor

Other solutions are the CLIs cscreen and displaysinfo from this thread

Good to know. This certainly avoids the issue with the plist not updating or not existing in a fresh install until the display pref pane is used. It’s a bit slow, but like I said it’s not like you’re going to run this repeatedly.

The non-standard installs are right out for me. I don’t want to go there.

Dang, now I’ll have to think about this a bit more.

Thanks,

Ok, taking both routes when needed for more complete data, but always deferring to accurate data.

It’s no longer prety, or even not ugly, but it works well and returns reasonable values in all the cases I can test here.


set mp to monitorProperties()
--With one monitor attached
--{monitor1:{Width:1440, Height:900, OriginX:0, OriginY:0}, monitor2:{Width:missing value, Height:missing value, OriginX:missing value, OriginY:missing value}, monitorCount:1}

--With two monitors attached. No update of the Display Preference pane.
--{monitor1:{Width:1440, Height:900, OriginX:missing value, OriginY:missing value}, monitor2:{Width:1024, Height:768, OriginX:missing value, OriginY:missing value}, monitorCount:2}

--With two monitors attached. With an update of the Display Preference pane.
--{monitor1:{Height:900, Width:1440, OriginX:0, OriginY:0}, monitor2:{Height:768, Width:1024, OriginX:1440, OriginY:132}, monitorCount:2}

on monitorProperties()
	--system_profiler parsing 
	set SPDisplaysData to (do shell script "system_profiler SPDisplaysDataType")
	set text item delimiters to "Displays:"
	set SPDisplaysData to text item 3 of SPDisplaysData
	set text item delimiters to (word 1 of SPDisplaysData)
	copy text item 1 of SPDisplaysData to text item delimiters
	set SPDisplaysData to text items 2 thru -1 of SPDisplaysData
	set text item delimiters to ""
	repeat with i from 2 to length of SPDisplaysData
		if character 1 of item i of SPDisplaysData is not " " then
			set monitor1 to items 2 thru (i - 1) of SPDisplaysData
			set monitor2 to items (i + 1) thru -1 of SPDisplaysData
			exit repeat
		end if
	end repeat
	--END OF system_profiler parsing 
	
	SPDisplaysData
	set {monitorCount, output} to {1, {}}
	repeat with curList in {monitor1, monitor2}
		set mainDisplay to false
		curList
		if item 1 of curList contains "Status: No display connected" then
			return {monitor1:{Width:y as integer, Height:x as integer, OriginX:0, OriginY:0}, monitor2:{Width:missing value, Height:missing value, OriginX:missing value, OriginY:missing value}, monitorCount:monitorCount}
		else
			repeat with i from 1 to length of curList
				set curItem to item i of curList
				if curItem contains "Resolution:" then
					set {y, x} to {word 2 of curItem, word 4 of curItem}
				end if
				if curItem contains "Main Display: Yes" then
					set mainDisplay to true
				end if
			end repeat
		end if
		if mainDisplay then
			set display1 to {Width:y as integer, Height:x as integer, OriginX:missing value, OriginY:missing value}
		else
			set monitorCount to 2
			set display2 to {Width:y as integer, Height:x as integer, OriginX:missing value, OriginY:missing value}
		end if
	end repeat
	
	-- If there are two monitors then use com.apple.windowserver to try to acquire Origins
	set {monitor1, monitor2} to {{}, {Height:missing value, Width:missing value, OriginX:missing value, OriginY:missing value}}
	set PrefFilePath to do shell script "find " & (POSIX path of ((path to preferences from user domain as Unicode text) & "ByHost:")) & " -name 'com.apple.windowserver*'"
	tell application "System Events"
		set wsp to item 1 of (item 1 of (get value of property list items of property list file PrefFilePath))
	end tell
	repeat with mon from 1 to length of wsp
		set monData to item mon of wsp
		if (|OriginX| of monData is 0) and (|OriginY| of monData is 0) then
			set monitor1 to {Height:|Height| of monData, Width:|Width| of monData, OriginX:|OriginX| of monData, OriginY:|OriginY| of monData}
		else
			set monitor2 to {Height:|Height| of monData, Width:|Width| of monData, OriginX:|OriginX| of monData, OriginY:|OriginY| of monData}
		end if
	end repeat
	set WSmp to {monitor1:monitor1, monitor2:monitor2, monitorCount:(length of wsp) as integer}
	--END OF If there are two monitors then use com.apple.windowserver to try to acquire Origins
	
	if monitorCount is monitorCount of WSmp then --If monitor count matches, compare dimensions reported by the two sources.
		if (Height of display1 is (Height of monitor1 of WSmp)) and (Width of display1 is (Width of monitor1 of WSmp)) and (Height of display2 is (Height of monitor2 of WSmp)) and (Width of display2 is (Width of monitor2 of WSmp)) then
			return WSmp -- All match, return windowserver data since it is most complete.
		end if
	end if
	return {monitor1:display1, monitor2:display2, monitorCount:monitorCount} -- Not all match, return system_profiler data.
end monitorProperties

Check my post The definitive guide to screen resolution for macOS Ventura (13+) to get screen properties like height, width, resolution an relative position to the main screen of all dialyse connected for macOS Ventura (13.x). Cheers, Moritz