summaryrefslogtreecommitdiffstats
path: root/src/gui/widgets/qmenu_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/widgets/qmenu_mac.mm')
-rw-r--r--src/gui/widgets/qmenu_mac.mm279
1 files changed, 184 insertions, 95 deletions
diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm
index 7e4bbb5..aaa113b 100644
--- a/src/gui/widgets/qmenu_mac.mm
+++ b/src/gui/widgets/qmenu_mac.mm
@@ -247,7 +247,7 @@ bool qt_mac_activate_action(MenuRef menu, uint command, QAction::ActionEvent act
//now walk up firing for each "caused" widget (like in the platform independent menu)
QWidget *caused = 0;
- if (GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), 0, &caused) == noErr) {
+ if (action_e == QAction::Hover && GetMenuItemProperty(menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget, sizeof(caused), 0, &caused) == noErr) {
MenuRef caused_menu = 0;
if (QMenu *qmenu2 = qobject_cast<QMenu*>(caused))
caused_menu = qmenu2->macMenu();
@@ -260,25 +260,17 @@ bool qt_mac_activate_action(MenuRef menu, uint command, QAction::ActionEvent act
QWidget *widget = 0;
GetMenuItemProperty(caused_menu, 0, kMenuCreatorQt, kMenuPropertyQWidget, sizeof(widget), 0, &widget);
if (QMenu *qmenu = qobject_cast<QMenu*>(widget)) {
- if (action_e == QAction::Trigger) {
- emit qmenu->triggered(action->action);
- } else if (action_e == QAction::Hover) {
- action->action->showStatusText(widget);
- emit qmenu->hovered(action->action);
- }
+ action->action->showStatusText(widget);
+ emit qmenu->hovered(action->action);
} else if (QMenuBar *qmenubar = qobject_cast<QMenuBar*>(widget)) {
- if (action_e == QAction::Trigger) {
- emit qmenubar->triggered(action->action);
- } else if (action_e == QAction::Hover) {
- action->action->showStatusText(widget);
- emit qmenubar->hovered(action->action);
- }
+ action->action->showStatusText(widget);
+ emit qmenubar->hovered(action->action);
break; //nothing more..
}
//walk up
if (GetMenuItemProperty(caused_menu, 0, kMenuCreatorQt, kMenuPropertyCausedQWidget,
- sizeof(caused), 0, &caused) != noErr)
+ sizeof(caused), 0, &caused) != noErr)
break;
if (QMenu *qmenu2 = qobject_cast<QMenu*>(caused))
caused_menu = qmenu2->macMenu();
@@ -649,7 +641,7 @@ static NSMenuItem *createNSMenuItem(const QString &title)
NSMenuItem *item = [[NSMenuItem alloc]
initWithTitle:qt_mac_QStringToNSString(title)
action:@selector(qtDispatcherToQAction:) keyEquivalent:@""];
- [item setTarget:getMenuLoader()];
+ [item setTarget:nil];
return item;
}
#endif
@@ -673,6 +665,7 @@ void qt_mac_set_modal_state_helper_recursive(OSMenuRef menu, OSMenuRef merge, bo
}
}
#else
+ bool modalWindowOnScreen = qApp->activeModalWidget() != 0;
for (NSMenuItem *item in [menu itemArray]) {
OSMenuRef submenu = [item submenu];
if (submenu != merge) {
@@ -682,10 +675,20 @@ void qt_mac_set_modal_state_helper_recursive(OSMenuRef menu, OSMenuRef merge, bo
// The item should follow what the QAction has.
if ([item tag]) {
QAction *action = reinterpret_cast<QAction *>([item tag]);
- syncNSMenuItemEnabled(item, action->isEnabled());
- } else {
- syncNSMenuItemEnabled(item, YES);
- }
+ syncNSMenuItemEnabled(item, action->isEnabled());
+ } else {
+ syncNSMenuItemEnabled(item, YES);
+ }
+ // We sneak in some extra code here to handle a menu problem:
+ // If there is no window on screen, we cannot set 'nil' as
+ // menu item target, because then cocoa will disable the item
+ // (guess it assumes that there will be no first responder to
+ // catch the trigger anyway?) OTOH, If we have a modal window,
+ // then setting the menu loader as target will make cocoa not
+ // deliver the trigger because the loader is then seen as modally
+ // shaddowed). So either way there are shortcomings. Instead, we
+ // decide the target as late as possible:
+ [item setTarget:modalWindowOnScreen ? nil : getMenuLoader()];
} else {
syncNSMenuItemEnabled(item, NO);
}
@@ -749,32 +752,6 @@ bool qt_mac_menubar_is_open()
return qt_mac_menus_open_count > 0;
}
-void qt_mac_clear_menubar()
-{
- if (QApplication::testAttribute(Qt::AA_MacPluginApplication))
- return;
-
-#ifndef QT_MAC_USE_COCOA
- MenuRef clear_menu = 0;
- if (CreateNewMenu(0, 0, &clear_menu) == noErr) {
- SetRootMenu(clear_menu);
- ReleaseMenu(clear_menu);
- } else {
- qWarning("QMenu: Internal error at %s:%d", __FILE__, __LINE__);
- }
- ClearMenuBar();
- qt_mac_command_set_enabled(0, kHICommandPreferences, false);
- InvalMenuBar();
-#else
- QMacCocoaAutoReleasePool pool;
- QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
- NSMenu *menu = [loader menu];
- [loader ensureAppMenuInMenu:menu];
- [NSApp setMainMenu:menu];
-#endif
-}
-
-
QMacMenuAction::~QMacMenuAction()
{
#ifdef QT_MAC_USE_COCOA
@@ -943,6 +920,7 @@ static NSMenuItem *qt_mac_menu_merge_action(OSMenuRef merge, QMacMenuAction *act
static QString qt_mac_menu_merge_text(QMacMenuAction *action)
{
QString ret;
+ extern QString qt_mac_applicationmenu_string(int type);
#ifdef QT_MAC_USE_COCOA
QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
#endif
@@ -950,22 +928,26 @@ static QString qt_mac_menu_merge_text(QMacMenuAction *action)
ret = action->action->text();
#ifndef QT_MAC_USE_COCOA
else if (action->command == kHICommandAbout)
- ret = QMenuBar::tr("About %1").arg(qAppName());
+ ret = qt_mac_applicationmenu_string(6).arg(qAppName());
else if (action->command == kHICommandAboutQt)
ret = QMenuBar::tr("About Qt");
else if (action->command == kHICommandPreferences)
- ret = QMenuBar::tr("Preferences");
+ ret = qt_mac_applicationmenu_string(4);
else if (action->command == kHICommandQuit)
- ret = QMenuBar::tr("Quit %1").arg(qAppName());
+ ret = qt_mac_applicationmenu_string(5).arg(qAppName());
#else
- else if (action->menuItem == [loader aboutMenuItem])
- ret = QMenuBar::tr("About %1").arg(qAppName());
- else if (action->menuItem == [loader aboutQtMenuItem])
- ret = QMenuBar::tr("About Qt");
- else if (action->menuItem == [loader preferencesMenuItem])
- ret = QMenuBar::tr("Preferences");
- else if (action->menuItem == [loader quitMenuItem])
- ret = QMenuBar::tr("Quit %1").arg(qAppName());
+ else if (action->menuItem == [loader aboutMenuItem]) {
+ ret = qt_mac_applicationmenu_string(6).arg(qAppName());
+ } else if (action->menuItem == [loader aboutQtMenuItem]) {
+ if (action->action->text() == QString("About Qt"))
+ ret = QMenuBar::tr("About Qt");
+ else
+ ret = action->action->text();
+ } else if (action->menuItem == [loader preferencesMenuItem]) {
+ ret = qt_mac_applicationmenu_string(4);
+ } else if (action->menuItem == [loader quitMenuItem]) {
+ ret = qt_mac_applicationmenu_string(5).arg(qAppName());
+ }
#endif
return ret;
}
@@ -1130,7 +1112,7 @@ QMenuPrivate::QMacMenuPrivate::addAction(QMacMenuAction *action, QMacMenuAction
action->menu = merge;
[cmd retain];
[cmd setAction:@selector(qtDispatcherToQAction:)];
- [cmd setTarget:getMenuLoader()];
+ [cmd setTarget:nil];
[action->menuItem release];
action->menuItem = cmd;
QMenuMergeList *list = QMenuPrivate::mergeMenuItemsHash.value(merge);
@@ -1420,7 +1402,11 @@ QMenuPrivate::QMacMenuPrivate::syncAction(QMacMenuAction *action)
} else {
[item setTitle: qt_mac_QStringToNSString(finalString)];
}
- [item setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(text))];
+
+ if (action->action->menuRole() == QAction::AboutRole || action->action->menuRole() == QAction::QuitRole)
+ [item setTitle:qt_mac_QStringToNSString(text)];
+ else
+ [item setTitle:qt_mac_QStringToNSString(qt_mac_removeMnemonics(text))];
// Cocoa Enabled
[item setEnabled: action->action->isEnabled()];
@@ -1845,7 +1831,7 @@ void QMenuBarPrivate::macDestroyMenuBar()
menubars()->remove(tlw);
mac_menubar = 0;
- if (qt_mac_current_menubar.qmenubar == q) {
+ if (!qt_mac_current_menubar.qmenubar || qt_mac_current_menubar.qmenubar == q) {
#ifdef QT_MAC_USE_COCOA
QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
[loader removeActionsFromAppMenu];
@@ -1936,43 +1922,53 @@ static bool qt_mac_is_ancestor(QWidget* possibleAncestor, QWidget *child)
Returns true if the entries of menuBar should be disabled,
based on the modality type of modalWidget.
*/
-static bool qt_mac_should_disable_menu(QMenuBar *menuBar, QWidget *modalWidget)
+static bool qt_mac_should_disable_menu(QMenuBar *menuBar)
{
- if (modalWidget == 0 || menuBar == 0)
+ QWidget *modalWidget = qApp->activeModalWidget();
+ if (!modalWidget)
+ return false;
+
+ if (menuBar && menuBar == menubars()->value(modalWidget))
+ // The menu bar is owned by the modal widget.
+ // In that case we should enable it:
return false;
- // If there is an application modal window on
- // screen, the entries of the menubar should be disabled:
+ // When there is an application modal window on screen, the entries of
+ // the menubar should be disabled. The exception in Qt is that if the
+ // modal window is the only window on screen, then we enable the menu bar.
QWidget *w = modalWidget;
+ QWidgetList topLevelWidgets = QApplication::topLevelWidgets();
while (w) {
- if (w->isVisible() && w->windowModality() == Qt::ApplicationModal)
- return true;
+ if (w->isVisible() && w->windowModality() == Qt::ApplicationModal) {
+ for (int i=0; i<topLevelWidgets.size(); ++i) {
+ QWidget *top = topLevelWidgets.at(i);
+ if (w != top && top->isVisible()) {
+ // INVARIANT: we found another visible window
+ // on screen other than our modalWidget. We therefore
+ // disable the menu bar to follow normal modality logic:
+ return true;
+ }
+ }
+ // INVARIANT: We have only one window on screen that happends
+ // to be application modal. We choose to enable the menu bar
+ // in that case to e.g. enable the quit menu item.
+ return false;
+ }
w = w->parentWidget();
}
// INVARIANT: modalWidget is window modal. Disable menu entries
- // if the menu bar belongs to an ancestor of modalWidget:
- return qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget);
+ // if the menu bar belongs to an ancestor of modalWidget. If menuBar
+ // is nil, we understand it as the default menu bar set by the nib:
+ return menuBar ? qt_mac_is_ancestor(menuBar->parentWidget(), modalWidget) : false;
}
-/*!
- \internal
-
- This function will update the current menu bar and set it as the
- active menu bar in the Menu Manager.
-
- \warning This function is not portable.
-
- \sa QMenu::macMenu(), QMenuBar::macMenu()
-*/
-bool QMenuBar::macUpdateMenuBar()
+static QWidget *findWindowThatShouldDisplayMenubar()
{
- cancelAllMenuTracking();
- QMenuBar *mb = 0;
- //find a menu bar
QWidget *w = qApp->activeWindow();
-
if (!w) {
+ // We have no active window on screen. Try to
+ // find a window from the list of top levels:
QWidgetList tlws = QApplication::topLevelWidgets();
for(int i = 0; i < tlws.size(); ++i) {
QWidget *tlw = tlws.at(i);
@@ -1983,6 +1979,12 @@ bool QMenuBar::macUpdateMenuBar()
}
}
}
+ return w;
+}
+
+static QMenuBar *findMenubarForWindow(QWidget *w)
+{
+ QMenuBar *mb = 0;
if (w) {
mb = menubars()->value(w);
#ifndef QT_NO_MAINWINDOW
@@ -1996,11 +1998,96 @@ bool QMenuBar::macUpdateMenuBar()
while(w && !mb)
mb = menubars()->value((w = w->parentWidget()));
}
- if (!mb)
+
+ if (!mb) {
+ // We could not find a menu bar for the window. Lets
+ // check if we have a global (parentless) menu bar instead:
mb = fallback;
- //now set it
+ }
+
+ return mb;
+}
+
+void qt_mac_clear_menubar()
+{
+ if (QApplication::testAttribute(Qt::AA_MacPluginApplication))
+ return;
+
+#ifndef QT_MAC_USE_COCOA
+ MenuRef clear_menu = 0;
+ if (CreateNewMenu(0, 0, &clear_menu) == noErr) {
+ SetRootMenu(clear_menu);
+ ReleaseMenu(clear_menu);
+ } else {
+ qWarning("QMenu: Internal error at %s:%d", __FILE__, __LINE__);
+ }
+ ClearMenuBar();
+ qt_mac_command_set_enabled(0, kHICommandPreferences, false);
+ InvalMenuBar();
+#else
+ QMacCocoaAutoReleasePool pool;
+ QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *loader = getMenuLoader();
+ NSMenu *menu = [loader menu];
+ [loader ensureAppMenuInMenu:menu];
+ [NSApp setMainMenu:menu];
+ const bool modal = qt_mac_should_disable_menu(0);
+ if (qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal)
+ qt_mac_set_modal_state(menu, modal);
+ qt_mac_current_menubar.qmenubar = 0;
+ qt_mac_current_menubar.modal = modal;
+#endif
+}
+
+/*!
+ \internal
+
+ This function will update the current menu bar and set it as the
+ active menu bar in the Menu Manager.
+
+ \warning This function is not portable.
+
+ \sa QMenu::macMenu(), QMenuBar::macMenu()
+*/
+bool QMenuBar::macUpdateMenuBar()
+{
+#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
+ if (!qt_cocoaPostMessage(getMenuLoader(), @selector(qtUpdateMenubar)))
+ return QMenuBarPrivate::macUpdateMenuBarImmediatly();
+ return true;
+#else
+ return QMenuBarPrivate::macUpdateMenuBarImmediatly();
+#endif
+}
+
+bool QMenuBarPrivate::macUpdateMenuBarImmediatly()
+{
bool ret = false;
+ cancelAllMenuTracking();
+ QWidget *w = findWindowThatShouldDisplayMenubar();
+ QMenuBar *mb = findMenubarForWindow(w);
+ extern bool qt_mac_app_fullscreen; //qapplication_mac.mm
+
+ // We need to see if we are in full screen mode, if so we need to
+ // switch the full screen mode to be able to show or hide the menubar.
+ if(w && mb) {
+ // This case means we are creating a menubar, check if full screen
+ if(w->isFullScreen()) {
+ // Ok, switch to showing the menubar when hovering over it.
+ SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar);
+ qt_mac_app_fullscreen = true;
+ }
+ } else if(w) {
+ // Removing a menubar
+ if(w->isFullScreen()) {
+ // Ok, switch to not showing the menubar when hovering on it
+ SetSystemUIMode(kUIModeAllHidden, 0);
+ qt_mac_app_fullscreen = true;
+ }
+ }
+
if (mb && mb->isNativeMenuBar()) {
+ bool modal = QApplicationPrivate::modalState();
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
#endif
@@ -2030,16 +2117,18 @@ bool QMenuBar::macUpdateMenuBar()
}
}
#endif
- QWidget *modalWidget = qApp->activeModalWidget();
- if (mb != menubars()->value(modalWidget)) {
- qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget));
- }
+ // Check if menu is modally shaddowed and should be disabled:
+ modal = qt_mac_should_disable_menu(mb);
+ if (mb != qt_mac_current_menubar.qmenubar || modal != qt_mac_current_menubar.modal)
+ qt_mac_set_modal_state(menu, modal);
}
qt_mac_current_menubar.qmenubar = mb;
- qt_mac_current_menubar.modal = QApplicationPrivate::modalState();
+ qt_mac_current_menubar.modal = modal;
ret = true;
} else if (qt_mac_current_menubar.qmenubar && qt_mac_current_menubar.qmenubar->isNativeMenuBar()) {
- const bool modal = QApplicationPrivate::modalState();
+ // INVARIANT: The currently active menu bar (if any) is not native. But we do have a
+ // native menu bar from before. So we need to decide whether or not is should be enabled:
+ const bool modal = qt_mac_should_disable_menu(qt_mac_current_menubar.qmenubar);
if (modal != qt_mac_current_menubar.modal) {
ret = true;
if (OSMenuRef menu = qt_mac_current_menubar.qmenubar->macMenu()) {
@@ -2051,16 +2140,15 @@ bool QMenuBar::macUpdateMenuBar()
[NSApp setMainMenu:menu];
syncMenuBarItemsVisiblity(qt_mac_current_menubar.qmenubar->d_func()->mac_menubar);
#endif
- QWidget *modalWidget = qApp->activeModalWidget();
- if (qt_mac_current_menubar.qmenubar != menubars()->value(modalWidget)) {
- qt_mac_set_modal_state(menu, qt_mac_should_disable_menu(mb, modalWidget));
- }
+ qt_mac_set_modal_state(menu, modal);
}
qt_mac_current_menubar.modal = modal;
}
}
- if(!ret)
+
+ if (!ret) {
qt_mac_clear_menubar();
+ }
return ret;
}
@@ -2131,3 +2219,4 @@ static OSMenuRef qt_mac_create_menu(QWidget *w)
QT_END_NAMESPACE
+