Update submenu items and retain/share item selected

Hi guys,

I got a problem with an agent app I am developing (a status icon with menus). Basically, I got a main menu and a submenu. I used an array to populate the submenu this way (the submenu is define in the awakeFromNib() handler).


        set subMenu to (current application's class "NSMenu"'s alloc)'s initWithTitle_("NameMenu")
        
       MySubMenu's setSubmenu_(subMenu)
       
set j to array

       repeat with i in j
           set newmenu to (current application's class "NSMenuItem"'s alloc)'s initWithTitle_action_keyEquivalent_(i, "SelectItem:", "")
           subMenu's addItem_(newmenu)
       end repeat
          set theSep to current application's NSMenuItem's separatorItem()
       subMenu's addItem_(theSep)

       set NoAccountSelectedItem to (current application's class "NSMenuItem"'s alloc)'s initWithTitle_action_keyEquivalent_("Not active", "SelectItem:", "")
  
     subMenu's addItem_(NoSelectedItem)

      NoSelectedItem's setState_(1)

I got my submenu items with the “nothing selected” set to state “ON” by default. It works well. I also managed to automatically change the stateto “ON” for a button selected and get all the others updated. Well not updated actually, but rebuilt. What I do now is using the SelectItem_(TheItem) handler to rebuild the submenu with the new button selected.

In addition, I need this submenu to be enabled only when a certain application is running. I can easily check for the running application using applescripts. I thought a loop (that runs forever) to check if the app is running was too much and I decided to exploit the menuWillOpen_(|menu|) handler so my app will only update the submenu status when the main menu is opened. The approach work but, again, I rebuild the submenu and make it active only when the app is running.

My only problem is that, in case the submenu is enabled, I want to keep the choice that I select through the SelectItem_(TheItem) but it obviously doesn’t work because, everytime I open the menu, the submenu is rebuilt with he “not active” choice selected by default. How can I tell menuWillOpen_(|menu|) what’s been chosen by SelectItem_()??? Is there any way to share a variable between handlers?

Thank you guys, I hope you can help me.

Pier

Hi,

it’s not necessary to poll for a running application.
Implement the notifications

NSWorkspaceDidLaunchApplicationNotification
NSWorkspaceDidTerminateApplicationNotification

of NSWorkspace and check for the bundle identifier.

Define a boolean property and set it depending on the running status of the application.
Then implement the method validateMenuItem and return the value of the property.

Just a few lines of code, no polling

Hi Stefan,

Thank you for your reply. Concerning polling for a running application, I think I need it anyway cause I need to check if a particular window of that app exists (Or can I do it through notifications too?). Secondly, could you tell me how to implement the validateMenuItem in my case? Is it a method that I need to call somehow within my other handlers? Maybe it’s something simple, but I’ve never used it before and I have no idea how to do it. Thank you so much in advance.

Pier

validateMenuItem is a delegate method of NSMenu.
It’s called automatically right before a menu is going to open.
You have to connect the delegate of the NSMenu instance to the target class (script) in Interface Builder

it expects to return YES/true to enable or NO/false to disable a menu item
The method is called separately for each menu item which is passed as the argument

To identify a menu item you could use the action, title, a custom tag, title of super menu etc.

for example (a bit pseudo code)


on validateMenuitem:theMenuitem
	if theMenuitem's action() is "whatever" then
		return true
	else if theMenuitem's menu()'s title() is "submenu" and application "myapp" is running and (exists window "window" of application "myapp") then
		return false
	else
		return true -- you have to return something anyway
	end if
end validateMenuitem:

But consider that this method can be called often and sending Apple Events like “application is running” each time the method is called is quite expensive

Thank you Stefan. I managed to implement it with a few changes.

However the script was giving me an error and I had to change:

set MenuTitle to theMenuitem's menu()'s title()

to

set MenuTitle to MenuItems's |menu|()'s |title|() as text

Thank you again.

Pier