--- a/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java Tue Oct 09 18:00:58 2012 +0400
+++ b/jdk/src/macosx/classes/sun/lwawt/macosx/CTrayIcon.java Tue Oct 09 20:59:41 2012 +0400
@@ -26,6 +26,7 @@
package sun.lwawt.macosx;
import sun.awt.SunToolkit;
+import sun.lwawt.macosx.event.NSEvent;
import javax.swing.*;
import java.awt.*;
@@ -42,6 +43,16 @@
private JDialog messageDialog;
private DialogEventHandler handler;
+ // In order to construct MouseEvent object, we need to specify a
+ // Component target. Because TrayIcon isn't Component's subclass,
+ // we use this dummy frame instead
+ private final Frame dummyFrame;
+
+ // A bitmask that indicates what mouse buttons produce MOUSE_CLICKED events
+ // on MOUSE_RELEASE. Click events are only generated if there were no drag
+ // events between MOUSE_PRESSED and MOUSE_RELEASED for particular button
+ private static int mouseClickButtons = 0;
+
CTrayIcon(TrayIcon target) {
super(0, true);
@@ -49,6 +60,7 @@
this.handler = null;
this.target = target;
this.popup = target.getPopupMenu();
+ this.dummyFrame = new Frame();
setPtr(createModel());
//if no one else is creating the peer.
@@ -119,6 +131,8 @@
disposeMessageDialog();
}
+ dummyFrame.dispose();
+
LWCToolkit.targetDisposedPeer(target, this);
target = null;
@@ -161,17 +175,78 @@
private native void setNativeImage(final long model, final long nsimage, final boolean autosize);
- //invocation from the AWTTrayIcon.m
- public void performAction() {
+ private void postEvent(final AWTEvent event) {
SunToolkit.executeOnEventHandlerThread(target, new Runnable() {
public void run() {
- final String cmd = target.getActionCommand();
- final ActionEvent event = new ActionEvent(target, ActionEvent.ACTION_PERFORMED, cmd);
SunToolkit.postEvent(SunToolkit.targetToAppContext(target), event);
}
});
}
+ //invocation from the AWTTrayIcon.m
+ private void handleMouseEvent(NSEvent nsEvent) {
+ int buttonNumber = nsEvent.getButtonNumber();
+ final SunToolkit tk = (SunToolkit)Toolkit.getDefaultToolkit();
+ if ((buttonNumber > 2 && !tk.areExtraMouseButtonsEnabled())
+ || buttonNumber > tk.getNumberOfButtons() - 1) {
+ return;
+ }
+
+ int jeventType = NSEvent.nsToJavaEventType(nsEvent.getType());
+
+ int jbuttonNumber = MouseEvent.NOBUTTON;
+ int jclickCount = 0;
+ if (jeventType != MouseEvent.MOUSE_MOVED) {
+ jbuttonNumber = NSEvent.nsToJavaButton(buttonNumber);
+ jclickCount = nsEvent.getClickCount();
+ }
+
+ int jmodifiers = NSEvent.nsToJavaMouseModifiers(buttonNumber,
+ nsEvent.getModifierFlags());
+ boolean isPopupTrigger = NSEvent.isPopupTrigger(jmodifiers);
+
+ int eventButtonMask = (jbuttonNumber > 0)?
+ MouseEvent.getMaskForButton(jbuttonNumber) : 0;
+ long when = System.currentTimeMillis();
+
+ if (jeventType == MouseEvent.MOUSE_PRESSED) {
+ mouseClickButtons |= eventButtonMask;
+ } else if (jeventType == MouseEvent.MOUSE_DRAGGED) {
+ mouseClickButtons = 0;
+ }
+
+ // The MouseEvent's coordinates are relative to screen
+ int absX = nsEvent.getAbsX();
+ int absY = nsEvent.getAbsY();
+
+ MouseEvent mouseEvent = new MouseEvent(dummyFrame, jeventType, when,
+ jmodifiers, absX, absY, absX, absY, jclickCount, isPopupTrigger,
+ jbuttonNumber);
+ mouseEvent.setSource(target);
+ postEvent(mouseEvent);
+
+ // fire ACTION event
+ if (jeventType == MouseEvent.MOUSE_PRESSED && isPopupTrigger) {
+ final String cmd = target.getActionCommand();
+ final ActionEvent event = new ActionEvent(target,
+ ActionEvent.ACTION_PERFORMED, cmd);
+ postEvent(event);
+ }
+
+ // synthesize CLICKED event
+ if (jeventType == MouseEvent.MOUSE_RELEASED) {
+ if ((mouseClickButtons & eventButtonMask) != 0) {
+ MouseEvent clickEvent = new MouseEvent(dummyFrame,
+ MouseEvent.MOUSE_CLICKED, when, jmodifiers, absX, absY,
+ absX, absY, jclickCount, isPopupTrigger, jbuttonNumber);
+ clickEvent.setSource(target);
+ postEvent(clickEvent);
+ }
+
+ mouseClickButtons &= ~eventButtonMask;
+ }
+ }
+
private native Point2D nativeGetIconLocation(long trayIconModel);
public void displayMessageOnEDT(String caption, String text,
@@ -256,6 +331,9 @@
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
dialog.setModal(false);
+ dialog.setModalExclusionType(Dialog.ModalExclusionType.TOOLKIT_EXCLUDE);
+ dialog.setAlwaysOnTop(true);
+ dialog.setAutoRequestFocus(false);
dialog.setResizable(false);
dialog.setContentPane(op);
--- a/jdk/src/macosx/native/sun/awt/CTrayIcon.h Tue Oct 09 18:00:58 2012 +0400
+++ b/jdk/src/macosx/native/sun/awt/CTrayIcon.h Tue Oct 09 20:59:41 2012 +0400
@@ -53,6 +53,7 @@
- (jobject) peer;
- (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize;
- (NSPoint) getLocationOnScreen;
+- (void) deliverJavaMouseEvent:(NSEvent*) event;
@end //AWTTrayIcon
@@ -68,6 +69,7 @@
-(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon;
-(void)setHighlighted:(BOOL)aFlag;
-(void)setImage:(NSImage*)anImage;
+-(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon;
@end //AWTTrayIconView
--- a/jdk/src/macosx/native/sun/awt/CTrayIcon.m Tue Oct 09 18:00:58 2012 +0400
+++ b/jdk/src/macosx/native/sun/awt/CTrayIcon.m Tue Oct 09 20:59:41 2012 +0400
@@ -29,6 +29,7 @@
#import "CTrayIcon.h"
#import "ThreadUtilities.h"
#include "GeomUtilities.h"
+#import "LWCToolkit.h"
#define kImageInset 4.0
@@ -76,8 +77,9 @@
// Its a bad idea to force the item to release our view by setting
// 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
- // to nil since we are done with it.
+ // and tray icon to nil since we are done with it.
[view setImage: nil];
+ [view setTrayIcon: nil];
[view release];
[theItem release];
@@ -115,6 +117,45 @@
return [[view window] convertBaseToScreen: NSZeroPoint];
}
+-(void) deliverJavaMouseEvent: (NSEvent *) event {
+ [AWTToolkit eventCountPlusPlus];
+
+ JNIEnv *env = [ThreadUtilities getJNIEnv];
+
+ NSPoint eventLocation = [event locationInWindow];
+ NSPoint localPoint = [view convertPoint: eventLocation fromView: nil];
+ localPoint.y = [view bounds].size.height - localPoint.y;
+
+ NSPoint absP = [NSEvent mouseLocation];
+ NSEventType type = [event type];
+
+ NSRect screenRect = [[NSScreen mainScreen] frame];
+ absP.y = screenRect.size.height - absP.y;
+ jint clickCount;
+
+ clickCount = [event clickCount];
+
+ static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/event/NSEvent");
+ static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDD)V");
+ jobject jEvent = JNFNewObject(env, jctor_NSEvent,
+ [event type],
+ [event modifierFlags],
+ clickCount,
+ [event buttonNumber],
+ (jint)localPoint.x, (jint)localPoint.y,
+ (jint)absP.x, (jint)absP.y,
+ [event deltaY],
+ [event deltaX]);
+ if (jEvent == nil) {
+ // Unable to create event by some reason.
+ return;
+ }
+
+ static JNF_CLASS_CACHE(jc_TrayIcon, "sun/lwawt/macosx/CTrayIcon");
+ static JNF_MEMBER_CACHE(jm_handleMouseEvent, jc_TrayIcon, "handleMouseEvent", "(Lsun/lwawt/macosx/event/NSEvent;)V");
+ JNFCallVoidMethod(env, peer, jm_handleMouseEvent, jEvent);
+}
+
@end //AWTTrayIcon
//================================================
@@ -123,7 +164,7 @@
-(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon {
self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)];
- trayIcon = theTrayIcon;
+ [self setTrayIcon: theTrayIcon];
isHighlighted = NO;
image = nil;
@@ -153,6 +194,10 @@
}
}
+-(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon {
+ trayIcon = theTrayIcon;
+}
+
- (void)menuWillOpen:(NSMenu *)menu
{
[self setHighlighted:YES];
@@ -191,30 +236,57 @@
];
}
-- (void) mouseDown:(NSEvent *)e {
- //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");
- static JNF_MEMBER_CACHE(jm_performAction, jc_CTrayIcon, "performAction", "()V");
- 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];
- } else {
- JNFCallVoidMethod(env, trayIcon.peer, jm_performAction);
+- (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];
+ }
}
}
-- (void) rightMouseDown:(NSEvent *)e {
- // Call CTrayIcon.performAction() method on right mouse press
- JNIEnv *env = [ThreadUtilities getJNIEnv];
- static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon");
- static JNF_MEMBER_CACHE(jm_performAction, jc_CTrayIcon, "performAction", "()V");
- JNFCallVoidMethod(env, trayIcon.peer, jm_performAction);
+- (void) mouseUp:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) mouseDragged:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) rightMouseDown:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) rightMouseUp:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) rightMouseDragged:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) otherMouseDown:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) otherMouseUp:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
+}
+
+- (void) otherMouseDragged:(NSEvent *)event {
+ [trayIcon deliverJavaMouseEvent: event];
}