1 /*
   2  * Copyright (c) 2011, 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 <Cocoa/Cocoa.h>
  27 #import <JavaNativeFoundation/JavaNativeFoundation.h>
  28 #import <JavaRuntimeSupport/JavaRuntimeSupport.h>
  29 
  30 #import "sun_lwawt_macosx_CPlatformWindow.h"
  31 #import "com_apple_eawt_event_GestureHandler.h"
  32 #import "com_apple_eawt_FullScreenHandler.h"
  33 
  34 #import "AWTWindow.h"
  35 #import "AWTView.h"
  36 #import "CMenu.h"
  37 #import "CMenuBar.h"
  38 #import "LWCToolkit.h"
  39 #import "GeomUtilities.h"
  40 #import "ThreadUtilities.h"
  41 #import "OSVersion.h"
  42 
  43 static const float GROW_BOX_SIZE = 12.f;
  44 
  45 #define MASK(KEY) \
  46     (sun_lwawt_macosx_CPlatformWindow_ ## KEY)
  47 
  48 #define IS(BITS, KEY) \
  49     ((BITS & MASK(KEY)) != 0)
  50 
  51 #define SET(BITS, KEY, VALUE) \
  52     BITS = VALUE ? BITS | MASK(KEY) : BITS & ~MASK(KEY)
  53 
  54 static JNF_CLASS_CACHE(jc_CPlatformWindow, "sun/lwawt/macosx/CPlatformWindow");
  55 
  56 @interface JavaResizeGrowBoxOverlayWindow : NSWindow { }
  57 
  58 @end
  59 
  60 @implementation JavaResizeGrowBoxOverlayWindow
  61 
  62 - (BOOL) accessibilityIsIgnored
  63 {
  64     return YES;
  65 }
  66 
  67 - (NSArray *)accessibilityChildrenAttribute
  68 {
  69     return nil;
  70 }
  71 @end
  72 
  73 @implementation AWTWindow
  74 
  75 @synthesize javaPlatformWindow;
  76 @synthesize javaMenuBar;
  77 @synthesize growBoxWindow;
  78 @synthesize javaMinSize;
  79 @synthesize javaMaxSize;
  80 @synthesize styleBits;
  81 
  82 - (void) updateMinMaxSize:(BOOL)resizable {
  83     if (resizable) {
  84         [self setMinSize:self.javaMinSize];
  85         [self setMaxSize:self.javaMaxSize];
  86     } else {
  87         NSRect currentFrame = [self frame];
  88         [self setMinSize:currentFrame.size];
  89         [self setMaxSize:currentFrame.size];
  90     }
  91 }
  92 
  93 // creates a new NSWindow style mask based on the _STYLE_PROP_BITMASK bits
  94 + (NSUInteger) styleMaskForStyleBits:(jint)styleBits {
  95     NSUInteger type = 0;
  96     if (IS(styleBits, DECORATED)) {
  97         type |= NSTitledWindowMask;
  98         if (IS(styleBits, CLOSEABLE))   type |= NSClosableWindowMask;
  99         if (IS(styleBits, MINIMIZABLE)) type |= NSMiniaturizableWindowMask;
 100         if (IS(styleBits, RESIZABLE))   type |= NSResizableWindowMask;
 101     } else {
 102         type |= NSBorderlessWindowMask;
 103     }
 104 
 105     if (IS(styleBits, TEXTURED))    type |= NSTexturedBackgroundWindowMask;
 106     if (IS(styleBits, UNIFIED))     type |= NSUnifiedTitleAndToolbarWindowMask;
 107     if (IS(styleBits, UTILITY))     type |= NSUtilityWindowMask;
 108     if (IS(styleBits, HUD))         type |= NSHUDWindowMask;
 109     if (IS(styleBits, SHEET))       type |= NSDocModalWindowMask;
 110 
 111     return type;
 112 }
 113 
 114 // updates _METHOD_PROP_BITMASK based properties on the window
 115 - (void) setPropertiesForStyleBits:(jint)bits mask:(jint)mask {
 116     if (IS(mask, RESIZABLE)) {
 117         BOOL resizable = IS(bits, RESIZABLE);
 118         [self updateMinMaxSize:resizable];
 119         [self setShowsResizeIndicator:resizable];
 120     }
 121 
 122     if (IS(mask, HAS_SHADOW)) {
 123         [self setHasShadow:IS(bits, HAS_SHADOW)];
 124     }
 125 
 126     if (IS(mask, ZOOMABLE)) {
 127         [[self standardWindowButton:NSWindowZoomButton] setEnabled:IS(bits, ZOOMABLE)];
 128     }
 129 
 130     if (IS(mask, ALWAYS_ON_TOP)) {
 131         [self setLevel:IS(bits, ALWAYS_ON_TOP) ? NSFloatingWindowLevel : NSNormalWindowLevel];
 132     }
 133 
 134     if (IS(mask, HIDES_ON_DEACTIVATE)) {
 135         [self setHidesOnDeactivate:IS(bits, HIDES_ON_DEACTIVATE)];
 136     }
 137 
 138     if (IS(mask, DRAGGABLE_BACKGROUND)) {
 139         [self setMovableByWindowBackground:IS(bits, DRAGGABLE_BACKGROUND)];
 140     }
 141 
 142     if (IS(mask, DOCUMENT_MODIFIED)) {
 143         [self setDocumentEdited:IS(bits, DOCUMENT_MODIFIED)];
 144     }
 145 
 146     if ([self respondsToSelector:@selector(toggleFullScreen:)]) {
 147         if (IS(mask, FULLSCREENABLE)) {
 148             [self setCollectionBehavior:(1 << 7) /*NSWindowCollectionBehaviorFullScreenPrimary*/];
 149         } else {
 150             [self setCollectionBehavior:NSWindowCollectionBehaviorDefault];
 151         }
 152     }
 153 
 154 }
 155 
 156 - (BOOL) shouldShowGrowBox {
 157     return isSnowLeopardOrLower() && IS(self.styleBits, RESIZABLE);
 158 }
 159 
 160 - (NSImage *) createGrowBoxImage {
 161     NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(GROW_BOX_SIZE, GROW_BOX_SIZE)];
 162     JRSUIControlRef growBoxWidget = JRSUIControlCreate(FALSE);
 163     JRSUIControlSetWidget(growBoxWidget, kJRSUI_Widget_growBoxTextured);
 164     JRSUIControlSetWindowType(growBoxWidget, kJRSUI_WindowType_utility);
 165     JRSUIRendererRef renderer = JRSUIRendererCreate();
 166     [image lockFocus]; // sets current graphics context to that of the image
 167     JRSUIControlDraw(renderer, growBoxWidget, [[NSGraphicsContext currentContext] graphicsPort], CGRectMake(0, 1, GROW_BOX_SIZE - 1, GROW_BOX_SIZE - 1));
 168     [image unlockFocus];
 169     JRSUIRendererRelease(renderer);
 170     JRSUIControlRelease(growBoxWidget);
 171     return image;
 172 }
 173 
 174 - (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)platformWindow
 175                     styleBits:(jint)bits
 176                     frameRect:(NSRect)rect
 177                   contentView:(NSView *)view
 178 {
 179 AWT_ASSERT_APPKIT_THREAD;
 180 
 181     NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:bits];
 182     NSRect contentRect = rect; //[NSWindow contentRectForFrameRect:rect styleMask:styleMask];
 183     if (contentRect.size.width <= 0.0) {
 184         contentRect.size.width = 1.0;
 185     }
 186     if (contentRect.size.height <= 0.0) {
 187         contentRect.size.height = 1.0;
 188     }
 189 
 190     self = [super initWithContentRect:contentRect
 191                             styleMask:styleMask
 192                               backing:NSBackingStoreBuffered
 193                                 defer:NO];
 194 
 195     if (self == nil) return nil; // no hope
 196 
 197     self.javaPlatformWindow = platformWindow;
 198     self.styleBits = bits;
 199     [self setPropertiesForStyleBits:styleBits mask:MASK(_METHOD_PROP_BITMASK)];
 200 
 201     [self setDelegate:self];
 202     [self setContentView:view];
 203     [self setInitialFirstResponder:view];
 204     [self setReleasedWhenClosed:NO];
 205     [self setPreservesContentDuringLiveResize:YES];
 206 
 207     if ([self shouldShowGrowBox]) {
 208         NSImage *growBoxImage = [self createGrowBoxImage];
 209         growBoxWindow = [[JavaResizeGrowBoxOverlayWindow alloc] initWithContentRect:NSMakeRect(0, 0, [growBoxImage size].width, [growBoxImage size].height) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
 210         [self.growBoxWindow setIgnoresMouseEvents:YES];
 211         [self.growBoxWindow setOpaque:NO];
 212         [self.growBoxWindow setBackgroundColor:[NSColor clearColor]];
 213         [self.growBoxWindow setHasShadow:NO];
 214         [self.growBoxWindow setReleasedWhenClosed:NO];
 215 
 216         NSImageView *imageView = [[NSImageView alloc] initWithFrame:[self.growBoxWindow frame]];
 217         [imageView setEditable:NO];
 218         [imageView setAnimates:NO];
 219         [imageView setAllowsCutCopyPaste:NO];
 220         [self.growBoxWindow setContentView:imageView];
 221         [imageView setImage:growBoxImage];
 222         [growBoxImage release];
 223         [imageView release];
 224 
 225         [self addChildWindow:self.growBoxWindow ordered:NSWindowAbove];
 226         [self adjustGrowBoxWindow];
 227     } else growBoxWindow = nil;
 228 
 229     return self;
 230 }
 231 
 232 - (void) dealloc {
 233 AWT_ASSERT_APPKIT_THREAD;
 234 
 235     JNIEnv *env = [ThreadUtilities getJNIEnv];
 236     [self.javaPlatformWindow setJObject:nil withEnv:env];
 237     self.growBoxWindow = nil;
 238 
 239     [super dealloc];
 240 }
 241 
 242 
 243 // NSWindow overrides
 244 - (BOOL) canBecomeKeyWindow {
 245 AWT_ASSERT_APPKIT_THREAD;
 246     return IS(self.styleBits, SHOULD_BECOME_KEY);
 247 }
 248 
 249 - (BOOL) canBecomeMainWindow {
 250 AWT_ASSERT_APPKIT_THREAD;
 251     return IS(self.styleBits, SHOULD_BECOME_MAIN);
 252 }
 253 
 254 - (BOOL) worksWhenModal {
 255 AWT_ASSERT_APPKIT_THREAD;
 256     return IS(self.styleBits, MODAL_EXCLUDED);
 257 }
 258 
 259 
 260 // Gesture support
 261 - (void)postGesture:(NSEvent *)event as:(jint)type a:(jdouble)a b:(jdouble)b {
 262 AWT_ASSERT_APPKIT_THREAD;
 263 
 264     JNIEnv *env = [ThreadUtilities getJNIEnv];
 265     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 266     if (platformWindow != NULL) {
 267         // extract the target AWT Window object out of the CPlatformWindow
 268         static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
 269         jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
 270         if (awtWindow != NULL) {
 271             // translate the point into Java coordinates
 272             NSPoint loc = [event locationInWindow];
 273             loc.y = [self frame].size.height - loc.y;
 274 
 275             // send up to the GestureHandler to recursively dispatch on the AWT event thread
 276             static JNF_CLASS_CACHE(jc_GestureHandler, "com/apple/eawt/event/GestureHandler");
 277             static JNF_STATIC_MEMBER_CACHE(sjm_handleGestureFromNative, jc_GestureHandler, "handleGestureFromNative", "(Ljava/awt/Window;IDDDD)V");
 278             JNFCallStaticVoidMethod(env, sjm_handleGestureFromNative, awtWindow, type, (jdouble)loc.x, (jdouble)loc.y, (jdouble)a, (jdouble)b);
 279             (*env)->DeleteLocalRef(env, awtWindow);
 280         }
 281         (*env)->DeleteLocalRef(env, platformWindow);
 282     }
 283 }
 284 
 285 - (void)beginGestureWithEvent:(NSEvent *)event {
 286     [self postGesture:event
 287                    as:com_apple_eawt_event_GestureHandler_PHASE
 288                     a:-1.0
 289                     b:0.0];
 290 }
 291 
 292 - (void)endGestureWithEvent:(NSEvent *)event {
 293     [self postGesture:event
 294                    as:com_apple_eawt_event_GestureHandler_PHASE
 295                     a:1.0
 296                     b:0.0];
 297 }
 298 
 299 - (void)magnifyWithEvent:(NSEvent *)event {
 300     [self postGesture:event
 301                    as:com_apple_eawt_event_GestureHandler_MAGNIFY
 302                     a:[event magnification]
 303                     b:0.0];
 304 }
 305 
 306 - (void)rotateWithEvent:(NSEvent *)event {
 307     [self postGesture:event
 308                    as:com_apple_eawt_event_GestureHandler_ROTATE
 309                     a:[event rotation]
 310                     b:0.0];
 311 }
 312 
 313 - (void)swipeWithEvent:(NSEvent *)event {
 314     [self postGesture:event
 315                    as:com_apple_eawt_event_GestureHandler_SWIPE
 316                     a:[event deltaX]
 317                     b:[event deltaY]];
 318 }
 319 
 320 
 321 // NSWindowDelegate methods
 322 
 323 - (void) adjustGrowBoxWindow {
 324     if (self.growBoxWindow != nil) {
 325         NSRect parentRect = [self frame];
 326         parentRect.origin.x += (parentRect.size.width - [self.growBoxWindow frame].size.width);
 327         [self.growBoxWindow setFrameOrigin:parentRect.origin];
 328     }
 329 }
 330 
 331 - (void) _deliverMoveResizeEvent {
 332 AWT_ASSERT_APPKIT_THREAD;
 333 
 334     // deliver the event if this is a user-initiated live resize or as a side-effect
 335     // of a Java initiated resize, because AppKit can override the bounds and force
 336     // the bounds of the window to avoid the Dock or remain on screen.
 337     [AWTToolkit eventCountPlusPlus];
 338     JNIEnv *env = [ThreadUtilities getJNIEnv];
 339     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 340     if (platformWindow == NULL) {
 341         // TODO: create generic AWT assert
 342     }
 343 
 344     [self adjustGrowBoxWindow];
 345 
 346     NSRect frame = ConvertNSScreenRect(env, [self frame]);
 347 
 348     static JNF_MEMBER_CACHE(jm_deliverMoveResizeEvent, jc_CPlatformWindow, "deliverMoveResizeEvent", "(IIII)V");
 349     JNFCallVoidMethod(env, platformWindow, jm_deliverMoveResizeEvent,
 350                       (jint)frame.origin.x,
 351                       (jint)frame.origin.y,
 352                       (jint)frame.size.width,
 353                       (jint)frame.size.height);
 354     (*env)->DeleteLocalRef(env, platformWindow);
 355 }
 356 
 357 - (void)windowDidMove:(NSNotification *)notification {
 358 AWT_ASSERT_APPKIT_THREAD;
 359 
 360     [self _deliverMoveResizeEvent];
 361 }
 362 
 363 - (void)windowDidResize:(NSNotification *)notification {
 364 AWT_ASSERT_APPKIT_THREAD;
 365 
 366     [self _deliverMoveResizeEvent];
 367 }
 368 
 369 - (void)windowDidExpose:(NSNotification *)notification {
 370 AWT_ASSERT_APPKIT_THREAD;
 371 
 372     [AWTToolkit eventCountPlusPlus];
 373     // TODO: don't see this callback invoked anytime so we track
 374     // window exposing in _setVisible:(BOOL)
 375 }
 376 
 377 - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)proposedFrame {
 378 AWT_ASSERT_APPKIT_THREAD;
 379 
 380     [AWTToolkit eventCountPlusPlus];
 381     JNIEnv *env = [ThreadUtilities getJNIEnv];
 382     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 383     if (platformWindow != NULL) {
 384         static JNF_MEMBER_CACHE(jm_deliverZoom, jc_CPlatformWindow, "deliverZoom", "(Z)V");
 385         JNFCallVoidMethod(env, platformWindow, jm_deliverZoom, ![window isZoomed]);
 386         (*env)->DeleteLocalRef(env, platformWindow);
 387     }
 388     return YES;
 389 }
 390 
 391 - (void) _deliverIconify:(BOOL)iconify {
 392 AWT_ASSERT_APPKIT_THREAD;
 393 
 394     [AWTToolkit eventCountPlusPlus];
 395     JNIEnv *env = [ThreadUtilities getJNIEnv];
 396     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 397     if (platformWindow != NULL) {
 398         static JNF_MEMBER_CACHE(jm_deliverIconify, jc_CPlatformWindow, "deliverIconify", "(Z)V");
 399         JNFCallVoidMethod(env, platformWindow, jm_deliverIconify, iconify);
 400         (*env)->DeleteLocalRef(env, platformWindow);
 401     }
 402 }
 403 
 404 - (void)windowDidMiniaturize:(NSNotification *)notification {
 405 AWT_ASSERT_APPKIT_THREAD;
 406 
 407     [self _deliverIconify:JNI_TRUE];
 408 }
 409 
 410 - (void)windowDidDeminiaturize:(NSNotification *)notification {
 411 AWT_ASSERT_APPKIT_THREAD;
 412 
 413     [self _deliverIconify:JNI_FALSE];
 414 }
 415 
 416 - (void) _deliverWindowFocusEvent:(BOOL)focused {
 417 //AWT_ASSERT_APPKIT_THREAD;
 418 
 419     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 420     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 421     if (platformWindow != NULL) {
 422         static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(Z)V");
 423         JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused);
 424         (*env)->DeleteLocalRef(env, platformWindow);
 425     }
 426 }
 427 
 428 
 429 - (void) windowDidBecomeKey: (NSNotification *) notification {
 430 AWT_ASSERT_APPKIT_THREAD;
 431     [AWTToolkit eventCountPlusPlus];
 432     [CMenuBar activate:self.javaMenuBar modallyDisabled:NO];
 433     [self _deliverWindowFocusEvent:YES];
 434 }
 435 
 436 - (void) windowDidResignKey: (NSNotification *) notification {
 437     // TODO: check why sometimes at start is invoked *not* on AppKit main thread.
 438 AWT_ASSERT_APPKIT_THREAD;
 439     [AWTToolkit eventCountPlusPlus];
 440     [self.javaMenuBar deactivate];
 441     [self _deliverWindowFocusEvent:NO];
 442 }
 443 
 444 - (void) windowDidBecomeMain: (NSNotification *) notification {
 445 AWT_ASSERT_APPKIT_THREAD;
 446     [AWTToolkit eventCountPlusPlus];
 447 
 448     JNIEnv *env = [ThreadUtilities getJNIEnv];
 449     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 450     if (platformWindow != NULL) {
 451         static JNF_MEMBER_CACHE(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
 452         JNFCallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
 453         (*env)->DeleteLocalRef(env, platformWindow);
 454     }
 455 }
 456 
 457 - (BOOL)windowShouldClose:(id)sender {
 458 AWT_ASSERT_APPKIT_THREAD;
 459     [AWTToolkit eventCountPlusPlus];
 460     JNIEnv *env = [ThreadUtilities getJNIEnv];
 461     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 462     if (platformWindow != NULL) {
 463         static JNF_MEMBER_CACHE(jm_deliverWindowClosingEvent, jc_CPlatformWindow, "deliverWindowClosingEvent", "()V");
 464         JNFCallVoidMethod(env, platformWindow, jm_deliverWindowClosingEvent);
 465         (*env)->DeleteLocalRef(env, platformWindow);
 466     }
 467     // The window will be closed (if allowed) as result of sending Java event
 468     return NO;
 469 }
 470 
 471 
 472 - (void)_notifyFullScreenOp:(jint)op withEnv:(JNIEnv *)env {
 473     static JNF_CLASS_CACHE(jc_FullScreenHandler, "com/apple/eawt/FullScreenHandler");
 474     static JNF_STATIC_MEMBER_CACHE(jm_notifyFullScreenOperation, jc_FullScreenHandler, "handleFullScreenEventFromNative", "(Ljava/awt/Window;I)V");
 475     static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
 476     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 477     if (platformWindow != NULL) {
 478         jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
 479         if (awtWindow != NULL) {
 480             JNFCallStaticVoidMethod(env, jm_notifyFullScreenOperation, awtWindow, op);
 481             (*env)->DeleteLocalRef(env, awtWindow);
 482         }
 483         (*env)->DeleteLocalRef(env, platformWindow);
 484     }
 485 }
 486 
 487 
 488 - (void)windowWillEnterFullScreen:(NSNotification *)notification {
 489     static JNF_MEMBER_CACHE(jm_windowWillEnterFullScreen, jc_CPlatformWindow, "windowWillEnterFullScreen", "()V");
 490     JNIEnv *env = [ThreadUtilities getJNIEnv];
 491     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 492     if (platformWindow != NULL) {
 493         JNFCallVoidMethod(env, platformWindow, jm_windowWillEnterFullScreen);
 494         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_ENTER withEnv:env];
 495         (*env)->DeleteLocalRef(env, platformWindow);
 496     }
 497 }
 498 
 499 - (void)windowDidEnterFullScreen:(NSNotification *)notification {
 500     static JNF_MEMBER_CACHE(jm_windowDidEnterFullScreen, jc_CPlatformWindow, "windowDidEnterFullScreen", "()V");
 501     JNIEnv *env = [ThreadUtilities getJNIEnv];
 502     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 503     if (platformWindow != NULL) {
 504         JNFCallVoidMethod(env, platformWindow, jm_windowDidEnterFullScreen);
 505         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_ENTER withEnv:env];
 506         (*env)->DeleteLocalRef(env, platformWindow);
 507     }
 508 }
 509 
 510 - (void)windowWillExitFullScreen:(NSNotification *)notification {
 511     static JNF_MEMBER_CACHE(jm_windowWillExitFullScreen, jc_CPlatformWindow, "windowWillExitFullScreen", "()V");
 512     JNIEnv *env = [ThreadUtilities getJNIEnv];
 513     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 514     if (platformWindow != NULL) {
 515         JNFCallVoidMethod(env, platformWindow, jm_windowWillExitFullScreen);
 516         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_EXIT withEnv:env];
 517         (*env)->DeleteLocalRef(env, platformWindow);
 518     }
 519 }
 520 
 521 - (void)windowDidExitFullScreen:(NSNotification *)notification {
 522     static JNF_MEMBER_CACHE(jm_windowDidExitFullScreen, jc_CPlatformWindow, "windowDidExitFullScreen", "()V");
 523     JNIEnv *env = [ThreadUtilities getJNIEnv];
 524     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 525     if (platformWindow != NULL) {
 526         JNFCallVoidMethod(env, platformWindow, jm_windowDidExitFullScreen);
 527         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_EXIT withEnv:env];
 528         (*env)->DeleteLocalRef(env, platformWindow);
 529     }
 530 }
 531 
 532 - (void)sendEvent:(NSEvent *)event {
 533         if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
 534 
 535             NSPoint p = [NSEvent mouseLocation];
 536             NSRect frame = [self frame];
 537             NSRect contentRect = [self contentRectForFrameRect:frame];
 538 
 539             // Check if the click happened in the non-client area (title bar)
 540             if (p.y >= (frame.origin.y + contentRect.size.height)) {
 541                 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 542                 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 543                 // Currently, no need to deliver the whole NSEvent.
 544                 static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
 545                 JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
 546             }
 547         }
 548         [super sendEvent:event];
 549 }
 550 
 551 - (void)constrainSize:(NSSize*)size {
 552     float minWidth = 0.f, minHeight = 0.f;
 553 
 554     if (IS(self.styleBits, DECORATED)) {
 555         NSRect frame = [self frame];
 556         NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[self styleMask]];
 557 
 558         float top = frame.size.height - contentRect.size.height;
 559         float left = contentRect.origin.x - frame.origin.x;
 560         float bottom = contentRect.origin.y - frame.origin.y;
 561         float right = frame.size.width - (contentRect.size.width + left);
 562 
 563         // Speculative estimation: 80 - enough for window decorations controls
 564         minWidth += left + right + 80;
 565         minHeight += top + bottom;
 566     }
 567 
 568     if ([self shouldShowGrowBox]) {
 569         minWidth = MAX(minWidth, GROW_BOX_SIZE);
 570         minHeight += GROW_BOX_SIZE;
 571     }
 572 
 573     minWidth = MAX(1.f, minWidth);
 574     minHeight = MAX(1.f, minHeight);
 575 
 576     size->width = MAX(size->width, minWidth);
 577     size->height = MAX(size->height, minHeight);
 578 }
 579 
 580 @end // AWTWindow
 581 
 582 
 583 /*
 584  * Class:     sun_lwawt_macosx_CPlatformWindow
 585  * Method:    nativeCreateNSWindow
 586  * Signature: (JJIIII)J
 587  */
 588 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeCreateNSWindow
 589 (JNIEnv *env, jobject obj, jlong contentViewPtr, jlong styleBits, jdouble x, jdouble y, jdouble w, jdouble h)
 590 {
 591     __block AWTWindow *window = nil;
 592 
 593 JNF_COCOA_ENTER(env);
 594 AWT_ASSERT_NOT_APPKIT_THREAD;
 595 
 596     JNFWeakJObjectWrapper *platformWindow = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
 597     NSView *contentView = OBJC(contentViewPtr);
 598     NSRect frameRect = NSMakeRect(x, y, w, h);
 599 
 600     [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
 601         AWT_ASSERT_APPKIT_THREAD;
 602 
 603         window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow
 604                                                   styleBits:styleBits
 605                                                   frameRect:frameRect
 606                                                 contentView:contentView];
 607 
 608         if (window) CFRetain(window);
 609         [window release]; // GC
 610     }];
 611 
 612 JNF_COCOA_EXIT(env);
 613 
 614     return ptr_to_jlong(window);
 615 }
 616 
 617 /*
 618  * Class:     sun_lwawt_macosx_CPlatformWindow
 619  * Method:    nativeSetNSWindowStyleBits
 620  * Signature: (JII)V
 621  */
 622 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStyleBits
 623 (JNIEnv *env, jclass clazz, jlong windowPtr, jint mask, jint bits)
 624 {
 625 JNF_COCOA_ENTER(env);
 626 AWT_ASSERT_NOT_APPKIT_THREAD;
 627 
 628     AWTWindow *window = OBJC(windowPtr);
 629     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 630         AWT_ASSERT_APPKIT_THREAD;
 631 
 632         // scans the bit field, and only updates the values requested by the mask
 633         // (this implicity handles the _CALLBACK_PROP_BITMASK case, since those are passive reads)
 634         jint newBits = window.styleBits & ~mask | bits & mask;
 635 
 636         // resets the NSWindow's style mask if the mask intersects any of those bits
 637         if (mask & MASK(_STYLE_PROP_BITMASK)) {
 638             [window setStyleMask:[AWTWindow styleMaskForStyleBits:newBits]];
 639         }
 640 
 641         // calls methods on NSWindow to change other properties, based on the mask
 642         if (mask & MASK(_METHOD_PROP_BITMASK)) {
 643             [window setPropertiesForStyleBits:bits mask:mask];
 644         }
 645 
 646         window.styleBits = newBits;
 647     }];
 648 
 649 JNF_COCOA_EXIT(env);
 650 }
 651 
 652 /*
 653  * Class:     sun_lwawt_macosx_CPlatformWindow
 654  * Method:    nativeSetNSWindowMenuBar
 655  * Signature: (JJ)V
 656  */
 657 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMenuBar
 658 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong menuBarPtr)
 659 {
 660 JNF_COCOA_ENTER(env);
 661 AWT_ASSERT_NOT_APPKIT_THREAD;
 662 
 663     AWTWindow *window = OBJC(windowPtr);
 664     CMenuBar *menuBar = OBJC(menuBarPtr);
 665     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 666         AWT_ASSERT_APPKIT_THREAD;
 667 
 668         if ([window isKeyWindow]) [window.javaMenuBar deactivate];
 669         window.javaMenuBar = menuBar;
 670 
 671         // if ([self isKeyWindow]) {
 672         [CMenuBar activate:window.javaMenuBar modallyDisabled:NO];
 673         // }
 674     }];
 675 
 676 JNF_COCOA_EXIT(env);
 677 }
 678 
 679 /*
 680  * Class:     sun_lwawt_macosx_CPlatformWindow
 681  * Method:    nativeGetNSWindowInsets
 682  * Signature: (J)Ljava/awt/Insets;
 683  */
 684 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowInsets
 685 (JNIEnv *env, jclass clazz, jlong windowPtr)
 686 {
 687     jobject ret = NULL;
 688 
 689 JNF_COCOA_ENTER(env);
 690 AWT_ASSERT_NOT_APPKIT_THREAD;
 691 
 692     AWTWindow *window = OBJC(windowPtr);
 693     __block NSRect contentRect = NSZeroRect;
 694     __block NSRect frame = NSZeroRect;
 695 
 696     [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^(){
 697         AWT_ASSERT_APPKIT_THREAD;
 698 
 699         frame = [window frame];
 700         contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[window styleMask]];
 701     }];
 702 
 703     jint top = (jint)(frame.size.height - contentRect.size.height);
 704     jint left = (jint)(contentRect.origin.x - frame.origin.x);
 705     jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
 706     jint right = (jint)(frame.size.width - (contentRect.size.width + left));
 707 
 708     static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
 709     static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
 710     ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right);
 711 
 712 JNF_COCOA_EXIT(env);
 713     return ret;
 714 }
 715 
 716 /*
 717  * Class:     sun_lwawt_macosx_CPlatformWindow
 718  * Method:    nativeSetNSWindowBounds
 719  * Signature: (JDDDD)V
 720  */
 721 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowBounds
 722 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY, jdouble width, jdouble height)
 723 {
 724 JNF_COCOA_ENTER(env);
 725 AWT_ASSERT_NOT_APPKIT_THREAD;
 726 
 727     NSRect jrect = NSMakeRect(originX, originY, width, height);
 728 
 729     // TODO: not sure we need displayIfNeeded message in our view
 730     AWTWindow *window = OBJC(windowPtr);
 731     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 732         AWT_ASSERT_APPKIT_THREAD;
 733 
 734         NSRect rect = ConvertNSScreenRect(NULL, jrect);
 735         [window constrainSize:&rect.size];
 736 
 737         [window setFrame:rect display:YES];
 738 
 739         // only start tracking events if pointer is above the toplevel
 740         // TODO: should post an Entered event if YES.
 741         NSPoint mLocation = [NSEvent mouseLocation];
 742         [window setAcceptsMouseMovedEvents:NSPointInRect(mLocation, rect)];
 743 
 744         // ensure we repaint the whole window after the resize operation
 745         // (this will also re-enable screen updates, which were disabled above)
 746         // TODO: send PaintEvent
 747     }];
 748 
 749 JNF_COCOA_EXIT(env);
 750 }
 751 
 752 /*
 753  * Class:     sun_lwawt_macosx_CPlatformWindow
 754  * Method:    nativeSetNSWindowMinMax
 755  * Signature: (JDDDD)V
 756  */
 757 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinMax
 758 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble minW, jdouble minH, jdouble maxW, jdouble maxH)
 759 {
 760 JNF_COCOA_ENTER(env);
 761 AWT_ASSERT_NOT_APPKIT_THREAD;
 762 
 763     if (minW < 1) minW = 1;
 764     if (minH < 1) minH = 1;
 765     if (maxW < 1) maxW = 1;
 766     if (maxH < 1) maxH = 1;
 767 
 768     AWTWindow *window = OBJC(windowPtr);
 769     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 770         AWT_ASSERT_APPKIT_THREAD;
 771 
 772         NSSize min = { minW, minH };
 773         NSSize max = { maxW, maxH };
 774 
 775         [window constrainSize:&min];
 776         [window constrainSize:&max];
 777 
 778         window.javaMinSize = min;
 779         window.javaMaxSize = max;
 780         [window updateMinMaxSize:IS(window.styleBits, RESIZABLE)];
 781     }];
 782 
 783 JNF_COCOA_EXIT(env);
 784 }
 785 
 786 /*
 787  * Class:     sun_lwawt_macosx_CPlatformWindow
 788  * Method:    nativePushNSWindowToBack
 789  * Signature: (J)V
 790  */
 791 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToBack
 792 (JNIEnv *env, jclass clazz, jlong windowPtr)
 793 {
 794 JNF_COCOA_ENTER(env);
 795 AWT_ASSERT_NOT_APPKIT_THREAD;
 796 
 797     AWTWindow *window = OBJC(windowPtr);
 798     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 799         AWT_ASSERT_APPKIT_THREAD;
 800 
 801         [window orderBack:nil];
 802     }];
 803 
 804 JNF_COCOA_EXIT(env);
 805 }
 806 
 807 /*
 808  * Class:     sun_lwawt_macosx_CPlatformWindow
 809  * Method:    nativePushNSWindowToFront
 810  * Signature: (J)V
 811  */
 812 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToFront
 813 (JNIEnv *env, jclass clazz, jlong windowPtr)
 814 {
 815 JNF_COCOA_ENTER(env);
 816 AWT_ASSERT_NOT_APPKIT_THREAD;
 817 
 818     AWTWindow *window = OBJC(windowPtr);
 819     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 820         AWT_ASSERT_APPKIT_THREAD;
 821 
 822         if (![window isKeyWindow]) {
 823             [window makeKeyAndOrderFront:window];
 824         } else {
 825             [window orderFront:window];
 826         }
 827     }];
 828 
 829 JNF_COCOA_EXIT(env);
 830 }
 831 
 832 /*
 833  * Class:     sun_lwawt_macosx_CPlatformWindow
 834  * Method:    nativeSetNSWindowTitle
 835  * Signature: (JLjava/lang/String;)V
 836  */
 837 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTitle
 838 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring jtitle)
 839 {
 840 JNF_COCOA_ENTER(env);
 841 AWT_ASSERT_NOT_APPKIT_THREAD;
 842 
 843     AWTWindow *window = OBJC(windowPtr);
 844     [window performSelectorOnMainThread:@selector(setTitle:)
 845                               withObject:JNFJavaToNSString(env, jtitle)
 846                            waitUntilDone:NO];
 847 
 848 JNF_COCOA_EXIT(env);
 849 }
 850 
 851 /*
 852  * Class:     sun_lwawt_macosx_CPlatformWindow
 853  * Method:    nativeSetNSWindowAlpha
 854  * Signature: (JF)V
 855  */
 856 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowAlpha
 857 (JNIEnv *env, jclass clazz, jlong windowPtr, jfloat alpha)
 858 {
 859 JNF_COCOA_ENTER(env);
 860 AWT_ASSERT_NOT_APPKIT_THREAD;
 861 
 862     AWTWindow *window = OBJC(windowPtr);
 863     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 864         AWT_ASSERT_APPKIT_THREAD;
 865 
 866         [window setAlphaValue:alpha];
 867         [window.growBoxWindow setAlphaValue:alpha];
 868     }];
 869 
 870 JNF_COCOA_EXIT(env);
 871 }
 872 
 873 /*
 874  * Class:     sun_lwawt_macosx_CPlatformWindow
 875  * Method:    nativeRevalidateNSWindowShadow
 876  * Signature: (J)V
 877  */
 878 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeRevalidateNSWindowShadow
 879 (JNIEnv *env, jclass clazz, jlong windowPtr)
 880 {
 881 JNF_COCOA_ENTER(env);
 882 AWT_ASSERT_NOT_APPKIT_THREAD;
 883 
 884     AWTWindow *window = OBJC(windowPtr);
 885     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 886         AWT_ASSERT_APPKIT_THREAD;
 887 
 888         [window invalidateShadow];
 889     }];
 890 
 891 JNF_COCOA_EXIT(env);
 892 }
 893 
 894 /*
 895  * Class:     sun_lwawt_macosx_CPlatformWindow
 896  * Method:    nativeScreenOn_AppKitThread
 897  * Signature: (J)I
 898  */
 899 JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeScreenOn_1AppKitThread
 900 (JNIEnv *env, jclass clazz, jlong windowPtr)
 901 {
 902     jint ret = 0;
 903 
 904 JNF_COCOA_ENTER(env);
 905 AWT_ASSERT_APPKIT_THREAD;
 906 
 907     AWTWindow *window = OBJC(windowPtr);
 908     NSDictionary *props = [[window screen] deviceDescription];
 909     ret = [[props objectForKey:@"NSScreenNumber"] intValue];
 910 
 911 JNF_COCOA_EXIT(env);
 912 
 913     return ret;
 914 }
 915 
 916 /*
 917  * Class:     sun_lwawt_macosx_CPlatformWindow
 918  * Method:    nativeSetNSWindowMinimizedIcon
 919  * Signature: (JJ)V
 920  */
 921 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinimizedIcon
 922 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong nsImagePtr)
 923 {
 924 JNF_COCOA_ENTER(env);
 925 AWT_ASSERT_NOT_APPKIT_THREAD;
 926 
 927     AWTWindow *window = OBJC(windowPtr);
 928     NSImage *image = OBJC(nsImagePtr);
 929     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 930         AWT_ASSERT_APPKIT_THREAD;
 931 
 932         [window setMiniwindowImage:image];
 933     }];
 934 
 935 JNF_COCOA_EXIT(env);
 936 }
 937 
 938 /*
 939  * Class:     sun_lwawt_macosx_CPlatformWindow
 940  * Method:    nativeSetNSWindowRepresentedFilename
 941  * Signature: (JLjava/lang/String;)V
 942  */
 943 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowRepresentedFilename
 944 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring filename)
 945 {
 946 JNF_COCOA_ENTER(env);
 947 AWT_ASSERT_NOT_APPKIT_THREAD;
 948 
 949     AWTWindow *window = OBJC(windowPtr);
 950     NSURL *url = (filename == NULL) ? nil : [NSURL fileURLWithPath:JNFNormalizedNSStringForPath(env, filename)];
 951     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
 952         AWT_ASSERT_APPKIT_THREAD;
 953 
 954         [window setRepresentedURL:url];
 955     }];
 956 
 957 JNF_COCOA_EXIT(env);
 958 }
 959 
 960 /*
 961  * Class:     sun_lwawt_macosx_CPlatformWindow
 962  * Method:    nativeSetNSWindowSecurityWarningPositioning
 963  * Signature: (JDDFF)V
 964  */
 965 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowSecurityWarningPositioning
 966 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble x, jdouble y, jfloat biasX, jfloat biasY)
 967 {
 968 JNF_COCOA_ENTER(env);
 969 AWT_ASSERT_NOT_APPKIT_THREAD;
 970 
 971     [JNFException raise:env as:kRuntimeException reason:"unimplemented"];
 972 
 973 JNF_COCOA_EXIT(env);
 974 }
 975 
 976 /*
 977  * Class:     sun_lwawt_macosx_CPlatformWindow
 978  * Method:    nativeGetScreenNSWindowIsOn_AppKitThread
 979  * Signature: (J)I
 980  */
 981 JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetScreenNSWindowIsOn_1AppKitThread
 982 (JNIEnv *env, jclass clazz, jlong windowPtr)
 983 {
 984     jint index = -1;
 985 
 986 JNF_COCOA_ENTER(env);
 987 AWT_ASSERT_APPKIT_THREAD;
 988 
 989     AWTWindow *window = OBJC(windowPtr);
 990     NSScreen* screen = [window screen];
 991 
 992     //+++gdb NOTE: This is using a linear search of the screens. If it should
 993     //  prove to be a bottleneck, this can definitely be improved. However,
 994     //  many screens should prove to be the exception, rather than the rule.
 995     NSArray* screens = [NSScreen screens];
 996     NSUInteger i;
 997     for (i = 0; i < [screens count]; i++)
 998     {
 999         if ([[screens objectAtIndex:i] isEqualTo:screen])
1000         {
1001             index = i;
1002             break;
1003         }
1004     }
1005 
1006 JNF_COCOA_EXIT(env);
1007     return 1;
1008 }
1009 
1010 
1011 /*
1012  * Class:     sun_lwawt_macosx_CPlatformWindow
1013  * Method:    _toggleFullScreenMode
1014  * Signature: (J)V
1015  */
1016 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow__1toggleFullScreenMode
1017 (JNIEnv *env, jobject peer, jlong windowPtr)
1018 {
1019 JNF_COCOA_ENTER(env);
1020 
1021     AWTWindow *window = OBJC(windowPtr);
1022     SEL toggleFullScreenSelector = @selector(toggleFullScreen:);
1023     if (![window respondsToSelector:toggleFullScreenSelector]) return;
1024 
1025     [JNFRunLoop performOnMainThreadWaiting:NO withBlock:^(){
1026         [window performSelector:toggleFullScreenSelector withObject:nil];
1027     }];
1028 
1029 JNF_COCOA_EXIT(env);
1030 }
1031 
1032 JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CMouseInfoPeer_nativeIsWindowUnderMouse
1033 (JNIEnv *env, jclass clazz, jlong windowPtr)
1034 {
1035     __block jboolean underMouse = JNI_FALSE;
1036 
1037 JNF_COCOA_ENTER(env);
1038 AWT_ASSERT_NOT_APPKIT_THREAD;
1039 
1040     AWTWindow *aWindow = OBJC(windowPtr);
1041     [JNFRunLoop performOnMainThreadWaiting:YES withBlock:^() {
1042         AWT_ASSERT_APPKIT_THREAD;
1043 
1044         NSPoint pt = [aWindow mouseLocationOutsideOfEventStream];
1045         underMouse = [[aWindow contentView] hitTest:pt] != nil;
1046     }];
1047 
1048 JNF_COCOA_EXIT(env);
1049 
1050     return underMouse;
1051 }