Skip to content

Instantly share code, notes, and snippets.

@henryroe
Last active March 7, 2021 21:54
Show Gist options
  • Save henryroe/8810193 to your computer and use it in GitHub Desktop.
Save henryroe/8810193 to your computer and use it in GitHub Desktop.
Demonstration of how to use an AppleScript Bundle to enable access to NSScreen in AppleScriptObjC
(*
Copy and paste this script into a new document in AppleScript Editor.
When saving, select "Script Bundle" as File Type.
Save the file to: "~/Library/Script Libraries/Access NSScreen.scptd"
Note: you may need to create the directory: "~/Library/Script Libraries"
Note: while this gist has the file ending "scpt", by selecting the
"Script Bundle" file type, the file extension "scptd" should be added.
Now, in the document's toolbar in AppleScript Editor click "Bundle Contents"
and select "Applescript/Objective-C Library" checkbox
Click "Compile" and save again.
Now, you can try out the next file ("demo Access NSScreen.scpt") to get the size
and layout of your displays.
*)
use framework "AppKit"
on getScreenLayout()
set output to {}
repeat with curScreen in current application's NSScreen's screens()
set theFrame to curScreen's frame()
set thisDisplay to {width:width of |size| of theFrame, height:height of |size| of theFrame, originX:x of origin of theFrame, originY:y of origin of theFrame}
copy thisDisplay to the end of the output
end repeat
return output
end getScreenLayout
use theLib : script "Access NSScreen"
use scripting additions
set theResult to theLib's getScreenLayout()
set theString to ""
set dispnum to 0
repeat with curDisplay in theResult
set theString to theString & "Display " & (dispnum as string) & return
set theString to theString & tab & "Size (width, height):" & tab & width of curDisplay & tab & height of curDisplay & return
set theString to theString & tab & "Origin (x, y):" & tab & tab & tab & originX of curDisplay & tab & originY of curDisplay & return
set dispnum to dispnum + 1
end repeat
display dialog theString
@cmaahs
Copy link

cmaahs commented Jan 16, 2018

The Access NSScreen.scptd worked great for me for a long time, and today it started producing an error on the |size| feature of the script. Not being a well versed applescript type, I cobbled together a fix that worked for me. Just thought I'd share in case others have come across the same issue. It seems like it was caused by an update for me.

`(*
Copy and paste this script into a new document in AppleScript Editor.
When saving, select "Script Bundle" as File Type.
Save the file to: ~/Library/Script Libraries/Access NSScreen.scptd
Note: you may need to create the directory: ~/Library/Script Libraries
Note: while this gist has the file ending "scpt", by selecting the
"Script Bundle" file type, the file extension "scptd" should be added.

Now, in the document's toolbar in AppleScript Editor click "Bundle Contents"
and select "Applescript/Objective-C Library" checkbox
Click "Compile" and save again.
Now, you can try out the next file ("demo Access NSScreen.scpt") to get the size
and layout of your displays.
*)

use framework "AppKit"

on getScreenLayout()
set output to {}
repeat with curScreen in current application's NSScreen's screens()
set theFrame to curScreen's frame()
set _origin to item 1 of theFrame
set _size to item 2 of theFrame
set thisDisplay to {width:item 1 of _size, height:item 2 of _size, originX:item 1 of _origin, originY:item 2 of _origin}
copy thisDisplay to the end of the output
end repeat
return output
end getScreenLayout`

@anjiro
Copy link

anjiro commented Jul 15, 2018

Note in High Sierra, the "Applescript/Objective-C Library" checkbox is missing. However, it appears to work without this checkbox. After updating the Access NSScreen.scptd, you have to restart anything that might have pre-loaded the library, including an individual Applescript Editor window or (in my case) Quicksilver.

@splicemaahs
Copy link

Thanks from my future self...

@ChristoferK
Copy link

There's no need to create a library to house one handler. It can just be declared on its own in a simple .applescript file, and then called within the same script to make use of it. demo Access NSScreen.scpt seems largely concerned with getting a string representation of the AppleScript list/record returned by getScreenLayout(), but it's possible to do away with most of that by utilising additional Objective-C properties. Here's a re-worked version of the two scripts, combined into one, which can be saved and run as either a plain text .applescript file or a compiled .scpt file:

use framework "AppKit"
use scripting additions

property this : a reference to current application
property NSScreen : a reference to NSScreen of this
property NSMutableDictionary : a reference to NSMutableDictionary of this

on getScreenLayout()
	set output to NSMutableDictionary's dictionary()
	repeat with screen in NSScreen's screens()
		(output's setObject:({width:item 1 of item 2 ¬
			, height:item 2 of item 2 ¬
			, X:item 1 of item 1 ¬
			, Y:item 2 of item 1} of screen's frame()) ¬
			forKey:("Display " & output's |count|()))
	end repeat
	return the output's |description|()
end getScreenLayout

display dialog getScreenLayout() as text

The output is formatted like so:

{
    "Display 0" =     {
        X = 0;
        Y = 0;
        height = 800;
        width = 1280;
    };
}

However, if you particularly wanted to get rid of the braces and punctuation, then you can simply replace:

return the output's |description|()

with:

tell the output's |description|() to return ¬
		(its stringByReplacingOccurrencesOfString:("[{};]") ¬
			withString:space options:NSRegularExpressionSearch ¬
			range:{0, its |length|()})

and declare NSRegularExpressionSearch as a property whose value is a reference to 1024. Then the output will look like this:

"Display 0" =      
        X = 0 
        Y = 0 
        height = 800 
        width = 1280

with additional displays formatted identically below the previous.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment