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