Right, I got this working without too much hacking.
Jules, maybe you could build this into Juce at some point?!
===
- Firstly, I used XCode to create a stripped-down .xib file in a new dummy project, named it
FileOpenTemplateMenu.xib… and added that to my affected projects.
It contains ONLY a File… menu, containing the Open Recent … sub-menu … which are completely
untouched from what XCode created (but: I stripped-out all other menu items!)
- I patched the Juce source code… just look for MPC blocks - only a few new lines!
EDIT: commented-out a few lines which were causing some display problems for the File menu - see the comments in the code!
// MPC (begin)
void MyJuceHack_Mac_PrepareFileOpenTemplateMenu(void);
void MyJuceHack_Mac_AppendFileOpenMenu(const char *menuName, NSMenu *m);
// MPC (end)
BEGIN_JUCE_NAMESPACE
class JuceMainMenuHandler : private MenuBarModel::Listener,
private DeletedAtShutdown
...
void addSubMenu (NSMenu* parent, const PopupMenu& child,
const String& name, const int menuId, const int tag)
{
NSMenuItem* item = [parent addItemWithTitle: juceStringToNS (name)
action: nil
keyEquivalent: @""];
[item setTag: tag];
NSMenu* sub = createMenu (child, name, menuId, tag);
// MPC (begin)
// EDIT - commented this line out, as keeping it in sometimes made the first selection of the File...
// menu display *really* weirdly! The call doesn't see to add anything anyhow!
// MyJuceHack_Mac_AppendFileOpenMenu(name.toUTF8().getAddress(), sub);
// MPC (end)
[parent setSubmenu: sub forItem: item];
[sub setAutoenablesItems: false];
[sub release];
}
...
void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy,
const String& name, const int menuId, const int tag)
{
// Note: This method used to update the contents of the existing menu in-place, but that caused
// weird side-effects which messed-up keyboard focus when switching between windows. By creating
// a new menu and replacing the old one with it, that problem seems to be avoided..
NSMenu* menu = [[NSMenu alloc] initWithTitle: juceStringToNS (name)];
PopupMenu::MenuItemIterator iter (menuToCopy);
while (iter.next())
addMenuItem (iter, menu, menuId, tag);
// MPC (begin)
MyJuceHack_Mac_AppendFileOpenMenu(name.toUTF8().getAddress(), menu);
// MPC (end)
[menu setAutoenablesItems: false];
[menu update];
[parentItem setTag: tag];
[parentItem setSubmenu: menu];
[menu release];
}
...
NSMenu* createMenu (const PopupMenu menu,
const String& menuName,
const int topLevelMenuId,
const int topLevelIndex)
{
NSMenu* m = [[NSMenu alloc] initWithTitle: juceStringToNS (menuName)];
[m setAutoenablesItems: false];
[m setDelegate: callback];
PopupMenu::MenuItemIterator iter (menu);
while (iter.next())
addMenuItem (iter, m, topLevelMenuId, topLevelIndex);
// MPC (begin)
MyJuceHack_Mac_AppendFileOpenMenu(menuName.toUTF8().getAddress(), m);
// MPC (end)
[m update];
return m;
}
...
// Since our app has no NIB, this initialises a standard app menu...
void rebuildMainMenu (const PopupMenu* extraItems)
{
// this can't be used in a plugin!
jassert (JUCEApplication::isStandaloneApp());
if (JUCEApplication::getInstance() != nullptr)
{
// MPC (begin)
MyJuceHack_Mac_PrepareFileOpenTemplateMenu();
// MPC (end)
...
- I added a few new functions to my own code…
// Menu extension for Juce applications, to have File Open menu!
NSNib* menuNib = NULL;
NSArray* menuArray = NULL;
NSArray* menuUrls = NULL;
NSMenuItem* recentItem = NULL;
NSMenu *recentMenu = NULL;
void MyJuceHack_Mac_PrepareFileOpenTemplateMenu(void)
{
if (menuNib == NULL)
{
menuNib = [[NSNib alloc ] initWithNibNamed:@"FileOpenTemplateMenu" bundle:nil];
if (menuNib != NULL)
{
menuArray = [[NSArray alloc] init];
[menuNib instantiateNibWithOwner:NSApp topLevelObjects:&menuArray];
[menuArray retain];
menuUrls = [[NSDocumentController sharedDocumentController] recentDocumentURLs];
}
}
}
void MyJuceHack_Mac_AppendFileOpenMenu(const char *menuName, NSMenu *m)
{
// Prepare on first use!
MyJuceHack_Mac_PrepareFileOpenTemplateMenu();
if (im_utf8_strcmp((const im_utf8_t*)menuName, (const im_utf8_t*) "File") == 0)
{
// File menu... add-in the recent item, if available!
if (recentItem == NULL)
{
// Not yet found it!
if (menuArray != NULL)
{
NSArray* array = menuArray;
NSArray* items = [[NSArray alloc] init];
for (id object in array) {
if([object isKindOfClass:[NSMenu class]])
{
items = [object itemArray];
break;
}
}
if(items != nil)
{
for (id object in items)
{
if([object hasSubmenu])
{
NSMenu* subMenu = [object submenu];
NSArray* subMenuItems = [subMenu itemArray];
if([subMenuItems count])
{
for (id subObject in subMenuItems)
{
if([subObject isKindOfClass:[NSMenuItem class]])
{
recentItem = subObject;
NSString *title = recentItem.title;
const char *lpTitle = [title UTF8String];
printf ("SubMenuItem=%s\n", lpTitle);
if([subObject hasSubmenu])
{
recentMenu = [subObject menu];
}
}
}
}
}
}
}
}
}
if (recentItem != NULL)
{
//Remove it from any owning menu first!
NSMenu *parent = [recentItem menu];
if (parent != nil)
{
[parent removeItem:recentItem];
}
[recentItem retain]; // This seems to be essential, for some reason!
NSMenu *myFileMenu = m;
[myFileMenu addItem:recentItem];
}
}
}
void MyJuceHack_Mac_RegisterOpenMacDocument(const String &PPath)
{
NSString *myPath = [[NSString alloc] initWithUTF8String:PPath.toUTF8().getAddress()];
NSURL *myUrl = [NSURL fileURLWithPath:myPath];
[myPath release];
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:myUrl];
}
-
I added calls in my code to MyJuceHack_Mac_RegisterOpenMacDocument whenever I’ve just
saved or just opened a file on Mac…
-
That is all - and it works!
Pete