macOS: simplify and improve method performKeyEquivalent: of class FLView and fix #1436
Build and Test / build-linux (push) Has been cancelled
Build and Test / build-wayland (push) Has been cancelled
Build and Test / build-macos (push) Has been cancelled
Build and Test / build-windows (push) Has been cancelled

Removal of support of very old macOS versions allows to simplify method performKeyEquivalent: of class FLView.
This in turn fixes issue #1436.
The new code has been tested OK from macOS 10.9 and above.
This commit is contained in:
ManoloFLTK
2026-05-18 17:18:49 +02:00
parent a47f1a7840
commit 0b7f6124b2
2 changed files with 33 additions and 37 deletions
+7 -4
View File
@@ -1,7 +1,7 @@
//
// MacOS system menu bar widget for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 by Bill Spitzak and others.
// Copyright 1998-2026 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
@@ -454,7 +454,10 @@ static int process_sys_menu_shortcuts(int event)
if (event != FL_SHORTCUT || !fl_sys_menu_bar || Fl::modal()) return 0;
// is the last event the shortcut of an item of the fl_sys_menu_bar menu ?
const Fl_Menu_Item *item = fl_sys_menu_bar->menu()->test_shortcut();
if (!item) return 0;
if (!item) { // It's not a shortcut of the user-part of menubar. Is it of the application menu?
NSMenu *app_menu = [[[NSApp mainMenu] itemAtIndex:0] submenu]; // the application menu
return (int)[app_menu performKeyEquivalent:[NSApp currentEvent]];
}
if (item->visible()) // have the system menu process the shortcut, highlighting the corresponding menu
[[NSApp mainMenu] performKeyEquivalent:[NSApp currentEvent]];
else // have FLTK process the shortcut associated to an invisible Fl_Menu_Item
@@ -659,10 +662,10 @@ void Fl_MacOS_Sys_Menu_Bar_Driver::create_window_menu(void)
if (fl_mac_os_version >= 101200 && window_menu_style() != Fl_Sys_Menu_Bar::tabbing_mode_none) {
window_menu_items[1].label("Show Previous Tab");
window_menu_items[1].callback(previous_tab_cb);
window_menu_items[1].shortcut(FL_SHIFT+FL_CTRL+0x9);
window_menu_items[1].shortcut(FL_SHIFT+FL_CTRL+FL_Tab);
window_menu_items[2].label("Show Next Tab");
window_menu_items[2].callback(next_tab_cb);
window_menu_items[2].shortcut(FL_CTRL+0x9);
window_menu_items[2].shortcut(FL_CTRL+FL_Tab);
window_menu_items[3].label("Move Tab To New Window");
window_menu_items[3].callback(move_tab_cb);
window_menu_items[4].label("Merge All Windows");
+26 -33
View File
@@ -1483,8 +1483,8 @@ static FLWindowDelegate *flwindowdelegate_instance = nil;
{
if (fl_mac_os_version >= 101300 && [NSApp isRunning]) [NSApp stop:nil];
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
{
static void attempt_close_all_windows() {
fl_lock_function();
while ( Fl_X::first ) {
Fl_Window *win = Fl::first_window();
@@ -1500,6 +1500,11 @@ static FLWindowDelegate *flwindowdelegate_instance = nil;
Fl::program_should_quit(1);
Fl_Cocoa_Screen_Driver::breakMacEventLoop(); // necessary when called through menu and in Fl::wait()
}
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender
{
attempt_close_all_windows();
return NSTerminateCancel;
}
- (void)applicationDidBecomeActive:(NSNotification *)notify
@@ -2087,14 +2092,12 @@ static void q_set_window_title(NSWindow *nsw, const char * name, const char *mi
Keyboard input sends keyDown: and performKeyEquivalent: messages to myview. The latter occurs for keys such as
ForwardDelete, arrows and F1, and when the Ctrl or Cmd modifiers are used. Other key presses send keyDown: messages.
The performKeyEquivalent: method directly calls Fl::handle(FL_KEYBOARD, focus-window) and returns always YES.
The keyDown: method calls [[myview inputContext] handleEvent:theEvent], and triggers system processing of keyboard events.
The performKeyEquivalent: method directly calls Fl::handle(FL_KEYBOARD, focus-window)
when the Ctrl or Cmd modifiers are used. If not, it also calls [[myview inputContext] handleEvent:theEvent].
The performKeyEquivalent: method returns YES when the keystroke has been handled and NO otherwise, which allows
shortcuts of the system menu to be processed. Three sorts of messages are then sent back by the system to myview:
doCommandBySelector:, setMarkedText: and insertText:. All 3 messages eventually produce Fl::handle(FL_KEYBOARD, win) calls.
The doCommandBySelector: message allows to process events such as new-line, forward and backward delete, arrows,
escape, tab, F1. The message setMarkedText: is sent when marked text, that is, temporary text that gets replaced later
Three sorts of messages are then sent back by the system to myview: doCommandBySelector:, setMarkedText: and insertText:.
All 3 messages eventually produce Fl::handle(FL_KEYBOARD, win) calls.
The doCommandBySelector: message allows to process events such as new-line, backward delete, escape, tab.
The message setMarkedText: is sent when marked text, that is, temporary text that gets replaced later
by some other text, is inserted. This happens when a dead key is pressed, and also
when entering complex scripts (e.g., Chinese). Fl_Cocoa_Screen_Driver::next_marked_length gives the byte
length of marked text before the FL_KEYBOARD event is processed. Fl::compose_state gives this length after this processing.
@@ -2327,33 +2330,23 @@ static void cocoaKeyboardHandler(NSEvent *theEvent)
}
fl_lock_function();
cocoaKeyboardHandler(theEvent);
BOOL handled;
Fl_Window *w = [(FLWindow*)[theEvent window] getFl_Window];
if ( (mods & NSEventModifierFlagControl) || (mods & NSEventModifierFlagCommand) ) {
NSString *s = [theEvent characters];
if ( (mods & NSEventModifierFlagShift) && (mods & NSEventModifierFlagCommand) ) {
s = [s uppercaseString]; // US keyboards return lowercase letter in s if cmd-shift-key is hit
}
[FLView prepareEtext:s];
Fl::compose_state = 0;
handled = Fl::handle(FL_KEYBOARD, w);
if (!handled) {
// detect Ctrl+Command+Space to open character palette, if not used before as shortcut
if ( (mods & NSEventModifierFlagControl) && (mods & NSEventModifierFlagCommand) &&
!(mods & (NSEventModifierFlagShift|NSEventModifierFlagOption)) && [pure isEqualToString:@" "] ) {
[NSApp orderFrontCharacterPalette:self];
}
}
NSString *s = [theEvent characters];
if ( (mods & NSEventModifierFlagShift) && (mods & NSEventModifierFlagCommand) ) {
s = [s uppercaseString]; // US keyboards return lowercase letter in s if cmd-shift-key is hit
}
else {
in_key_event = YES;
need_handle = NO;
handled = [[self inputContext] handleEvent:theEvent];
if (need_handle) handled = Fl::handle(FL_KEYBOARD, w);
in_key_event = NO;
[FLView prepareEtext:s];
Fl::compose_state = 0;
BOOL handled = Fl::handle(FL_KEYBOARD, w);
if (!handled) {
// detect Ctrl+Command+Space to open character palette, if not used before as shortcut
if ( (mods & NSEventModifierFlagControl) && (mods & NSEventModifierFlagCommand) &&
!(mods & (NSEventModifierFlagShift|NSEventModifierFlagOption)) && [pure isEqualToString:@" "] ) {
[NSApp orderFrontCharacterPalette:self];
}
}
fl_unlock_function();
return handled;
return YES;
}
- (BOOL)acceptsFirstMouse:(NSEvent*)theEvent
{
@@ -3907,7 +3900,7 @@ static PrintWithTitlebarItem *print_with_titlebar_item = NULL;
}
- (void)terminate:(id)sender
{
[NSApp terminate:sender];
attempt_close_all_windows();
}
@end