summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES12
-rw-r--r--FL/Fl_Sys_Menu_Bar.H37
-rw-r--r--FL/Fl_Sys_Menu_Bar_Driver.H10
-rw-r--r--src/Fl_MacOS_Sys_Menu_Bar.mm218
-rw-r--r--src/Fl_Sys_Menu_Bar.cxx49
-rw-r--r--src/Fl_cocoa.mm65
-rw-r--r--src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H9
-rw-r--r--test/menubar.cxx6
8 files changed, 366 insertions, 40 deletions
diff --git a/CHANGES b/CHANGES
index 9f27401e4..83393f698 100644
--- a/CHANGES
+++ b/CHANGES
@@ -18,6 +18,18 @@ Changes in FLTK 1.4.0 Released: ??? ?? 2017
New Features and Extensions
- (add new items here)
+ - MacOS platform: Added support for rescaling the GUI of any app at run-time
+ using the command/+/-/0/ keystrokes.
+ - MSWindows platform: Added optional support for rescaling the GUI of any app
+ at run-time using the ctrl/+/-/0/ keystrokes. This requires to build the
+ FLTK library with -DFLTK_HIDPI_SUPPORT (for now). This option also makes
+ app detect the desktop scaling factor and automatically scale their GUI
+ accordingly. This effectively renders WIN32 FLTK apps "per-monitor DPI-aware"
+ whereas they were "DPI-unaware" with FLTK 1.3.4.
+ - FLTK apps on the MacOS platform contain automatically a Window menu, which,
+ under MacOS ≥ 10.12, allows to group/ungroup windows in tabbed form. The new
+ Fl_Sys_Menu_Bar::window_menu_style() function allows to specify various
+ styles for the Window menu, even not to create it.
- New function: int fl_open_ext(const char* fname, int binary, int oflags, ...)
to control the opening of files in binary/text mode in a cross-platform way.
- New Fl_SVG_Image class: gives support of scalable vector graphics images
diff --git a/FL/Fl_Sys_Menu_Bar.H b/FL/Fl_Sys_Menu_Bar.H
index eb2235e81..815d36e9e 100644
--- a/FL/Fl_Sys_Menu_Bar.H
+++ b/FL/Fl_Sys_Menu_Bar.H
@@ -24,33 +24,48 @@
class Fl_Sys_Menu_Bar_Driver;
/**
- A class to create, modify and delete menus that appear on Mac OS X in the menu bar at the top of the screen.
+ A class to create and modify menus that appear on Mac OS X in the menu bar at the top of the screen.
+ To use this class, just replace Fl_Menu_Bar by Fl_Sys_Menu_Bar, and, on the Mac platform,
+ a system menu at the top of the screen will be available. This menu will match an array
+ of Fl_Menu_Item's exactly as in all other FLTK menus.
On other than Mac OS X platforms, Fl_Sys_Menu_Bar is a synonym of class Fl_Menu_Bar.
- \n To use this class, just replace Fl_Menu_Bar by Fl_Sys_Menu_Bar, and, on the Mac platform,
- a system menu at the top of the screen will be available. This menu will match an array
- of Fl_Menu_Item's exactly as with standard FLTK menus.
+
+ On the MacOS platform, the system menu bar of any FLTK app begins with the Application
+ menu which the FLTK library automatically constructs. Functions
+ Fl_Mac_App_Menu::custom_application_menu_items() and fl_mac_set_about() can be used to further customize
+ the Application menu. The FLTK library also automatically constructs and handles a Window menu which can be
+ further customized (or even removed) calling
+ Fl_Sys_Menu_Bar::window_menu_style(window_menu_style_enum style).
+ Other member functions of this class allow the app to generate the rest of the system menu bar.
+ It is recommended to localize the system menu bar using the standard Mac OS X localization procedure
+ (see \ref osissues_localize).
Changes to the menu state are immediately visible in the menubar when they are made
using member functions of the Fl_Sys_Menu_Bar class. Other changes (e.g., by a call to
Fl_Menu_Item::set()) should be followed by a call to update() to be
visible in the menubar across all platforms.
- A few FLTK features are not supported by the Mac System menu:
+ A few FLTK menu features are not supported by the Mac System menu:
\li no symbolic labels
\li no embossed labels
\li no font sizes
-
- You can configure a callback for the 'About' menu item to invoke your own code with Fl_Sys_Menu_Bar::about().
- */
+ */
class FL_EXPORT Fl_Sys_Menu_Bar : public Fl_Menu_Bar {
protected:
virtual void draw();
public:
+ /** Possible styles of the Window menu in the system menu bar */
+ typedef enum {
+ no_window_menu = 0, ///< No Window menu in the system menu bar
+ tabbing_mode_none, ///< No tabbed windows, but the system menu bar contains a Window menu
+ tabbing_mode_automatic, ///< Windows are created by themselves but can be tabbed later
+ tabbing_mode_preferred ///< Windows are tabbed when created
+ } window_menu_style_enum;
Fl_Sys_Menu_Bar(int x,int y,int w,int h,const char *l=0);
virtual ~Fl_Sys_Menu_Bar();
static Fl_Sys_Menu_Bar_Driver *driver();
- /** Return the system menu's array of Fl_Menu_Item's
+ /** Return the system menu's array of Fl_Menu_Item's
*/
const Fl_Menu_Item *menu() const {return Fl_Menu_::menu();}
void menu(const Fl_Menu_Item *m);
@@ -81,6 +96,10 @@ public:
void shortcut (int i, int s);
void setonly (Fl_Menu_Item *item);
static void about(Fl_Callback *cb, void *data);
+
+ static window_menu_style_enum window_menu_style();
+ static void window_menu_style(window_menu_style_enum style);
+ static void create_window_menu();
};
extern Fl_Sys_Menu_Bar *fl_sys_menu_bar;
diff --git a/FL/Fl_Sys_Menu_Bar_Driver.H b/FL/Fl_Sys_Menu_Bar_Driver.H
index 1a2dfac25..7d869ae64 100644
--- a/FL/Fl_Sys_Menu_Bar_Driver.H
+++ b/FL/Fl_Sys_Menu_Bar_Driver.H
@@ -19,11 +19,15 @@
#ifndef Fl_Sys_Menu_Bar_Driver_H
#define Fl_Sys_Menu_Bar_Driver_H
+#if !defined(FL_DOXYGEN)
+
#include <FL/Fl_Sys_Menu_Bar.H>
class Fl_Sys_Menu_Bar_Driver {
friend class Fl_Sys_Menu_Bar;
public:
+ static Fl_Sys_Menu_Bar::window_menu_style_enum window_menu_style_;
+ static Fl_Sys_Menu_Bar_Driver *driver_; // to be assigned with a unique object of this class or of a derived class
Fl_Sys_Menu_Bar *bar;
Fl_Sys_Menu_Bar_Driver();
virtual ~Fl_Sys_Menu_Bar_Driver();
@@ -45,10 +49,12 @@ public:
virtual void remove(int index) { bar->Fl_Menu_Bar::remove(index); }
virtual void replace(int index, const char *name) { bar->Fl_Menu_Bar::replace(index, name); }
virtual void mode(int i, int fl) { bar->Fl_Menu_Bar::mode(i, fl); }
-
- static Fl_Sys_Menu_Bar_Driver *driver_; // to be assigned with a unique object of this class or of a derived class
+ virtual void create_window_menu() {}
+ static Fl_Sys_Menu_Bar::window_menu_style_enum window_menu_style() { return window_menu_style_; }
+ static void window_menu_style(Fl_Sys_Menu_Bar::window_menu_style_enum style) { window_menu_style_ = style; }
};
+#endif // !defined(FL_DOXYGEN)
#endif // Fl_Sys_Menu_Bar_Driver_H
diff --git a/src/Fl_MacOS_Sys_Menu_Bar.mm b/src/Fl_MacOS_Sys_Menu_Bar.mm
index 9dec537bb..dcedcd293 100644
--- a/src/Fl_MacOS_Sys_Menu_Bar.mm
+++ b/src/Fl_MacOS_Sys_Menu_Bar.mm
@@ -21,9 +21,30 @@
#include <FL/Fl_Sys_Menu_Bar_Driver.H>
#include <FL/x.H>
#include "drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H"
+#include "flstring.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#import <Cocoa/Cocoa.h> // keep this after include of Fl_Sys_Menu_Bar_Driver.H because of check() conflict
+typedef const Fl_Menu_Item *pFl_Menu_Item;
-Fl_Sys_Menu_Bar_Driver* Fl_MacOS_Sys_Menu_Bar_Driver::driver() {
+static Fl_Menu_Bar *custom_menu;
+static NSString *localized_Window = nil;
+
+static char *remove_ampersand(const char *s);
+extern void (*fl_lock_function)();
+extern void (*fl_unlock_function)();
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+static void previous_tab_cb(Fl_Widget *, void *data);
+static void next_tab_cb(Fl_Widget *, void *data);
+static void move_tab_cb(Fl_Widget *, void *data);
+static void merge_all_windows_cb(Fl_Widget *, void *data);
+#endif
+
+Fl_MacOS_Sys_Menu_Bar_Driver* Fl_MacOS_Sys_Menu_Bar_Driver::driver() {
static Fl_MacOS_Sys_Menu_Bar_Driver *once = new Fl_MacOS_Sys_Menu_Bar_Driver();
if (driver_ != once) {
if (driver_) {
@@ -36,22 +57,6 @@ Fl_Sys_Menu_Bar_Driver* Fl_MacOS_Sys_Menu_Bar_Driver::driver() {
return once;
}
-
-#import <Cocoa/Cocoa.h>
-
-#include "flstring.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <stdarg.h>
-
-typedef const Fl_Menu_Item *pFl_Menu_Item;
-
-static Fl_Menu_Bar *custom_menu;
-
-static char *remove_ampersand(const char *s);
-extern void (*fl_lock_function)();
-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.
@@ -92,6 +97,9 @@ const char *Fl_Mac_App_Menu::quit = "Quit %@";
- (void) setKeyEquivalentModifierMask:(int)value;
- (void) setFltkShortcut:(int)key;
+ (int) addNewItem:(const Fl_Menu_Item*)mitem menu:(NSMenu*)menu action:(SEL)selector;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+- (BOOL)validateMenuItem:(NSMenuItem *)item;
+#endif
@end
@implementation FLMenuItem
@@ -197,6 +205,37 @@ const char *Fl_Mac_App_Menu::quit = "Quit %@";
[item release];
return retval;
}
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+- (BOOL)validateMenuItem:(NSMenuItem *)item {
+ // return YES for all but items of the Window menu
+ if (fl_mac_os_version < 101200 ||
+ Fl_Sys_Menu_Bar::window_menu_style() <= Fl_Sys_Menu_Bar::tabbing_mode_none ||
+ [item hasSubmenu]) return YES;
+ NSString *title = [[item parentItem] title]; // 10.6
+ if (!title || !localized_Window || [title compare:localized_Window] != NSOrderedSame) return YES;
+ const Fl_Menu_Item *flitem = [(FLMenuItem*)item getFlItem];
+ Fl_Callback *item_cb = flitem->callback();
+ if (item_cb == previous_tab_cb || item_cb == next_tab_cb || item_cb == move_tab_cb) {
+ // is the current window tabbed?
+ Fl_Window *win = Fl::first_window();
+ NSWindow *main = win ? (NSWindow*)fl_xid(win) : nil;
+ return (main && [main tabbedWindows] != nil);
+ } else if (item_cb == merge_all_windows_cb) {
+ // is there any untabbed, tabbable window?
+ int total = 0, untabbed = 0;
+ while ((++flitem)->label()) {
+ total++;
+ NSWindow *nsw = (NSWindow*)fl_xid( (Fl_Window*)flitem->user_data() );
+ if (![nsw tabbedWindows] && [nsw tabbingMode] != NSWindowTabbingModeDisallowed) {
+ untabbed++;
+ }
+ }
+ return (untabbed > 0 && total >= 2);
+ }
+ return YES;
+}
+#endif
@end
@@ -341,6 +380,12 @@ static void convertToMenuBar(const Fl_Menu_Item *mm)
[fl_system_menu removeItem:[fl_system_menu itemAtIndex:i]];
}
if (mm) createSubMenu(fl_system_menu, mm, NULL, @selector(doCallback));
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+ if (localized_Window) {
+ NSMenuItem *item = [fl_system_menu itemWithTitle:localized_Window];
+ if (item) [[item submenu] setAutoenablesItems:YES];
+ }
+#endif
}
void Fl_MacOS_Sys_Menu_Bar_Driver::update()
@@ -483,6 +528,145 @@ void Fl_Mac_App_Menu::custom_application_menu_items(const Fl_Menu_Item *m)
[item release];
}
}
+
+
+static void minimize_win_cb(Fl_Widget *, void *data)
+{
+ [[NSApp mainWindow] miniaturize:nil];
+}
+
+static void window_menu_cb(Fl_Widget *, void *data)
+{
+ if (data) ((Fl_Window*)data)->show();
+}
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+
+static void previous_tab_cb(Fl_Widget *, void *data)
+{
+ [[NSApp mainWindow] selectPreviousTab:nil];
+}
+
+static void next_tab_cb(Fl_Widget *, void *data)
+{
+ [[NSApp mainWindow] selectNextTab:nil];
+}
+
+static void move_tab_cb(Fl_Widget *, void *data)
+{
+ [[NSApp mainWindow] moveTabToNewWindow:nil];
+}
+
+static void merge_all_windows_cb(Fl_Widget *, void *)
+{
+ Fl_Window *first = Fl::first_window();
+ if (first) {
+ [(NSWindow*)fl_xid(first) mergeAllWindows:nil];
+ }
+}
+
+#endif
+
+
+static bool window_menu_installed = false;
+
+void Fl_MacOS_Sys_Menu_Bar_Driver::create_window_menu(void)
+{
+ if (window_menu_style() == Fl_Sys_Menu_Bar::no_window_menu) return;
+ if (window_menu_installed) return;
+ window_menu_installed = true;
+ int rank = 0;
+ if (fl_sys_menu_bar && fl_sys_menu_bar->menu()) {
+ if (fl_sys_menu_bar->find_index("Window") >= 0) { // there's already a "Window" menu -> don't create another
+ window_menu_style_ = Fl_Sys_Menu_Bar::no_window_menu;
+ return;
+ }
+ // put the Window menu last in menu bar or before Help if it's present
+ const Fl_Menu_Item *item = fl_sys_menu_bar->menu();
+ while (item->label() && strcmp(item->label(), "Help") != 0) {
+ item = item->next();
+ }
+ rank = fl_sys_menu_bar->find_index(item);
+ } else if (!fl_sys_menu_bar) {
+ fl_open_display();
+ new Fl_Sys_Menu_Bar(0,0,0,0);
+ }
+ rank = fl_sys_menu_bar->Fl_Menu_::insert(rank, "Window", 0, NULL, 0, FL_SUBMENU);
+ localized_Window = NSLocalizedString(@"Window", nil);
+
+ fl_sys_menu_bar->Fl_Menu_::insert(++rank, "Minimize", FL_COMMAND+'m', minimize_win_cb, 0, FL_MENU_DIVIDER);
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+ if (fl_mac_os_version >= 101200 && window_menu_style() != Fl_Sys_Menu_Bar::tabbing_mode_none) {
+ fl_sys_menu_bar->Fl_Menu_::insert(++rank, "Show Previous Tab", FL_SHIFT+FL_CTRL+0x9, previous_tab_cb, 0, 0);
+ fl_sys_menu_bar->Fl_Menu_::insert(++rank, "Show Next Tab", FL_CTRL+0x9, next_tab_cb, 0, 0);
+ fl_sys_menu_bar->Fl_Menu_::insert(++rank, "Move Tab To New Window", 0, move_tab_cb, 0, 0);
+ fl_sys_menu_bar->Fl_Menu_::insert(++rank, "Merge All Windows", 0, merge_all_windows_cb, 0, FL_MENU_DIVIDER);
+ }
+#endif
+ ((Fl_Menu_Item*)fl_sys_menu_bar->menu()+rank)->user_data(&window_menu_style_);
+ fl_sys_menu_bar->update();
+}
+
+int Fl_MacOS_Sys_Menu_Bar_Driver::find_first_window()
+{
+ int count = bar->size(), i;
+ for (i = 0; i < count; i++) {
+ if (bar->menu()[i].user_data() == &window_menu_style_) break;
+ }
+ return i < count ? i : -1;
+}
+
+void Fl_MacOS_Sys_Menu_Bar_Driver::new_window(Fl_Window *win)
+{
+ if (!window_menu_style() || !win->label()) return;
+ int index = find_first_window();
+ if (index < 0) return;
+ while ((bar->menu()+index+1)->label()) index++;
+ const char *p = win->iconlabel() ? win->iconlabel() : win->label();
+ int index2 = bar->Fl_Menu_::insert(index+1, p, 0, window_menu_cb, win, FL_MENU_RADIO);
+ setonly((Fl_Menu_Item*)bar->menu()+index2);
+}
+
+void Fl_MacOS_Sys_Menu_Bar_Driver::remove_window(Fl_Window *win)
+{
+ if (!window_menu_style()) return;
+ int index = find_first_window() + 1;
+ if (index < 1) return;
+ while (true) {
+ Fl_Menu_Item *item = (Fl_Menu_Item*)bar->menu() + index;
+ if (!item->label()) return;
+ if (item->user_data() == win) {
+ bool doit = item->value();
+ remove(index);
+ if (doit) {
+ item = (Fl_Menu_Item*)bar->menu() + find_first_window() + 1;
+ if (item->label()) {
+ ((Fl_Window*)item->user_data())->show();
+ setonly(item);
+ }
+ }
+ break;
+ }
+ index++;
+ }
+}
+
+void Fl_MacOS_Sys_Menu_Bar_Driver::rename_window(Fl_Window *win)
+{
+ if (!window_menu_style()) return;
+ int index = find_first_window() + 1;
+ if (index < 1) return;
+ while (true) {
+ Fl_Menu_Item *item = (Fl_Menu_Item*)bar->menu() + index;
+ if (!item->label()) return;
+ if (item->user_data() == win) {
+ replace(index, win->iconlabel() ? win->iconlabel() : win->label());
+ return;
+ }
+ index++;
+ }
+}
+
#endif /* __APPLE__ */
//
diff --git a/src/Fl_Sys_Menu_Bar.cxx b/src/Fl_Sys_Menu_Bar.cxx
index 6c4ee9a51..1e1dab81b 100644
--- a/src/Fl_Sys_Menu_Bar.cxx
+++ b/src/Fl_Sys_Menu_Bar.cxx
@@ -166,13 +166,58 @@ void Fl_Sys_Menu_Bar::replace(int index, const char *name)
* \param data a pointer transmitted as 2nd argument to the callback.
*/
void Fl_Sys_Menu_Bar::about(Fl_Callback *cb, void *data) {
- if (fl_sys_menu_bar) fl_sys_menu_bar->driver()->about(cb, data);
+ driver()->about(cb, data);
}
void Fl_Sys_Menu_Bar::draw() {
driver()->draw();
}
+
+
+/** Get the style of the Window menu in the system menu bar */
+Fl_Sys_Menu_Bar::window_menu_style_enum Fl_Sys_Menu_Bar::window_menu_style() {
+ return Fl_Sys_Menu_Bar_Driver::window_menu_style();
+}
+
+/** Set the desired style of the Window menu in the system menu bar.
+ This function, to be called before the first call to Fl_Window::show(), allows to
+ control whether the system menu bar should contain a Window menu,
+ and if yes, whether new windows should be displayed in tabbed form. These are
+ the effects of various values for \p style :
+ \li \c no_window_menu : don't add a Window menu to the system menu bar
+ \li \c tabbing_mode_none : add a simple Window menu to the system menu bar
+ \li \c tabbing_mode_automatic : the window menu also contains "Merge All Windows" to group
+ all windows in a single tabbed display mode. This is the \b default Window menu style
+ for FLTK apps.
+ \li \c tabbing_mode_preferred : new windows are displayed in tabbed mode when first created
+
+ The Window menu, if present, is entirely created and controlled by the FLTK library.
+ Mac OS version 10.12 or later must be running for windows to be displayed in tabbed form.
+ Under non MacOS platforms, this function does nothing.
+ \version 1.4
+ */
+void Fl_Sys_Menu_Bar::window_menu_style(Fl_Sys_Menu_Bar::window_menu_style_enum style) {
+ Fl_Sys_Menu_Bar_Driver::window_menu_style(style);
+}
+
+/** Adds a Window menu, to the end of the system menu bar.
+ FLTK apps typically don't need to call this function which is automatically
+ called by the library the first time a window is shown. The default system menu bar
+ contains a Window menu with a "Merge All Windows" item.
+ Other Window menu styles can be obtained calling
+ Fl_Sys_Menu_Bar::window_menu_style(window_menu_style_enum) before the first Fl_Window::show().
+ Alternatively, an app can call create_window_menu() after having populated the system menu bar,
+ for example with menu(const Fl_Menu_Item *), and before the first Fl_Window::show().
+
+ This function does nothing on non MacOS platforms.
+ \version 1.4
+ */
+void Fl_Sys_Menu_Bar::create_window_menu() {
+ fl_open_display();
+ driver()->create_window_menu();
+}
+
#if !defined(FL_DOXYGEN)
Fl_Sys_Menu_Bar_Driver *Fl_Sys_Menu_Bar::driver() {
if (!Fl_Sys_Menu_Bar_Driver::driver_) { // initialize this static variable if it was not initialized previously
@@ -186,6 +231,8 @@ Fl_Sys_Menu_Bar_Driver *Fl_Sys_Menu_Bar_Driver::driver_ = 0;
Fl_Sys_Menu_Bar_Driver::Fl_Sys_Menu_Bar_Driver() {bar = NULL;}
Fl_Sys_Menu_Bar_Driver::~Fl_Sys_Menu_Bar_Driver() {}
+
+Fl_Sys_Menu_Bar::window_menu_style_enum Fl_Sys_Menu_Bar_Driver::window_menu_style_ = Fl_Sys_Menu_Bar::tabbing_mode_automatic;
#endif // !defined(FL_DOXYGEN)
//
diff --git a/src/Fl_cocoa.mm b/src/Fl_cocoa.mm
index 88b1adc51..1649f0b53 100644
--- a/src/Fl_cocoa.mm
+++ b/src/Fl_cocoa.mm
@@ -1309,9 +1309,14 @@ static FLWindowDelegate *flwindowdelegate_instance = nil;
}
- (void)windowDidMove:(NSNotification *)notif
{
- fl_lock_function();
FLWindow *nsw = (FLWindow*)[notif object];
Fl_Window *window = [nsw getFl_Window];
+ if (abs([[nsw contentView] frame].size.height - window->h() * fl_graphics_driver->scale()) > 0.5) {
+ // the contentView, but not the window frame, is resized. This happens with tabbed windows.
+ [self windowDidResize:notif];
+ return;
+ }
+ fl_lock_function();
resize_from_system = window;
NSPoint pt2;
pt2 = [nsw convertBaseToScreen:NSMakePoint(0, [[nsw contentView] frame].size.height)];
@@ -1402,6 +1407,19 @@ static FLWindowDelegate *flwindowdelegate_instance = nil;
Fl_Window *window = [nsw getFl_Window];
Fl::first_window(window);
update_e_xy_and_e_xy_root(nsw);
+ if (fl_sys_menu_bar && Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style()) {
+ // select the corresponding Window menu item
+ int index = Fl_MacOS_Sys_Menu_Bar_Driver::driver()->find_first_window() + 1;
+ while (index > 0) {
+ Fl_Menu_Item *item = (Fl_Menu_Item*)fl_sys_menu_bar->menu() + index;
+ if (!item->label()) break;
+ if (item->user_data() == window) {
+ fl_sys_menu_bar->setonly(item);
+ break;
+ }
+ index++;
+ }
+ }
fl_unlock_function();
}
- (void)windowDidDeminiaturize:(NSNotification *)notif
@@ -1868,7 +1886,13 @@ void Fl_Cocoa_Screen_Driver::disable_im() {
// Gets the border sizes and the titlebar size
-static void get_window_frame_sizes(int &bx, int &by, int &bt) {
+static void get_window_frame_sizes(int &bx, int &by, int &bt, Fl_Window *win) {
+ FLWindow *flw = fl_xid(win);
+ if (flw) {
+ bt = [flw frame].size.height - [[flw contentView] frame].size.height;
+ bx = by = 0;
+ return;
+ }
static int top = 0, left, bottom;
if (!top) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -1952,7 +1976,7 @@ static int fake_X_wm(Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) {
} else {
ret = 1;
}
- get_window_frame_sizes(bx, by, bt);
+ get_window_frame_sizes(bx, by, bt, w);
}
// The coordinates of the whole window, including non-client area
xoff = bx;
@@ -2278,6 +2302,11 @@ static FLTextInputContext* fltextinputcontext_instance = nil;
fl_lock_function();
FLWindow *cw = (FLWindow*)[self window];
Fl_Window *window = [cw getFl_Window];
+ if ( !window->parent() && window->border() && abs(rect.size.height - window->h() * fl_graphics_driver->scale()) > 0.5 ) { // this happens with tabbed window
+ window->resize([cw frame].origin.x/fl_graphics_driver->scale(),
+ (main_screen_height - ([cw frame].origin.y + rect.size.height))/fl_graphics_driver->scale(),
+ rect.size.width/fl_graphics_driver->scale(), rect.size.height/fl_graphics_driver->scale());
+ }
through_drawRect = YES;
Fl_Cocoa_Window_Driver *d = Fl_Cocoa_Window_Driver::driver(window);
if (fl_mac_os_version >= 100700) { // determine whether window is mapped to a retina display
@@ -2919,6 +2948,7 @@ Fl_X* Fl_Cocoa_Window_Driver::makeWindow()
fl_open_display();
NSInteger winlevel = NSNormalWindowLevel;
NSUInteger winstyle;
+ Fl_Sys_Menu_Bar::driver()->create_window_menu(); // effective once at most
Fl_Window* w = pWindow;
if (w->parent()) {
w->border(0);
@@ -3029,6 +3059,18 @@ Fl_X* Fl_Cocoa_Window_Driver::makeWindow()
contentRect:crect
styleMask:winstyle];
[cw setFrameOrigin:crect.origin];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
+ if (fl_mac_os_version >= 101200) {
+ if (!w->parent() && (winstyle & NSTitledWindowMask) && (winstyle & NSResizableWindowMask)
+ && !w->modal() && !w->non_modal() && Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style() > Fl_Sys_Menu_Bar::tabbing_mode_none) {
+ if (Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style() == Fl_Sys_Menu_Bar::tabbing_mode_preferred)
+ [cw setTabbingMode:NSWindowTabbingModePreferred];
+ else [cw setTabbingMode:NSWindowTabbingModeAutomatic];
+ } else {
+ [cw setTabbingMode:NSWindowTabbingModeDisallowed];
+ }
+ }
+#endif
if (!w->parent()) {
[cw setHasShadow:YES];
[cw setAcceptsMouseMovedEvents:YES];
@@ -3105,7 +3147,10 @@ Fl_X* Fl_Cocoa_Window_Driver::makeWindow()
} else { // a top-level window
[cw makeKeyAndOrderFront:nil];
}
-
+ if (fl_sys_menu_bar && Fl_MacOS_Sys_Menu_Bar_Driver::window_menu_style() && !w->parent() && w->border() &&
+ !w->modal() && !w->non_modal()) {
+ Fl_MacOS_Sys_Menu_Bar_Driver::driver()->new_window(w);
+ }
int old_event = Fl::e_number;
w->handle(Fl::e_number = FL_SHOW);
Fl::e_number = old_event;
@@ -3121,7 +3166,7 @@ Fl_X* Fl_Cocoa_Window_Driver::makeWindow()
*/
void Fl_Cocoa_Window_Driver::size_range() {
int bx, by, bt;
- get_window_frame_sizes(bx, by, bt);
+ get_window_frame_sizes(bx, by, bt, pWindow);
Fl_Window_Driver::size_range();
NSSize minSize = NSMakeSize(minw(), minh() + bt);
NSSize maxSize = NSMakeSize(maxw() ? maxw():32000, maxh() ? maxh() + bt:32000);
@@ -3172,6 +3217,8 @@ const char *Fl_Darwin_System_Driver::filename_name( const char *name )
void Fl_Cocoa_Window_Driver::label(const char *name, const char *mininame) {
if (shown() || Fl_X::i(pWindow)) {
q_set_window_title(fl_xid(pWindow), name, mininame);
+ if (fl_sys_menu_bar && Fl_Sys_Menu_Bar_Driver::window_menu_style())
+ Fl_MacOS_Sys_Menu_Bar_Driver::driver()->rename_window(pWindow);
}
}
@@ -3230,7 +3277,7 @@ void Fl_Cocoa_Window_Driver::resize(int X,int Y,int W,int H) {
}
pWindow->Fl_Group::resize(X,Y,W,H);
// transmit changes in FLTK coords to cocoa
- get_window_frame_sizes(bx, by, bt);
+ get_window_frame_sizes(bx, by, bt, pWindow);
bx = X; by = Y;
parent = pWindow->window();
while (parent) {
@@ -3552,6 +3599,8 @@ int Fl_Darwin_System_Driver::clipboard_contains(const char *type) {
}
void Fl_Cocoa_Window_Driver::destroy(FLWindow *xid) {
+ if (fl_sys_menu_bar && Fl_Sys_Menu_Bar_Driver::window_menu_style())
+ Fl_MacOS_Sys_Menu_Bar_Driver::driver()->remove_window([xid getFl_Window]);
[xid close];
}
@@ -4291,7 +4340,7 @@ int Fl_Cocoa_Window_Driver::decorated_w()
if (!shown() || parent() || !border() || !visible())
return w();
int bx, by, bt;
- get_window_frame_sizes(bx, by, bt);
+ get_window_frame_sizes(bx, by, bt, pWindow);
return w() + 2 * bx;
}
@@ -4300,7 +4349,7 @@ int Fl_Cocoa_Window_Driver::decorated_h()
if (!shown() || parent() || !border() || !visible())
return h();
int bx, by, bt;
- get_window_frame_sizes(bx, by, bt);
+ get_window_frame_sizes(bx, by, bt, pWindow);
return h() + bt + by;
}
diff --git a/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H b/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H
index b2a6f125b..8c332c6cb 100644
--- a/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H
+++ b/src/drivers/Cocoa/Fl_MacOS_Sys_Menu_Bar_Driver.H
@@ -1,7 +1,7 @@
//
// "$Id$"
//
-// system menu bar widget for the Fast Light Tool Kit (FLTK).
+// Definition of class Fl_MacOS_Sys_Menu_Bar_Driver for the Fast Light Tool Kit (FLTK).
//
// Copyright 2017 by Bill Spitzak and others.
//
@@ -39,7 +39,12 @@ public:
virtual void remove(int index);
virtual void replace(int index, const char *name);
virtual void mode(int i, int fl);
- static Fl_Sys_Menu_Bar_Driver* driver();
+ virtual void create_window_menu();
+ int find_first_window();
+ void new_window(Fl_Window *win);
+ void remove_window(Fl_Window *win);
+ void rename_window(Fl_Window *win);
+ static Fl_MacOS_Sys_Menu_Bar_Driver* driver();
};
diff --git a/test/menubar.cxx b/test/menubar.cxx
index 6062db889..40bc9ffbe 100644
--- a/test/menubar.cxx
+++ b/test/menubar.cxx
@@ -3,7 +3,7 @@
//
// Menubar test program for the Fast Light Tool Kit (FLTK).
//
-// Copyright 1998-2010 by Bill Spitzak and others.
+// Copyright 1998-2017 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
@@ -199,6 +199,7 @@ void menu_location_cb(Fl_Widget* w, void* data)
smenubar->callback(test_cb);
}
else { // switch to window menu bar
+ menubar->menu(smenubar->menu());
smenubar->clear();
delete smenubar;
menubar->show();
@@ -246,6 +247,8 @@ int main(int argc, char **argv) {
Fl_Choice ch2(500,100,150,25,"Use:");
ch2.menu(menu_location);
ch2.callback(menu_location_cb, &menubar);
+ ch2.value(1);
+ menu_location_cb(&ch2, &menubar);
#endif
window.end();
@@ -257,6 +260,7 @@ int main(int argc, char **argv) {
{0}
};
Fl_Mac_App_Menu::custom_application_menu_items(custom);
+ //Fl_Sys_Menu_Bar::window_menu_style(Fl_Sys_Menu_Bar::no_window_menu);
#endif
window.show(argc, argv);
return Fl::run();