src/gui/util/qsystemtrayicon_mac.mm
changeset 30 5dc02b23752f
parent 19 fcece45ef507
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
    73 **
    73 **
    74 ****************************************************************************/
    74 ****************************************************************************/
    75 
    75 
    76 #define QT_MAC_SYSTEMTRAY_USE_GROWL
    76 #define QT_MAC_SYSTEMTRAY_USE_GROWL
    77 
    77 
    78 @class QNSMenu;
       
    79 
       
    80 #include <private/qt_cocoa_helpers_mac_p.h>
    78 #include <private/qt_cocoa_helpers_mac_p.h>
    81 #include <private/qsystemtrayicon_p.h>
    79 #include <private/qsystemtrayicon_p.h>
    82 #include <qtemporaryfile.h>
    80 #include <qtemporaryfile.h>
    83 #include <qimagewriter.h>
    81 #include <qimagewriter.h>
    84 #include <qapplication.h>
    82 #include <qapplication.h>
    91 QT_BEGIN_NAMESPACE
    89 QT_BEGIN_NAMESPACE
    92 extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); //qapplication_mac.cpp
    90 extern bool qt_mac_execute_apple_script(const QString &script, AEDesc *ret); //qapplication_mac.cpp
    93 extern void qtsystray_sendActivated(QSystemTrayIcon *i, int r); //qsystemtrayicon.cpp
    91 extern void qtsystray_sendActivated(QSystemTrayIcon *i, int r); //qsystemtrayicon.cpp
    94 extern NSString *keySequenceToKeyEqivalent(const QKeySequence &accel); // qmenu_mac.mm
    92 extern NSString *keySequenceToKeyEqivalent(const QKeySequence &accel); // qmenu_mac.mm
    95 extern NSUInteger keySequenceModifierMask(const QKeySequence &accel);  // qmenu_mac.mm
    93 extern NSUInteger keySequenceModifierMask(const QKeySequence &accel);  // qmenu_mac.mm
       
    94 extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
    96 QT_END_NAMESPACE
    95 QT_END_NAMESPACE
    97 
    96 
    98 QT_USE_NAMESPACE
    97 QT_USE_NAMESPACE
    99 
    98 
   100 @class QNSImageView;
    99 @class QT_MANGLE_NAMESPACE(QNSMenu);
   101 
   100 @class QT_MANGLE_NAMESPACE(QNSImageView);
   102 @interface QNSStatusItem : NSObject {
   101 
       
   102 @interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject {
   103     NSStatusItem *item;
   103     NSStatusItem *item;
   104     QSystemTrayIcon *icon;
   104     QSystemTrayIcon *icon;
   105     QSystemTrayIconPrivate *iconPrivate;
   105     QSystemTrayIconPrivate *iconPrivate;
   106     QNSImageView *imageCell;
   106     QT_MANGLE_NAMESPACE(QNSImageView) *imageCell;
   107 }
   107 }
   108 -(id)initWithIcon:(QSystemTrayIcon*)icon iconPrivate:(QSystemTrayIconPrivate *)iprivate;
   108 -(id)initWithIcon:(QSystemTrayIcon*)icon iconPrivate:(QSystemTrayIconPrivate *)iprivate;
   109 -(void)dealloc;
   109 -(void)dealloc;
   110 -(QSystemTrayIcon*)icon;
   110 -(QSystemTrayIcon*)icon;
   111 -(NSStatusItem*)item;
   111 -(NSStatusItem*)item;
   112 -(QRectF)geometry;
   112 -(QRectF)geometry;
   113 - (void)triggerSelector:(id)sender;
   113 - (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
   114 - (void)doubleClickSelector:(id)sender;
   114 - (void)doubleClickSelector:(id)sender;
   115 @end
   115 @end
   116 
   116 
   117 @interface QNSImageView : NSImageView {
   117 @interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
   118     BOOL down;
   118     BOOL down;
   119     QNSStatusItem *parent;
   119     QT_MANGLE_NAMESPACE(QNSStatusItem) *parent;
   120 }
   120 }
   121 -(id)initWithParent:(QNSStatusItem*)myParent;
   121 -(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent;
   122 -(QSystemTrayIcon*)icon;
   122 -(QSystemTrayIcon*)icon;
   123 -(void)menuTrackingDone:(NSNotification*)notification;
   123 -(void)menuTrackingDone:(NSNotification*)notification;
   124 -(void)mousePressed:(NSEvent *)mouseEvent;
   124 -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
   125 @end
   125 @end
   126 
   126 
   127 
   127 
   128 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
   128 #if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
   129 
   129 
   131 -(void)menuNeedsUpdate:(NSMenu*)menu;
   131 -(void)menuNeedsUpdate:(NSMenu*)menu;
   132 @end
   132 @end
   133 #endif
   133 #endif
   134 
   134 
   135 
   135 
   136 @interface QNSMenu : NSMenu <NSMenuDelegate> {
   136 @interface QT_MANGLE_NAMESPACE(QNSMenu) : NSMenu <NSMenuDelegate> {
   137     QMenu *qmenu;
   137     QMenu *qmenu;
   138 }
   138 }
   139 -(QMenu*)menu;
   139 -(QMenu*)menu;
   140 -(id)initWithQMenu:(QMenu*)qmenu;
   140 -(id)initWithQMenu:(QMenu*)qmenu;
   141 -(void)selectedAction:(id)item;
   141 -(void)selectedAction:(id)item;
   145 class QSystemTrayIconSys
   145 class QSystemTrayIconSys
   146 {
   146 {
   147 public:
   147 public:
   148     QSystemTrayIconSys(QSystemTrayIcon *icon, QSystemTrayIconPrivate *d) {
   148     QSystemTrayIconSys(QSystemTrayIcon *icon, QSystemTrayIconPrivate *d) {
   149         QMacCocoaAutoReleasePool pool;
   149         QMacCocoaAutoReleasePool pool;
   150         item = [[QNSStatusItem alloc] initWithIcon:icon iconPrivate:d];
   150         item = [[QT_MANGLE_NAMESPACE(QNSStatusItem) alloc] initWithIcon:icon iconPrivate:d];
   151     }
   151     }
   152     ~QSystemTrayIconSys() {
   152     ~QSystemTrayIconSys() {
   153         QMacCocoaAutoReleasePool pool;
   153         QMacCocoaAutoReleasePool pool;
   154         [[[item item] view] setHidden: YES];
   154         [[[item item] view] setHidden: YES];
   155         [item release];
   155         [item release];
   156     }
   156     }
   157     QNSStatusItem *item;
   157     QT_MANGLE_NAMESPACE(QNSStatusItem) *item;
   158 };
   158 };
   159 
   159 
   160 void QSystemTrayIconPrivate::install_sys()
   160 void QSystemTrayIconPrivate::install_sys()
   161 {
   161 {
   162     Q_Q(QSystemTrayIcon);
   162     Q_Q(QSystemTrayIcon);
   296 QT_END_NAMESPACE
   296 QT_END_NAMESPACE
   297 
   297 
   298 @implementation NSStatusItem (Qt)
   298 @implementation NSStatusItem (Qt)
   299 @end
   299 @end
   300 
   300 
   301 @implementation QNSImageView
   301 @implementation QT_MANGLE_NAMESPACE(QNSImageView)
   302 -(id)initWithParent:(QNSStatusItem*)myParent {
   302 -(id)initWithParent:(QT_MANGLE_NAMESPACE(QNSStatusItem)*)myParent {
   303     self = [super init];
   303     self = [super init];
   304     parent = myParent;
   304     parent = myParent;
   305     down = NO;
   305     down = NO;
   306     return self;
   306     return self;
   307 }
   307 }
   331         [self icon]->contextMenu()->hide();
   331         [self icon]->contextMenu()->hide();
   332 
   332 
   333     [self setNeedsDisplay:YES];
   333     [self setNeedsDisplay:YES];
   334 }
   334 }
   335 
   335 
   336 -(void)mousePressed:(NSEvent *)mouseEvent
   336 -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton
   337 {
   337 {
   338     int clickCount = [mouseEvent clickCount];
   338     down = YES;
   339     down = !down;
   339     int clickCount = [mouseEvent clickCount];  
   340     if(!down && [self icon]->contextMenu())
       
   341         [self icon]->contextMenu()->hide();
       
   342     [self setNeedsDisplay:YES];
   340     [self setNeedsDisplay:YES];
   343 
   341 
   344 #ifndef QT_MAC_USE_COCOA
   342 #ifndef QT_MAC_USE_COCOA
   345     const short scale = GetMBarHeight()-4;
   343     const short scale = GetMBarHeight()-4;
   346 #else
   344 #else
   347     CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
   345     CGFloat hgt = [[[NSApplication sharedApplication] mainMenu] menuBarHeight];
   348     const short scale = hgt - 4;
   346     const short scale = hgt - 4;
   349 #endif
   347 #endif
   350 
   348 
   351     if( down && ![self icon]->icon().isNull() ) {
   349     if (![self icon]->icon().isNull() ) {
   352         NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage([self icon]->icon().pixmap(QSize(scale, scale), QIcon::Selected)));
   350         NSImage *nsaltimage = static_cast<NSImage *>(qt_mac_create_nsimage([self icon]->icon().pixmap(QSize(scale, scale), QIcon::Selected)));
   353         [self setImage: nsaltimage];
   351         [self setImage: nsaltimage];
   354         [nsaltimage release];
   352         [nsaltimage release];
   355     }
   353     }
   356 
   354 
   357 
   355     if ((clickCount == 2)) {
   358     if (down)
   356         [self menuTrackingDone:nil];
   359         [parent triggerSelector:self];
       
   360     else if ((clickCount%2))
       
   361         [parent doubleClickSelector:self];
   357         [parent doubleClickSelector:self];
   362     while (down) {
   358     } else {
   363         mouseEvent = [[self window] nextEventMatchingMask:NSLeftMouseDownMask | NSLeftMouseUpMask
   359         [parent triggerSelector:self button:mouseButton];
   364                         | NSLeftMouseDraggedMask | NSRightMouseDownMask | NSRightMouseUpMask
   360     }
   365                         | NSRightMouseDraggedMask];
       
   366         switch ([mouseEvent type]) {
       
   367             case NSRightMouseDown:
       
   368             case NSRightMouseUp:
       
   369             case NSLeftMouseDown:
       
   370             case NSLeftMouseUp:
       
   371                 [self menuTrackingDone:nil];
       
   372                 break;
       
   373             case NSRightMouseDragged:
       
   374             case NSLeftMouseDragged:
       
   375             default:
       
   376                 /* Ignore any other kind of event. */
       
   377                 break;
       
   378         }
       
   379     };
       
   380 }
   361 }
   381 
   362 
   382 -(void)mouseDown:(NSEvent *)mouseEvent
   363 -(void)mouseDown:(NSEvent *)mouseEvent
   383 {
   364 {
   384     [self mousePressed:mouseEvent];
   365     [self mousePressed:mouseEvent button:Qt::LeftButton];
       
   366 }
       
   367 
       
   368 -(void)mouseUp:(NSEvent *)mouseEvent
       
   369 {
       
   370     Q_UNUSED(mouseEvent);
       
   371     [self menuTrackingDone:nil];
   385 }
   372 }
   386 
   373 
   387 - (void)rightMouseDown:(NSEvent *)mouseEvent
   374 - (void)rightMouseDown:(NSEvent *)mouseEvent
   388 {
   375 {
   389     [self mousePressed:mouseEvent];
   376     [self mousePressed:mouseEvent button:Qt::RightButton];
   390 }
   377 }
   391 
   378 
       
   379 -(void)rightMouseUp:(NSEvent *)mouseEvent
       
   380 {
       
   381     Q_UNUSED(mouseEvent);
       
   382     [self menuTrackingDone:nil];
       
   383 }
       
   384 
       
   385 - (void)otherMouseDown:(NSEvent *)mouseEvent
       
   386 {
       
   387     [self mousePressed:mouseEvent button:cocoaButton2QtButton([mouseEvent buttonNumber])];
       
   388 }
       
   389 
       
   390 -(void)otherMouseUp:(NSEvent *)mouseEvent
       
   391 {
       
   392     Q_UNUSED(mouseEvent);
       
   393     [self menuTrackingDone:nil];
       
   394 }
   392 
   395 
   393 -(void)drawRect:(NSRect)rect {
   396 -(void)drawRect:(NSRect)rect {
   394     [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
   397     [[parent item] drawStatusBarBackgroundInRect:rect withHighlight:down];
   395     [super drawRect:rect];
   398     [super drawRect:rect];
   396 }
   399 }
   397 @end
   400 @end
   398 
   401 
   399 @implementation QNSStatusItem
   402 @implementation QT_MANGLE_NAMESPACE(QNSStatusItem)
   400 
   403 
   401 -(id)initWithIcon:(QSystemTrayIcon*)i iconPrivate:(QSystemTrayIconPrivate *)iPrivate
   404 -(id)initWithIcon:(QSystemTrayIcon*)i iconPrivate:(QSystemTrayIconPrivate *)iPrivate
   402 {
   405 {
   403     self = [super init];
   406     self = [super init];
   404     if(self) {
   407     if(self) {
   405         icon = i;
   408         icon = i;
   406         iconPrivate = iPrivate;
   409         iconPrivate = iPrivate;
   407         item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
   410         item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
   408         imageCell = [[QNSImageView alloc] initWithParent:self];
   411         imageCell = [[QT_MANGLE_NAMESPACE(QNSImageView) alloc] initWithParent:self];
   409         [item setView: imageCell];
   412         [item setView: imageCell];
   410     }
   413     }
   411     return self;
   414     return self;
   412 }
   415 }
   413 -(void)dealloc {
   416 -(void)dealloc {
   431         NSRect windowRect = [window frame];
   434         NSRect windowRect = [window frame];
   432         return QRectF(windowRect.origin.x, screenRect.size.height-windowRect.origin.y-windowRect.size.height, windowRect.size.width, windowRect.size.height);
   435         return QRectF(windowRect.origin.x, screenRect.size.height-windowRect.origin.y-windowRect.size.height, windowRect.size.width, windowRect.size.height);
   433     }
   436     }
   434     return QRectF();
   437     return QRectF();
   435 }
   438 }
   436 - (void)triggerSelector:(id)sender {
   439 
       
   440 - (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton {
   437     Q_UNUSED(sender);
   441     Q_UNUSED(sender);
   438     if(!icon)
   442     if (!icon)
   439         return;
   443         return;
   440     qtsystray_sendActivated(icon, QSystemTrayIcon::Trigger);
   444 
       
   445     if (mouseButton == Qt::MidButton)
       
   446         qtsystray_sendActivated(icon, QSystemTrayIcon::MiddleClick);
       
   447     else
       
   448         qtsystray_sendActivated(icon, QSystemTrayIcon::Trigger);
       
   449 
   441     if (icon->contextMenu()) {
   450     if (icon->contextMenu()) {
   442 #if 0
       
   443         const QRectF geom = [self geometry];
       
   444         if(!geom.isNull()) {
       
   445             [[NSNotificationCenter defaultCenter] addObserver:imageCell
       
   446                                                   selector:@selector(menuTrackingDone:)
       
   447                                                   name:nil
       
   448                                                   object:self];
       
   449             icon->contextMenu()->exec(geom.topLeft().toPoint(), 0);
       
   450             [imageCell menuTrackingDone:nil];
       
   451         } else 
       
   452 #endif
       
   453         {
       
   454 #ifndef QT_MAC_USE_COCOA
   451 #ifndef QT_MAC_USE_COCOA
   455             [[[self item] view] removeAllToolTips];
   452         [[[self item] view] removeAllToolTips];
   456             iconPrivate->updateToolTip_sys();
   453         iconPrivate->updateToolTip_sys();
   457 #endif
   454 #endif
   458             NSMenu *m = [[QNSMenu alloc] initWithQMenu:icon->contextMenu()];
   455         NSMenu *m = [[QT_MANGLE_NAMESPACE(QNSMenu) alloc] initWithQMenu:icon->contextMenu()];
   459             [m setAutoenablesItems: NO];
   456         [m setAutoenablesItems: NO];
   460             [[NSNotificationCenter defaultCenter] addObserver:imageCell
   457         [[NSNotificationCenter defaultCenter] addObserver:imageCell
   461                                                   selector:@selector(menuTrackingDone:)
   458          selector:@selector(menuTrackingDone:)
   462                                                   name:NSMenuDidEndTrackingNotification
   459              name:NSMenuDidEndTrackingNotification
   463                                                   object:m];
   460                  object:m];
   464             [item popUpStatusItemMenu: m];
   461         [item popUpStatusItemMenu: m];
   465             [m release];
   462         [m release];
   466         }
   463     }
   467     }
   464 }
   468 }
   465 
   469 - (void)doubleClickSelector:(id)sender {
   466 - (void)doubleClickSelector:(id)sender {
   470     Q_UNUSED(sender);
   467     Q_UNUSED(sender);
   471     if(!icon)
   468     if(!icon)
   472         return;
   469         return;
   473     qtsystray_sendActivated(icon, QSystemTrayIcon::DoubleClick);
   470     qtsystray_sendActivated(icon, QSystemTrayIcon::DoubleClick);
   474 }
   471 }
       
   472 
   475 @end
   473 @end
   476 
   474 
   477 class QSystemTrayIconQMenu : public QMenu
   475 class QSystemTrayIconQMenu : public QMenu
   478 {
   476 {
   479 public:
   477 public:
   480     void doAboutToShow() { emit aboutToShow(); }
   478     void doAboutToShow() { emit aboutToShow(); }
   481 private:
   479 private:
   482     QSystemTrayIconQMenu();
   480     QSystemTrayIconQMenu();
   483 };
   481 };
   484 
   482 
   485 @implementation QNSMenu
   483 @implementation QT_MANGLE_NAMESPACE(QNSMenu)
   486 -(id)initWithQMenu:(QMenu*)qm {
   484 -(id)initWithQMenu:(QMenu*)qm {
   487     self = [super init];
   485     self = [super init];
   488     if(self) {
   486     if(self) {
   489         self->qmenu = qm;
   487         self->qmenu = qm;
   490         [self setDelegate:self];
   488         [self setDelegate:self];
   493 }
   491 }
   494 -(QMenu*)menu {
   492 -(QMenu*)menu {
   495     return qmenu;
   493     return qmenu;
   496 }
   494 }
   497 -(void)menuNeedsUpdate:(NSMenu*)nsmenu {
   495 -(void)menuNeedsUpdate:(NSMenu*)nsmenu {
   498     QNSMenu *menu = static_cast<QNSMenu *>(nsmenu);
   496     QT_MANGLE_NAMESPACE(QNSMenu) *menu = static_cast<QT_MANGLE_NAMESPACE(QNSMenu) *>(nsmenu);
   499     emit static_cast<QSystemTrayIconQMenu*>(menu->qmenu)->doAboutToShow();
   497     emit static_cast<QSystemTrayIconQMenu*>(menu->qmenu)->doAboutToShow();
   500     for(int i = [menu numberOfItems]-1; i >= 0; --i)
   498     for(int i = [menu numberOfItems]-1; i >= 0; --i)
   501         [menu removeItemAtIndex:i];
   499         [menu removeItemAtIndex:i];
   502     QList<QAction*> actions = menu->qmenu->actions();;
   500     QList<QAction*> actions = menu->qmenu->actions();;
   503     for(int i = 0; i < actions.size(); ++i) {
   501     for(int i = 0; i < actions.size(); ++i) {
   538                 NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(icon.pixmap(QSize(scale, scale))));
   536                 NSImage *nsimage = static_cast<NSImage *>(qt_mac_create_nsimage(icon.pixmap(QSize(scale, scale))));
   539                 [item setImage: nsimage];
   537                 [item setImage: nsimage];
   540                 [nsimage release];
   538                 [nsimage release];
   541             }
   539             }
   542             if(action->menu()) {
   540             if(action->menu()) {
   543                 QNSMenu *sub = [[QNSMenu alloc] initWithQMenu:action->menu()];
   541                 QT_MANGLE_NAMESPACE(QNSMenu) *sub = [[QT_MANGLE_NAMESPACE(QNSMenu) alloc] initWithQMenu:action->menu()];
   544                 [item setSubmenu:sub];
   542                 [item setSubmenu:sub];
   545             } else {
   543             } else {
   546                 [item setAction:@selector(selectedAction:)];
   544                 [item setAction:@selector(selectedAction:)];
   547                 [item setTarget:self];
   545                 [item setTarget:self];
   548             }
   546             }