MacOS – How to keep an application on top of all windows using AppleScript

applescriptmacoswindow-manager

I have an AppleScript .app file that basically consists of a series of dialogs.

I would like to keep this application on top of all other windows (including on top of any new windows that are created while the application is still running), until the AppleScript is complete and the application automatically closes.

Can pinning a window on top be accomplished in AppleScript?

Best Answer

Method 1: SystemUIServer

After hours of searching online and testing out various solutions, I've found one method to keep a running AppleScript on top of all windows. The method is provided in post #2 of this MacScripter.net thread.

Here is the code:

tell application "SystemUIServer"
   activate
end tell

I placed my entire AppleScript code within the above tell statement. This worked perfectly on the first dialog, but, unfortunately, this caused an error soon after progressing through the AppleScript.

What I had to do was manually encapsulate every dialog in its own tell statement. For every instance of:

choose from list
display alert
display dialog

I had to add a statement. I have countless dialogs embedded in the AppleScript in question, so this took me several hours to complete.

So, this is not a great answer, as it is potentially very laborious. Ideally, one could insert the SystemUIServer statement just once in their code and be done with it.


A note on the default timeout:

If you encapsulate a dialog within the above tell block, by default, the script will timeout if the user does not click a button within 2 minutes. When this timeout occurs, the script will be cancelled. The user will be given the following error:

SystemUIServer got an error: AppleEvent timed out.

(Strangely enough, however, even after the user closes this error dialog, the original dialog will still remain pinned to the top until the user clicks a button on the dialog.)

Here's the relevant description from the AppleScript documentation for with timeout:

When a command fails to complete in the allotted time (whether the default of two minutes, or a time set by a with timeout statement), AppleScript stops running the script and returns the error "event timed out". AppleScript does not cancel the operation—it merely stops execution of the script. If you want the script to continue, you can wrap the statements in a try statement. However, whether your script can send a command to cancel an offending lengthy operation after a timeout is dependent on the application that is performing the command.

Hence, if you do not want to have a timeout affect your dialogs, then do the following:

tell application "SystemUIServer"
    with timeout of 999999 seconds
       activate
        display dialog "Hello World"
    end timeout
end tell

A note on input dialogs:

Method 1 does not work properly with a display dialog that has a text field (i.e., default answer "").

While the dialog is kept on top of all other windows, if the user clicks anywhere outside of the bounds of the dialog, the user will not be able to type text in the text box. The blinking text cursor will permanently disappear.

The top bar of the dialog box immediately turns white when the user clicks out of the dialog. It is not possible to get the bar to return to the dark grey color (which reflects a foreground/active state), so that text can be typed.

The user will still be able to press any buttons in the dialog, but the primary function of the dialog, i.e., to get a text input from the user, will be seriously hampered.

In short, I do not recommend including input dialogs in a SystemUIServer tell block.


Method 2: FastScripts app

Another way to keep every dialog of an AppleScript file pinned on top of all other windows is to use a third-party application entitled FastScripts to trigger the script files. FastScripts keeps all dialogs pinned on top by default, which is very helpful. I don't even know if this feature can be disabled (if you wanted to turn it off; I don't).

FastScripts can launch a .scpt file via either a custom keyboard shortcut or manually (simply click on the FastScripts icon in the menu bar to be presented with a drop-down list of your scripts).

(I know that when I asked this question originally, I specified that the AppleScript was saved as an .app file. But, an AppleScript .app file can be converted to an AppleScript .scpt file easily and in little time.)

Of course, this method is appealing because one does not need to edit one bit of their AppleScript code for the desired effect to be implemented. FastScripts does all of the hard work.