Scripting the Recent Items item under the apple menu

I would like to do the Item “clear menu” under the “Recent Items” sub-menu under the apple menu, for OS X.

It’s probably very, very simple - which matches my knowledge, I guess.

John Love:lol:

Try this, John (it’s about as simple as I can manage right now):

tell application "System Events" to click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)

Thanks bunches, Kai

However, I’ve gotten back NSReceiverEvaluationScriptError=4, which error is very very common judging from the volumes of forums out there on AppleScript for 10.4.2

Nobody seems ready to throw the dart at AppleScript or at 10.4.2

Thanks again.

John Love

That’s a pity, John - it works just fine in 10.4.3, where some aspects of UI scripting seem to have improved quite significantly.

Previously, it’s often been necessary to go through a rather elaborate process of clicking on certain elements, pausing for their children to appear - and then continuing down the path to the final target. Since I can no longer test in 10.4.2, it’s very hard to know for sure exactly what might work. (Solutions in this area are frequently the result of a little experience and a great deal of trial and error.) The code I posted previously does at least show the sort of path required to reach the menu item “Clear Menu”. Going purely from memory (not advisable in cases like this - but what can you do?), you might need to produce something like the following. Please bear in mind that it probably won’t work right off, as it’s purely a guess

Untested:

tell application "System Events" to tell menu bar item "Apple" of ¬
	menu bar 1 of (first process whose frontmost is true)
	click
	tell menu "Apple"
		repeat until exists
			delay 0.2
		end repeat
		tell menu item "Recent Items"
			click
			tell menu "Recent Items"
				repeat until exists
					delay 0.2
				end repeat
				tell menu item "Clear Menu"
					if enabled then click
				end tell
			end tell
		end tell
		if exists then keystroke return
	end tell
end tell

(Kinda tortuous, eh?) Since that’s unlikely to do the trick initially, perhaps someone still using 10.4.2 could help you knock it into shape…

Another approach possibly worth trying involves keystrokes. This technique works for me but, again, may not in earlier OS/AS versions:

tell application "System Events" to tell (first process whose frontmost is true)
	click menu bar item "Apple" of menu bar 1
	keystroke "Recent Items" & return & "Clear Menu" & return
end tell

Finally, if all else fails, you could always consider running this:

activate application "Software Update"

Only (half) kidding… :wink:

I’ve tried two of these in 10.4.3 and I get:

System Events got an error: NSReceiverEvaluationScriptError: 4

As well. It highlights this in the first one:

click menu item “Clear Menu” of menu “Recent Items” of menu item “Recent Items” of menu “Apple” of menu bar item “Apple” of menu bar 1 of (first process whose frontmost is true)

And this in the third one:

click menu bar item “Apple” of menu bar 1

How did you get it to work?

jenny:

This is interesting. I cut and pasted your text into Script Editor, added the term [tell app “System Events” to] and it compiled and executed perfectly. I am also running 10.4.3. Here is your text with the added tell app:

tell application "System Events" to click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)

Would you please copy your entire text from your Script Editor, and enclose it within the Applescript brackets on your next post so we can check it out?

Thanks.

Right…

tell application "System Events" to click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)

It’s exactly the same script. I took screenshots…

After compile: http://img307.imageshack.us/img307/8757/picture17tr.png
After run: http://img119.imageshack.us/img119/4176/picture28bq.png
The highlighted text: http://img119.imageshack.us/img119/412/picture39oi.png

I’m perplexed. Is there something I’m missing?

Jenny

Jenny:

Great screenshots, thanks. Try making sure your system is enabled for GUI scripting. Go to System Preferences, click on Universal Access (On my machine, it is the last item to the right in the System section). Make sure the box on the bottom is checked to enable access for assistive devices.

I sure hope that is it for you…

That did it! Thanks so much, John.

Jenny

Oooh. Sorry. Craig. I’m new here…

I have one more problem I was hoping you could help me with:

The script works fine when I run it in Script Editor, but when I save it as an Application and launch it, it runs without error, but it doesn’t do what it’s supposed to (clear the Recent Items menu). I have no idea why. Any suggestions?

Thanks again.

Jenny

Jenny:

I don’t care what you call me, but thanks anyway. I am not much of a GUI scripter; I am more of a parasitic GUI stealer. From what I can see with The Great Kai’s script, the offending portion is the final menu bar, as it is accessing the frontmost process, which is always Script Editor when run from the editor. In my opinion, it should be the application script itself when called as an application, yet it does not work, as you indicated. I also saved it as a script in my library, and it still would not function correctly. This will most likely require some experimentation on our parts, unless The Great Kai happens to peruse our thread and confer the solution upon us. I will play around with it over the next few days and get back here if I stumble upon something. Please do the same if you get lucky; this is extremely interesting.

Hi. That happens here too. I think it’s because the script itself is the frontmost application when it sends the command to System Events, but it quits before System Events finishes carrying out the ‘click’ command in its menu. There probably is an error being thrown, but application errors are often ignored in OS X unless you take steps to trap and display them. Inserting a pause before the script quits seems to help.

tell application "System Events" to click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)
delay 1 -- This could possibly be shorter.

Or you could activate something else first, like the Finder. I’ve just thought of this and haven’t tested it:

tell application "Finder" to activate
tell application "System Events" to click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)

It makes him sound like a circus act. :wink:

“And now, ladies and gentlemen, for my next script, I shall clear a Recent Items menu using nothing more than an AppleScript saved as an application. Could I have a volunteer from the audience, please?” :lol:

“And do it with only three commands and half the keyboard.”

I wonder if we could sell tickets?

