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