On Jun 23, 2015, at 2:40 PM, Steve Mills < email@hidden> wrote:
If I run the script from ScriptDebugger, from the system script menu, or from LaunchBar, it works as expected. But if I run it via a global key equiv I've set on a DragThing item, it works wrong. It appears that different apps are returning different values for NSScreen's frame. Could this be because DragThing still appears to be a Carbon app?
use scripting additions use framework "AppKit" -- for NSScreen
set ss to current application's NSScreen's screens() set leftScreenBox to (ss's objectAtIndex:1)'s frame()
Do you have more than one display? AppleScript indexes are one-based, but Objective-C's are zero-based. So, "objectAtIndex:1" is asking for the second screen, not the first one. There are two potential problems:
1. If you only have one display, "objectAtIndex:1" will return an error and your script will stop executing.
2. As far as I am aware, except for the first screen (index zero, which always refers to the "default" screen) the screens aren't in any particular order in the array; therefore, even if it succeeds, the exact screen selected with index one may vary from process to process.
If you want the first screen, you can use Objective-C's "indexAtObject:0" or "firstObject". AppleScript's "item 1" or "first item" will also work with NSArrays.
While I'm at it, I'd like to make some other comments about the code:
1. Since the script doesn't use scripting additions, there's no reason to 'use scripting additions'. One of the goals of "use" is to add more structure and explicitness to the otherwise very dynamic AppleScript language, and part of this is being concise and not "use"ing things unless you actually need them. (I understand if this is an excerpt from a larger script that does use additions, but I thought this was a good opportunity to mention this.)
2. "screens" and "frame" are properties, not functions, so you shouldn't use "()" with them. Although it may currently work, it is superfluous and the exact meaning of using parenthesis after a property name may change in the future. (e.g., it should probably mean instead "get the property, whose value is a function, then call that function", just as it does when sending the message to an AppleScript object that has a property whose value is a handler.)
Since I'm new to AppleScriptObjC, is there some way to have "current application" be the app that is being targeted by the script, so I can ensure it's working with a Cocoa app that will return the correct values? Like:
tell app "Safari" set ss to current application's NSScreen's screens() end tell
From my tests, "current application" always seems to be the app that executed the script.
No, you cannot send Objective-C messages to another process, in AppleScript or Objective-C†. That's the reason why looking up Objective-C identifiers in AppleScript requires the "current application" prefix, to ensure you're trying to interact with the Objective-C runtime (in the current process) and not sending a message to some other application process.
Hypothetically, there could be a scriptable application that explicitly supports getting the screen layout, but I don't know of one offhand, and you can't send arbitrary events (either Objective-C messages or AppleScript events) to arbitrary programs.
I'd like to stress that "current application" always means the current application. Its primary purpose is to allow you to target the current application when inside a "tell" block, by ignoring the current target ("it"). If you want to send a message to the current target explicitly, use "it" instead:
tell application "Safari" name -- implicitly sent to "it", which means it is sent to Safari its name -- explicitly sent to "it", which means it is sent to Safari current application's name -- explicitly sent to the current application instead of "it" my name -- explicitly sent to "me", the current script, instead of "it" end tell
In Script Editor, the following equivalent script
tell application "Safari" to {name, its name, current application's name, my name}
returns
{"Safari", "Safari", "Script Editor", "Untitled 3"}
† For the pedantic, Objective-C has a feature called Distributed Objects that allows sending messages to objects in another process, but it's something that an application has to support, and it doesn't give you the ability to send arbitrary messages to arbitrary objects.
-- Chris Page The other, other AppleScript Chris
|