jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CTrayIcon.m
changeset 26751 70bac69b37c9
parent 25859 3317bb8137f4
child 32872 abca6234313d
equal deleted inserted replaced
26750:d0d6c64a2e2b 26751:70bac69b37c9
       
     1 /*
       
     2  * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #import <AppKit/AppKit.h>
       
    27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
       
    28 #import "jni_util.h"
       
    29 
       
    30 #import "CTrayIcon.h"
       
    31 #import "ThreadUtilities.h"
       
    32 #include "GeomUtilities.h"
       
    33 #import "LWCToolkit.h"
       
    34 
       
    35 #define kImageInset 4.0
       
    36 
       
    37 /**
       
    38  * If the image of the specified size won't fit into the status bar,
       
    39  * then scale it down proprtionally. Otherwise, leave it as is.
       
    40  */
       
    41 static NSSize ScaledImageSizeForStatusBar(NSSize imageSize) {
       
    42     NSRect imageRect = NSMakeRect(0.0, 0.0, imageSize.width, imageSize.height);
       
    43 
       
    44     // There is a black line at the bottom of the status bar
       
    45     // that we don't want to cover with image pixels.
       
    46     CGFloat desiredHeight = [[NSStatusBar systemStatusBar] thickness] - 1.0;
       
    47     CGFloat scaleFactor = MIN(1.0, desiredHeight/imageSize.height);
       
    48 
       
    49     imageRect.size.width *= scaleFactor;
       
    50     imageRect.size.height *= scaleFactor;
       
    51     imageRect = NSIntegralRect(imageRect);
       
    52 
       
    53     return imageRect.size;
       
    54 }
       
    55 
       
    56 @implementation AWTTrayIcon
       
    57 
       
    58 - (id) initWithPeer:(jobject)thePeer {
       
    59     if (!(self = [super init])) return nil;
       
    60 
       
    61     peer = thePeer;
       
    62 
       
    63     theItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
       
    64     [theItem retain];
       
    65 
       
    66     view = [[AWTTrayIconView alloc] initWithTrayIcon:self];
       
    67     [theItem setView:view];
       
    68 
       
    69     return self;
       
    70 }
       
    71 
       
    72 -(void) dealloc {
       
    73     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
       
    74     JNFDeleteGlobalRef(env, peer);
       
    75 
       
    76     [[NSStatusBar systemStatusBar] removeStatusItem: theItem];
       
    77 
       
    78     // Its a bad idea to force the item to release our view by setting
       
    79     // the item's view to nil: it can lead to a crash in some scenarios.
       
    80     // The item will release the view later on, so just set the view's image
       
    81     // and tray icon to nil since we are done with it.
       
    82     [view setImage: nil];
       
    83     [view setTrayIcon: nil];
       
    84     [view release];
       
    85 
       
    86     [theItem release];
       
    87 
       
    88     [super dealloc];
       
    89 }
       
    90 
       
    91 - (void) setTooltip:(NSString *) tooltip{
       
    92     [view setToolTip:tooltip];
       
    93 }
       
    94 
       
    95 -(NSStatusItem *) theItem{
       
    96     return theItem;
       
    97 }
       
    98 
       
    99 - (jobject) peer{
       
   100     return peer;
       
   101 }
       
   102 
       
   103 - (void) setImage:(NSImage *) imagePtr sizing:(BOOL)autosize{
       
   104     NSSize imageSize = [imagePtr size];
       
   105     NSSize scaledSize = ScaledImageSizeForStatusBar(imageSize);
       
   106     if (imageSize.width != scaledSize.width ||
       
   107         imageSize.height != scaledSize.height) {
       
   108         [imagePtr setSize: scaledSize];
       
   109     }
       
   110 
       
   111     CGFloat itemLength = scaledSize.width + 2.0*kImageInset;
       
   112     [theItem setLength:itemLength];
       
   113 
       
   114     [view setImage:imagePtr];
       
   115 }
       
   116 
       
   117 - (NSPoint) getLocationOnScreen {
       
   118     return [[view window] convertBaseToScreen: NSZeroPoint];
       
   119 }
       
   120 
       
   121 -(void) deliverJavaMouseEvent: (NSEvent *) event {
       
   122     [AWTToolkit eventCountPlusPlus];
       
   123 
       
   124     JNIEnv *env = [ThreadUtilities getJNIEnv];
       
   125 
       
   126     NSPoint eventLocation = [event locationInWindow];
       
   127     NSPoint localPoint = [view convertPoint: eventLocation fromView: nil];
       
   128     localPoint.y = [view bounds].size.height - localPoint.y;
       
   129 
       
   130     NSPoint absP = [NSEvent mouseLocation];
       
   131     NSEventType type = [event type];
       
   132 
       
   133     NSRect screenRect = [[NSScreen mainScreen] frame];
       
   134     absP.y = screenRect.size.height - absP.y;
       
   135     jint clickCount;
       
   136 
       
   137     clickCount = [event clickCount];
       
   138 
       
   139     static JNF_CLASS_CACHE(jc_NSEvent, "sun/lwawt/macosx/NSEvent");
       
   140     static JNF_CTOR_CACHE(jctor_NSEvent, jc_NSEvent, "(IIIIIIIIDD)V");
       
   141     jobject jEvent = JNFNewObject(env, jctor_NSEvent,
       
   142                                   [event type],
       
   143                                   [event modifierFlags],
       
   144                                   clickCount,
       
   145                                   [event buttonNumber],
       
   146                                   (jint)localPoint.x, (jint)localPoint.y,
       
   147                                   (jint)absP.x, (jint)absP.y,
       
   148                                   [event deltaY],
       
   149                                   [event deltaX]);
       
   150     CHECK_NULL(jEvent);
       
   151 
       
   152     static JNF_CLASS_CACHE(jc_TrayIcon, "sun/lwawt/macosx/CTrayIcon");
       
   153     static JNF_MEMBER_CACHE(jm_handleMouseEvent, jc_TrayIcon, "handleMouseEvent", "(Lsun/lwawt/macosx/NSEvent;)V");
       
   154     JNFCallVoidMethod(env, peer, jm_handleMouseEvent, jEvent);
       
   155     (*env)->DeleteLocalRef(env, jEvent);
       
   156 }
       
   157 
       
   158 @end //AWTTrayIcon
       
   159 //================================================
       
   160 
       
   161 @implementation AWTTrayIconView
       
   162 
       
   163 -(id)initWithTrayIcon:(AWTTrayIcon *)theTrayIcon {
       
   164     self = [super initWithFrame:NSMakeRect(0, 0, 1, 1)];
       
   165 
       
   166     [self setTrayIcon: theTrayIcon];
       
   167     isHighlighted = NO;
       
   168     image = nil;
       
   169 
       
   170     return self;
       
   171 }
       
   172 
       
   173 -(void) dealloc {
       
   174     [image release];
       
   175     [super dealloc];
       
   176 }
       
   177 
       
   178 - (void)setHighlighted:(BOOL)aFlag
       
   179 {
       
   180     if (isHighlighted != aFlag) {
       
   181         isHighlighted = aFlag;
       
   182         [self setNeedsDisplay:YES];
       
   183     }
       
   184 }
       
   185 
       
   186 - (void)setImage:(NSImage*)anImage {
       
   187     [anImage retain];
       
   188     [image release];
       
   189     image = anImage;
       
   190 
       
   191     if (image != nil) {
       
   192         [self setNeedsDisplay:YES];
       
   193     }
       
   194 }
       
   195 
       
   196 -(void)setTrayIcon:(AWTTrayIcon*)theTrayIcon {
       
   197     trayIcon = theTrayIcon;
       
   198 }
       
   199 
       
   200 - (void)menuWillOpen:(NSMenu *)menu
       
   201 {
       
   202     [self setHighlighted:YES];
       
   203 }
       
   204 
       
   205 - (void)menuDidClose:(NSMenu *)menu
       
   206 {
       
   207     [menu setDelegate:nil];
       
   208     [self setHighlighted:NO];
       
   209 }
       
   210 
       
   211 - (void)drawRect:(NSRect)dirtyRect
       
   212 {
       
   213     if (image == nil) {
       
   214         return;
       
   215     }
       
   216 
       
   217     NSRect bounds = [self bounds];
       
   218     NSSize imageSize = [image size];
       
   219 
       
   220     NSRect drawRect = {{ (bounds.size.width - imageSize.width) / 2.0,
       
   221         (bounds.size.height - imageSize.height) / 2.0 }, imageSize};
       
   222 
       
   223     // don't cover bottom pixels of the status bar with the image
       
   224     if (drawRect.origin.y < 1.0) {
       
   225         drawRect.origin.y = 1.0;
       
   226     }
       
   227     drawRect = NSIntegralRect(drawRect);
       
   228 
       
   229     [trayIcon.theItem drawStatusBarBackgroundInRect:bounds
       
   230                                 withHighlight:isHighlighted];
       
   231     [image drawInRect:drawRect
       
   232              fromRect:NSZeroRect
       
   233             operation:NSCompositeSourceOver
       
   234              fraction:1.0
       
   235      ];
       
   236 }
       
   237 
       
   238 - (void)mouseDown:(NSEvent *)event {
       
   239     [trayIcon deliverJavaMouseEvent: event];
       
   240 
       
   241     // don't show the menu on ctrl+click: it triggers ACTION event, like right click
       
   242     if (([event modifierFlags] & NSControlKeyMask) == 0) {
       
   243         //find CTrayIcon.getPopupMenuModel method and call it to get popup menu ptr.
       
   244         JNIEnv *env = [ThreadUtilities getJNIEnv];
       
   245         static JNF_CLASS_CACHE(jc_CTrayIcon, "sun/lwawt/macosx/CTrayIcon");
       
   246         static JNF_MEMBER_CACHE(jm_getPopupMenuModel, jc_CTrayIcon, "getPopupMenuModel", "()J");
       
   247         jlong res = JNFCallLongMethod(env, trayIcon.peer, jm_getPopupMenuModel);
       
   248 
       
   249         if (res != 0) {
       
   250             CPopupMenu *cmenu = jlong_to_ptr(res);
       
   251             NSMenu* menu = [cmenu menu];
       
   252             [menu setDelegate:self];
       
   253             [trayIcon.theItem popUpStatusItemMenu:menu];
       
   254             [self setNeedsDisplay:YES];
       
   255         }
       
   256     }
       
   257 }
       
   258 
       
   259 - (void) mouseUp:(NSEvent *)event {
       
   260     [trayIcon deliverJavaMouseEvent: event];
       
   261 }
       
   262 
       
   263 - (void) mouseDragged:(NSEvent *)event {
       
   264     [trayIcon deliverJavaMouseEvent: event];
       
   265 }
       
   266 
       
   267 - (void) rightMouseDown:(NSEvent *)event {
       
   268     [trayIcon deliverJavaMouseEvent: event];
       
   269 }
       
   270 
       
   271 - (void) rightMouseUp:(NSEvent *)event {
       
   272     [trayIcon deliverJavaMouseEvent: event];
       
   273 }
       
   274 
       
   275 - (void) rightMouseDragged:(NSEvent *)event {
       
   276     [trayIcon deliverJavaMouseEvent: event];
       
   277 }
       
   278 
       
   279 - (void) otherMouseDown:(NSEvent *)event {
       
   280     [trayIcon deliverJavaMouseEvent: event];
       
   281 }
       
   282 
       
   283 - (void) otherMouseUp:(NSEvent *)event {
       
   284     [trayIcon deliverJavaMouseEvent: event];
       
   285 }
       
   286 
       
   287 - (void) otherMouseDragged:(NSEvent *)event {
       
   288     [trayIcon deliverJavaMouseEvent: event];
       
   289 }
       
   290 
       
   291 
       
   292 @end //AWTTrayIconView
       
   293 //================================================
       
   294 
       
   295 /*
       
   296  * Class:     sun_lwawt_macosx_CTrayIcon
       
   297  * Method:    nativeCreate
       
   298  * Signature: ()J
       
   299  */
       
   300 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CTrayIcon_nativeCreate
       
   301 (JNIEnv *env, jobject peer) {
       
   302     __block AWTTrayIcon *trayIcon = nil;
       
   303 
       
   304 JNF_COCOA_ENTER(env);
       
   305 
       
   306     jobject thePeer = JNFNewGlobalRef(env, peer);
       
   307     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
       
   308         trayIcon = [[AWTTrayIcon alloc] initWithPeer:thePeer];
       
   309     }];
       
   310 
       
   311 JNF_COCOA_EXIT(env);
       
   312 
       
   313     return ptr_to_jlong(trayIcon);
       
   314 }
       
   315 
       
   316 
       
   317 /*
       
   318  * Class: java_awt_TrayIcon
       
   319  * Method: initIDs
       
   320  * Signature: ()V
       
   321  */
       
   322 JNIEXPORT void JNICALL Java_java_awt_TrayIcon_initIDs
       
   323 (JNIEnv *env, jclass cls) {
       
   324     //Do nothing.
       
   325 }
       
   326 
       
   327 /*
       
   328  * Class:     sun_lwawt_macosx_CTrayIcon
       
   329  * Method:    nativeSetToolTip
       
   330  * Signature: (JLjava/lang/String;)V
       
   331  */
       
   332 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTrayIcon_nativeSetToolTip
       
   333 (JNIEnv *env, jobject self, jlong model, jstring jtooltip) {
       
   334 JNF_COCOA_ENTER(env);
       
   335 
       
   336     AWTTrayIcon *icon = jlong_to_ptr(model);
       
   337     NSString *tooltip = JNFJavaToNSString(env, jtooltip);
       
   338     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
       
   339         [icon setTooltip:tooltip];
       
   340     }];
       
   341 
       
   342 JNF_COCOA_EXIT(env);
       
   343 }
       
   344 
       
   345 /*
       
   346  * Class:     sun_lwawt_macosx_CTrayIcon
       
   347  * Method:    setNativeImage
       
   348  * Signature: (JJZ)V
       
   349  */
       
   350 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CTrayIcon_setNativeImage
       
   351 (JNIEnv *env, jobject self, jlong model, jlong imagePtr, jboolean autosize) {
       
   352 JNF_COCOA_ENTER(env);
       
   353 
       
   354     AWTTrayIcon *icon = jlong_to_ptr(model);
       
   355     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
       
   356         [icon setImage:jlong_to_ptr(imagePtr) sizing:autosize];
       
   357     }];
       
   358 
       
   359 JNF_COCOA_EXIT(env);
       
   360 }
       
   361 
       
   362 JNIEXPORT jobject JNICALL
       
   363 Java_sun_lwawt_macosx_CTrayIcon_nativeGetIconLocation
       
   364 (JNIEnv *env, jobject self, jlong model) {
       
   365     jobject jpt = NULL;
       
   366 
       
   367 JNF_COCOA_ENTER(env);
       
   368 
       
   369     __block NSPoint pt = NSZeroPoint;
       
   370     AWTTrayIcon *icon = jlong_to_ptr(model);
       
   371     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
       
   372         NSPoint loc = [icon getLocationOnScreen];
       
   373         pt = ConvertNSScreenPoint(env, loc);
       
   374     }];
       
   375 
       
   376     jpt = NSToJavaPoint(env, pt);
       
   377 
       
   378 JNF_COCOA_EXIT(env);
       
   379 
       
   380     return jpt;
       
   381 }