diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoamenu.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoamenu.mm | 222 |
1 files changed, 7 insertions, 215 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index a54284dbae..7a550b163b 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -38,222 +38,15 @@ ****************************************************************************/ #include "qcocoamenu.h" +#include "qcocoansmenu.h" #include "qcocoahelpers.h" #include <QtCore/QtDebug> -#include <QtCore/qmetaobject.h> -#include <QtCore/private/qthread_p.h> -#include <QtGui/private/qguiapplication_p.h> #include "qcocoaapplication.h" #include "qcocoamenuloader.h" #include "qcocoamenubar.h" #include "qcocoawindow.h" -#import "qnsview.h" - -QT_BEGIN_NAMESPACE - -NSString *qt_mac_removePrivateUnicode(NSString* string) -{ - int len = [string length]; - if (len) { - QVarLengthArray <unichar, 10> characters(len); - bool changed = false; - for (int i = 0; i<len; i++) { - characters[i] = [string characterAtIndex:i]; - // check if they belong to key codes in private unicode range - // currently we need to handle only the NSDeleteFunctionKey - if (characters[i] == NSDeleteFunctionKey) { - characters[i] = NSDeleteCharacter; - changed = true; - } - } - if (changed) - return [NSString stringWithCharacters:characters.data() length:len]; - } - return string; -} - -QT_END_NAMESPACE - -@interface QT_MANGLE_NAMESPACE(QCocoaMenuDelegate) : NSObject <NSMenuDelegate> { - QCocoaMenu *m_menu; -} - -- (id) initWithMenu:(QCocoaMenu*) m; -- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier; - -@end - -QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaMenuDelegate); - -@implementation QCocoaMenuDelegate - -- (id) initWithMenu:(QCocoaMenu*) m -{ - if ((self = [super init])) - m_menu = m; - - return self; -} - -- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu -{ - Q_ASSERT(m_menu->nsMenu() == menu); - return menu.numberOfItems; -} - -- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel -{ - Q_UNUSED(index); - Q_ASSERT(m_menu->nsMenu() == menu); - if (shouldCancel) { - // TODO detach all submenus - return NO; - } - - QCocoaMenuItem *menuItem = reinterpret_cast<QCocoaMenuItem *>(item.tag); - if (m_menu->items().contains(menuItem)) { - if (QCocoaMenu *itemSubmenu = menuItem->menu()) - itemSubmenu->setAttachedItem(item); - } - return YES; -} - -- (void)menu:(NSMenu*)menu willHighlightItem:(NSMenuItem*)item -{ - Q_UNUSED(menu); - if (item && [item tag]) { - QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); - cocoaItem->hovered(); - } -} - -- (void) menuWillOpen:(NSMenu*)m -{ - Q_UNUSED(m); - m_menu->setIsOpen(true); - emit m_menu->aboutToShow(); -} - -- (void) menuDidClose:(NSMenu*)m -{ - Q_UNUSED(m); - m_menu->setIsOpen(false); - // wrong, but it's the best we can do - emit m_menu->aboutToHide(); -} - -- (void) itemFired:(NSMenuItem*) item -{ - QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>([item tag]); - // Menu-holding items also get a target to play nicely - // with NSMenuValidation but should not trigger. - if (cocoaItem->menu()) - return; - QScopedScopeLevelCounter scopeLevelCounter(QGuiApplicationPrivate::instance()->threadData); - QGuiApplicationPrivate::modifier_buttons = [QNSView convertKeyModifiers:[NSEvent modifierFlags]]; - static QMetaMethod activatedSignal = QMetaMethod::fromSignal(&QCocoaMenuItem::activated); - activatedSignal.invoke(cocoaItem, Qt::QueuedConnection); -} - -- (BOOL)validateMenuItem:(NSMenuItem*)menuItem -{ - QCocoaMenuItem *cocoaItem = reinterpret_cast<QCocoaMenuItem *>(menuItem.tag); - // Menu-holding items are always enabled, as it's conventional in Cocoa - if (!cocoaItem || cocoaItem->menu()) - return YES; - - return cocoaItem->isEnabled(); -} - -- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action -{ - /* - Check if the menu actually has a keysequence defined for this key event. - If it does, then we will first send the key sequence to the QWidget that has focus - since (in Qt's eyes) it needs to a chance at the key event first (QEvent::ShortcutOverride). - If the widget accepts the key event, we then return YES, but set the target and action to be nil, - which means that the action should not be triggered, and instead dispatch the event ourselves. - In every other case we return NO, which means that Cocoa can do as it pleases - (i.e., fire the menu action). - */ - - // Change the private unicode keys to the ones used in setting the "Key Equivalents" - NSString *characters = qt_mac_removePrivateUnicode([event characters]); - // Interested only in Shift, Cmd, Ctrl & Alt Keys, so ignoring masks like, Caps lock, Num Lock ... - const NSUInteger mask = NSShiftKeyMask | NSControlKeyMask | NSCommandKeyMask | NSAlternateKeyMask; - if (NSMenuItem *menuItem = [self findItem:menu forKey:characters forModifiers:([event modifierFlags] & mask)]) { - if (!menuItem.target) { - // This item was modified by QCocoaMenuBar::redirectKnownMenuItemsToFirstResponder - // and it looks like we're running a modal session for NSOpenPanel/NSSavePanel. - // QCocoaFileDialogHelper is actually the only place we use this and we run NSOpenPanel modal - // (modal sheet, window modal, application modal). - // Whatever the current first responder is, let's give it a chance - // and do not touch the Qt's focusObject (which is different from some native view - // having a focus inside NSSave/OpenPanel. - *target = nil; - *action = menuItem.action; - return YES; - } - - QObject *object = qApp->focusObject(); - if (object) { - QChar ch; - int keyCode; - ulong nativeModifiers = [event modifierFlags]; - Qt::KeyboardModifiers modifiers = [QNSView convertKeyModifiers: nativeModifiers]; - NSString *charactersIgnoringModifiers = [event charactersIgnoringModifiers]; - NSString *characters = [event characters]; - - if ([charactersIgnoringModifiers length] > 0) { // convert the first character into a key code - if ((modifiers & Qt::ControlModifier) && ([characters length] != 0)) { - ch = QChar([characters characterAtIndex:0]); - } else { - ch = QChar([charactersIgnoringModifiers characterAtIndex:0]); - } - keyCode = qt_mac_cocoaKey2QtKey(ch); - } else { - // might be a dead key - ch = QChar::ReplacementCharacter; - keyCode = Qt::Key_unknown; - } - - QKeyEvent accel_ev(QEvent::ShortcutOverride, (keyCode & (~Qt::KeyboardModifierMask)), - Qt::KeyboardModifiers(modifiers & Qt::KeyboardModifierMask)); - accel_ev.ignore(); - QCoreApplication::sendEvent(object, &accel_ev); - if (accel_ev.isAccepted()) { - [[NSApp keyWindow] sendEvent: event]; - *target = nil; - *action = nil; - return YES; - } - } - } - return NO; -} - -- (NSMenuItem *)findItem:(NSMenu *)menu forKey:(NSString *)key forModifiers:(NSUInteger)modifier -{ - for (NSMenuItem *item in [menu itemArray]) { - if (![item isEnabled] || [item isHidden] || [item isSeparatorItem]) - continue; - if ([item hasSubmenu]) { - if (NSMenuItem *nested = [self findItem:[item submenu] forKey:key forModifiers:modifier]) - return nested; - } - - NSString *menuKey = [item keyEquivalent]; - if (menuKey - && NSOrderedSame == [menuKey compare:key] - && modifier == [item keyEquivalentModifierMask]) - return item; - } - return nil; -} - -@end QT_BEGIN_NAMESPACE @@ -267,9 +60,7 @@ QCocoaMenu::QCocoaMenu() : { QMacAutoReleasePool pool; - m_nativeMenu = [[NSMenu alloc] initWithTitle:@"Untitled"]; - [m_nativeMenu setAutoenablesItems:YES]; - m_nativeMenu.delegate = [[QCocoaMenuDelegate alloc] initWithMenu:this]; + m_nativeMenu = [[QCocoaNSMenu alloc] initWithQPAMenu:this]; } QCocoaMenu::~QCocoaMenu() @@ -279,10 +70,6 @@ QCocoaMenu::~QCocoaMenu() item->setMenuParent(0); } - QMacAutoReleasePool pool; - NSObject *delegate = m_nativeMenu.delegate; - m_nativeMenu.delegate = nil; - [delegate release]; [m_nativeMenu release]; } @@ -307,6 +94,11 @@ void QCocoaMenu::setFont(const QFont &font) } } +NSMenu *QCocoaMenu::nsMenu() const +{ + return static_cast<NSMenu *>(m_nativeMenu); +} + void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) { QMacAutoReleasePool pool; |