ExtendScript - one of the scripting languages supported by Creative Suite applications, and the only one cross-platform - has several extra features compared to Javascript. Besides Filesystem access (a notable addition), there’s the ScriptUI component: which allows you to add graphic user interfaces (GUI) to scripts. Photoshop support is dated to CS2, according to the unofficial (yet essential) ScriptUI for Dummies guide made by Peter Kahrel. As it happens often in scripting CS applications, the implementation of some feature is version and platform dependent - i.e. PS CS5 on PC is different from PS CS6 on Mac. In this post I’m going to focus on one particular aspect of ScriptUI, namely the Window object.
Two of a kind
Windows can be either dialogs or palettes (at least in Photoshop). They look and are substantially different.
Palettes
Open the ExtendScript ToolKit (ESTK) and run the following code:
The result (it runs in ESTK, since the first line is the preprocessing directive #target estoolkit
) is as follows:
The above is a palette, a non-modal window. Something that lets you interact either with the window itself (clicking buttons, dragging sliders, etc) and with the host program - here the ESTK (so you can select, say, menu items, other panels, etc.). It’s the Javascript equivalent of Panels and third party Extensions - they show up and wait there, letting you work with Photoshop.
Dialogs
In ESTK run the following code:
Compared to the first script, there’s little difference (the windowResource string contains dialog
instead of palette
) and the Window looks like this:
We’re still within ESTK: the red, closing button is disappeared, the titlebar is bigger, but the main difference is that dialogs are modal: that is, the focus is on them and you can not interact with the host application. If you try to select, say, a menu item the program complains with a beep.
Photoshop support
In the ScriptUI for Dummies guide it’s asserted that Photoshop doesn’t support palette windows. While the more hours I spend debugging unwanted behaviors the more I tend to agree with Peter Kahrel, I would personally express the statement as follows:
Photoshop supports both dialog and palette Windows; while the former kind’s behavior is consistent with other CS applications, palette implementation in PS is peculiar and version/platform dependent.
PS dialogs implementation
It’s basically what you’d expect - a modal window (which aspect depends on the PS version and platform). Yet the behavior is exactly the same no matter what is the combination, PC/Mac - CS5/CS6. In order to test it, just change the first line of the two scripts above:
One thing to notice is that PC versions have a red X closing button, while Mac versions do not (for some reason, CS5 rendering of the slider bar is thicker compared to CS6).
PS palettes implementation
Here things get “interesting”. First, if you run the palette example with #target photoshop
you’re not going to see very much. The Window that you expect to see just flashes briefly and disappear. This is what will happen to every Snp*.jsx examples provided alongside with the ESTK application, not just my code. The answer lies in the fact that palettes keep showing only if there’s something going on in the script, they can not stay idle waiting for the user to do something like modal dialogs do.
In the above example, after the win.show()
the script is busy creating a new document, applying and blurring some noise just to kill some time. In the meantime, the palette window shows and keep showing; when the script is done with the task, the palette is automatically closed with no need of user interaction whatsoever, nor explicit win.close()
. In order to keep Photoshop busy, I’ve found two working alternatives (because a straight $.sleep()
loop makes PS quite non-responsive) involving the following functions:
The comments in the code should be self-explanatory. As far as I know, waitForRedraw()
should work also in earlier PS versions - it’s not documented, it’s just used in one Reference’s demo scripts.
PS palette working example
One possible way to implement working palette Windows in Photoshop has the following logic:
The key point is the isDone
variable, which is set false at the beginning. After the Window is shown, a while loop keeps checking for this sentinel value and call app.refresh()
, or alternatively waitForRedraw()
in order to keep the palette showing. Instead of an explicit call to win.close()
, it’s a better option to attach to the buttons’ onClick()
functions a sentinel value’s switch to true. This way the while loop breaks and the Window automatically closes.
Mind you, it’s crucial to set isDone = true
even in the win.onClose()
function, otherwise Photoshop will keep evaluating the variable even after the Window has been closed clicking the red dismiss button (see following screenshot) - resulting in some degree of non-responsiveness.
Few cosmetic differences are present this time too, including the position of the dismiss button (top-left for Mac, top-right for PC). This button is taken into account with the onClose()
function as shown in the code example.
Platform specific behaviors (aka bugs)
Things are getting weird if you start to compare Mac and PC implementations of ScriptUI windows in Photoshop CS5 and CS6 (the tests on the PC side have been made on a virtualized Window7 system running in Parallels Desktop). It happens that, depending on how you mix platform, version and Window type, you end up with different behaviors (modal and non-modal), as follows:
While dialog’s behavior is nicely uniform between Mac and PC, CS5 and CS6; palettes are a fiasco. Mac behavior is always non-modal (as it should be - palettes are non-modal by definition), while PC’s one depends on the Photoshop version and function used. Basically, only CS5 with app.refresh() works as it’s supposed to do, while in CS6 both functions fail. From my personal standpoint, this is a bug - and I haven’t found any workaround yet.
Conclusions
To sum up:
- Palettes are defined within Creative Suite applications as non-modal Windows that can wait idle.
- The Photoshop implementation misses entirely the “can wait idle” part - palettes keep showing only if there’s some code running in background.
- There’s a workaround to make palettes behave as they’re supposed to do, involving either
app.refresh()
orwaitForRedraw()
loops and a sentinel variable. - On Mac the workaround, no matter on CS5 and CS6 or what function is used, makes the palettes non-modal (as they’re supposed to be by definition)
- On PC, only app.refresh() in CS5 returns a non-modal Window - CS6 ones are always modal.
Which is quite a pain in the neck, especially if you need your palettes to work as they’re supposed to do in a platform and version independent way.