1 /*
   2  * Copyright (c) 2011, 2015, 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 
  29 #import "sun_lwawt_macosx_CPlatformWindow.h"
  30 #import "com_apple_eawt_event_GestureHandler.h"
  31 #import "com_apple_eawt_FullScreenHandler.h"
  32 #import "ApplicationDelegate.h"
  33 
  34 #import "AWTWindow.h"
  35 #import "AWTView.h"
  36 #import "GeomUtilities.h"
  37 #import "ThreadUtilities.h"
  38 
  39 #define MASK(KEY) \
  40     (sun_lwawt_macosx_CPlatformWindow_ ## KEY)
  41 
  42 #define IS(BITS, KEY) \
  43     ((BITS & MASK(KEY)) != 0)
  44 
  45 #define SET(BITS, KEY, VALUE) \
  46     BITS = VALUE ? BITS | MASK(KEY) : BITS & ~MASK(KEY)
  47 
  48 static JNF_CLASS_CACHE(jc_CPlatformWindow, "sun/lwawt/macosx/CPlatformWindow");
  49 
  50 // Cocoa windowDidBecomeKey/windowDidResignKey notifications
  51 // doesn't provide information about "opposite" window, so we
  52 // have to do a bit of tracking. This variable points to a window
  53 // which had been the key window just before a new key window
  54 // was set. It would be nil if the new key window isn't an AWT
  55 // window or the app currently has no key window.
  56 static AWTWindow* lastKeyWindow = nil;
  57 
  58 // --------------------------------------------------------------
  59 // NSWindow/NSPanel descendants implementation
  60 #define AWT_NS_WINDOW_IMPLEMENTATION                            \
  61 - (id) initWithDelegate:(AWTWindow *)delegate                   \
  62               frameRect:(NSRect)contectRect                     \
  63               styleMask:(NSUInteger)styleMask                   \
  64             contentView:(NSView *)view                          \
  65 {                                                               \
  66     self = [super initWithContentRect:contectRect               \
  67                             styleMask:styleMask                 \
  68                               backing:NSBackingStoreBuffered    \
  69                                 defer:NO];                      \
  70                                                                 \
  71     if (self == nil) return nil;                                \
  72                                                                 \
  73     [self setDelegate:delegate];                                \
  74     [self setContentView:view];                                 \
  75     [self setInitialFirstResponder:view];                       \
  76     [self setReleasedWhenClosed:NO];                            \
  77     [self setPreservesContentDuringLiveResize:YES];             \
  78                                                                 \
  79     return self;                                                \
  80 }                                                               \
  81                                                                 \
  82 /* NSWindow overrides */                                        \
  83 - (BOOL) canBecomeKeyWindow {                                   \
  84     return [(AWTWindow*)[self delegate] canBecomeKeyWindow];    \
  85 }                                                               \
  86                                                                 \
  87 - (BOOL) canBecomeMainWindow {                                  \
  88     return [(AWTWindow*)[self delegate] canBecomeMainWindow];   \
  89 }                                                               \
  90                                                                 \
  91 - (BOOL) worksWhenModal {                                       \
  92     return [(AWTWindow*)[self delegate] worksWhenModal];        \
  93 }                                                               \
  94                                                                 \
  95 - (void)sendEvent:(NSEvent *)event {                            \
  96     [(AWTWindow*)[self delegate] sendEvent:event];              \
  97     [super sendEvent:event];                                    \
  98 }
  99 
 100 @implementation AWTWindow_Normal
 101 AWT_NS_WINDOW_IMPLEMENTATION
 102 
 103 // Gesture support
 104 - (void)postGesture:(NSEvent *)event as:(jint)type a:(jdouble)a b:(jdouble)b {
 105     AWT_ASSERT_APPKIT_THREAD;
 106 
 107     JNIEnv *env = [ThreadUtilities getJNIEnv];
 108     jobject platformWindow = [((AWTWindow *)self.delegate).javaPlatformWindow jObjectWithEnv:env];
 109     if (platformWindow != NULL) {
 110         // extract the target AWT Window object out of the CPlatformWindow
 111         static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
 112         jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
 113         if (awtWindow != NULL) {
 114             // translate the point into Java coordinates
 115             NSPoint loc = [event locationInWindow];
 116             loc.y = [self frame].size.height - loc.y;
 117 
 118             // send up to the GestureHandler to recursively dispatch on the AWT event thread
 119             static JNF_CLASS_CACHE(jc_GestureHandler, "com/apple/eawt/event/GestureHandler");
 120             static JNF_STATIC_MEMBER_CACHE(sjm_handleGestureFromNative, jc_GestureHandler, "handleGestureFromNative", "(Ljava/awt/Window;IDDDD)V");
 121             JNFCallStaticVoidMethod(env, sjm_handleGestureFromNative, awtWindow, type, (jdouble)loc.x, (jdouble)loc.y, (jdouble)a, (jdouble)b);
 122             (*env)->DeleteLocalRef(env, awtWindow);
 123         }
 124         (*env)->DeleteLocalRef(env, platformWindow);
 125     }
 126 }
 127 
 128 - (void)beginGestureWithEvent:(NSEvent *)event {
 129     [self postGesture:event
 130                    as:com_apple_eawt_event_GestureHandler_PHASE
 131                     a:-1.0
 132                     b:0.0];
 133 }
 134 
 135 - (void)endGestureWithEvent:(NSEvent *)event {
 136     [self postGesture:event
 137                    as:com_apple_eawt_event_GestureHandler_PHASE
 138                     a:1.0
 139                     b:0.0];
 140 }
 141 
 142 - (void)magnifyWithEvent:(NSEvent *)event {
 143     [self postGesture:event
 144                    as:com_apple_eawt_event_GestureHandler_MAGNIFY
 145                     a:[event magnification]
 146                     b:0.0];
 147 }
 148 
 149 - (void)rotateWithEvent:(NSEvent *)event {
 150     [self postGesture:event
 151                    as:com_apple_eawt_event_GestureHandler_ROTATE
 152                     a:[event rotation]
 153                     b:0.0];
 154 }
 155 
 156 - (void)swipeWithEvent:(NSEvent *)event {
 157     [self postGesture:event
 158                    as:com_apple_eawt_event_GestureHandler_SWIPE
 159                     a:[event deltaX]
 160                     b:[event deltaY]];
 161 }
 162 
 163 @end
 164 @implementation AWTWindow_Panel
 165 AWT_NS_WINDOW_IMPLEMENTATION
 166 @end
 167 // END of NSWindow/NSPanel descendants implementation
 168 // --------------------------------------------------------------
 169 
 170 
 171 @implementation AWTWindow
 172 
 173 @synthesize nsWindow;
 174 @synthesize javaPlatformWindow;
 175 @synthesize javaMenuBar;
 176 @synthesize javaMinSize;
 177 @synthesize javaMaxSize;
 178 @synthesize styleBits;
 179 @synthesize isEnabled;
 180 @synthesize ownerWindow;
 181 @synthesize preFullScreenLevel;
 182 @synthesize standardFrame;
 183 
 184 - (void) updateMinMaxSize:(BOOL)resizable {
 185     if (resizable) {
 186         [self.nsWindow setMinSize:self.javaMinSize];
 187         [self.nsWindow setMaxSize:self.javaMaxSize];
 188     } else {
 189         NSRect currentFrame = [self.nsWindow frame];
 190         [self.nsWindow setMinSize:currentFrame.size];
 191         [self.nsWindow setMaxSize:currentFrame.size];
 192     }
 193 }
 194 
 195 // creates a new NSWindow style mask based on the _STYLE_PROP_BITMASK bits
 196 + (NSUInteger) styleMaskForStyleBits:(jint)styleBits {
 197     NSUInteger type = 0;
 198     if (IS(styleBits, DECORATED)) {
 199         type |= NSTitledWindowMask;
 200         if (IS(styleBits, CLOSEABLE))   type |= NSClosableWindowMask;
 201         if (IS(styleBits, MINIMIZABLE)) type |= NSMiniaturizableWindowMask;
 202         if (IS(styleBits, RESIZABLE))   type |= NSResizableWindowMask;
 203     } else {
 204         type |= NSBorderlessWindowMask;
 205     }
 206 
 207     if (IS(styleBits, TEXTURED))      type |= NSTexturedBackgroundWindowMask;
 208     if (IS(styleBits, UNIFIED))       type |= NSUnifiedTitleAndToolbarWindowMask;
 209     if (IS(styleBits, UTILITY))       type |= NSUtilityWindowMask;
 210     if (IS(styleBits, HUD))           type |= NSHUDWindowMask;
 211     if (IS(styleBits, SHEET))         type |= NSDocModalWindowMask;
 212     if (IS(styleBits, NONACTIVATING)) type |= NSNonactivatingPanelMask;
 213 
 214     return type;
 215 }
 216 
 217 // updates _METHOD_PROP_BITMASK based properties on the window
 218 - (void) setPropertiesForStyleBits:(jint)bits mask:(jint)mask {
 219     if (IS(mask, RESIZABLE)) {
 220         BOOL resizable = IS(bits, RESIZABLE);
 221         [self updateMinMaxSize:resizable];
 222         [self.nsWindow setShowsResizeIndicator:resizable];
 223         // Zoom button should be disabled, if the window is not resizable,
 224         // otherwise button should be restored to initial state.
 225         BOOL zoom = resizable && IS(bits, ZOOMABLE);
 226         [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:zoom];
 227     }
 228 
 229     if (IS(mask, HAS_SHADOW)) {
 230         [self.nsWindow setHasShadow:IS(bits, HAS_SHADOW)];
 231     }
 232 
 233     if (IS(mask, ZOOMABLE)) {
 234         [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:IS(bits, ZOOMABLE)];
 235     }
 236 
 237     if (IS(mask, ALWAYS_ON_TOP)) {
 238         [self.nsWindow setLevel:IS(bits, ALWAYS_ON_TOP) ? NSFloatingWindowLevel : NSNormalWindowLevel];
 239     }
 240 
 241     if (IS(mask, HIDES_ON_DEACTIVATE)) {
 242         [self.nsWindow setHidesOnDeactivate:IS(bits, HIDES_ON_DEACTIVATE)];
 243     }
 244 
 245     if (IS(mask, DRAGGABLE_BACKGROUND)) {
 246         [self.nsWindow setMovableByWindowBackground:IS(bits, DRAGGABLE_BACKGROUND)];
 247     }
 248 
 249     if (IS(mask, DOCUMENT_MODIFIED)) {
 250         [self.nsWindow setDocumentEdited:IS(bits, DOCUMENT_MODIFIED)];
 251     }
 252 
 253     if (IS(mask, FULLSCREENABLE) && [self.nsWindow respondsToSelector:@selector(toggleFullScreen:)]) {
 254         if (IS(bits, FULLSCREENABLE)) {
 255             [self.nsWindow setCollectionBehavior:(1 << 7) /*NSWindowCollectionBehaviorFullScreenPrimary*/];
 256         } else {
 257             [self.nsWindow setCollectionBehavior:NSWindowCollectionBehaviorDefault];
 258         }
 259     }
 260 
 261 }
 262 
 263 - (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)platformWindow
 264                   ownerWindow:owner
 265                     styleBits:(jint)bits
 266                     frameRect:(NSRect)rect
 267                   contentView:(NSView *)view
 268 {
 269 AWT_ASSERT_APPKIT_THREAD;
 270 
 271     NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:bits];
 272     NSRect contentRect = rect; //[NSWindow contentRectForFrameRect:rect styleMask:styleMask];
 273     if (contentRect.size.width <= 0.0) {
 274         contentRect.size.width = 1.0;
 275     }
 276     if (contentRect.size.height <= 0.0) {
 277         contentRect.size.height = 1.0;
 278     }
 279 
 280     self = [super init];
 281 
 282     if (self == nil) return nil; // no hope
 283 
 284     if (IS(bits, UTILITY) ||
 285         IS(bits, NONACTIVATING) ||
 286         IS(bits, HUD) ||
 287         IS(bits, HIDES_ON_DEACTIVATE))
 288     {
 289         self.nsWindow = [[AWTWindow_Panel alloc] initWithDelegate:self
 290                             frameRect:contentRect
 291                             styleMask:styleMask
 292                           contentView:view];
 293     }
 294     else
 295     {
 296         // These windows will appear in the window list in the dock icon menu
 297         self.nsWindow = [[AWTWindow_Normal alloc] initWithDelegate:self
 298                             frameRect:contentRect
 299                             styleMask:styleMask
 300                           contentView:view];
 301     }
 302 
 303     if (self.nsWindow == nil) return nil; // no hope either
 304     [self.nsWindow release]; // the property retains the object already
 305 
 306     self.isEnabled = YES;
 307     self.javaPlatformWindow = platformWindow;
 308     self.styleBits = bits;
 309     self.ownerWindow = owner;
 310     [self setPropertiesForStyleBits:styleBits mask:MASK(_METHOD_PROP_BITMASK)];
 311 
 312     if (IS(self.styleBits, IS_POPUP)) {
 313         [self.nsWindow setCollectionBehavior:(1 << 8) /*NSWindowCollectionBehaviorFullScreenAuxiliary*/]; 
 314     }
 315 
 316     return self;
 317 }
 318 
 319 + (BOOL) isAWTWindow:(NSWindow *)window {
 320     return [window isKindOfClass: [AWTWindow_Panel class]] || [window isKindOfClass: [AWTWindow_Normal class]];
 321 }
 322 
 323 // returns id for the topmost window under mouse
 324 + (NSInteger) getTopmostWindowUnderMouseID {
 325     NSInteger result = -1;
 326     
 327     NSRect screenRect = [[NSScreen mainScreen] frame];
 328     NSPoint nsMouseLocation = [NSEvent mouseLocation];
 329     CGPoint cgMouseLocation = CGPointMake(nsMouseLocation.x, screenRect.size.height - nsMouseLocation.y);
 330 
 331     NSMutableArray *windows = (NSMutableArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
 332 
 333     for (NSDictionary *window in windows) {
 334         NSInteger layer = [[window objectForKey:(id)kCGWindowLayer] integerValue];
 335         if (layer == 0) {
 336             CGRect rect;
 337             CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[window objectForKey:(id)kCGWindowBounds], &rect);
 338             if (CGRectContainsPoint(rect, cgMouseLocation)) {
 339                 result = [[window objectForKey:(id)kCGWindowNumber] integerValue];
 340                 break;
 341             }
 342         }
 343     }
 344     [windows release];
 345     return result;
 346 }
 347 
 348 // checks that this window is under the mouse cursor and this point is not overlapped by others windows
 349 - (BOOL) isTopmostWindowUnderMouse {
 350     return [self.nsWindow windowNumber] == [AWTWindow getTopmostWindowUnderMouseID];
 351 }
 352 
 353 + (AWTWindow *) getTopmostWindowUnderMouse {
 354     NSEnumerator *windowEnumerator = [[NSApp windows] objectEnumerator];
 355     NSWindow *window;
 356 
 357     NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
 358 
 359     while ((window = [windowEnumerator nextObject]) != nil) {
 360         if ([window windowNumber] == topmostWindowUnderMouseID) {
 361             BOOL isAWTWindow = [AWTWindow isAWTWindow: window];
 362             return isAWTWindow ? (AWTWindow *) [window delegate] : nil;
 363         }
 364     }
 365     return nil;
 366 }
 367 
 368 + (void) synthesizeMouseEnteredExitedEvents:(NSWindow*)window withType:(NSEventType)eventType {
 369 
 370     NSPoint screenLocation = [NSEvent mouseLocation];
 371     NSPoint windowLocation = [window convertScreenToBase: screenLocation];
 372     int modifierFlags = (eventType == NSMouseEntered) ? NSMouseEnteredMask : NSMouseExitedMask;
 373 
 374     NSEvent *mouseEvent = [NSEvent enterExitEventWithType: eventType
 375                                                  location: windowLocation
 376                                             modifierFlags: modifierFlags
 377                                                 timestamp: 0
 378                                              windowNumber: [window windowNumber]
 379                                                   context: nil
 380                                               eventNumber: 0
 381                                            trackingNumber: 0
 382                                                  userData: nil
 383                            ];
 384 
 385     [[window contentView] deliverJavaMouseEvent: mouseEvent];
 386 }
 387 
 388 + (void) synthesizeMouseEnteredExitedEventsForAllWindows {
 389 
 390     NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
 391     NSArray *windows = [NSApp windows];
 392     NSWindow *window;
 393 
 394     NSEnumerator *windowEnumerator = [windows objectEnumerator];
 395     while ((window = [windowEnumerator nextObject]) != nil) {
 396         if ([AWTWindow isAWTWindow: window]) {
 397             BOOL isUnderMouse = ([window windowNumber] == topmostWindowUnderMouseID);
 398             BOOL mouseIsOver = [[window contentView] mouseIsOver];
 399             if (isUnderMouse && !mouseIsOver) {
 400                 [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseEntered];
 401             } else if (!isUnderMouse && mouseIsOver) {
 402                 [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseExited];
 403             }
 404         }
 405     }
 406 }
 407 
 408 + (NSNumber *) getNSWindowDisplayID_AppKitThread:(NSWindow *)window {
 409     AWT_ASSERT_APPKIT_THREAD;
 410     NSScreen *screen = [window screen];
 411     NSDictionary *deviceDescription = [screen deviceDescription];
 412     return [deviceDescription objectForKey:@"NSScreenNumber"];
 413 }
 414 
 415 - (void) dealloc {
 416 AWT_ASSERT_APPKIT_THREAD;
 417 
 418     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 419     [self.javaPlatformWindow setJObject:nil withEnv:env];
 420 
 421     self.nsWindow = nil;
 422     self.ownerWindow = nil;
 423     [super dealloc];
 424 }
 425 
 426 // NSWindow overrides
 427 - (BOOL) canBecomeKeyWindow {
 428 AWT_ASSERT_APPKIT_THREAD;
 429     return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_KEY);
 430 }
 431 
 432 - (BOOL) canBecomeMainWindow {
 433 AWT_ASSERT_APPKIT_THREAD;
 434     if (!self.isEnabled) {
 435         // Native system can bring up the NSWindow to
 436         // the top even if the window is not main.
 437         // We should bring up the modal dialog manually
 438         [AWTToolkit eventCountPlusPlus];
 439 
 440         JNIEnv *env = [ThreadUtilities getJNIEnv];
 441         jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 442         if (platformWindow != NULL) {
 443             static JNF_MEMBER_CACHE(jm_checkBlockingAndOrder, jc_CPlatformWindow,
 444                                     "checkBlockingAndOrder", "()Z");
 445             JNFCallBooleanMethod(env, platformWindow, jm_checkBlockingAndOrder);
 446             (*env)->DeleteLocalRef(env, platformWindow);
 447         }
 448     }
 449 
 450     return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_MAIN);
 451 }
 452 
 453 - (BOOL) worksWhenModal {
 454 AWT_ASSERT_APPKIT_THREAD;
 455     return IS(self.styleBits, MODAL_EXCLUDED);
 456 }
 457 
 458 
 459 // NSWindowDelegate methods
 460 
 461 - (void) _deliverMoveResizeEvent {
 462 AWT_ASSERT_APPKIT_THREAD;
 463 
 464     // deliver the event if this is a user-initiated live resize or as a side-effect
 465     // of a Java initiated resize, because AppKit can override the bounds and force
 466     // the bounds of the window to avoid the Dock or remain on screen.
 467     [AWTToolkit eventCountPlusPlus];
 468     JNIEnv *env = [ThreadUtilities getJNIEnv];
 469     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 470     if (platformWindow == NULL) {
 471         // TODO: create generic AWT assert
 472     }
 473 
 474     NSRect frame = ConvertNSScreenRect(env, [self.nsWindow frame]);
 475 
 476     static JNF_MEMBER_CACHE(jm_deliverMoveResizeEvent, jc_CPlatformWindow, "deliverMoveResizeEvent", "(IIIIZ)V");
 477     JNFCallVoidMethod(env, platformWindow, jm_deliverMoveResizeEvent,
 478                       (jint)frame.origin.x,
 479                       (jint)frame.origin.y,
 480                       (jint)frame.size.width,
 481                       (jint)frame.size.height,
 482                       (jboolean)[self.nsWindow inLiveResize]);
 483     (*env)->DeleteLocalRef(env, platformWindow);
 484 
 485     [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
 486 }
 487 
 488 - (void)windowDidMove:(NSNotification *)notification {
 489 AWT_ASSERT_APPKIT_THREAD;
 490 
 491     [self _deliverMoveResizeEvent];
 492 }
 493 
 494 - (void)windowDidResize:(NSNotification *)notification {
 495 AWT_ASSERT_APPKIT_THREAD;
 496 
 497     [self _deliverMoveResizeEvent];
 498 }
 499 
 500 - (void)windowDidExpose:(NSNotification *)notification {
 501 AWT_ASSERT_APPKIT_THREAD;
 502 
 503     [AWTToolkit eventCountPlusPlus];
 504     // TODO: don't see this callback invoked anytime so we track
 505     // window exposing in _setVisible:(BOOL)
 506 }
 507 
 508 - (NSRect)windowWillUseStandardFrame:(NSWindow *)window
 509                         defaultFrame:(NSRect)newFrame {
 510 
 511     return [self standardFrame];
 512 }
 513 
 514 - (void) _deliverIconify:(BOOL)iconify {
 515 AWT_ASSERT_APPKIT_THREAD;
 516 
 517     [AWTToolkit eventCountPlusPlus];
 518     JNIEnv *env = [ThreadUtilities getJNIEnv];
 519     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 520     if (platformWindow != NULL) {
 521         static JNF_MEMBER_CACHE(jm_deliverIconify, jc_CPlatformWindow, "deliverIconify", "(Z)V");
 522         JNFCallVoidMethod(env, platformWindow, jm_deliverIconify, iconify);
 523         (*env)->DeleteLocalRef(env, platformWindow);
 524     }
 525 }
 526 
 527 - (void)windowDidMiniaturize:(NSNotification *)notification {
 528 AWT_ASSERT_APPKIT_THREAD;
 529 
 530     [self _deliverIconify:JNI_TRUE];
 531 }
 532 
 533 - (void)windowDidDeminiaturize:(NSNotification *)notification {
 534 AWT_ASSERT_APPKIT_THREAD;
 535 
 536     [self _deliverIconify:JNI_FALSE];
 537 }
 538 
 539 - (void) _deliverWindowFocusEvent:(BOOL)focused oppositeWindow:(AWTWindow *)opposite {
 540 //AWT_ASSERT_APPKIT_THREAD;
 541     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 542     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 543     if (platformWindow != NULL) {
 544         jobject oppositeWindow = [opposite.javaPlatformWindow jObjectWithEnv:env];
 545 
 546         static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(ZLsun/lwawt/macosx/CPlatformWindow;)V");
 547         JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused, oppositeWindow);
 548         (*env)->DeleteLocalRef(env, platformWindow);
 549         (*env)->DeleteLocalRef(env, oppositeWindow);
 550     }
 551 }
 552 
 553 
 554 - (void) windowDidBecomeKey: (NSNotification *) notification {
 555 AWT_ASSERT_APPKIT_THREAD;
 556     [AWTToolkit eventCountPlusPlus];
 557     AWTWindow *opposite = [AWTWindow lastKeyWindow];
 558 
 559     // Finds appropriate menubar in our hierarchy,
 560     AWTWindow *awtWindow = self;
 561     while (awtWindow.ownerWindow != nil) {
 562         awtWindow = awtWindow.ownerWindow;
 563     }
 564 
 565     CMenuBar *menuBar = nil;
 566     BOOL isDisabled = NO;
 567     if ([awtWindow.nsWindow isVisible]){
 568         menuBar = awtWindow.javaMenuBar;
 569         isDisabled = !awtWindow.isEnabled;
 570     }
 571 
 572     if (menuBar == nil) {
 573         menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
 574         isDisabled = NO;
 575     }
 576 
 577     [CMenuBar activate:menuBar modallyDisabled:isDisabled];
 578 
 579     [AWTWindow setLastKeyWindow:nil];
 580 
 581     [self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
 582 }
 583 
 584 - (void) windowDidResignKey: (NSNotification *) notification {
 585     // TODO: check why sometimes at start is invoked *not* on AppKit main thread.
 586 AWT_ASSERT_APPKIT_THREAD;
 587     [AWTToolkit eventCountPlusPlus];
 588     [self.javaMenuBar deactivate];
 589 
 590     // In theory, this might cause flickering if the window gaining focus
 591     // has its own menu. However, I couldn't reproduce it on practice, so
 592     // perhaps this is a non issue.
 593     CMenuBar* defaultMenu = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
 594     if (defaultMenu != nil) {
 595         [CMenuBar activate:defaultMenu modallyDisabled:NO];
 596     }
 597 
 598     // the new key window
 599     NSWindow *keyWindow = [NSApp keyWindow];
 600     AWTWindow *opposite = nil;
 601     if ([AWTWindow isAWTWindow: keyWindow]) {
 602         opposite = (AWTWindow *)[keyWindow delegate];
 603         [AWTWindow setLastKeyWindow: self];
 604     } else {
 605         [AWTWindow setLastKeyWindow: nil];
 606     }
 607 
 608     [self _deliverWindowFocusEvent:NO oppositeWindow: opposite];
 609 }
 610 
 611 - (void) windowDidBecomeMain: (NSNotification *) notification {
 612 AWT_ASSERT_APPKIT_THREAD;
 613     [AWTToolkit eventCountPlusPlus];
 614 
 615     JNIEnv *env = [ThreadUtilities getJNIEnv];
 616     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 617     if (platformWindow != NULL) {
 618         static JNF_MEMBER_CACHE(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
 619         JNFCallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
 620         (*env)->DeleteLocalRef(env, platformWindow);
 621     }
 622 }
 623 
 624 - (BOOL)windowShouldClose:(id)sender {
 625 AWT_ASSERT_APPKIT_THREAD;
 626     [AWTToolkit eventCountPlusPlus];
 627     JNIEnv *env = [ThreadUtilities getJNIEnv];
 628     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 629     if (platformWindow != NULL) {
 630         static JNF_MEMBER_CACHE(jm_deliverWindowClosingEvent, jc_CPlatformWindow, "deliverWindowClosingEvent", "()V");
 631         JNFCallVoidMethod(env, platformWindow, jm_deliverWindowClosingEvent);
 632         (*env)->DeleteLocalRef(env, platformWindow);
 633     }
 634     // The window will be closed (if allowed) as result of sending Java event
 635     return NO;
 636 }
 637 
 638 
 639 - (void)_notifyFullScreenOp:(jint)op withEnv:(JNIEnv *)env {
 640     static JNF_CLASS_CACHE(jc_FullScreenHandler, "com/apple/eawt/FullScreenHandler");
 641     static JNF_STATIC_MEMBER_CACHE(jm_notifyFullScreenOperation, jc_FullScreenHandler, "handleFullScreenEventFromNative", "(Ljava/awt/Window;I)V");
 642     static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
 643     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 644     if (platformWindow != NULL) {
 645         jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
 646         if (awtWindow != NULL) {
 647             JNFCallStaticVoidMethod(env, jm_notifyFullScreenOperation, awtWindow, op);
 648             (*env)->DeleteLocalRef(env, awtWindow);
 649         }
 650         (*env)->DeleteLocalRef(env, platformWindow);
 651     }
 652 }
 653 
 654 
 655 - (void)windowWillEnterFullScreen:(NSNotification *)notification {
 656     static JNF_MEMBER_CACHE(jm_windowWillEnterFullScreen, jc_CPlatformWindow, "windowWillEnterFullScreen", "()V");
 657     JNIEnv *env = [ThreadUtilities getJNIEnv];
 658     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 659     if (platformWindow != NULL) {
 660         JNFCallVoidMethod(env, platformWindow, jm_windowWillEnterFullScreen);
 661         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_ENTER withEnv:env];
 662         (*env)->DeleteLocalRef(env, platformWindow);
 663     }
 664 }
 665 
 666 - (void)windowDidEnterFullScreen:(NSNotification *)notification {
 667     static JNF_MEMBER_CACHE(jm_windowDidEnterFullScreen, jc_CPlatformWindow, "windowDidEnterFullScreen", "()V");
 668     JNIEnv *env = [ThreadUtilities getJNIEnv];
 669     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 670     if (platformWindow != NULL) {
 671         JNFCallVoidMethod(env, platformWindow, jm_windowDidEnterFullScreen);
 672         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_ENTER withEnv:env];
 673         (*env)->DeleteLocalRef(env, platformWindow);
 674     }
 675     [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
 676 }
 677 
 678 - (void)windowWillExitFullScreen:(NSNotification *)notification {
 679     static JNF_MEMBER_CACHE(jm_windowWillExitFullScreen, jc_CPlatformWindow, "windowWillExitFullScreen", "()V");
 680     JNIEnv *env = [ThreadUtilities getJNIEnv];
 681     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 682     if (platformWindow != NULL) {
 683         JNFCallVoidMethod(env, platformWindow, jm_windowWillExitFullScreen);
 684         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_EXIT withEnv:env];
 685         (*env)->DeleteLocalRef(env, platformWindow);
 686     }
 687 }
 688 
 689 - (void)windowDidExitFullScreen:(NSNotification *)notification {
 690     static JNF_MEMBER_CACHE(jm_windowDidExitFullScreen, jc_CPlatformWindow, "windowDidExitFullScreen", "()V");
 691     JNIEnv *env = [ThreadUtilities getJNIEnv];
 692     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 693     if (platformWindow != NULL) {
 694         JNFCallVoidMethod(env, platformWindow, jm_windowDidExitFullScreen);
 695         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_EXIT withEnv:env];
 696         (*env)->DeleteLocalRef(env, platformWindow);
 697     }
 698     [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
 699 }
 700 
 701 - (void)sendEvent:(NSEvent *)event {
 702         if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
 703 
 704             NSPoint p = [NSEvent mouseLocation];
 705             NSRect frame = [self.nsWindow frame];
 706             NSRect contentRect = [self.nsWindow contentRectForFrameRect:frame];
 707 
 708             // Check if the click happened in the non-client area (title bar)
 709             if (p.y >= (frame.origin.y + contentRect.size.height)) {
 710                 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 711                 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 712                 if (platformWindow != NULL) {
 713                     // Currently, no need to deliver the whole NSEvent.
 714                     static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
 715                     JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
 716                     (*env)->DeleteLocalRef(env, platformWindow);
 717                 }
 718             }
 719         }
 720 }
 721 
 722 - (void)constrainSize:(NSSize*)size {
 723     float minWidth = 0.f, minHeight = 0.f;
 724 
 725     if (IS(self.styleBits, DECORATED)) {
 726         NSRect frame = [self.nsWindow frame];
 727         NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[self.nsWindow styleMask]];
 728 
 729         float top = frame.size.height - contentRect.size.height;
 730         float left = contentRect.origin.x - frame.origin.x;
 731         float bottom = contentRect.origin.y - frame.origin.y;
 732         float right = frame.size.width - (contentRect.size.width + left);
 733 
 734         // Speculative estimation: 80 - enough for window decorations controls
 735         minWidth += left + right + 80;
 736         minHeight += top + bottom;
 737     }
 738 
 739     minWidth = MAX(1.f, minWidth);
 740     minHeight = MAX(1.f, minHeight);
 741 
 742     size->width = MAX(size->width, minWidth);
 743     size->height = MAX(size->height, minHeight);
 744 }
 745 
 746 - (void) setEnabled: (BOOL)flag {
 747     self.isEnabled = flag;
 748 
 749     if (IS(self.styleBits, CLOSEABLE)) {
 750         [[self.nsWindow standardWindowButton:NSWindowCloseButton] setEnabled: flag];
 751     }
 752 
 753     if (IS(self.styleBits, MINIMIZABLE)) {
 754         [[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled: flag];
 755     }
 756 
 757     if (IS(self.styleBits, ZOOMABLE)) {
 758         [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: flag];
 759     }
 760 
 761     if (IS(self.styleBits, RESIZABLE)) {
 762         [self updateMinMaxSize:flag];
 763         [self.nsWindow setShowsResizeIndicator:flag];
 764     }
 765 }
 766 
 767 + (void) setLastKeyWindow:(AWTWindow *)window {
 768     [window retain];
 769     [lastKeyWindow release];
 770     lastKeyWindow = window;
 771 }
 772 
 773 + (AWTWindow *) lastKeyWindow {
 774     return lastKeyWindow;
 775 }
 776 
 777 - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame {
 778     return !NSEqualSizes(self.nsWindow.frame.size, newFrame.size);
 779 }
 780 
 781 
 782 @end // AWTWindow
 783 
 784 
 785 /*
 786  * Class:     sun_lwawt_macosx_CPlatformWindow
 787  * Method:    nativeCreateNSWindow
 788  * Signature: (JJIIII)J
 789  */
 790 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeCreateNSWindow
 791 (JNIEnv *env, jobject obj, jlong contentViewPtr, jlong ownerPtr, jlong styleBits, jdouble x, jdouble y, jdouble w, jdouble h)
 792 {
 793     __block AWTWindow *window = nil;
 794 
 795 JNF_COCOA_ENTER(env);
 796 
 797     JNFWeakJObjectWrapper *platformWindow = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
 798     NSView *contentView = OBJC(contentViewPtr);
 799     NSRect frameRect = NSMakeRect(x, y, w, h);
 800     AWTWindow *owner = [OBJC(ownerPtr) delegate];
 801     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 802 
 803         window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow
 804                                                ownerWindow:owner
 805                                                  styleBits:styleBits
 806                                                  frameRect:frameRect
 807                                                contentView:contentView];
 808         // the window is released is CPlatformWindow.nativeDispose()
 809 
 810         if (window) [window.nsWindow retain];
 811     }];
 812 
 813 JNF_COCOA_EXIT(env);
 814 
 815     return ptr_to_jlong(window ? window.nsWindow : nil);
 816 }
 817 
 818 /*
 819  * Class:     sun_lwawt_macosx_CPlatformWindow
 820  * Method:    nativeSetNSWindowStyleBits
 821  * Signature: (JII)V
 822  */
 823 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStyleBits
 824 (JNIEnv *env, jclass clazz, jlong windowPtr, jint mask, jint bits)
 825 {
 826 JNF_COCOA_ENTER(env);
 827 
 828     NSWindow *nsWindow = OBJC(windowPtr);
 829     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 830 
 831         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 832 
 833         // scans the bit field, and only updates the values requested by the mask
 834         // (this implicity handles the _CALLBACK_PROP_BITMASK case, since those are passive reads)
 835         jint newBits = window.styleBits & ~mask | bits & mask;
 836 
 837         // resets the NSWindow's style mask if the mask intersects any of those bits
 838         if (mask & MASK(_STYLE_PROP_BITMASK)) {
 839             [nsWindow setStyleMask:[AWTWindow styleMaskForStyleBits:newBits]];
 840         }
 841 
 842         // calls methods on NSWindow to change other properties, based on the mask
 843         if (mask & MASK(_METHOD_PROP_BITMASK)) {
 844             [window setPropertiesForStyleBits:newBits mask:mask];
 845         }
 846 
 847         window.styleBits = newBits;
 848     }];
 849 
 850 JNF_COCOA_EXIT(env);
 851 }
 852 
 853 /*
 854  * Class:     sun_lwawt_macosx_CPlatformWindow
 855  * Method:    nativeSetNSWindowMenuBar
 856  * Signature: (JJ)V
 857  */
 858 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMenuBar
 859 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong menuBarPtr)
 860 {
 861 JNF_COCOA_ENTER(env);
 862 
 863     NSWindow *nsWindow = OBJC(windowPtr);
 864     CMenuBar *menuBar = OBJC(menuBarPtr);
 865     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 866 
 867         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 868 
 869         if ([nsWindow isKeyWindow]) {
 870             [window.javaMenuBar deactivate];
 871         }
 872 
 873         window.javaMenuBar = menuBar;
 874 
 875         CMenuBar* actualMenuBar = menuBar;
 876         if (actualMenuBar == nil) {
 877             actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
 878         }
 879 
 880         if ([nsWindow isKeyWindow]) {
 881             [CMenuBar activate:actualMenuBar modallyDisabled:NO];
 882         }
 883     }];
 884 
 885 JNF_COCOA_EXIT(env);
 886 }
 887 
 888 /*
 889  * Class:     sun_lwawt_macosx_CPlatformWindow
 890  * Method:    nativeGetNSWindowInsets
 891  * Signature: (J)Ljava/awt/Insets;
 892  */
 893 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowInsets
 894 (JNIEnv *env, jclass clazz, jlong windowPtr)
 895 {
 896     jobject ret = NULL;
 897 
 898 JNF_COCOA_ENTER(env);
 899 
 900     NSWindow *nsWindow = OBJC(windowPtr);
 901     __block NSRect contentRect = NSZeroRect;
 902     __block NSRect frame = NSZeroRect;
 903 
 904     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 905 
 906         frame = [nsWindow frame];
 907         contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[nsWindow styleMask]];
 908     }];
 909 
 910     jint top = (jint)(frame.size.height - contentRect.size.height);
 911     jint left = (jint)(contentRect.origin.x - frame.origin.x);
 912     jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
 913     jint right = (jint)(frame.size.width - (contentRect.size.width + left));
 914 
 915     static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
 916     static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
 917     ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right);
 918 
 919 JNF_COCOA_EXIT(env);
 920     return ret;
 921 }
 922 
 923 /*
 924  * Class:     sun_lwawt_macosx_CPlatformWindow
 925  * Method:    nativeSetNSWindowBounds
 926  * Signature: (JDDDD)V
 927  */
 928 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowBounds
 929 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY, jdouble width, jdouble height)
 930 {
 931 JNF_COCOA_ENTER(env);
 932 
 933     NSRect jrect = NSMakeRect(originX, originY, width, height);
 934 
 935     // TODO: not sure we need displayIfNeeded message in our view
 936     NSWindow *nsWindow = OBJC(windowPtr);
 937     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 938 
 939         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 940 
 941         NSRect rect = ConvertNSScreenRect(NULL, jrect);
 942         [window constrainSize:&rect.size];
 943 
 944         [nsWindow setFrame:rect display:YES];
 945 
 946         // only start tracking events if pointer is above the toplevel
 947         // TODO: should post an Entered event if YES.
 948         NSPoint mLocation = [NSEvent mouseLocation];
 949         [nsWindow setAcceptsMouseMovedEvents:NSPointInRect(mLocation, rect)];
 950 
 951         // ensure we repaint the whole window after the resize operation
 952         // (this will also re-enable screen updates, which were disabled above)
 953         // TODO: send PaintEvent
 954     }];
 955 
 956 JNF_COCOA_EXIT(env);
 957 }
 958 
 959 /*
 960  * Class:     sun_lwawt_macosx_CPlatformWindow
 961  * Method:    nativeSetNSWindowStandardFrame
 962  * Signature: (JDDDD)V
 963  */
 964 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStandardFrame
 965 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY,
 966      jdouble width, jdouble height)
 967 {
 968     JNF_COCOA_ENTER(env);
 969     
 970     NSRect jrect = NSMakeRect(originX, originY, width, height);
 971     
 972     NSWindow *nsWindow = OBJC(windowPtr);
 973     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 974         
 975         NSRect rect = ConvertNSScreenRect(NULL, jrect);
 976         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 977         window.standardFrame = rect;
 978     }];
 979     
 980     JNF_COCOA_EXIT(env);
 981 }
 982 
 983 /*
 984  * Class:     sun_lwawt_macosx_CPlatformWindow
 985  * Method:    nativeSetNSWindowMinMax
 986  * Signature: (JDDDD)V
 987  */
 988 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinMax
 989 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble minW, jdouble minH, jdouble maxW, jdouble maxH)
 990 {
 991 JNF_COCOA_ENTER(env);
 992 
 993     if (minW < 1) minW = 1;
 994     if (minH < 1) minH = 1;
 995     if (maxW < 1) maxW = 1;
 996     if (maxH < 1) maxH = 1;
 997 
 998     NSWindow *nsWindow = OBJC(windowPtr);
 999     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1000 
1001         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1002 
1003         NSSize min = { minW, minH };
1004         NSSize max = { maxW, maxH };
1005 
1006         [window constrainSize:&min];
1007         [window constrainSize:&max];
1008 
1009         window.javaMinSize = min;
1010         window.javaMaxSize = max;
1011         [window updateMinMaxSize:IS(window.styleBits, RESIZABLE)];
1012     }];
1013 
1014 JNF_COCOA_EXIT(env);
1015 }
1016 
1017 /*
1018  * Class:     sun_lwawt_macosx_CPlatformWindow
1019  * Method:    nativePushNSWindowToBack
1020  * Signature: (J)V
1021  */
1022 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToBack
1023 (JNIEnv *env, jclass clazz, jlong windowPtr)
1024 {
1025 JNF_COCOA_ENTER(env);
1026 
1027     NSWindow *nsWindow = OBJC(windowPtr);
1028     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1029         [nsWindow orderBack:nil];
1030     }];
1031 
1032 JNF_COCOA_EXIT(env);
1033 }
1034 
1035 /*
1036  * Class:     sun_lwawt_macosx_CPlatformWindow
1037  * Method:    nativePushNSWindowToFront
1038  * Signature: (J)V
1039  */
1040 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToFront
1041 (JNIEnv *env, jclass clazz, jlong windowPtr)
1042 {
1043 JNF_COCOA_ENTER(env);
1044 
1045     NSWindow *nsWindow = OBJC(windowPtr);
1046     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1047 
1048         if (![nsWindow isKeyWindow]) {
1049             [nsWindow makeKeyAndOrderFront:nsWindow];
1050         } else {
1051             [nsWindow orderFront:nsWindow];
1052         }
1053     }];
1054 
1055 JNF_COCOA_EXIT(env);
1056 }
1057 
1058 /*
1059  * Class:     sun_lwawt_macosx_CPlatformWindow
1060  * Method:    nativeSetNSWindowTitle
1061  * Signature: (JLjava/lang/String;)V
1062  */
1063 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTitle
1064 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring jtitle)
1065 {
1066 JNF_COCOA_ENTER(env);
1067 
1068     NSWindow *nsWindow = OBJC(windowPtr);
1069     [nsWindow performSelectorOnMainThread:@selector(setTitle:)
1070                               withObject:JNFJavaToNSString(env, jtitle)
1071                            waitUntilDone:NO];
1072 
1073 JNF_COCOA_EXIT(env);
1074 }
1075 
1076 /*
1077  * Class:     sun_lwawt_macosx_CPlatformWindow
1078  * Method:    nativeRevalidateNSWindowShadow
1079  * Signature: (J)V
1080  */
1081 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeRevalidateNSWindowShadow
1082 (JNIEnv *env, jclass clazz, jlong windowPtr)
1083 {
1084 JNF_COCOA_ENTER(env);
1085 
1086     NSWindow *nsWindow = OBJC(windowPtr);
1087     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1088         [nsWindow invalidateShadow];
1089     }];
1090 
1091 JNF_COCOA_EXIT(env);
1092 }
1093 
1094 /*
1095  * Class:     sun_lwawt_macosx_CPlatformWindow
1096  * Method:    nativeScreenOn_AppKitThread
1097  * Signature: (J)I
1098  */
1099 JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeScreenOn_1AppKitThread
1100 (JNIEnv *env, jclass clazz, jlong windowPtr)
1101 {
1102     jint ret = 0;
1103 
1104 JNF_COCOA_ENTER(env);
1105 AWT_ASSERT_APPKIT_THREAD;
1106 
1107     NSWindow *nsWindow = OBJC(windowPtr);
1108     NSDictionary *props = [[nsWindow screen] deviceDescription];
1109     ret = [[props objectForKey:@"NSScreenNumber"] intValue];
1110 
1111 JNF_COCOA_EXIT(env);
1112 
1113     return ret;
1114 }
1115 
1116 /*
1117  * Class:     sun_lwawt_macosx_CPlatformWindow
1118  * Method:    nativeSetNSWindowMinimizedIcon
1119  * Signature: (JJ)V
1120  */
1121 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinimizedIcon
1122 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong nsImagePtr)
1123 {
1124 JNF_COCOA_ENTER(env);
1125 
1126     NSWindow *nsWindow = OBJC(windowPtr);
1127     NSImage *image = OBJC(nsImagePtr);
1128     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1129         [nsWindow setMiniwindowImage:image];
1130     }];
1131 
1132 JNF_COCOA_EXIT(env);
1133 }
1134 
1135 /*
1136  * Class:     sun_lwawt_macosx_CPlatformWindow
1137  * Method:    nativeSetNSWindowRepresentedFilename
1138  * Signature: (JLjava/lang/String;)V
1139  */
1140 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowRepresentedFilename
1141 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring filename)
1142 {
1143 JNF_COCOA_ENTER(env);
1144 
1145     NSWindow *nsWindow = OBJC(windowPtr);
1146     NSURL *url = (filename == NULL) ? nil : [NSURL fileURLWithPath:JNFNormalizedNSStringForPath(env, filename)];
1147     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1148         [nsWindow setRepresentedURL:url];
1149     }];
1150 
1151 JNF_COCOA_EXIT(env);
1152 }
1153 
1154 /*
1155  * Class:     sun_lwawt_macosx_CPlatformWindow
1156  * Method:    nativeGetTopmostPlatformWindowUnderMouse
1157  * Signature: (J)V
1158  */
1159 JNIEXPORT jobject
1160 JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetTopmostPlatformWindowUnderMouse
1161 (JNIEnv *env, jclass clazz)
1162 {
1163     __block jobject topmostWindowUnderMouse = nil;
1164 
1165     JNF_COCOA_ENTER(env);
1166 
1167     [ThreadUtilities performOnMainThreadWaiting:YES block:^{
1168         AWTWindow *awtWindow = [AWTWindow getTopmostWindowUnderMouse];
1169         if (awtWindow != nil) {
1170             topmostWindowUnderMouse = [awtWindow.javaPlatformWindow jObject];
1171         }
1172     }];
1173 
1174     JNF_COCOA_EXIT(env);
1175 
1176     return topmostWindowUnderMouse;
1177 }
1178 
1179 /*
1180  * Class:     sun_lwawt_macosx_CPlatformWindow
1181  * Method:    nativeSynthesizeMouseEnteredExitedEvents
1182  * Signature: (J)V
1183  */
1184 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMouseEnteredExitedEvents
1185 (JNIEnv *env, jclass clazz)
1186 {
1187     JNF_COCOA_ENTER(env);
1188 
1189     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1190         [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
1191     }];
1192 
1193     JNF_COCOA_EXIT(env);
1194 }
1195 
1196 /*
1197  * Class:     sun_lwawt_macosx_CPlatformWindow
1198  * Method:    _toggleFullScreenMode
1199  * Signature: (J)V
1200  */
1201 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow__1toggleFullScreenMode
1202 (JNIEnv *env, jobject peer, jlong windowPtr)
1203 {
1204 JNF_COCOA_ENTER(env);
1205 
1206     NSWindow *nsWindow = OBJC(windowPtr);
1207     SEL toggleFullScreenSelector = @selector(toggleFullScreen:);
1208     if (![nsWindow respondsToSelector:toggleFullScreenSelector]) return;
1209 
1210     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1211         [nsWindow performSelector:toggleFullScreenSelector withObject:nil];
1212     }];
1213 
1214 JNF_COCOA_EXIT(env);
1215 }
1216 
1217 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetEnabled
1218 (JNIEnv *env, jclass clazz, jlong windowPtr, jboolean isEnabled)
1219 {
1220 JNF_COCOA_ENTER(env);
1221 
1222     NSWindow *nsWindow = OBJC(windowPtr);
1223     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1224         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1225 
1226         [window setEnabled: isEnabled];
1227     }];
1228 
1229 JNF_COCOA_EXIT(env);
1230 }
1231 
1232 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeDispose
1233 (JNIEnv *env, jclass clazz, jlong windowPtr)
1234 {
1235 JNF_COCOA_ENTER(env);
1236 
1237     NSWindow *nsWindow = OBJC(windowPtr);
1238     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1239         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1240 
1241         if ([AWTWindow lastKeyWindow] == window) {
1242             [AWTWindow setLastKeyWindow: nil];
1243         }
1244 
1245         // AWTWindow holds a reference to the NSWindow in its nsWindow
1246         // property. Unsetting the delegate allows it to be deallocated
1247         // which releases the reference. This, in turn, allows the window
1248         // itself be deallocated.
1249         [nsWindow setDelegate: nil];
1250 
1251         [window release];
1252     }];
1253 
1254 JNF_COCOA_EXIT(env);
1255 }
1256 
1257 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeEnterFullScreenMode
1258 (JNIEnv *env, jclass clazz, jlong windowPtr)
1259 {
1260 JNF_COCOA_ENTER(env);
1261 
1262     NSWindow *nsWindow = OBJC(windowPtr);
1263     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1264         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1265         NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1266         CGDirectDisplayID aID = [screenID intValue];
1267 
1268         if (CGDisplayCapture(aID) == kCGErrorSuccess) {
1269             // remove window decoration
1270             NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1271             [nsWindow setStyleMask:(styleMask & ~NSTitledWindowMask) | NSBorderlessWindowMask];
1272 
1273             int shieldLevel = CGShieldingWindowLevel();
1274             window.preFullScreenLevel = [nsWindow level];
1275             [nsWindow setLevel: shieldLevel];
1276 
1277             NSRect screenRect = [[nsWindow screen] frame];
1278             [nsWindow setFrame:screenRect display:YES];
1279         } else {
1280             [JNFException raise:[ThreadUtilities getJNIEnv]
1281                              as:kRuntimeException
1282                          reason:"Failed to enter full screen."];
1283         }
1284     }];
1285 
1286 JNF_COCOA_EXIT(env);
1287 }
1288 
1289 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeExitFullScreenMode
1290 (JNIEnv *env, jclass clazz, jlong windowPtr)
1291 {
1292 JNF_COCOA_ENTER(env);
1293 
1294     NSWindow *nsWindow = OBJC(windowPtr);
1295     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1296         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1297         NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1298         CGDirectDisplayID aID = [screenID intValue];
1299 
1300         if (CGDisplayRelease(aID) == kCGErrorSuccess) {
1301             NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1302             [nsWindow setStyleMask:styleMask]; 
1303             [nsWindow setLevel: window.preFullScreenLevel];
1304 
1305             // GraphicsDevice takes care of restoring pre full screen bounds
1306         } else {
1307             [JNFException raise:[ThreadUtilities getJNIEnv]
1308                              as:kRuntimeException
1309                          reason:"Failed to exit full screen."];
1310         }
1311     }];
1312 
1313 JNF_COCOA_EXIT(env);
1314 }
1315