It would simplify my life immensely if my Qt 4.8 Cocoa application received a signal or event or anything that allowed me to intervene between the first mouse click in the menu bar and when the first menu is shown.
In a straight Cocoa application, I can register a routine to receive a NSMenuDidBeginTrackingNotification notification: [[NSNotificationCenter defaultCenter] addObserver:self // the NSObject containing the called routine selector:@selector(begunTracking:) // the routine called with notification name:NSMenuDidBeginTrackingNotification object:[NSApp mainMenu]]; // the object which emits the NSMenuDidBeginTrackingNotification which calls -calledWhenTrackingHasBegun(NSNotification *)notification on the menubar mouse down. Note that the notification comes from a specific object: the mainMenu object returned by the cocoa application NSApp object. This works fine in a trivial Cocoa application (first example code). However, in a simple Qt application (such as the second example code), the notification is never received. I'm wondering if [NSApp mainMenu] isn't returning the native menu bar that Qt is actually using? I wonder this because the log entries generated in MainMenuObserver:init() indicate a completely different menu than the one my application built: 11/21/12 4:06:38 PM MacMenuBarMouseDown[18132] mainMenu: <NSMenu: 0x1167104a0> Title: qt_menu Supermenu: 0x0 (None), autoenable: YES Items: ( "<NSMenuItem: 0x116710560 NewApplication, submenu: 0x11670d260 (NewApplication)>" ) 11/21/12 4:06:46 PM MacMenuBarMouseDown[18132] num items: 1 11/21/12 4:06:51 PM MacMenuBarMouseDown[18132] array: ( "<NSMenuItem: 0x116710560 NewApplication, submenu: 0x11670d260 (NewApplication)>" ) Q1) How can I get the actual menubar object on which to install the observer? Surely it exists somewhere! (I see a few calls to [NSApp setMainMenu:menu]; in Qt 4.8.3's qmenu_mac.mm source, but darn if I can figure out what's happening in there with QCocoaMenuLoader et al.) Better would be a Qt-supported notify event or filter API that would report a mouse down in whatever Qt uses for a menu bar. Q2) Is there an existing Qt 4.8+ feature that detects the start of mouse tracking in the menu bar on Mac (and Win and Linux)? --Jim ------------- Objective C Example code which works in native app, but not in Qt ---------------------- void InstallMainMenuObserver() { static MainMenuObserver *myObserver= nil; if( myObserver == nil ) myObserver = [[MainMenuObserver alloc] init]; } @implementation MainMenuObserver - (id) init { self = [super init]; if (!self) return nil; NSMenu *menu= [NSApp mainMenu]; NSLog(@"mainMenu: %@", menu); [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(begunTracking:) name:NSMenuDidBeginTrackingNotification object:menu]; return self; } - (void) dealloc { // If you don't remove yourself as an observer, the Notification Center // will continue to try and send notification objects to the deallocated // object. [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } - (void)begunTracking:(NSNotification *)notification { if ([[notification name] isEqualToString:NSMenuDidBeginTrackingNotification]) NSLog(@"Successfully received NSMenuDidBeginTrackingNotification!"); } @end ------------- Qt Example code ---------------------- (This program generates a simple three-menu menubar: the first is the default application menu, the second is a "Test" menu, then a "Another" menu). +++ main.cpp: #include <QApplication> #include <QMenu> #include <QMenuBar> #ifdef DOTRACKING #include "CocoaUtils.h" #endif int main( int argc, char* argv[]) { QApplication app(argc, argv); // "QMenuBar on Mac OS X // If you want all windows in a Mac application to share one menu bar, // you must create a menu bar that does not have a parent." QMenuBar *menuBar = new QMenuBar(0); // Create a parent-less menu bar this way bool isNative= menuBar->isNativeMenuBar(); // returns true QMenu * menu= new QMenu("Test"); QAction *action= new QAction(QLatin1String("First menu item"), menu); menu->addAction( action ); action= new QAction(QLatin1String("Second menu item"), menu); menu->addAction( action ); action= new QAction(QLatin1String("Third menu item"), menu); menu->addAction( action ); menuBar->addMenu( menu ); // first added menu (there should already be an Application menu in the menu bar) menu= new QMenu("Another"); action= new QAction(QLatin1String("Fourth menu item"), menu); menu->addAction( action ); menuBar->addMenu( menu ); // second added menu (there should be 3 now) #ifdef DOTRACKING InstallMainMenuObserver(); // CocoaUtils.h/mm #endif app.exec(); } +++ CocoaUtils.h: #if defined __cplusplus || defined __OBJC__ extern "C" { #endif // __cplusplus void InstallMainMenuObserver(); #if defined __OBJC__ // The definition of "slots" in Qt5 conflicts with the definition // in CAOpenGLLayer.h, which gets included when we include Cocoa/Cocoa.h // below. So we undefine "slots" if necessary. #if defined(slots) #undef slots #endif #import <Cocoa/Cocoa.h> #import <AppKit/NSMenu.h> @interface MainMenuObserver : NSObject { @private } - (void)begunTracking:(NSNotification *)notification; @end #endif // __OBJC__ #if defined __cplusplus || defined __OBJC__ } #endif // __cplusplus +++ CocoaUtils.mmm: #import <Cocoa/Cocoa.h> #import <AppKit/NSMenu.h> #import "CocoaUtils.h" void InstallMainMenuObserver() { static MainMenuObserver *myObserver= nil; if( myObserver == nil ) myObserver = [[MainMenuObserver alloc] init]; } @implementation MainMenuObserver - (id) init { self = [super init]; if (!self) return nil; NSMenu *menu= [NSApp mainMenu]; NSLog(@"mainMenu: %@", menu); // debugging: see if the menubar has our expected items. NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSLog(@"num items: %d", [menu numberOfItems]); // should be 2: one for the application menu and one for the "Test" menu. This is 1, instead. NSLog(@"array: %@", [menu itemArray]); [pool release]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(begunTracking:) name:NSMenuDidBeginTrackingNotification object:menu]; return self; } - (void) dealloc { // If you don't remove yourself as an observer, the Notification Center // will continue to try and send notification objects to the deallocated // object. [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } - (void)begunTracking:(NSNotification *)notification { if ([[notification name] isEqualToString:NSMenuDidBeginTrackingNotification]) // <<<< A BREAKPOINT HERE IS NEVER HIT NSLog(@"Successfully received NSMenuDidBeginTrackingNotification!"); // should be seen in the Console app. } @end +++ MacMenuBarMouseDown.pro: ######################################### # MacMenuBarMouseDown.pro ######################################### QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets macx:CONFIG += x86_64 TARGET = MacMenuBarMouseDown TEMPLATE = app SOURCES += main.cpp mac { HEADERS += CocoaUtils.h OBJECTIVE_SOURCES += CocoaUtils.mm DEFINES += DOTRACKING # identify code related to NSMenuDidBeginTrackingNotification } HEADERS += OTHER_FILES += MacMenuBarMouseDown.pro ######################################### # SYSTEM LIBRARIES ######################################### #to support native drawing on Macintosh mac:LIBS += -framework ApplicationServices mac:LIBS += -framework Cocoa mac:LIBS += -framework Carbon mac:LIBS += -framework CoreAudio mac:LIBS += -framework AudioUnit mac:LIBS += -framework QTKit ======================================================================== Jim "How does it work?" Prouty Voice: (503) 620-3001, FAX: (503) 620-6754 Makers of IGOR Pro, scientific data analysis and graphing for Mac and PC http://www.wavemetrics.com _______________________________________________ Interest mailing list Interest@qt-project.org http://lists.qt-project.org/mailman/listinfo/interest