From 8e38376b411cc3190cad04f497b6efcde8842173 Mon Sep 17 00:00:00 2001 From: peterz Date: Fri, 2 Oct 2020 13:47:42 +0300 Subject: [PATCH 1/3] 8252015: [macos11] java.awt.TrayIcon requires updates for template images --- .../classes/sun/lwawt/macosx/CTrayIcon.java | 6 +- .../native/libawt_lwawt/awt/CTrayIcon.h | 30 ++- .../native/libawt_lwawt/awt/CTrayIcon.m | 242 ++++++++---------- 3 files changed, 133 insertions(+), 145 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java index faa7571246117..0a45ee9e8c808 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java @@ -194,6 +194,8 @@ public void updateImage() { } void updateNativeImage(Image image) { + boolean imageTemplate = Boolean.parseBoolean(System.getProperty("sun.awt.enableTemplateImages", "false")); + MediaTracker tracker = new MediaTracker(new Button("")); tracker.addImage(image, 0); try { @@ -211,13 +213,13 @@ void updateNativeImage(Image image) { if (cimage != null) { cimage.execute(imagePtr -> { execute(ptr -> { - setNativeImage(ptr, imagePtr, imageAutoSize); + setNativeImage(ptr, imagePtr, imageAutoSize, imageTemplate); }); }); } } - private native void setNativeImage(final long model, final long nsimage, final boolean autosize); + private native void setNativeImage(final long model, final long nsimage, final boolean autosize, final boolean template); private void postEvent(final AWTEvent event) { SunToolkit.executeOnEventHandlerThread(target, new Runnable() { diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h index 49e0e7d8645bd..07b00b7a74f57 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h @@ -37,35 +37,45 @@ extern "C" { #endif -@class AWTTrayIconView; +@class AWTTrayIconDelegate; /* * AWTTrayIcon */ -@interface AWTTrayIcon : NSObject { +@interface AWTTrayIcon : NSResponder { jobject peer; - AWTTrayIconView *view; + AWTTrayIconDelegate *menuDelegate; NSStatusItem *theItem; + NSTrackingArea *trackingArea; } - (id) initWithPeer:(jobject)thePeer; - (void) setTooltip:(NSString *)tooltip; - (NSStatusItem *)theItem; - (jobject) peer; -- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize; +- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize template:(BOOL)isTemplate; - (NSPoint) getLocationOnScreen; - (void) deliverJavaMouseEvent:(NSEvent*) event; - +- (void) setMenu:(NSMenu *)menu; +- (void) mouseDown:(id)sender; +- (void) mouseUp:(NSEvent *)event; +- (void) mouseDragged:(NSEvent *)event; +- (void) mouseMoved: (NSEvent *)event; +- (void) rightMouseDown:(NSEvent *)event; +- (void) rightMouseUp:(NSEvent *)event; +- (void) rightMouseDragged:(NSEvent *)event; +- (void) otherMouseDown:(NSEvent *)event; +- (void) otherMouseUp:(NSEvent *)event; +- (void) otherMouseDragged:(NSEvent *)event; @end //AWTTrayIcon //================================================================================== /* - * AWTTrayIconView */ -@interface AWTTrayIconView : NSView { + * AWTTrayIconDelegate */ +@interface AWTTrayIconDelegate : NSObject { @public AWTTrayIcon *trayIcon; NSImage* image; - NSTrackingArea *trackingArea; BOOL isHighlighted; } -(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon; @@ -73,8 +83,10 @@ extern "C" { -(void)setImage:(NSImage*)anImage; -(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon; -(void)addTrackingArea; +-(void)updateMenuRes; +-(NSMenu *)getMenu; -@end //AWTTrayIconView +@end //AWTTrayIconDelegate #ifdef __cplusplus } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m index 23e17fb7b1494..ee6ae6b79b0db 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m @@ -67,12 +67,28 @@ - (id) initWithPeer:(jobject)thePeer { theItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; [theItem retain]; - view = [[AWTTrayIconView alloc] initWithTrayIcon:self]; - [theItem setView:view]; + menuDelegate = [[AWTTrayIconDelegate alloc] initWithTrayIcon:self]; + + [theItem.button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown]; + theItem.button.action = @selector(mouseDown:); + theItem.button.target = self; + + trackingArea = [[NSTrackingArea alloc] initWithRect: CGRectZero + options: NSTrackingMouseMoved | + NSTrackingInVisibleRect | + NSTrackingActiveAlways + owner: self + userInfo: nil]; + + [[theItem button] addTrackingArea:trackingArea]; return self; } +-(void) setMenu:(NSMenu *) menu{ + [theItem setMenu: menu]; +} + -(void) dealloc { JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; JNFDeleteGlobalRef(env, peer); @@ -83,17 +99,23 @@ -(void) dealloc { // the item's view to nil: it can lead to a crash in some scenarios. // The item will release the view later on, so just set the view's image // and tray icon to nil since we are done with it. - [view setImage: nil]; - [view setTrayIcon: nil]; - [view release]; + [menuDelegate setImage: nil]; + [menuDelegate setTrayIcon: nil]; + [menuDelegate release]; + + [trackingArea release]; [theItem release]; [super dealloc]; } - (void) setTooltip:(NSString *) tooltip{ - [view setToolTip:tooltip]; + [[theItem button] setToolTip:tooltip]; +} + +- (void) updateMenuRes { + [menuDelegate updateMenuRes]; } -(NSStatusItem *) theItem{ @@ -104,7 +126,7 @@ - (jobject) peer{ return peer; } -- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize { +- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize template:(BOOL)isTemplate { NSSize imageSize = [imagePtr size]; NSSize scaledSize = ScaledImageSizeForStatusBar(imageSize, autosize); if (imageSize.width != scaledSize.width || @@ -114,12 +136,10 @@ - (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize { CGFloat itemLength = scaledSize.width + 2.0*kImageInset; [theItem setLength:itemLength]; + theItem.button.image = imagePtr; - [view setImage:imagePtr]; -} - -- (NSPoint) getLocationOnScreen { - return [[view window] convertBaseToScreen: NSZeroPoint]; + [[[theItem button] image] setTemplate: isTemplate]; + [[theItem button] setNeedsDisplay: true]; } -(void) deliverJavaMouseEvent: (NSEvent *) event { @@ -128,8 +148,9 @@ -(void) deliverJavaMouseEvent: (NSEvent *) event { JNIEnv *env = [ThreadUtilities getJNIEnv]; NSPoint eventLocation = [event locationInWindow]; - NSPoint localPoint = [view convertPoint: eventLocation fromView: nil]; - localPoint.y = [view bounds].size.height - localPoint.y; + + NSPoint localPoint = [[theItem button] convertPoint: eventLocation fromView: nil]; + localPoint.y = [[theItem button] bounds].size.height - localPoint.y; NSPoint absP = [NSEvent mouseLocation]; NSEventType type = [event type]; @@ -166,160 +187,113 @@ -(void) deliverJavaMouseEvent: (NSEvent *) event { (*env)->DeleteLocalRef(env, jEvent); } -@end //AWTTrayIcon -//================================================ - -@implementation AWTTrayIconView --(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon { - self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)]; +- (void) mouseDown:(id)sender { + [self deliverJavaMouseEvent: [NSApp currentEvent]]; - [self setTrayIcon: theTrayIcon]; - isHighlighted = NO; - image = nil; - trackingArea = nil; + //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr. + JNIEnv *env = [ThreadUtilities getJNIEnv]; + static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); + static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); + jlong res = JNFCallLongMethod(env, menuDelegate->trayIcon->peer, jm_getPopupMenuModel); + + if (res != 0) { + CPopupMenu *cmenu = jlong_to_ptr(res); + NSMenu* menu = [cmenu menu]; + [menu setDelegate:menuDelegate]; + [theItem popUpStatusItemMenu: menu]; + } +} - [self addTrackingArea]; - return self; +- (void) mouseUp:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)addTrackingArea { - NSTrackingAreaOptions options = NSTrackingMouseMoved | - NSTrackingInVisibleRect | - NSTrackingActiveAlways; - trackingArea = [[NSTrackingArea alloc] initWithRect: CGRectZero - options: options - owner: self - userInfo: nil]; - [self addTrackingArea:trackingArea]; +- (void) mouseDragged:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } --(void) dealloc { - [image release]; - [trackingArea release]; - [super dealloc]; +- (void) mouseMoved: (NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)setHighlighted:(BOOL)aFlag -{ - if (isHighlighted != aFlag) { - isHighlighted = aFlag; - [self setNeedsDisplay:YES]; - } +- (void) rightMouseDown:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)setImage:(NSImage*)anImage { - [anImage retain]; - [image release]; - image = anImage; - - if (image != nil) { - [self setNeedsDisplay:YES]; - } +- (void) rightMouseUp:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } --(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon { - trayIcon = theTrayIcon; +- (void) rightMouseDragged:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)menuWillOpen:(NSMenu *)menu -{ - [self setHighlighted:YES]; +- (void) otherMouseDown:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)menuDidClose:(NSMenu *)menu -{ - [menu setDelegate:nil]; - [self setHighlighted:NO]; +- (void) otherMouseUp:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)drawRect:(NSRect)dirtyRect -{ - if (image == nil) { - return; - } - - NSRect bounds = [self bounds]; - NSSize imageSize = [image size]; - - NSRect drawRect = {{ (bounds.size.width - imageSize.width) / 2.0, - (bounds.size.height - imageSize.height) / 2.0 }, imageSize}; - - // don't cover bottom pixels of the status bar with the image - if (drawRect.origin.y < 1.0) { - drawRect.origin.y = 1.0; - } - drawRect = NSIntegralRect(drawRect); - - [trayIcon.theItem drawStatusBarBackgroundInRect:bounds - withHighlight:isHighlighted]; - [image drawInRect:drawRect - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0 - ]; +- (void) otherMouseDragged:(NSEvent *)event { + [self deliverJavaMouseEvent: event]; } -- (void)mouseDown:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; - - // don't show the menu on ctrl+click: it triggers ACTION event, like right click - if (([event modifierFlags] & NSControlKeyMask) == 0) { - //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr. - JNIEnv *env = [ThreadUtilities getJNIEnv]; - static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); - static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); - jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel); - - if (res != 0) { - CPopupMenu *cmenu = jlong_to_ptr(res); - NSMenu* menu = [cmenu menu]; - [menu setDelegate:self]; - [trayIcon.theItem popUpStatusItemMenu:menu]; - [self setNeedsDisplay:YES]; - } - } -} +@end //AWTTrayIcon +//================================================ -- (void) mouseUp:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; -} +@implementation AWTTrayIconDelegate -- (void) mouseDragged:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; -} +-(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon { + self = [super init]; -- (void) mouseMoved: (NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; -} + [self setTrayIcon: theTrayIcon]; + image = nil; -- (void) rightMouseDown:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; + return self; } -- (void) rightMouseUp:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; +-(void) dealloc { + [image release]; + [super dealloc]; } -- (void) rightMouseDragged:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; -} +-(void)setImage:(NSImage*)anImage { + [anImage retain]; + [image release]; + image = anImage; -- (void) otherMouseDown:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; + if (image != nil) { + [self setNeedsDisplay:YES]; + } } -- (void) otherMouseUp:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; +-(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon { + trayIcon = theTrayIcon; } -- (void) otherMouseDragged:(NSEvent *)event { - [trayIcon deliverJavaMouseEvent: event]; +- (NSMenu *) getMenu { + JNIEnv *env = [ThreadUtilities getJNIEnv]; + static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); + static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); + jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel); + if (res != 0) { + CPopupMenu *cmenu = jlong_to_ptr(res); + NSMenu* menu = [cmenu menu]; + [menu setDelegate:self]; + return menu; + } else { + NSMenu* menu = [[NSMenu alloc] initWithTitle:@""]; + [menu setDelegate:self]; + return menu; + } + return NULL; } - -@end //AWTTrayIconView +@end //AWTTrayIconDelegate //================================================ /* @@ -375,15 +349,15 @@ - (void) otherMouseDragged:(NSEvent *)event { /* * Class: sun_lwawt_macosx_CTrayIcon * Method: setNativeImage - * Signature: (JJZ)V + * Signature: (JJZZ)V */ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTrayIcon_setNativeImage -(JNIEnv *env, jobject self, jlong model, jlong imagePtr, jboolean autosize) { +(JNIEnv *env, jobject self, jlong model, jlong imagePtr, jboolean autosize, jboolean isTemplate) { JNF_COCOA_ENTER(env); AWTTrayIcon *icon = jlong_to_ptr(model); [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - [icon setImage:jlong_to_ptr(imagePtr) sizing:autosize]; + [icon setImage:jlong_to_ptr(imagePtr) sizing:autosize template:isTemplate]; }]; JNF_COCOA_EXIT(env); From 585299954948c6075f73ec31df36d372dc523080 Mon Sep 17 00:00:00 2001 From: peterz Date: Wed, 11 Nov 2020 12:26:30 +0300 Subject: [PATCH 2/3] 8252015: Added property description to TrayIcon javadoc --- src/java.desktop/share/classes/java/awt/TrayIcon.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/java.desktop/share/classes/java/awt/TrayIcon.java b/src/java.desktop/share/classes/java/awt/TrayIcon.java index ccbf0ae0599b2..12482912da01a 100644 --- a/src/java.desktop/share/classes/java/awt/TrayIcon.java +++ b/src/java.desktop/share/classes/java/awt/TrayIcon.java @@ -71,6 +71,15 @@ * a {@code TrayIcon}. Otherwise the constructor will throw a * SecurityException. * + *

+ * @implnote + * When the {@systemProperty apple.awt.enableTemplateImages} property is + * set, all images associated with instances of this class are treated + * as template images by the native desktop system. This means all color + * information is discarded, and the image is adapted automatically to + * be visible when desktop theme and/or colors change. This property + * only affects MacOSX. + * *

See the {@link SystemTray} class overview for an example on how * to use the {@code TrayIcon} API. * From 3027d8211d900bc61341173786574e4e9927c56a Mon Sep 17 00:00:00 2001 From: peterz Date: Fri, 4 Dec 2020 17:35:56 +0300 Subject: [PATCH 3/3] 8252015: fixed failing tests; renamed system property --- .../classes/sun/lwawt/macosx/CTrayIcon.java | 10 +- .../native/libawt_lwawt/awt/CTrayIcon.h | 30 +-- .../native/libawt_lwawt/awt/CTrayIcon.m | 212 +++++++++--------- 3 files changed, 122 insertions(+), 130 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java index 0a45ee9e8c808..b92c62f4620fe 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java @@ -45,6 +45,8 @@ import java.awt.image.BufferedImage; import java.awt.image.ImageObserver; import java.awt.peer.TrayIconPeer; +import java.security.AccessController; +import java.security.PrivilegedAction; import javax.swing.Icon; import javax.swing.UIManager; @@ -69,6 +71,10 @@ public class CTrayIcon extends CFRetainedResource implements TrayIconPeer { // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button private static int mouseClickButtons = 0; + private final static boolean useTemplateImages = AccessController.doPrivileged((PrivilegedAction) + () -> Boolean.getBoolean("apple.awt.enableTemplateImages") + ); + CTrayIcon(TrayIcon target) { super(0, true); @@ -194,8 +200,6 @@ public void updateImage() { } void updateNativeImage(Image image) { - boolean imageTemplate = Boolean.parseBoolean(System.getProperty("sun.awt.enableTemplateImages", "false")); - MediaTracker tracker = new MediaTracker(new Button("")); tracker.addImage(image, 0); try { @@ -213,7 +217,7 @@ void updateNativeImage(Image image) { if (cimage != null) { cimage.execute(imagePtr -> { execute(ptr -> { - setNativeImage(ptr, imagePtr, imageAutoSize, imageTemplate); + setNativeImage(ptr, imagePtr, imageAutoSize, useTemplateImages); }); }); } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h index 07b00b7a74f57..458594157be97 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.h @@ -37,16 +37,15 @@ extern "C" { #endif -@class AWTTrayIconDelegate; +@class AWTTrayIconView; /* * AWTTrayIcon */ -@interface AWTTrayIcon : NSResponder { +@interface AWTTrayIcon : NSObject { jobject peer; - AWTTrayIconDelegate *menuDelegate; + AWTTrayIconView *view; NSStatusItem *theItem; - NSTrackingArea *trackingArea; } - (id) initWithPeer:(jobject)thePeer; @@ -56,37 +55,24 @@ extern "C" { - (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize template:(BOOL)isTemplate; - (NSPoint) getLocationOnScreen; - (void) deliverJavaMouseEvent:(NSEvent*) event; -- (void) setMenu:(NSMenu *)menu; -- (void) mouseDown:(id)sender; -- (void) mouseUp:(NSEvent *)event; -- (void) mouseDragged:(NSEvent *)event; -- (void) mouseMoved: (NSEvent *)event; -- (void) rightMouseDown:(NSEvent *)event; -- (void) rightMouseUp:(NSEvent *)event; -- (void) rightMouseDragged:(NSEvent *)event; -- (void) otherMouseDown:(NSEvent *)event; -- (void) otherMouseUp:(NSEvent *)event; -- (void) otherMouseDragged:(NSEvent *)event; + @end //AWTTrayIcon //================================================================================== /* - * AWTTrayIconDelegate */ -@interface AWTTrayIconDelegate : NSObject { + * AWTTrayIconView */ +@interface AWTTrayIconView : NSStatusBarButton { @public AWTTrayIcon *trayIcon; - NSImage* image; + NSTrackingArea *trackingArea; BOOL isHighlighted; } -(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon; -(void)setHighlighted:(BOOL)aFlag; --(void)setImage:(NSImage*)anImage; -(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon; -(void)addTrackingArea; --(void)updateMenuRes; --(NSMenu *)getMenu; -@end //AWTTrayIconDelegate +@end //AWTTrayIconView #ifdef __cplusplus } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m index ee6ae6b79b0db..233888591694f 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m @@ -67,28 +67,12 @@ - (id) initWithPeer:(jobject)thePeer { theItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; [theItem retain]; - menuDelegate = [[AWTTrayIconDelegate alloc] initWithTrayIcon:self]; - - [theItem.button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown]; - theItem.button.action = @selector(mouseDown:); - theItem.button.target = self; - - trackingArea = [[NSTrackingArea alloc] initWithRect: CGRectZero - options: NSTrackingMouseMoved | - NSTrackingInVisibleRect | - NSTrackingActiveAlways - owner: self - userInfo: nil]; - - [[theItem button] addTrackingArea:trackingArea]; + view = [[AWTTrayIconView alloc] initWithTrayIcon:self]; + [theItem setView:view]; return self; } --(void) setMenu:(NSMenu *) menu{ - [theItem setMenu: menu]; -} - -(void) dealloc { JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; JNFDeleteGlobalRef(env, peer); @@ -99,23 +83,17 @@ -(void) dealloc { // the item's view to nil: it can lead to a crash in some scenarios. // The item will release the view later on, so just set the view's image // and tray icon to nil since we are done with it. + [view setImage: nil]; + [view setTrayIcon: nil]; + [view release]; - [menuDelegate setImage: nil]; - [menuDelegate setTrayIcon: nil]; - [menuDelegate release]; - - [trackingArea release]; [theItem release]; [super dealloc]; } - (void) setTooltip:(NSString *) tooltip{ - [[theItem button] setToolTip:tooltip]; -} - -- (void) updateMenuRes { - [menuDelegate updateMenuRes]; + [view setToolTip:tooltip]; } -(NSStatusItem *) theItem{ @@ -136,10 +114,13 @@ - (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize template:(BOOL)isTe CGFloat itemLength = scaledSize.width + 2.0*kImageInset; [theItem setLength:itemLength]; - theItem.button.image = imagePtr; - [[[theItem button] image] setTemplate: isTemplate]; - [[theItem button] setNeedsDisplay: true]; + [imagePtr setTemplate: isTemplate]; + [view setImage:imagePtr]; +} + +- (NSPoint) getLocationOnScreen { + return [[view window] convertBaseToScreen: NSZeroPoint]; } -(void) deliverJavaMouseEvent: (NSEvent *) event { @@ -148,9 +129,8 @@ -(void) deliverJavaMouseEvent: (NSEvent *) event { JNIEnv *env = [ThreadUtilities getJNIEnv]; NSPoint eventLocation = [event locationInWindow]; - - NSPoint localPoint = [[theItem button] convertPoint: eventLocation fromView: nil]; - localPoint.y = [[theItem button] bounds].size.height - localPoint.y; + NSPoint localPoint = [view convertPoint: eventLocation fromView: nil]; + localPoint.y = [view bounds].size.height - localPoint.y; NSPoint absP = [NSEvent mouseLocation]; NSEventType type = [event type]; @@ -187,113 +167,135 @@ -(void) deliverJavaMouseEvent: (NSEvent *) event { (*env)->DeleteLocalRef(env, jEvent); } +@end //AWTTrayIcon +//================================================ -- (void) mouseDown:(id)sender { - [self deliverJavaMouseEvent: [NSApp currentEvent]]; +@implementation AWTTrayIconView - //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr. - JNIEnv *env = [ThreadUtilities getJNIEnv]; - static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); - static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); - jlong res = JNFCallLongMethod(env, menuDelegate->trayIcon->peer, jm_getPopupMenuModel); - - if (res != 0) { - CPopupMenu *cmenu = jlong_to_ptr(res); - NSMenu* menu = [cmenu menu]; - [menu setDelegate:menuDelegate]; - [theItem popUpStatusItemMenu: menu]; - } -} +-(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon { + self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [self setTrayIcon: theTrayIcon]; + [self setImage: nil]; + isHighlighted = NO; + trackingArea = nil; -- (void) mouseUp:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; -} + [self addTrackingArea]; -- (void) mouseDragged:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; + return self; } -- (void) mouseMoved: (NSEvent *)event { - [self deliverJavaMouseEvent: event]; +- (void)addTrackingArea { + NSTrackingAreaOptions options = NSTrackingMouseMoved | + NSTrackingInVisibleRect | + NSTrackingActiveAlways; + trackingArea = [[NSTrackingArea alloc] initWithRect: CGRectZero + options: options + owner: self + userInfo: nil]; + [self addTrackingArea:trackingArea]; } -- (void) rightMouseDown:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; +-(void) dealloc { + [trackingArea release]; + [super dealloc]; } -- (void) rightMouseUp:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; +- (void)setHighlighted:(BOOL)aFlag +{ + if (isHighlighted != aFlag) { + isHighlighted = aFlag; + [self setNeedsDisplay:YES]; + } } -- (void) rightMouseDragged:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; +-(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon { + trayIcon = theTrayIcon; } -- (void) otherMouseDown:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; +- (void)menuWillOpen:(NSMenu *)menu +{ + [self setHighlighted:YES]; } -- (void) otherMouseUp:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; +- (void)menuDidClose:(NSMenu *)menu +{ + [menu setDelegate:nil]; + [self setHighlighted:NO]; } -- (void) otherMouseDragged:(NSEvent *)event { - [self deliverJavaMouseEvent: event]; +- (void)drawRect:(NSRect)dirtyRect +{ + if (self.image == nil) { + return; + } + + NSRect bounds = [self bounds]; + [trayIcon.theItem drawStatusBarBackgroundInRect:bounds + withHighlight:isHighlighted]; + + [super drawRect: dirtyRect]; } -@end //AWTTrayIcon -//================================================ +- (void)mouseDown:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; + + // don't show the menu on ctrl+click: it triggers ACTION event, like right click + if (([event modifierFlags] & NSControlKeyMask) == 0) { + //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr. + JNIEnv *env = [ThreadUtilities getJNIEnv]; + static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); + static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); + jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel); + + if (res != 0) { + CPopupMenu *cmenu = jlong_to_ptr(res); + NSMenu* menu = [cmenu menu]; + [menu setDelegate:self]; + [trayIcon.theItem popUpStatusItemMenu:menu]; + [self setNeedsDisplay:YES]; + } + } +} -@implementation AWTTrayIconDelegate +- (void) mouseUp:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} --(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon { - self = [super init]; +- (void) mouseDragged:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} - [self setTrayIcon: theTrayIcon]; - image = nil; +- (void) mouseMoved: (NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} - return self; +- (void) rightMouseDown:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; } --(void) dealloc { - [image release]; - [super dealloc]; +- (void) rightMouseUp:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; } --(void)setImage:(NSImage*)anImage { - [anImage retain]; - [image release]; - image = anImage; +- (void) rightMouseDragged:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; +} - if (image != nil) { - [self setNeedsDisplay:YES]; - } +- (void) otherMouseDown:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; } --(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon { - trayIcon = theTrayIcon; +- (void) otherMouseUp:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; } -- (NSMenu *) getMenu { - JNIEnv *env = [ThreadUtilities getJNIEnv]; - static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon"); - static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J"); - jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel); - if (res != 0) { - CPopupMenu *cmenu = jlong_to_ptr(res); - NSMenu* menu = [cmenu menu]; - [menu setDelegate:self]; - return menu; - } else { - NSMenu* menu = [[NSMenu alloc] initWithTitle:@""]; - [menu setDelegate:self]; - return menu; - } - return NULL; +- (void) otherMouseDragged:(NSEvent *)event { + [trayIcon deliverJavaMouseEvent: event]; } -@end //AWTTrayIconDelegate + +@end //AWTTrayIconView //================================================ /*