Where Can I Find Details On PlugIns?
Richard Gaskin
ambassador at fourthworld.com
Sun Dec 28 14:06:47 EST 2003
Rob Cozens wrote:
> I'm in the process of designing & testing a SDB Tools plugIn for
> developers, and I'm having problems understanding how this should be
> done.
Such fortuitious timing, as I recently released WebMerge 2.3 and Sophie 1.0
which each have a plugin system, and have been drafting notes for a possible
session on plugins at the upcoming Rev seminar.
In its simplest form, a "plugin" is simply a stackfile and a "plugin system"
is merely a way to open it.
It's a nice extra to use the stack's title for display in a Plugins menu,
since the title will usually have a more meaningful name than the stack file
or possibly even the stack (I tend to use single-word abbreviations for
stack names with "Hungarian-lite" prefixes to minimize the risk of name
conflicts). To account for stacks which may not have their title set you
may want to use "the effective title" to get the string for its menu item.
In WebMerge I walk through a list of stack files in a Tools folder, creating
a simple lookup table with two items on each line, the first being the
string that appears in the Plugins menu and the second being the path to the
corresponding stack file. I store this in a custom property in the app's
Tools menu, and on menuPick I use lineoffset to find the matching stack file
and then open it.
Rev's Plugin Manager goes a few steps deeper to provide extra niceties:
> I see in the Rev Dictionary and Examples plugIn where the plugIn can
> receive special messages (eg: revCloseStack, revPreOpenStack, etc.;
> but no revOpenStack); but so far as I can tell, my plugIn is
> receiving closeStack and preOpenStack, etc....so why are these
> additional messages necessary, how are they used, and why no
> revOpenStack?
The messages like revPreOpenStack are not to provide notification of your
own stack's opening, since as you noted it already gets the native message.
Instead it might be helpful to think of it as revPreOpenSomeOtherStack,
useful if your plugin needs to update itself to display a list of currently
open stacks.
There are at least two ways to let plugins reliably get messages they might
not normally get: frontscripts and a dispatcher.
FrontScripts
-----------
You can catch any system messages you like with frontScripts, and you can
have a plugin insert a frontScript on openStack and remove it on closeStack,
making its message handling self-contained in a way that will work anywhere,
whether in an IDE's plugins folder or in your standalone (see the 4W Props
plugin in RevNet as an example of self-containment, though its practical
usefulness in a standalone is probably nil <g>).
There are two potential drawbacks to the frontScripts approach:
- While it's a good habit to pass system messages, an inexperienced plugin
author may forget. If a frontscript handles a message it does not pass, no
other object in the message path wll get the message. Same with changing
global properties without first saving their values and restoring them
before your handler exits: make no assumptions about the environment and
clean up after yourself and you'll introduce no undesirable side effects.
- At runtime (in a standalone) you can currently have only 10 frontScripts
inserted into the message path at any given time. The only plugins that
need a frontScript are in the subset which need to update themselves to
reflect user selection with the pointer tool (rarely relevant in a
standalone unless you provide a drawing environment) or list currently open
windows, etc.; most will use libraries, of which 50 are allowed at runtime,
if they need to extend the message path at all. While no such limits apply
within the IDE, it is theoretically possible in a standalone to have more
plugins open that want frontscripts than the number of available slots
allow. In practice this seems unlikely, but is a possibility.
Dispatcher
----------
My guess about Rev's dispatcher sending messages which largely mirror
built-in messages and properties is to provide two benefits:
- Convenience -- You just set properties rather than handle inserting
and removing a frontScript yourself.
- Message passing - Rev's dispatcher doles out the mirror messages
in a way that bypasses the side effects of forgetting
to pass system messages.
Choosing Between the Two
------------------------
Whether using frontScripts or a dispatcher is best for your application
depends on the likelihood that more than 10 plugins written for it will need
to handle system messages they don't ordinarily get and be open at the same
time.
For both Sophie and WebMerge I chose to rely on frontScripts, as it keeps
the message path as simple as possible, extending it only as needed. With
both apps, none of the plugins currently shipping with them need to handle
out-out-path system messages at all.
If your app provides drawing tools or other pointer-tool-driven environment
then it may make sense to use a dispatcher to enable more plugins to do live
updates in response to the selectedObjectChanged message and others.
Keep in mind however that responding to the selectedObjectChanged message
drectly can slow the subjective experience dramatically -- drag-select
around 20 objects while the Inspector is open and you'll see what I mean.
To counter this, if you expect to have a lot of palettes updating themselves
in response to user selection it may be useful to "buffer" your update
message with something like this:
on selectedObjectChanged
if "UpdateMyFancyPalette" is not in the pendingMessages then
send "UpdateMyFancyPalette" to me in 100 millisecs
end if
pass selectedObjectChanged
end selectedObjectChanged
on UpdateMyFancyPalette
-- do update stuff
end UpdateMyFancyPalette
The 1/10-second delay is barely noticeable, but it can dramatically improve
the subjective experience of responding to selection gestures.
> I also note that if Rev is closed and I start it by double-clicking
> on a stack in my development folder that also exists in the Rev
> PlugIn folder, revPreferences is opened instead of my stack. Is this
> normal?
The engine's default behavior (and therefore your standalone's) is to open
any stacks double-clicked to launch it.
A startup or preOpenStack handler can insert an appleEvent handler (Mac) or
a routine that checks the value of the global variables $1, $2, etc. (Win
and Unix) to override the default behavior. This seems to be the case with
Rev though I'm uncertain as to why this should be necessary; hopefully
Jeanne or another RunRev team member can chime in on this.
> What is the proper procedure for developing and testing plugIn stacks?
Since a "plugin" is just a stack file, just open it and use it. :) To
ensure that nothing in the plugin opening mechanism gets in its way you'll
want to test it in the native environment (your standalone or the Rev IDE
Plugins folder, whichever you're writing for).
If you're writing for use in Rev, extra bonus points if you take the time to
declare your variables for compatibility with the explicitVariables global
property. That's a handy property for debugging, and it's disappointing
when you come across a favorite tool that won't work while you have that
turned on (I've done that myself in some plugins, and have been going back
and updating their scripts for compatibility with explicitVariables).
Of course if your standalone doesn't use explicitVariables then plugins
written for your environment won't need to account for it.
--
Richard Gaskin
Fourth World Media Corporation
Developer of WebMerge: Publish any database on any Web site
___________________________________________________________
Ambassador at FourthWorld.com http://www.FourthWorld.com
Tel: 323-225-3717 AIM: FourthWorldInc
More information about the use-livecode
mailing list