System Events and the Dock

I posted this in another post but I have a feeling not many people will end up seeing it. I thought I would put it out there as a more general question. I was trying to use system events to click on an application in the Dock with Control and Option and then select force quit. I realize there may be a better way to accomplish the end result, but how would you do something like this? I’d like to know if I have the option to access the Dock like this for future reference. Here is what I had tried. The commented out lines are the ones that didn’t do what I expected them to do. All this does is launch QuarkXPress. I am in OX 10.3.9.


tell application "System Events"
   tell process "Dock"
       click button "QuarkXPress"
       --key code 126 using {control down, option down}     --up arrow
       --key code 36    --Return
   end tell
end tell
beep 1

Model: Mac G5
Operating System: Mac OS X (10.3.9)

What you have there doesn’t work for me, but the normal way to force quit would be:

tell application "System Events" to tell process "myApp" to quit without saving

I think the main reason it doesn’t do what I want it to do is that you have to click and hold the mouse button down for the sub-menu to appear. I haven’t seen a system events command to click and hold. Is that possible?? If not, I think I will just abandon accessing the dock in this manner.

Using gui scripting on the dock to quit an app is undeniably the long (and wrong) way to terminate an app. Actually, gui-scripting anything to quit an app is unnecessary and full of potential problems.

Actually, a “force quit” is not the same as a regular quit. An application hung up in a terminal loop or currently working on an complex computation may not always respond to an applescript quit command in a predictable or timely manner. In my opinion, a better, and more reliable method is to use a shell script.

do shell script "killall 'QuarkXPress'"

This all assumes that you actually want to immediately and unconditionally terminate the process. It will not save anything, and does not care what’s happening with the app. If you’re looking for more tame and less dangerous, then go with a ‘tell “someApp” to quit…’ applescript command. Note that this is not a force quit, but rather just a regular quit. Also note that if you control-click/click-hold on a dock item, and then hold the option key down while viewing it’s menu, you have the ability to actually ‘force quit’ the app, rather than just quit it.

j

The only caveat here is that not all apps have process names that match their Finder names, but generally they do. If killall doesn’t work, look in the Activity Monitor (in Applications/Utilities) to find out what it is called. You can also force quit from there.

I concur that, if you really must force-quit an application, ‘killall’ is a pretty good way to go about it.

Nevertheless, since part of Matt-Boy’s question relates to the general possibilities of UI scripting (for a variety of purposes), the subject might be worth exploring a little further.

A couple of things struck me recently, while trying to get a UI script to work on both a French-speaking Panther machine, as well as an English Tiger. Firstly, UI scripting might involve identifying various elements (such as menu items) by name - so, if a more portable script is required, some consideration needs to be given to localization issues. (However, let’s leave that little complication aside for the moment.) :slight_smile:

The other point is that, in terms of UI scripting, there seem to be some significant differences between Panther and Tiger. I’m not necessarily referring to just a few changes in syntax or a handful of extra features, either. While much of the AppleScript language tends to remain fairly consistent, with due consideration given to legacy code, etc., it seems quite a different matter when it comes to the user interface, which is still evolving at quite a pace. From one upgrade to the next, even an apparently simple dialog panel (while appearing fairly similar to its predecessor) may turn out to have been structurally altered ‘under the hood’.

That’s probably why Matt-Boy’s original (Panther) code didn’t fare too well on Adam’s Tiger machine - and why the following examples may well fall flat on anything pre-Tiger, too. (Nevertheless, I hope there’s something in them that might prove useful…)

Purely as a UI scripting exercise, I thought it might be interesting to attempt a force-quit routine via the UI - although this first effort doesn’t attempt to negotiate the dock:

set p to "TextEdit"
tell application "System Events" to if process p exists then
	key code 53 using {command down, option down}
	tell window "Force Quit Applications" of process "loginwindow"
		select (first row of table 1 of scroll area 1 whose value of text field 1 is p)
		click button "Force Quit"
		click button "Force Quit" of sheet 1
		click (first button whose description is "close button")
	end tell
end if

Anyway, lest I be accused of side-stepping the ‘click and hold’ issue, mentioned earlier in the discussion, I guess we’d better move on to some Dock/UI scripting. While a variation of this next example can certainly produce a force-quit, the result is difficult to visually distinguish from a regular quit - especially since you won’t see any menu names change (as you might when you manually click the icon and press the option key). The “Hide Others” command should provide a better demonstration, since it’s much easier to see what it does - compared to the “Hide” command.

set p to "TextEdit"
tell application "System Events" to if process p exists then tell process "Dock"
	tell UI element p of list 1
		perform action "AXShowMenu"
		tell menu item "Hide Others" of menu 1 to if exists then select
		keystroke return
	end tell
end tell

Neat, Kai.

How did you discover that perform action “AXShowMenu” would pop up a dock icon, and that "Hide Others would work (i.e. be in the menu) even when the option key was not down?

If you have folder icons below the invisible separator in the dock are they in list 2? That could be neat because they pop up all the items in the folder a damned sight faster than other ways of displaying that list.

Adam

Cool! Those are some great tricks. Thanks, kai.

It’s a pleasure, Matt-Boy. :slight_smile:

Process of elimination really, Adam - along with a bit of judicious poking and prodding (essential skills for UI scripting). :wink:

This tells us that the Dock has only one UI element, a list:

tell application "System Events" to process "Dock"'s UI elements

--> {list 1 of application process "Dock" of application "System Events"}

And this lets us know what actions are generally available to the UI elements in that list:

tell application "System Events" to name of UI element 1's actions of process "Dock"'s list 1

--> {"AXPress", "AXShowMenu"}

We already know that the “AXPress” action (click) will open/activate the target - so that’s no good. Since we want access to the target’s menu (as with a manual click and hold), the “AXShowMenu” action would seem a pretty good bet (especially since it’s the only remaining option).

To be honest, I didn’t know - but something like this routine gave me a list of all menu items - including those not displayed:

set p to "TextEdit"
launch application p
tell application "System Events" to tell UI element p of process "Dock"'s list 1
	perform action "AXShowMenu"
	name of menu 1's menu items
end tell

--> {"Remove from Dock", "Open at Login", "Show In Finder", "Hide", "Hide Others", "Quit", "Force Quit"}

From there, it was simply a matter of trying the old ‘select/return’ routine (since ‘click’ didn’t work). :expressionless:

As we’ve now seen, there’s only the one list - although it contains all of the docked items…

You mean something like this?

tell application "System Events" to tell process "Dock"'s list 1
	set l to name of UI elements whose subrole is "AXFolderDockItem"
	tell me to set i to (choose from list l with prompt "Choose a Dock folder:")
	if i is not false then perform action "AXShowMenu" of UI element (i's item 1)
end tell

:slight_smile: