[Openmcl-devel] AppleScript'ing equivalents in Lisp?

Gary Byers gb at clozure.com
Tue Oct 21 02:55:33 PDT 2008


On Mon, 20 Oct 2008, Christian Lynbech wrote:

> Being an utter newbie at this Mac thing, I wondered if there where an
> relatively easy way to access application functionality as I understand
> one can with AppleScript?

One approach (that's in some sense very high-level and in other senses ...
not so much) that's present in 10.5 is the Scripting Bridge, described
at:

<http://developer.apple.com/documentation/Cocoa/Conceptual/ScriptingBridgeConcepts/Introduction/chapter_1_section_1.html> .)

The short version is that the Scripting Bridge lets you treat scriptable
applications like ObjC objects; invoking methods on these objects sends
AppleEvents to the application and allows you to exercise control over
its "scriptable" functionality.

To translate the step-by-step instructions in that guide from an xcode-centric
viewpoint to a CCL-centric one:

0) Ensure that you're running Leopard and have its XCode tools installed.

1) Ensure that you have CCL's interface translator installed.

2) In a terminal window, generate an "iTunes.h" header file.

shell> sdef /Applications/iTunes.app | sdp -fh --basename iTunes

This currently seems to generate a warning:

sdp: unknown type name "tdta"

which, according to the thread in:

<http://lists.apple.com/archives/cocoa-dev/2008/Jul/msg02051.html>

can be safely ignored.

3) Create an entry in CCL's interfaces for the "itunes" class described
in the header file.

shell> cd ccl
shell> mkdir -p darwin-x86-headers64/itunes/C

4) Add a little shell script in that directory.  For long-forgotten historical
reasons, some things expect this script to be named "populate.sh".

--- ccl/darwin-x86-headers64/itunes/c/populate.sh --
#!/bin/sh
SDK=/Developer/SDKs/MacOSX10.5.sdk
rm -rf Developer System
CFLAGS="-m64 -fobjc-abi-version=2 -Wno-endif-labels -isysroot ${SDK} -mmacosx-version-min=10.5";export CFLAGS
h-to-ffi.sh /Users/gb/iTunes.h
---- end of file ----

You may wish to either change your initials to "gb", or change the path in
the last line of that script.

5) Run the interface translator (to create a .ffi file from the specified
.h file), then the interface parser (to create .cdb database files from
the ffi file.)  This can be done in one fell swoop inside CCL via:

? (create-interfaces :itunes)

This will run the translator once and then run the parser twice (a second
pass is necessary to resolve forward-referenced types and constants in
some cases.)  There may be some warnings on the first pass to the
effect that some .cdb files are missing; they're being created, so
ignore those warnings.

6) Fire up the Cocoa IDE.  (Some of this stuff doesn't work in the
hybrid environment you get via '(require "COCOA")'; use '(require
"COCOA-APPLICATION")' to create a double-clickable application, then
double-click on it.

7) In the IDE, load the Scripting Bridge extension framework.  When
we load an ObjC extension framework, we generally have to provide
a set of interfaces that describe that framework's functionality,
so that lisp's ObjC bridge knows what ObjC classes and methods defined
in the framework it should import.  The "iTunes.h" file includes all
of the ScriptingBridge interfaces, so if we use it here we'll get
those interfaces as well as those that describe iTunes:

? (objc:load-framework "ScriptingBridge" :itunes)

8) The ObjC bridge's rules for translating ObjC class names into
lisp class names are sometimes somewhat arbitrary; they are in this
case, where the ObjC class named "SBApplication" gets mapped to the
lisp name NS:S-B-APPLICATION.  Whatever we think of that translation,
we're going to create an instance of that class, using iTunes' unique
bundle identifier.  Note that the bundle identifier is an NSString
constant (#"...").

? (defvar *itunes-app* (make-instance 'ns:s-b-application
                          :with-bundle-identifier #@"com.apple.iTunes"))
#<S-B-APPLICATION <ITunesApplication @0x124e3b40: application "iTunes" (not running)> (#x124E3B40)>

9) We can invoke any method on that application that's defined in the
'iTunes.h' header file (as well as those methods that it inherits from
SBApplication, which are described in
/System/Library/Frameworks/ScriptingBridge.framework/Headers/SBApplication.h>

? (#/run *itunes-app*)

? (#/activate *itunes-app*)

? (#/quit *itunes-app*)

We've now exhausted my knowledge of iTunes, I'm afraid.  (In particular,
I don't know how to access the dialog that tells you every few days
that a new version is available and that whatever you're doing can't
be as important as downloading that new version and rebooting to
install it.)

>
> I have the dual problem of finding out which objects to access and how
> to access them. AppleScript does not look that frightening but I would
> rather access the information from an environment that I know and love :-)
>
> My first target project is to sanitize some track information in
> iTunes. Sometimes what should have been the track title, ends up in the
> composer field and handling that one track at a time is frustratingly
> laborious when I just want to shuffle some existing fields in some
> one-of fashion.
>
>

I don't know if that's exposed as "scriptable" functionality; if so,
it should be described in the .h file and the procedure described above
should let you invoke that functionality from CCL.

> ------------------------+-----------------------------------------------------
> Christian Lynbech       | christian #\@ defun #\. dk
> ------------------------+-----------------------------------------------------
> Hit the philistines three times over the head with the Elisp reference manual.
>                                        - petonic at hal.com (Michael A. Petonic)
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>
>



More information about the Openmcl-devel mailing list