summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Fl_Sys_Menu_Bar.cxx289
-rw-r--r--src/Fl_Sys_Menu_Bar.mm437
-rw-r--r--src/Fl_cocoa.mm215
-rw-r--r--src/Makefile4
4 files changed, 440 insertions, 505 deletions
diff --git a/src/Fl_Sys_Menu_Bar.cxx b/src/Fl_Sys_Menu_Bar.cxx
deleted file mode 100644
index b3ed78073..000000000
--- a/src/Fl_Sys_Menu_Bar.cxx
+++ /dev/null
@@ -1,289 +0,0 @@
-//
-// "$Id$"
-//
-// MacOS system menu bar widget for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2010 by Bill Spitzak and others.
-//
-// This library is free software. Distribution and use rights are outlined in
-// the file "COPYING" which should have been included with this file. If this
-// file is missing or damaged, see the license at:
-//
-// http://www.fltk.org/COPYING.php
-//
-// Please report all bugs and problems on the following page:
-//
-// http://www.fltk.org/str.php
-//
-
-/**
- * This code is a quick hack! It was written as a proof of concept.
- * It has been tested on the "menubar" sample program and provides
- * basic functionality.
- *
- * To use the System Menu Bar, simply replace the main Fl_Menu_Bar
- * in an application with Fl_Sys_Menu_Bar.
- *
- * FLTK features not supported by the Mac System menu
- *
- * - no invisible menu items
- * - no symbolic labels
- * - embossed labels will be underlined instead
- * - no font sizes
- * - Shortcut Characters should be English alphanumeric only, no modifiers yet
- * - no disable main menus
- * - changes to menubar in run-time don't update!
- * (disable, etc. - toggle and radio button do!)
- *
- * No care was taken to clean up the menu bar after destruction!
- * ::menu(bar) should only be called once!
- * Many other calls of the parent class don't work.
- * Changing the menu items has no effect on the menu bar.
- * Starting with OS X 10.5, FLTK applications must be created as
- * a bundle for the System Menu Bar (and maybe other features) to work!
- */
-
-#if defined(__APPLE__) || defined(FL_DOXYGEN)
-
-#include <FL/x.H>
-#include <FL/Fl.H>
-#include <FL/Fl_Sys_Menu_Bar.H>
-
-#include "flstring.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-
-#define MenuHandle void *
-
-typedef const Fl_Menu_Item *pFl_Menu_Item;
-
-
-/*
- * Set a shortcut for an Apple menu item using the FLTK shortcut descriptor.
- */
-static void setMenuShortcut( MenuHandle mh, int miCnt, const Fl_Menu_Item *m )
-{
- if ( !m->shortcut_ )
- return;
- if ( m->flags & FL_SUBMENU )
- return;
- if ( m->flags & FL_SUBMENU_POINTER )
- return;
- char key = m->shortcut_ & 0xff;
- if ( !isalnum( key ) )
- return;
-
- void *menuItem = Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::itemAtIndex, mh, miCnt);
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setKeyEquivalent, menuItem, m->shortcut_ & 0xff );
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setKeyEquivalentModifierMask, menuItem, m->shortcut_ );
-}
-
-
-/*
- * Set the Toggle and Radio flag based on FLTK flags
- */
-static void setMenuFlags( MenuHandle mh, int miCnt, const Fl_Menu_Item *m )
-{
- if ( m->flags & FL_MENU_TOGGLE )
- {
- void *menuItem = Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::itemAtIndex, mh, miCnt);
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setState, menuItem, m->flags & FL_MENU_VALUE );
- }
- else if ( m->flags & FL_MENU_RADIO ) {
- void *menuItem = Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::itemAtIndex, mh, miCnt);
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setState, menuItem, m->flags & FL_MENU_VALUE );
- }
-}
-
-
-/*
- * create a sub menu for a specific menu handle
- */
-static void createSubMenu( void * mh, pFl_Menu_Item &mm, const Fl_Menu_Item *mitem)
-{
- void *submenu;
- int miCnt, flags;
-
- void *menuItem;
- submenu = Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::initWithTitle, mitem->text);
- int cnt;
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::numberOfItems, mh, &cnt);
- cnt--;
- menuItem = Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::itemAtIndex, mh, cnt);
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setSubmenu, menuItem, submenu);
-
- while ( mm->text )
- {
- char visible = mm->visible() ? 1 : 0;
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::addNewItem, submenu, mm, &miCnt);
- setMenuFlags( submenu, miCnt, mm );
- setMenuShortcut( submenu, miCnt, mm );
- if ( mm->flags & FL_MENU_INACTIVE || mitem->flags & FL_MENU_INACTIVE) {
- void *item = Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::itemAtIndex, submenu, miCnt);
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setEnabled, item, 0);
- }
- flags = mm->flags;
- if ( mm->flags & FL_SUBMENU )
- {
- mm++;
- createSubMenu( submenu, mm, mm - 1 );
- }
- else if ( mm->flags & FL_SUBMENU_POINTER )
- {
- const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
- createSubMenu( submenu, smm, mm );
- }
- if ( flags & FL_MENU_DIVIDER ) {
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::addSeparatorItem, submenu);
- }
- if ( !visible ) {
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::removeItem, submenu, miCnt);
- }
- mm++;
- }
-}
-
-
-/*
- * convert a complete Fl_Menu_Item array into a series of menus in the top menu bar
- * ALL PREVIOUS SYSTEM MENUS, EXCEPT THE APPLICATION MENU, ARE REPLACED BY THE NEW DATA
- */
-static void convertToMenuBar(const Fl_Menu_Item *mm)
-{
- int rank;
- int count;//first, delete all existing system menus
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::numberOfItems, fl_system_menu, &count);
- for(int i = count - 1; i > 0; i--) {
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::removeItem, fl_system_menu, i);
- }
- //now convert FLTK stuff into MacOS menus
- for (;;)
- {
- if ( !mm || !mm->text )
- break;
- char visible = mm->visible() ? 1 : 0;
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::addNewItem, fl_system_menu, mm, &rank);
-
- 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);
- }
- if ( !visible ) {
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::removeItem, fl_system_menu, rank);
- }
- mm++;
- }
-}
-
-
-/**
- * @brief create a system menu bar using the given list of menu structs
- *
- * \author Matthias Melcher
- *
- * @param m list of Fl_Menu_Item
- */
-void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m)
-{
- fl_open_display();
- Fl_Menu_Bar::menu( m );
- convertToMenuBar(m);
-}
-
-
-/**
- * @brief add to the system menu bar a new menu item
- *
- * add to the system menu bar a new menu item, with a title string, shortcut int,
- * callback, argument to the callback, and flags.
- *
- * @see Fl_Menu_::add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
- */
-int Fl_Sys_Menu_Bar::add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
-{
- fl_open_display();
- int rank = Fl_Menu_::add(label, shortcut, cb, user_data, flags);
- convertToMenuBar(Fl_Menu_::menu());
- return rank;
-}
-
-/**
- * @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,
- * callback, argument to the callback, and flags.
- *
- * @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)
-{
- fl_open_display();
- int rank = Fl_Menu_::insert(index, label, shortcut, cb, user_data, flags);
- convertToMenuBar(Fl_Menu_::menu());
- return rank;
-}
-
-void Fl_Sys_Menu_Bar::clear()
-{
- Fl_Menu_::clear();
- convertToMenuBar(NULL);
-}
-
-int Fl_Sys_Menu_Bar::clear_submenu(int index)
-{
- int retval = Fl_Menu_::clear_submenu(index);
- if (retval != -1) convertToMenuBar(Fl_Menu_::menu());
- return retval;
-}
-
-/**
- * @brief remove an item from the system menu bar
- *
- * @param rank the rank of the item to remove
- */
-void Fl_Sys_Menu_Bar::remove(int rank)
-{
- Fl_Menu_::remove(rank);
- convertToMenuBar(Fl_Menu_::menu());
-}
-
-
-/**
- * @brief rename an item from the system menu bar
- *
- * @param rank the rank 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)
-{
- Fl_Menu_::replace(rank, name);
- convertToMenuBar(Fl_Menu_::menu());
-}
-
-
-/*
- * Draw the menu bar.
- * Nothing here because the OS does this for us.
- */
-void Fl_Sys_Menu_Bar::draw() {
-}
-
-
-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
- fl_sys_menu_bar = this;
-}
-
-
-#endif /* __APPLE__ */
-
-//
-// End of "$Id$".
-//
diff --git a/src/Fl_Sys_Menu_Bar.mm b/src/Fl_Sys_Menu_Bar.mm
new file mode 100644
index 000000000..a14a53215
--- /dev/null
+++ b/src/Fl_Sys_Menu_Bar.mm
@@ -0,0 +1,437 @@
+//
+// "$Id$"
+//
+// MacOS system menu bar widget for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2013 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+/**
+ * This code is a quick hack! It was written as a proof of concept.
+ * It has been tested on the "menubar" sample program and provides
+ * basic functionality.
+ *
+ * To use the System Menu Bar, simply replace the main Fl_Menu_Bar
+ * in an application with Fl_Sys_Menu_Bar.
+ *
+ * FLTK features not supported by the Mac System menu
+ *
+ * - no invisible menu items
+ * - no symbolic labels
+ * - embossed labels will be underlined instead
+ * - no font sizes
+ * - Shortcut Characters should be English alphanumeric only, no modifiers yet
+ * - no disable main menus
+ * - changes to menubar in run-time don't update!
+ * (disable, etc. - toggle and radio button do!)
+ *
+ * No care was taken to clean up the menu bar after destruction!
+ * ::menu(bar) should only be called once!
+ * Many other calls of the parent class don't work.
+ * Changing the menu items has no effect on the menu bar.
+ * Starting with OS X 10.5, FLTK applications must be created as
+ * a bundle for the System Menu Bar (and maybe other features) to work!
+ */
+
+#if defined(__APPLE__) || defined(FL_DOXYGEN)
+#include <FL/Fl_Menu_Item.H>
+#include <FL/Fl_Sys_Menu_Bar.H>
+#include <FL/x.H>
+#include <FL/Fl.H>
+
+#import <Cocoa/Cocoa.h>
+
+#include "flstring.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+typedef const Fl_Menu_Item *pFl_Menu_Item;
+
+Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
+
+static char *remove_ampersand(const char *s);
+extern void (*fl_lock_function)();
+extern void (*fl_unlock_function)();
+
+@interface FLMenuItem : NSMenuItem {
+}
+- (void) doCallback:(id)unused;
+- (void) directCallback:(id)unused;
+- (const Fl_Menu_Item*) getFlItem;
+- (void) setKeyEquivalent:(char)value;
+- (void) setKeyEquivalentModifierMask:(int)value;
++ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu;
+@end
+
+@implementation FLMenuItem
+- (const Fl_Menu_Item*) getFlItem
+{
+ return *(const Fl_Menu_Item **)[(NSData*)[self representedObject] bytes];
+}
+- (void) doCallback:(id)unused
+{
+ fl_lock_function();
+ const Fl_Menu_Item *item = [self getFlItem];
+ fl_sys_menu_bar->picked(item);
+ if ( item->flags & FL_MENU_TOGGLE ) { // update the menu toggle symbol
+ [self setState:(item->value() ? NSOnState : NSOffState)];
+ }
+ else if ( item->flags & FL_MENU_RADIO ) { // update the menu radio symbols
+ NSMenu* menu = [self menu];
+ NSInteger flRank = [menu indexOfItem:self];
+ NSInteger last = [menu numberOfItems] - 1;
+ int from = flRank;
+ while(from > 0) {
+ if ([[menu itemAtIndex:from-1] isSeparatorItem]) break;
+ item = [(FLMenuItem*)[menu itemAtIndex:from-1] getFlItem];
+ if ( !(item->flags & FL_MENU_RADIO) ) break;
+ from--;
+ }
+ int to = flRank;
+ while (to < last) {
+ if ([[menu itemAtIndex:to+1] isSeparatorItem]) break;
+ item = [(FLMenuItem*)[menu itemAtIndex:to+1] getFlItem];
+ if (!(item->flags & FL_MENU_RADIO)) break;
+ to++;
+ }
+ for(int i = from; i <= to; i++) {
+ NSMenuItem *nsitem = [menu itemAtIndex:i];
+ [nsitem setState:(nsitem != self ? NSOffState : NSOnState)];
+ }
+ }
+ fl_unlock_function();
+}
+- (void) directCallback:(id)unused
+{
+ fl_lock_function();
+ Fl_Menu_Item *item = (Fl_Menu_Item *)[(NSData*)[self representedObject] bytes];
+ if ( item && item->callback() ) item->do_callback(NULL);
+ fl_unlock_function();
+}
+- (void) setKeyEquivalent:(char)key
+{
+ NSString *equiv = [[NSString alloc] initWithBytes:&key length:1 encoding:NSASCIIStringEncoding];
+ [super setKeyEquivalent:equiv];
+ [equiv release];
+}
+- (void) setKeyEquivalentModifierMask:(int)value
+{
+ NSUInteger macMod = 0;
+ if ( value & FL_META ) macMod = NSCommandKeyMask;
+ if ( value & FL_SHIFT || isupper(value) ) macMod |= NSShiftKeyMask;
+ if ( value & FL_ALT ) macMod |= NSAlternateKeyMask;
+ if ( value & FL_CTRL ) macMod |= NSControlKeyMask;
+ [super setKeyEquivalentModifierMask:macMod];
+}
++ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu
+{
+ char *name = remove_ampersand(mitem->label());
+ CFStringRef cfname = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+ free(name);
+ FLMenuItem *item = [[FLMenuItem alloc] initWithTitle:(NSString*)cfname
+ action:@selector(doCallback:)
+ keyEquivalent:@""];
+ NSData *pointer = [NSData dataWithBytes:&mitem length:sizeof(Fl_Menu_Item*)];
+ [item setRepresentedObject:pointer];
+ [menu addItem:item];
+ CFRelease(cfname);
+ [item setTarget:item];
+ int retval = [menu indexOfItem:item];
+ [item release];
+ return retval;
+}
+@end
+
+
+void fl_mac_set_about( Fl_Callback *cb, void *user_data, int shortcut)
+{
+ fl_open_display();
+ Fl_Menu_Item aboutItem;
+ memset(&aboutItem, 0, sizeof(Fl_Menu_Item));
+ aboutItem.callback(cb);
+ aboutItem.user_data(user_data);
+ aboutItem.shortcut(shortcut);
+ NSMenu *appleMenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
+ CFStringRef cfname = CFStringCreateCopy(NULL, (CFStringRef)[[appleMenu itemAtIndex:0] title]);
+ [appleMenu removeItemAtIndex:0];
+ FLMenuItem *item = [[[FLMenuItem alloc] initWithTitle:(NSString*)cfname
+ action:@selector(directCallback:)
+ keyEquivalent:@""] autorelease];
+ if (aboutItem.shortcut()) {
+ [item setKeyEquivalent:(aboutItem.shortcut() & 0xff)];
+ [item setKeyEquivalentModifierMask:aboutItem.shortcut()];
+ }
+ NSData *pointer = [NSData dataWithBytes:&aboutItem length:sizeof(Fl_Menu_Item)];
+ [item setRepresentedObject:pointer];
+ [appleMenu insertItem:item atIndex:0];
+ CFRelease(cfname);
+ [item setTarget:item];
+}
+
+/*
+ * Set a shortcut for an Apple menu item using the FLTK shortcut descriptor.
+ */
+static void setMenuShortcut( NSMenu* mh, int miCnt, const Fl_Menu_Item *m )
+{
+ if ( !m->shortcut_ )
+ return;
+ if ( m->flags & FL_SUBMENU )
+ return;
+ if ( m->flags & FL_SUBMENU_POINTER )
+ return;
+ char key = m->shortcut_ & 0xff;
+ if ( !isalnum( key ) )
+ return;
+
+ FLMenuItem* menuItem = (FLMenuItem*)[mh itemAtIndex:miCnt];
+ [menuItem setKeyEquivalent:(m->shortcut_ & 0xff)];
+ [menuItem setKeyEquivalentModifierMask:m->shortcut_];
+}
+
+
+/*
+ * Set the Toggle and Radio flag based on FLTK flags
+ */
+static void setMenuFlags( NSMenu* mh, int miCnt, const Fl_Menu_Item *m )
+{
+ if ( m->flags & FL_MENU_TOGGLE )
+ {
+ NSMenuItem *menuItem = [mh itemAtIndex:miCnt];
+ [menuItem setState:(m->flags & FL_MENU_VALUE ? NSOnState : NSOffState)];
+ }
+ else if ( m->flags & FL_MENU_RADIO ) {
+ NSMenuItem *menuItem = [mh itemAtIndex:miCnt];
+ [menuItem setState:(m->flags & FL_MENU_VALUE ? NSOnState : NSOffState)];
+ }
+}
+
+static char *remove_ampersand(const char *s)
+{
+ char *ret = strdup(s);
+ const char *p = s;
+ char *q = ret;
+ while(*p != 0) {
+ if (p[0]=='&') {
+ if (p[1]=='&') {
+ *q++ = '&'; p+=2;
+ } else {
+ p++;
+ }
+ } else {
+ *q++ = *p++;
+ }
+ }
+ *q = 0;
+ return ret;
+}
+
+
+/*
+ * create a sub menu for a specific menu handle
+ */
+static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *mitem)
+{
+ 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];
+
+ while ( mm->text )
+ {
+ char visible = mm->visible() ? 1 : 0;
+ miCnt = [FLMenuItem addNewItem:mm menu:submenu];
+ setMenuFlags( submenu, miCnt, mm );
+ setMenuShortcut( submenu, miCnt, mm );
+ if ( mm->flags & FL_MENU_INACTIVE || mitem->flags & FL_MENU_INACTIVE) {
+ NSMenuItem *item = [submenu itemAtIndex:miCnt];
+ [item setEnabled:NO];
+ }
+ flags = mm->flags;
+ if ( mm->flags & FL_SUBMENU )
+ {
+ mm++;
+ createSubMenu( submenu, mm, mm - 1 );
+ }
+ else if ( mm->flags & FL_SUBMENU_POINTER )
+ {
+ const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_;
+ createSubMenu( submenu, smm, mm );
+ }
+ if ( flags & FL_MENU_DIVIDER ) {
+ [submenu addItem:[NSMenuItem separatorItem]];
+ }
+ if ( !visible ) {
+ [submenu removeItem:[submenu itemAtIndex:miCnt]];
+ }
+ mm++;
+ }
+}
+
+
+/*
+ * convert a complete Fl_Menu_Item array into a series of menus in the top menu bar
+ * ALL PREVIOUS SYSTEM MENUS, EXCEPT THE APPLICATION MENU, ARE REPLACED BY THE NEW DATA
+ */
+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;
+ char visible = mm->visible() ? 1 : 0;
+ 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);
+ }
+ if ( !visible ) {
+ [fl_system_menu removeItem:[fl_system_menu itemAtIndex:rank]];
+ }
+ mm++;
+ }
+}
+
+
+/**
+ * @brief create a system menu bar using the given list of menu structs
+ *
+ * \author Matthias Melcher
+ *
+ * @param m list of Fl_Menu_Item
+ */
+void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m)
+{
+ fl_open_display();
+ Fl_Menu_Bar::menu( m );
+ convertToMenuBar(m);
+}
+
+
+/**
+ * @brief add to the system menu bar a new menu item
+ *
+ * add to the system menu bar a new menu item, with a title string, shortcut int,
+ * callback, argument to the callback, and flags.
+ *
+ * @see Fl_Menu_::add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
+ */
+int Fl_Sys_Menu_Bar::add(const char* label, int shortcut, Fl_Callback *cb, void *user_data, int flags)
+{
+ fl_open_display();
+ int rank = Fl_Menu_::add(label, shortcut, cb, user_data, flags);
+ convertToMenuBar(Fl_Menu_::menu());
+ return rank;
+}
+
+/**
+ * @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,
+ * callback, argument to the callback, and flags.
+ *
+ * @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)
+{
+ fl_open_display();
+ int rank = Fl_Menu_::insert(index, label, shortcut, cb, user_data, flags);
+ convertToMenuBar(Fl_Menu_::menu());
+ return rank;
+}
+
+void Fl_Sys_Menu_Bar::clear()
+{
+ Fl_Menu_::clear();
+ convertToMenuBar(NULL);
+}
+
+int Fl_Sys_Menu_Bar::clear_submenu(int index)
+{
+ int retval = Fl_Menu_::clear_submenu(index);
+ if (retval != -1) convertToMenuBar(Fl_Menu_::menu());
+ return retval;
+}
+
+/**
+ * @brief remove an item from the system menu bar
+ *
+ * @param rank the rank of the item to remove
+ */
+void Fl_Sys_Menu_Bar::remove(int rank)
+{
+ Fl_Menu_::remove(rank);
+ convertToMenuBar(Fl_Menu_::menu());
+}
+
+
+/**
+ * @brief rename an item from the system menu bar
+ *
+ * @param rank the rank 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)
+{
+ Fl_Menu_::replace(rank, name);
+ convertToMenuBar(Fl_Menu_::menu());
+}
+
+
+/*
+ * Draw the menu bar.
+ * Nothing here because the OS does this for us.
+ */
+void Fl_Sys_Menu_Bar::draw() {
+}
+
+
+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
+ fl_sys_menu_bar = this;
+}
+
+
+#endif /* __APPLE__ */
+
+//
+// End of "$Id$".
+//
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
index a17ed7782..61916e3e5 100644
--- a/src/Fl_cocoa.mm
+++ b/src/Fl_cocoa.mm
@@ -41,7 +41,7 @@ extern "C" {
#include <FL/x.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Tooltip.H>
-#include <FL/Fl_Sys_Menu_Bar.H>
+#include <FL/Fl_Menu_Item.H>
#include <FL/Fl_Printer.H>
#include <FL/Fl_Input_.H>
#include <FL/Fl_Secret_Input.H>
@@ -95,8 +95,6 @@ Fl_Display_Device *Fl_Display_Device::_display = new Fl_Display_Device(new Fl_Qu
// public variables
CGContextRef fl_gc = 0;
-void *fl_system_menu; // this is really a NSMenu*
-Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0;
void *fl_default_cursor; // this is really a NSCursor*
void *fl_capture = 0; // (NSWindow*) we need this to compensate for a missing(?) mouse capture
bool fl_show_iconic; // true if called from iconize() - shows the next created window in collapsed state
@@ -1345,7 +1343,6 @@ void fl_open_display() {
}
}
if (![NSApp servicesMenu]) createAppleMenu();
- fl_system_menu = [NSApp mainMenu];
main_screen_height = [[[NSScreen screens] objectAtIndex:0] frame].size.height;
[[NSNotificationCenter defaultCenter] addObserver:[FLWindowDelegate createOnce]
selector:@selector(anyWindowWillClose:)
@@ -3181,216 +3178,6 @@ static void createAppleMenu(void)
[menuItem release];
}
-@interface FLMenuItem : NSMenuItem {
-}
-- (void) doCallback:(id)unused;
-- (void) directCallback:(id)unused;
-- (const Fl_Menu_Item*) getFlItem;
-@end
-@implementation FLMenuItem
-- (const Fl_Menu_Item*) getFlItem
-{
- return *(const Fl_Menu_Item **)[(NSData*)[self representedObject] bytes];
-}
-- (void) doCallback:(id)unused
-{
- fl_lock_function();
- const Fl_Menu_Item *item = [self getFlItem];
- fl_sys_menu_bar->picked(item);
- if ( item->flags & FL_MENU_TOGGLE ) { // update the menu toggle symbol
- [self setState:(item->value() ? NSOnState : NSOffState)];
- }
- else if ( item->flags & FL_MENU_RADIO ) { // update the menu radio symbols
- NSMenu* menu = [self menu];
- NSInteger flRank = [menu indexOfItem:self];
- NSInteger last = [menu numberOfItems] - 1;
- int from = flRank;
- while(from > 0) {
- if ([[menu itemAtIndex:from-1] isSeparatorItem]) break;
- item = [(FLMenuItem*)[menu itemAtIndex:from-1] getFlItem];
- if ( !(item->flags & FL_MENU_RADIO) ) break;
- from--;
- }
- int to = flRank;
- while (to < last) {
- if ([[menu itemAtIndex:to+1] isSeparatorItem]) break;
- item = [(FLMenuItem*)[menu itemAtIndex:to+1] getFlItem];
- if (!(item->flags & FL_MENU_RADIO)) break;
- to++;
- }
- for(int i = from; i <= to; i++) {
- NSMenuItem *nsitem = [menu itemAtIndex:i];
- [nsitem setState:(nsitem != self ? NSOffState : NSOnState)];
- }
- }
- fl_unlock_function();
-}
-- (void) directCallback:(id)unused
-{
- fl_lock_function();
- Fl_Menu_Item *item = (Fl_Menu_Item *)[(NSData*)[self representedObject] bytes];
- if ( item && item->callback() ) item->do_callback(NULL);
- fl_unlock_function();
-}
-@end
-
-void fl_mac_set_about( Fl_Callback *cb, void *user_data, int shortcut)
-{
- fl_open_display();
- Fl_Menu_Item aboutItem;
- memset(&aboutItem, 0, sizeof(Fl_Menu_Item));
- aboutItem.callback(cb);
- aboutItem.user_data(user_data);
- aboutItem.shortcut(shortcut);
- NSMenu *appleMenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
- CFStringRef cfname = CFStringCreateCopy(NULL, (CFStringRef)[[appleMenu itemAtIndex:0] title]);
- [appleMenu removeItemAtIndex:0];
- FLMenuItem *item = [[[FLMenuItem alloc] initWithTitle:(NSString*)cfname
- action:@selector(directCallback:)
- keyEquivalent:@""] autorelease];
- if (aboutItem.shortcut()) {
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setKeyEquivalent, item, aboutItem.shortcut() & 0xff);
- Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::setKeyEquivalentModifierMask, item, aboutItem.shortcut() );
- }
- NSData *pointer = [NSData dataWithBytes:&aboutItem length:sizeof(Fl_Menu_Item)];
- [item setRepresentedObject:pointer];
- [appleMenu insertItem:item atIndex:0];
- CFRelease(cfname);
- [item setTarget:item];
-}
-
-static char *remove_ampersand(const char *s)
-{
- char *ret = strdup(s);
- const char *p = s;
- char *q = ret;
- while(*p != 0) {
- if (p[0]=='&') {
- if (p[1]=='&') {
- *q++ = '&'; p+=2;
- } else {
- p++;
- }
- } else {
- *q++ = *p++;
- }
- }
- *q = 0;
- return ret;
-}
-
-void *Fl_Sys_Menu_Bar::doMenuOrItemOperation(Fl_Sys_Menu_Bar::menuOrItemOperation operation, ...)
-/* these operations apply to menus, submenus, or menu items
- */
-{
- NSAutoreleasePool *localPool;
- localPool = [[NSAutoreleasePool alloc] init];
- NSMenu *menu;
- NSMenuItem *item;
- int value;
- void *pter;
- void *retval = NULL;
- va_list ap;
- va_start(ap, operation);
-
- if (operation == Fl_Sys_Menu_Bar::itemAtIndex) { // arguments: NSMenu*, int. Returns the item
- menu = va_arg(ap, NSMenu*);
- value = va_arg(ap, int);
- retval = (void *)[menu itemAtIndex:value];
- }
- else if (operation == Fl_Sys_Menu_Bar::setKeyEquivalent) { // arguments: NSMenuItem*, int
- item = va_arg(ap, NSMenuItem*);
- value = va_arg(ap, int);
- char key = value;
- NSString *equiv = [[NSString alloc] initWithBytes:&key length:1 encoding:NSASCIIStringEncoding];
- [item setKeyEquivalent:equiv];
- [equiv release];
- }
- else if (operation == Fl_Sys_Menu_Bar::setKeyEquivalentModifierMask) { // arguments: NSMenuItem*, int
- item = va_arg(ap, NSMenuItem*);
- value = va_arg(ap, int);
- NSUInteger macMod = 0;
- if ( value & FL_META ) macMod = NSCommandKeyMask;
- if ( value & FL_SHIFT || isupper(value) ) macMod |= NSShiftKeyMask;
- if ( value & FL_ALT ) macMod |= NSAlternateKeyMask;
- if ( value & FL_CTRL ) macMod |= NSControlKeyMask;
- [item setKeyEquivalentModifierMask:macMod];
- }
- else if (operation == Fl_Sys_Menu_Bar::setState) { // arguments: NSMenuItem*, int
- item = va_arg(ap, NSMenuItem*);
- value = va_arg(ap, int);
- [item setState:(value ? NSOnState : NSOffState)];
- }
- else if (operation == Fl_Sys_Menu_Bar::initWithTitle) { // arguments: const char*title. Returns the newly created menu
- // creates a new (sub)menu
- char *ts = remove_ampersand(va_arg(ap, char *));
- CFStringRef title = CFStringCreateWithCString(NULL, ts, kCFStringEncodingUTF8);
- free(ts);
- NSMenu *menu = [[NSMenu alloc] initWithTitle:(NSString*)title];
- CFRelease(title);
- [menu setAutoenablesItems:NO];
- retval = (void *)menu;
- }
- else if (operation == Fl_Sys_Menu_Bar::numberOfItems) { // arguments: NSMenu *menu, int *pcount
- // upon return, *pcount is set to menu's item count
- menu = va_arg(ap, NSMenu*);
- pter = va_arg(ap, void *);
- *(int*)pter = [menu numberOfItems];
- }
- else if (operation == Fl_Sys_Menu_Bar::setSubmenu) { // arguments: NSMenuItem *item, NSMenu *menu
- // sets 'menu' as submenu attached to 'item'
- item = va_arg(ap, NSMenuItem*);
- menu = va_arg(ap, NSMenu*);
- [item setSubmenu:menu];
- [menu release];
- }
- else if (operation == Fl_Sys_Menu_Bar::setEnabled) { // arguments: NSMenuItem*, int
- item = va_arg(ap, NSMenuItem*);
- value = va_arg(ap, int);
- [item setEnabled:(value ? YES : NO)];
- }
- else if (operation == Fl_Sys_Menu_Bar::addSeparatorItem) { // arguments: NSMenu*
- menu = va_arg(ap, NSMenu*);
- [menu addItem:[NSMenuItem separatorItem]];
- }
- else if (operation == Fl_Sys_Menu_Bar::setTitle) { // arguments: NSMenuItem*, const char *
- item = va_arg(ap, NSMenuItem*);
- char *ts = remove_ampersand(va_arg(ap, char *));
- CFStringRef title = CFStringCreateWithCString(NULL, ts, kCFStringEncodingUTF8);
- free(ts);
- [item setTitle:(NSString*)title];
- CFRelease(title);
- }
- else if (operation == Fl_Sys_Menu_Bar::removeItem) { // arguments: NSMenu*, int
- menu = va_arg(ap, NSMenu*);
- value = va_arg(ap, int);
- [menu removeItem:[menu itemAtIndex:value]];
- }
- else if (operation == Fl_Sys_Menu_Bar::addNewItem) { // arguments: NSMenu *menu, Fl_Menu_Item* mitem, int *prank
- // creates a new menu item at the end of 'menu'
- // attaches the item of fl_sys_menu_bar to it
- // upon return, puts the rank (counted in NSMenu) of the new item in *prank unless prank is NULL
- menu = va_arg(ap, NSMenu*);
- Fl_Menu_Item *mitem = va_arg(ap, Fl_Menu_Item *);
- int *prank = va_arg(ap, int*);
- char *name = remove_ampersand(mitem->label());
- CFStringRef cfname = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
- free(name);
- FLMenuItem *item = [[FLMenuItem alloc] initWithTitle:(NSString*)cfname
- action:@selector(doCallback:)
- keyEquivalent:@""];
- NSData *pointer = [NSData dataWithBytes:&mitem length:sizeof(Fl_Menu_Item*)];
- [item setRepresentedObject:pointer];
- [menu addItem:item];
- CFRelease(cfname);
- [item setTarget:item];
- if (prank != NULL) *prank = [menu indexOfItem:item];
- [item release];
- }
- va_end(ap);
- [localPool release];
- return retval;
-}
void Fl_X::set_key_window()
{
diff --git a/src/Makefile b/src/Makefile
index 3098f19bb..e9e2aa248 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -49,7 +49,6 @@ CPPFILES = \
Fl_Menu.cxx \
Fl_Menu_.cxx \
Fl_Menu_Bar.cxx \
- Fl_Sys_Menu_Bar.cxx \
Fl_Menu_Button.cxx \
Fl_Menu_Window.cxx \
Fl_Menu_add.cxx \
@@ -161,7 +160,8 @@ CPPFILES = \
OBJCPPFILES = \
Fl_cocoa.mm \
Fl_Quartz_Printer.mm \
- Fl_Native_File_Chooser_MAC.mm
+ Fl_Native_File_Chooser_MAC.mm \
+ Fl_Sys_Menu_Bar.mm
FLCPPFILES = \
forms_compatability.cxx \