summaryrefslogtreecommitdiff
path: root/src/Fl_Sys_Menu_Bar.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Sys_Menu_Bar.mm')
-rw-r--r--src/Fl_Sys_Menu_Bar.mm196
1 files changed, 115 insertions, 81 deletions
diff --git a/src/Fl_Sys_Menu_Bar.mm b/src/Fl_Sys_Menu_Bar.mm
index 0b62fa5..fe252b3 100644
--- a/src/Fl_Sys_Menu_Bar.mm
+++ b/src/Fl_Sys_Menu_Bar.mm
@@ -1,5 +1,5 @@
//
-// "$Id: Fl_Sys_Menu_Bar.mm 10106 2014-02-19 16:02:56Z manolo $"
+// "$Id: Fl_Sys_Menu_Bar.mm 11786 2016-06-18 00:32:18Z greg.ercolano $"
//
// MacOS system menu bar widget for the Fast Light Tool Kit (FLTK).
//
@@ -40,16 +40,6 @@
#import <Cocoa/Cocoa.h>
-#ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h
-#if defined(__LP64__) && __LP64__
-typedef long NSInteger;
-typedef unsigned long NSUInteger;
-#else
-typedef long NSInteger;
-typedef unsigned int NSUInteger;
-#endif
-#endif
-
#include "flstring.h"
#include <stdio.h>
#include <ctype.h>
@@ -58,6 +48,7 @@ typedef unsigned int NSUInteger;
typedef const Fl_Menu_Item *pFl_Menu_Item;
Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
+static Fl_Menu_Bar *custom_menu;
static char *remove_ampersand(const char *s);
extern void (*fl_lock_function)();
@@ -65,8 +56,12 @@ extern void (*fl_unlock_function)();
/* Each MacOS system menu item contains a pointer to a record of type sys_menu_item defined below.
The purpose of these records is to associate each MacOS system menu item with a relevant Fl_Menu_Item.
+
+ Note: in the below, 'rank' is similar to an FLTK menu() 'index'.
+ Let's avoid exposing Mac internal terminology like 'rank' to FLTK users; stick with 'index'.
+
If use_rank is YES, the "rank" field is used, and fl_sys_menu_bar->menu() + rank is the address
- of the relevant Fl_Menu_Item;
+ of the relevant Fl_Menu_Item;
Otherwise, the "item" field points to the relevant Fl_Menu_Item.
This allows the MacOS system menu to use the same Fl_Menu_Item's as those used by FLTK menus,
the address of which can be relocated by the FLTK menu logic.
@@ -85,12 +80,14 @@ typedef struct {
@interface FLMenuItem : NSMenuItem {
}
-- (void) doCallback:(id)unused;
-- (void) directCallback:(id)unused;
- (const Fl_Menu_Item*) getFlItem;
+- (void) itemCallback:(Fl_Menu_*)menu;
+- (void) doCallback;
+- (void) customCallback;
+- (void) directCallback;
- (void) setKeyEquivalentModifierMask:(int)value;
- (void) setFltkShortcut:(int)key;
-+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu;
++ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu action:(SEL)selector;
@end
@implementation FLMenuItem
@@ -101,11 +98,10 @@ typedef struct {
if (smi->use_rank) return fl_sys_menu_bar->menu() + smi->rank;
return smi->item;
}
-- (void) doCallback:(id)unused
+- (void) itemCallback:(Fl_Menu_*)menu
{
- fl_lock_function();
const Fl_Menu_Item *item = [self getFlItem];
- fl_sys_menu_bar->picked(item);
+ menu->picked(item);
if ( item->flags & FL_MENU_TOGGLE ) { // update the menu toggle symbol
[self setState:(item->value() ? NSOnState : NSOffState)];
}
@@ -132,9 +128,20 @@ typedef struct {
[nsitem setState:(nsitem != self ? NSOffState : NSOnState)];
}
}
+}
+- (void) doCallback
+{
+ fl_lock_function();
+ [self itemCallback:fl_sys_menu_bar];
fl_unlock_function();
}
-- (void) directCallback:(id)unused
+- (void) customCallback
+{
+ fl_lock_function();
+ [self itemCallback:custom_menu];
+ fl_unlock_function();
+}
+- (void) directCallback
{
fl_lock_function();
Fl_Menu_Item *item = (Fl_Menu_Item *)[(NSData*)[self representedObject] bytes];
@@ -164,22 +171,22 @@ typedef struct {
[self setKeyEquivalent:[NSString stringWithCharacters:&mac_key length:1]];
[self setKeyEquivalentModifierMask:mod];
}
-+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu
++ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu action:(SEL)selector
{
char *name = remove_ampersand(mitem->label());
- CFStringRef cfname = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+ NSString *title = NSLocalizedString([NSString stringWithUTF8String:name], nil);
free(name);
- FLMenuItem *item = [[FLMenuItem alloc] initWithTitle:(NSString*)cfname
- action:@selector(doCallback:)
+ FLMenuItem *item = [[FLMenuItem alloc] initWithTitle:title
+ action:selector
keyEquivalent:@""];
sys_menu_item smi;
- smi.rank = fl_sys_menu_bar->find_index(mitem); // ≥ 0 if mitem is in the menu items of fl_sys_menu_bar, -1 if not
+ // >= 0 if mitem is in the menu items of fl_sys_menu_bar, -1 if not
+ smi.rank = (fl_sys_menu_bar ? fl_sys_menu_bar->find_index(mitem) : -1);
smi.use_rank = (smi.rank >= 0);
if (!smi.use_rank) smi.item = mitem;
NSData *pointer = [NSData dataWithBytes:&smi length:sizeof(smi)];
[item setRepresentedObject:pointer];
[menu addItem:item];
- CFRelease(cfname);
[item setTarget:item];
int retval = [menu indexOfItem:item];
[item release];
@@ -200,7 +207,7 @@ void fl_mac_set_about( Fl_Callback *cb, void *user_data, int shortcut)
CFStringRef cfname = CFStringCreateCopy(NULL, (CFStringRef)[[appleMenu itemAtIndex:0] title]);
[appleMenu removeItemAtIndex:0];
FLMenuItem *item = [[[FLMenuItem alloc] initWithTitle:(NSString*)cfname
- action:@selector(directCallback:)
+ action:@selector(directCallback)
keyEquivalent:@""] autorelease];
if (aboutItem.shortcut())
[item setFltkShortcut:aboutItem.shortcut()];
@@ -267,36 +274,36 @@ static char *remove_ampersand(const char *s)
/*
* create a sub menu for a specific menu handle
*/
-static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *mitem)
+static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *mitem, SEL selector)
{
NSMenu *submenu;
int miCnt, flags;
- NSMenuItem *menuItem;
- char *ts = remove_ampersand(mitem->text);
- CFStringRef title = CFStringCreateWithCString(NULL, ts, kCFStringEncodingUTF8);
- free(ts);
- submenu = [[NSMenu alloc] initWithTitle:(NSString*)title];
- CFRelease(title);
- [submenu setAutoenablesItems:NO];
-
- int cnt;
- cnt = [mh numberOfItems];
- cnt--;
- menuItem = [mh itemAtIndex:cnt];
- [menuItem setSubmenu:submenu];
- [submenu release];
+ if (mitem) {
+ NSMenuItem *menuItem;
+ char *ts = remove_ampersand(mitem->text);
+ NSString *title = NSLocalizedString([NSString stringWithUTF8String:ts], nil);
+ free(ts);
+ submenu = [[NSMenu alloc] initWithTitle:(NSString*)title];
+ [submenu setAutoenablesItems:NO];
+
+ int cnt;
+ cnt = [mh numberOfItems];
+ cnt--;
+ menuItem = [mh itemAtIndex:cnt];
+ [menuItem setSubmenu:submenu];
+ [submenu release];
+ } else submenu = mh;
- while ( mm->text )
- {
+ while ( mm->text ) {
if (!mm->visible() ) { // skip invisible items and submenus
mm = mm->next(0);
continue;
}
- miCnt = [FLMenuItem addNewItem:mm menu:submenu];
+ miCnt = [FLMenuItem addNewItem:mm menu:submenu action:selector];
setMenuFlags( submenu, miCnt, mm );
setMenuShortcut( submenu, miCnt, mm );
- if ( mm->flags & FL_MENU_INACTIVE || mitem->flags & FL_MENU_INACTIVE) {
+ if ( mm->flags & FL_MENU_INACTIVE || (mitem && (mitem->flags & FL_MENU_INACTIVE))) {
NSMenuItem *item = [submenu itemAtIndex:miCnt];
[item setEnabled:NO];
}
@@ -304,12 +311,12 @@ static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *m
if ( mm->flags & FL_SUBMENU )
{
mm++;
- createSubMenu( submenu, mm, mm - 1 );
+ createSubMenu( submenu, mm, mm - 1, selector);
}
else if ( mm->flags & FL_SUBMENU_POINTER )
{
const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
- createSubMenu( submenu, smm, mm);
+ createSubMenu( submenu, smm, mm, selector);
}
if ( flags & FL_MENU_DIVIDER ) {
[submenu addItem:[NSMenuItem separatorItem]];
@@ -326,33 +333,12 @@ static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *m
static void convertToMenuBar(const Fl_Menu_Item *mm)
{
NSMenu *fl_system_menu = [NSApp mainMenu];
- int rank;
int count;//first, delete all existing system menus
count = [fl_system_menu numberOfItems];
for(int i = count - 1; i > 0; i--) {
[fl_system_menu removeItem:[fl_system_menu itemAtIndex:i]];
}
- //now convert FLTK stuff into MacOS menus
- for (;;)
- {
- if ( !mm || !mm->text )
- break;
- if (!mm->visible() ) { // skip invisible menus
- mm = mm->next(0);
- continue;
- }
- rank = [FLMenuItem addNewItem:mm menu:fl_system_menu];
-
- if ( mm->flags & FL_SUBMENU ) {
- mm++;
- createSubMenu(fl_system_menu, mm, mm - 1);
- }
- else if ( mm->flags & FL_SUBMENU_POINTER ) {
- const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
- createSubMenu(fl_system_menu, smm, mm);
- }
- mm++;
- }
+ if (mm) createSubMenu(fl_system_menu, mm, NULL, @selector(doCallback));
}
@@ -372,10 +358,15 @@ void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m)
/**
- * @brief add to the system menu bar a new menu item
+ * @brief Add a new menu item to the system menu bar.
*
- * add to the system menu bar a new menu item, with a title string, shortcut int,
- * callback, argument to the callback, and flags.
+ * @param label - new menu item's label
+ * @param shortcut - new menu item's integer shortcut (can be 0 for none, or e.g. FL_ALT+'x')
+ * @param cb - callback to be invoked when item selected (can be 0 for none, in which case the menubar's callback() can be used instead)
+ * @param user_data - argument to the callback
+ * @param flags - item's flags, e.g. ::FL_MENU_TOGGLE, etc.
+ *
+ * \returns the index into the menu() array, where the entry was added
*
* @see Fl_Menu_::add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
*/
@@ -389,7 +380,8 @@ int Fl_Sys_Menu_Bar::add(const char* label, int shortcut, Fl_Callback *cb, void
/**
* Forms-compatible procedure to add items to the system menu bar
-*
+ *
+ * \returns the index into the menu() array, where the entry was added
* @see Fl_Menu_::add(const char* str)
*/
int Fl_Sys_Menu_Bar::add(const char* str)
@@ -403,9 +395,10 @@ int Fl_Sys_Menu_Bar::add(const char* str)
/**
* @brief insert in the system menu bar a new menu item
*
- * insert in the system menu bar a new menu item, with a title string, shortcut int,
+ * Insert in the system menu bar a new menu item, with a title string, shortcut int,
* callback, argument to the callback, and flags.
*
+ * \returns the index into the menu() array, where the entry was inserted
* @see Fl_Menu_::insert(int index, const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
*/
int Fl_Sys_Menu_Bar::insert(int index, const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
@@ -432,11 +425,11 @@ int Fl_Sys_Menu_Bar::clear_submenu(int index)
/**
* @brief remove an item from the system menu bar
*
- * @param rank the rank of the item to remove
+ * @param index the index of the item to remove
*/
-void Fl_Sys_Menu_Bar::remove(int rank)
+void Fl_Sys_Menu_Bar::remove(int index)
{
- Fl_Menu_::remove(rank);
+ Fl_Menu_::remove(index);
update();
}
@@ -444,12 +437,12 @@ void Fl_Sys_Menu_Bar::remove(int rank)
/**
* @brief rename an item from the system menu bar
*
- * @param rank the rank of the item to rename
+ * @param index the index of the item to rename
* @param name the new item name as a UTF8 string
*/
-void Fl_Sys_Menu_Bar::replace(int rank, const char *name)
+void Fl_Sys_Menu_Bar::replace(int index, const char *name)
{
- Fl_Menu_::replace(rank, name);
+ Fl_Menu_::replace(index, name); // index
update();
}
@@ -489,6 +482,7 @@ Fl_Sys_Menu_Bar::Fl_Sys_Menu_Bar(int x,int y,int w,int h,const char *l)
: Fl_Menu_Bar(x,y,w,h,l)
{
deactivate(); // don't let the old area take events
+ if (fl_sys_menu_bar) delete fl_sys_menu_bar;
fl_sys_menu_bar = this;
Fl::add_handler(process_sys_menu_shortcuts);
}
@@ -501,8 +495,48 @@ Fl_Sys_Menu_Bar::~Fl_Sys_Menu_Bar()
Fl::remove_handler(process_sys_menu_shortcuts);
}
+/** \class Fl_Mac_App_Menu
+ Mac OS-specific class allowing to customize and localize the application menu.
+
+ The public class attributes are used to build the application menu. They can be localized
+ at run time to any UTF-8 text by placing instructions such as this before fl_open_display()
+ gets called:
+ \verbatim
+ Fl_Mac_App_Menu::print = "Imprimer la fenêtre";
+ \endverbatim
+ \see \ref osissues_macos for another way to localization.
+ */
+
+
+/** Adds custom menu item(s) to the application menu of the system menu bar.
+ They are positioned after the "Print Front Window" item, or at its place
+ if it was removed with <tt>Fl_Mac_App_Menu::print = ""</tt>.
+ \param m zero-ending array of Fl_Menu_Item 's.
+ */
+void Fl_Mac_App_Menu::custom_application_menu_items(const Fl_Menu_Item *m)
+{
+ fl_open_display(); // create the system menu, if needed
+ custom_menu = new Fl_Menu_Bar(0,0,0,0);
+ custom_menu->menu(m);
+ NSMenu *menu = [[[NSApp mainMenu] itemAtIndex:0] submenu]; // the application menu
+ NSInteger to_rank;
+ if ([[menu itemAtIndex:2] action] != @selector(printPanel)) { // the 'Print' item was removed
+ [menu insertItem:[NSMenuItem separatorItem] atIndex:1];
+ to_rank = 2;
+ } else to_rank = 3; // after the "Print Front Window" item
+ NSInteger count = [menu numberOfItems];
+ createSubMenu(menu, m, NULL, @selector(customCallback)); // add new items at end of application menu
+ NSInteger count2 = [menu numberOfItems];
+ for (NSInteger i = count; i < count2; i++) { // move new items to their desired position in application menu
+ NSMenuItem *item = [menu itemAtIndex:i];
+ [item retain];
+ [menu removeItemAtIndex:i];
+ [menu insertItem:item atIndex:to_rank++];
+ [item release];
+ }
+}
#endif /* __APPLE__ */
//
-// End of "$Id: Fl_Sys_Menu_Bar.mm 10106 2014-02-19 16:02:56Z manolo $".
+// End of "$Id: Fl_Sys_Menu_Bar.mm 11786 2016-06-18 00:32:18Z greg.ercolano $".
//