:lol: You guys just slay me! I was just on my way to bed when I caught a glimpse of this discussion. And after all that flattery, how could I resist throwing in one or two thoughts? :slight_smile:

I concur with Nigel’s general assessment of the problem - in that the click is just not getting through.

What I think may actually be happening is that the script application executes the click command and then, having done its job, proceeds to quit. System Events then receives the click command and attempts to execute it, drilling down through the menu hierarchy to hit the target (menu item “Clear Menu”). However, before the target can be reached, it no longer exists - because what was the frontmost process (the script application) has now already quit. :o

Edit: Actually, having just re-read Nigel’s earlier comments, I now realise that’s pretty much what he said (but using fewer words)… :stuck_out_tongue:

So Nigel’s idea to activate Finder works fine here:

tell application "System Events" to tell process "Finder"
	set frontmost to true
	click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of ¬
		menu "Apple" of menu bar item "Apple" of menu bar 1
end tell

If you’d rather not activate Finder for some reason, you could just “deactivate” the applet (well, make it invisible, anyway) - and then work on the process that was frontmost before it was launched:

tell application "System Events" to tell (a reference to (first process whose frontmost is true))
	set visible to false
	click menu item "Clear Menu" of menu "Recent Items" of menu item ¬
		"Recent Items" of menu "Apple" of menu bar item "Apple" of menu bar 1
end tell

Personally, I still quite like the delay method - although that could probably be fine-tuned so that the application is allowed to quit almost immediately after the click has registered:

tell application "System Events" to tell menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of ¬
	menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)
	click
	repeat while enabled
		delay 0.1
	end repeat
end tell

Now I really must get some shuteye (early start in the morning - um… [looks at clock] oops… in a few hours time)!

I look forward to chatting with y’all later… :smiley:

The following repeat loop works, but only when I finish with “Clearing the Recent Items”; but when I do that followed by an immediate restart or shut down, no clearing gets done:

tell application "System Events" to tell menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of ¬
   menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)
   click
   repeat while enabled
       delay 0.1
   end repeat
end tell

When I then do an immediate restart or shut down, only a

delay 15

works; not even a delay 10 gives ample time.

There’s just gotta be folders out there holding all the Recent Applications, Documents and Servers, so I can test the number of items in these folders … but I cannot find these.

What works for me is to use GUI Scripting for the restart too. In the script below, the delay is to allow the “Do you really want to restart?” dialog to draw with its default button activated before “pressing return”. 1) The delay time may need adjusting. 2) It may be possible to script the button click directly, earlier.

on main()
	tell application "System Events"
		tell menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)
			click menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items"
			click menu item "Restart."
		end tell
		delay 0.5
		keystroke return
	end tell
end main

main()

My experience differs slightly here, John - in that it seems to work for me on log out and restart, but not on shut down. :confused:

While alias files used to be placed in dedicated folders to keep track of recent items, that was in the good old, pre-OS X days. This kind of information is now usually stored in a plist file.

When application-specific changes are made in the UI, they’re generally saved to file when that application quits. However, the changes we’re making here (in the Apple menu) are system-wide - and these seem to be normally saved during idle periods (when general housekeeping chores are carried out). So, if a shutdown occurs immediately following such a change, the save operation could well be missed.

I hadn’t realised that you were planning to shut down/restart right after the ‘Clear Menu’ routine - in which case I’d probably go for an approach that forces a modification to the relevant plist file itself. For a really belt-and-braces method, you might want to combine both routines:

set p to POSIX path of (path to preferences) & "com.apple.recentitems.plist"

tell application "System Events"
	
	tell menu item "Clear Menu" of menu "Recent Items" of menu item "Recent Items" of ¬
		menu "Apple" of menu bar item "Apple" of menu bar 1 of (first process whose frontmost is true)
		click
		repeat while enabled
			delay 0.1
		end repeat
	end tell
	
	tell property list file p to repeat with i in {"Documents", "Applications", "Servers"}
		set value of property list item "CustomListItems" of property list item i to {}
	end repeat
	
	shut down (* or restart *)
	
end tell

However, in my own tests so far, this seems to work just as well on its own (whether restarting or shutting down):

set p to POSIX path of (path to preferences) & "com.apple.recentitems.plist"

tell application "System Events"
	
	tell property list file p to repeat with i in {"Documents", "Applications", "Servers"}
		set value of property list item "CustomListItems" of property list item i to {}
	end repeat
	
	shut down (* or restart *)
	
end tell

It didn’t work (at all) for me either, kai. While fooling around with some ideas last night, I tried scripting the opening of the Recent Items menu after the ‘click’ command to see if that made any difference. The items had disappeared from the menu, but were back again after the machine restarted. But your ‘property list file’ idea seems to get right to the “heart” of the matter in this respect. It works on my Tiger machine and is much nicer than using GUI Scripting. :slight_smile:

Thanks for that, Nigel.

Of course, I wasn’t questioning John’s experience - but merely reporting my own. I should have added that I’d only tested this some half-a-dozen times - which, in a situation like this, isn’t nearly enough to draw any real conclusions, anyway. (IMHO, performing repeated tests involving a shutdown or restart has got to be the computer equivalent of watching paint dry! ;))

Yeah - I also tried something very similar. If anything, it confirms my postulation that the changes are made at the UI level - but aren’t being saved to the plist file before the machine shuts down or restarts.

Thanks (again) for the confirmation. I’ve scripted changes previously to a plist file, without using System Events’ Property List Suite (introduced in AppleScript 1.10/Mac OS X version 10.4) - but I’d really rather not. For a situation like this, modifying the property list file would certainly be my preferred approach. :slight_smile: