Is it possible to add a menu item to menu File of an applescript app?

I found this code by mnoriega that adds a menu and submenus to the right hand side of the menu bar.
Here is the link:
https://macscripter.net/viewtopic.php?pid=196659
I would like to add a few menu items to the File menu of an applescript app that at present shows only one item “Use Startup Screen” and it is disabled.
If that is not possible then is it possible to have the menu on the left after the Edit menu?
Thanks in advance.


use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property theStatusItem : missing value
property BigMenu : missing value

on run
	init() of me
end run

on init()
	
	set theList to {"Fruit", {"Apple", "Banana"}, "Vegetable", {"Lettuce", "Tomato"}, "", "Quit"}
	set theStatusItem to current application's NSStatusBar's systemStatusBar()'s statusItemWithLength:(current application's NSVariableStatusItemLength)
	
	theStatusItem's setTitle:"Food"
	theStatusItem's setHighlightMode:true
	theStatusItem's setMenu:createMenu(theList)
	
end init

on createMenu(aList)
	set aMenu to current application's NSMenu's alloc()'s init()
	set aCount to 10
	
	set prevMenuItem to ""
	
	repeat with i in aList
		set j to contents of i
		set aClass to (class of j) as string
		
		if j is equal to "" then
			set aMenuItem to (current application's NSMenuItem's separatorItem())
			(aMenu's addItem:aMenuItem)
		else
			if (aClass = "text") or (aClass = "string") then
				
				if j = "Quit" then
					set aMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:j action:"actionHandler:" keyEquivalent:"")
				else
					set aMenuItem to (current application's NSMenuItem's alloc()'s initWithTitle:j action:"actionHandler:" keyEquivalent:"")
				end if
				
				(aMenuItem's setTag:aCount)
				(aMenuItem's setTarget:me)
				(aMenu's addItem:aMenuItem)
				
				set aCount to aCount + 10
				copy aMenuItem to prevMenuItem
				
				
			else if aClass = "list" then
				--Generate Submenu
				set subMenu to current application's NSMenu's new()
				(aMenuItem's setSubmenu:subMenu)
				
				set subCounter to 1
				
				repeat with ii in j
					set jj to contents of ii
					
					set subMenuItem1 to (current application's NSMenuItem's alloc()'s initWithTitle:jj action:"actionHandler:" keyEquivalent:"")
					(subMenuItem1's setTarget:me)
					(subMenuItem1's setTag:(aCount + subCounter))
					(subMenu's addItem:subMenuItem1)
					
					set subCounter to subCounter + 1
				end repeat
				
			end if
			
		end if
		
	end repeat
	
	return aMenu
end createMenu

on actionHandler:sender
	set theTag to tag of sender as integer
	set theTitle to title of sender as string
	
	if theTitle is not equal to "Quit" then
		display dialog (theTag as string) & " " & theTitle as string
	else
		current application's NSStatusBar's systemStatusBar()'s removeStatusItem:theStatusItem
		quit
	end if
end actionHandler:

Perhaps someday someone will find a way to edit menu items using AsObjC. Personally, I was only able to achieve the removal of existing menu items.

Then I tried to add custom (configured by me instead of standard) menubar items File, Edit, View, Windows, but although the script worked without errors, custom items did not appear in the menu bar.

I read on the net that the NSMenu class contains bugs in the implementation. Therefore, it may well be that this task, and even more so along with AsObjC, is unsolvable.

I recommend erasing the built-in menus until there is a better solution, and adding elements with the same names to the status bar. Like here.

Important: the script should be saved and executed as stay-open application. If you will execute the script as is from Script Editor of Script Debugger, it will erase its menu items. Only after restarting the script editor the menu items will restore. :slight_smile:


use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"

property NSStatusBar : a reference to current application's NSStatusBar
property NSVariableStatusItemLength : a reference to current application's NSVariableStatusItemLength
property NSMenu : a reference to current application's NSMenu
property NSMenuItem : a reference to current application's NSMenuItem
property theStatusItem : missing value
property BigMenu : missing value

set theList to {"Fruit", {"Apple", "Banana"}, "Vegetable", {"Lettuce", "Tomato", {"Cow", "Horse"}}, "", "Quit"}

removeExistingMenuItems() -- remove existing menu items

set theStatusItem to NSStatusBar's systemStatusBar()'s statusItemWithLength:NSVariableStatusItemLength
theStatusItem's setTitle:"File"
theStatusItem's setHighlightMode:true
set aMenu to NSMenu's alloc()'s init()
set {aCount, prevMenuItem} to {10, ""}
makeNewSubMenu(theList, aCount, aMenu)
theStatusItem's setMenu:aMenu


on removeExistingMenuItems() -- removes existing menu items
	set menubar to NSMenu's alloc()'s init()
	current application's NSApp's setMainMenu:menubar
end removeExistingMenuItems


on makeNewSubMenu(aList, aCount, aMenu)
	repeat with i in aList
		set j to contents of i
		if j is equal to "" then
			(aMenu's addItem:(NSMenuItem's separatorItem()))
		else if ((class of j) as string) = "list" then
			--Generate Submenu
			set subMenu to NSMenu's new()
			(aMenuItem's setSubmenu:subMenu)
			my makeNewSubMenu(j, aCount, subMenu)
		else
			set aMenuItem to (NSMenuItem's alloc()'s initWithTitle:j action:"actionHandler:" keyEquivalent:"")
			(aMenuItem's setTag:aCount)
			(aMenuItem's setTarget:me)
			(aMenu's addItem:aMenuItem)
			set aCount to aCount + 10
			copy aMenuItem to prevMenuItem
		end if
	end repeat
end makeNewSubMenu

on actionHandler:sender
	set theTag to tag of sender as integer
	set theTitle to title of sender as string
	if theTitle is "Quit" then
		NSStatusBar's systemStatusBar()'s removeStatusItem:theStatusItem
		quit
	end if
	display dialog (theTag as string) & " " & theTitle
end actionHandler:

Thanks for your help KniazidisR I tried it and it works as expected.
Two more questions.
Is it possible to have the menu come to the left of the screen next to the app name instead of the right hand side?
I noticed that the app menu “removedMenus” does not have any menu items.
Is it possible to only delete the file and edit menu and leave that one as it was?

I think the clue lies in writing the removeExistingMenuItems() handler correctly.
It seems, I found the correct answer for your last questions: YES:


-- IMPORTANT: save and run this script as Stay-Open application
-- If you will execute the script as is from Script Editor of Script Debugger,
-- it will erase its menu items. Only after restarting the script editor
--  the menu items will restore. smile  


use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions


my removeExistingMenuItems()


on removeExistingMenuItems()
	
	-- Getting the main menu reference
	set anApp to current application's NSApplication's sharedApplication()
	set aMainMenu to anApp's mainMenu()
	-- or:
	-- set aMainMenu to current application's NSApp's mainMenu()
	
	-- getting items of main menu
	set theItemArray to aMainMenu's itemArray() -- gets all main menu's items
	set FileItem to theItemArray's objectAtIndex:1 -- gets  main menu's 2nd item ("File")
	set EditItem to theItemArray's objectAtIndex:2 -- gets  main menu's 3rd item ("Edit")
	
	-- removing items of main menu
	aMainMenu's removeItemAtIndex:1 -- removes "File" menu bar item
	-- aMainMenu's removeItemAtIndex:2 -- uncomment to remove "Edit" item as well
	-- aMainMenu's removeAllItems() -- uncomment to remove all items of main menu 
	
end removeExistingMenuItems

Today I had more free time to work on the final solution to the problem. I seem to have succeeded: :smiley:


-- script: Creating Menus example for AsObjC applications
-- written: by KniazidisR, 19 Sep 2022 17:10:25

-- IMPORTANT: save and run this script as Stay-Open application
-- If you will execute the script as is from Script Editor of Script Debugger,
-- it will erase its menu items. Only after restarting the script editor
-- the menu items will restore. smile 

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"


-- init new menu bar to build menus from scratch
set menubar to current application's NSMenu's alloc()'s init()

-- clear predefined menus
set menuBarItem to current application's NSMenuItem's new()
menubar's addItem:menuBarItem
current application's NSApp's setMainMenu:menubar
current application's NSApp's mainMenu()'s removeAllItems()

-- make and edit App name's menu 
set asstMenuItem to menubar's addItemWithTitle:"" action:(missing value) keyEquivalent:""
set asstMenu to current application's NSMenu's alloc()'s init()
menubar's setSubmenu:asstMenu forItem:asstMenuItem
set preferencesMenuItem to asstMenu's addItemWithTitle:"Preferences" action:"actionHandler:" keyEquivalent:""
(preferencesMenuItem's setTarget:me)
set quitMenuItem to asstMenu's addItemWithTitle:"Quit" action:"actionHandler:" keyEquivalent:"q"
(quitMenuItem's setTarget:me)

-- make and edit "File" menu 
set asstMenuItem to menubar's addItemWithTitle:"" action:(missing value) keyEquivalent:""
set asstMenu to current application's NSMenu's alloc()'s initWithTitle:"File"
menubar's setSubmenu:asstMenu forItem:asstMenuItem
set openMenuItem to asstMenu's addItemWithTitle:"Open" action:"actionHandler:" keyEquivalent:"o"
(openMenuItem's setTarget:me)
set saveMenuItem to asstMenu's addItemWithTitle:"Save" action:"actionHandler:" keyEquivalent:"s"
(saveMenuItem's setTarget:me)
set saveAsMenuItem to asstMenu's addItemWithTitle:"Save As..." action:"actionHandler:" keyEquivalent:"a"
(saveAsMenuItem's setTarget:me)
set printMenuItem to asstMenu's addItemWithTitle:"Print..." action:"actionHandler:" keyEquivalent:"p"
(printMenuItem's setTarget:me)

-- make and edit "Edit" menu
set asstMenuItem to menubar's addItemWithTitle:"" action:(missing value) keyEquivalent:""
set asstMenu to current application's NSMenu's alloc()'s initWithTitle:"Edit"
menubar's setSubmenu:asstMenu forItem:asstMenuItem
set openMenuItem to asstMenu's addItemWithTitle:"Copy" action:"actionHandler:" keyEquivalent:"c"
(openMenuItem's setTarget:me)
set saveMenuItem to asstMenu's addItemWithTitle:"Paste" action:"actionHandler:" keyEquivalent:"v"
(saveMenuItem's setTarget:me)
set saveAsMenuItem to asstMenu's addItemWithTitle:"Undo" action:"actionHandler:" keyEquivalent:"u"
(saveAsMenuItem's setTarget:me)
set printMenuItem to asstMenu's addItemWithTitle:"Redo" action:"actionHandler:" keyEquivalent:"r"
(printMenuItem's setTarget:me)


on actionHandler:sender
	set theTitle to title of sender as string
	if theTitle is "Quit" then quit
	display dialog "The \"" & theTitle & "\" menu item pressed"
end actionHandler:

NOTE: The fact that when executing a script directly in the script editors, it changes the menus of the script editors themselves, opens up brilliant new possibilities.

That worked like a charm!
Thank you very much KniazidisR for dedicating so much time to help me.

1 Like

KniazidisR - I just found your work today. It is exactly what I wanted to do. Thank you! I very much appreciate your taking the time to create and post it.

1 Like