Brett Kirksey wrote:
Okay, my first post of this didn't get a response, so I thought I'd just issue a challenge in the subject line to get someone's (anyone's) attention. :-)
I'm working on a script library saved as an application. I've
ran into something I can't figure out, so I thought one of you
guys may know what's going on.
Here's an example. Let's say you make a script with only the
following code:
on makeFinderWindow()
tell application "Finder"
set bar to make new Finder window
return bar
end tell
end makeFinderWindow
Now save it as a script _application_ named "Foo".
This means that you have defined a script object.
In an attempt to translate this in an object-oriented jargon, that
script object will behave, when running, as an instance of an
application class "foo".
Now make another script with only this code:
set newWindow to makeFinderWindow() of application "Foo"
tell application "Finder" to close newWindow
Run this script. It generates an error that <<class brow>>
doesn't understand the close command. If you comment out the
"close window" command, you can see the result of the script is
"Finder window id nn of application 'Foo'".
With the above, this seems to be rather logical.
Variable newWindow is set to some "Finder window" object belonging to
application foo; even if its displayed class and ID sound familiar,
this is an illusion: newWindow must be viewed as some kind of opaque
object brought by and known through foo.
When the Finder is told to close that object, it notes that it is not
one of its own objects; the Finder thus sends the close command to the
object, which obviously doesn't know how to handle it (because we have
not defined a handler for that command) [1].
But if you run the handler makeFinderWindow() from within "Foo",
the result is "Finder window id nn of application 'Finder'".
Yes, because "foo" got that reference directly from the Finder
application.
So,
when "Foo" passes the new finder window of "Finder" to the
calling script, it becomes a finder window of "Foo" instead and
then you can't work with it.
I've tried this with several different apps and several
different classes of objects, and it does the same thing. I just
know I'm missing something obvious, so I'm feeling pretty dumb.
Can someone enlighten me?
It is a consequence of the object paradigm (as implemented by
AppleScript, would some people add).
An object is either of a well-known nature, that knowledge being
brought by a set a basic classes (AppleScript being in the inheritance
chain of every script, these are for example integers, lists, strings,
records...).
Or it is just an object stemming from/belonging to another one (and it
is then assumed that the latter knows what to do with the first).
Shouldn't it be that way, any script would need to have an
instantaneous universal knowledge of every object of every possible
application, existing or to be written.
So, what are the workarounds?
First, there is Emmanuel's proposal to use window IDs.
In fact, this relies upon the fact that numbers (numeric objects) are
known by every application by means of AppleScript itself; you may
think about them as "integer of script applescript".
In counterpart, that approach requires that YOU tell the correct app
(the Finder) to use such a number as a window ID.
Another way is to go further with the object logics.
Since foo's makeFinderWindow() returns a kind of opaque object, one
could be tempted to ask foo to close that object too; let's thus try:
-- This is an attempt
on makeFinderWindow()
tell application "Finder"
set bar to make new Finder window
return bar
end tell
end makeFinderWindow
on closeFinderWindow(W)
close W
end closeFinderWindow
and rewrite the calling script as:
set newWindow to makeFinderWindow() of application "foo"
tell application "foo" to closeFinderWindow(newWindow)
The close command doesn't work much better :-(
In fact, closeFinderWindow() is unable to even fetch an object `«class
brow» id NNN`.
Note that when requested to create a window, foo returns that window
and immediately forgets it.
Moreover, when passed back to foo, any relationship to the Finder is
now lost.
No problem ;-)
Let's rewrite foo as [2]:
-- This is script foo v2
property parent : application "Finder"
on makeFinderWindow()
make new «class brow»
end makeFinderWindow
on closeFinderWindow(W)
close W
end closeFinderWindow
This works because foo now knows where to find a `«class brow» id
NNN` object and what to do with a close command sent to it: just ask
the parent.
But it then becomes clear that there was no need to let the window
reference go outside of foo; the whole thing may be rewritten as [3]:
-- This is script foo v3
property parent : application "Finder"
property bar : ""
on makeFinderWindow()
set bar to make new «class brow»
end makeFinderWindow
on closeFinderWindow()
close bar
end closeFinderWindow
-- This is the calling script
tell application "foo"
makeFinderWindow()
closeFinderWindow()
end tell
Hmm... not sure I managed to say something clever.
HTH anyway,
Axel
[1] It is not obvious to see that the close command is sent to that
elusive "Finder window". One may try to "demonstrate" that point by
returning a slightly richer object:
-- Script foo revisited
script |Finder window|
end script
on close
display dialog "Close event"
end close
on makeFinderWindow()
tell application "Finder" to make new Finder window
return a reference to |Finder window|
end makeFinderWindow
The result of the `set newWindow to makeFinderWindow() of
application "foo"` statement is then:
|Finder window| of application "foo"
while the `tell application "Finder" to close newWindow` statement will
raise a dialog box.
[2] One needs to write "«class brow»" instead of "Finder window",
because properties are set at run time, thus too late for the compiler
to know that it has to look into Finder's dictionary.
[3] Of course, it may happen that you don't want the Finder to be foo's
parent:
-- This is script foo v4
property bar : ""
on makeFinderWindow()
tell application "Finder"
set bar to make new Finder window
end tell
end makeFinderWindow
on closeFinderWindow()
close bar
end closeFinderWindow
|