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     NSInteger result = -1;
 265     
 266     NSRect screenRect = [[NSScreen mainScreen] frame];
 267     NSPoint nsMouseLocation = [NSEvent mouseLocation];
 268     CGPoint cgMouseLocation = CGPointMake(nsMouseLocation.x, screenRect.size.height - nsMouseLocation.y);
 269 
 270     NSMutableArray *windows = (NSMutableArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
 271 
 272     for (NSDictionary *window in windows) {
 273         NSInteger layer = [[window objectForKey:(id)kCGWindowLayer] integerValue];
 274         if (layer == 0) {
 275             CGRect rect;
 276             CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[window objectForKey:(id)kCGWindowBounds], &rect);
 277             if (CGRectContainsPoint(rect, cgMouseLocation)) {
 278                 result = [[window objectForKey:(id)kCGWindowNumber] integerValue];
 279                 break;
 280             }
 281         }
 282     }
 283     [windows release];
 284     return result;
 285 }
 286 
 287 // checks that this window is under the mouse cursor and this point is not overlapped by others windows
 288 - (BOOL) isTopmostWindowUnderMouse {
 289     return [self.nsWindow windowNumber] == [AWTWindow getTopmostWindowUnderMouseID];
 290 }
 291 
 292 + (AWTWindow *) getTopmostWindowUnderMouse {
 293     NSEnumerator *windowEnumerator = [[NSApp windows] objectEnumerator];
 294     NSWindow *window;
 295 
 296     NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
 297 
 298     while ((window = [windowEnumerator nextObject]) != nil) {
 299         if ([window windowNumber] == topmostWindowUnderMouseID) {
 300             BOOL isAWTWindow = [AWTWindow isAWTWindow: window];
 301             return isAWTWindow ? (AWTWindow *) [window delegate] : nil;
 302         }
 303     }
 304     return nil;
 305 }
 306 
 307 + (void) synthesizeMouseEnteredExitedEvents:(NSWindow*)window withType:(NSEventType)eventType {
 308 
 309     NSPoint screenLocation = [NSEvent mouseLocation];
 310     NSPoint windowLocation = [window convertScreenToBase: screenLocation];
 311     int modifierFlags = (eventType == NSMouseEntered) ? NSMouseEnteredMask : NSMouseExitedMask;
 312 
 313     NSEvent *mouseEvent = [NSEvent enterExitEventWithType: eventType
 314                                                  location: windowLocation
 315                                             modifierFlags: modifierFlags
 316                                                 timestamp: 0
 317                                              windowNumber: [window windowNumber]
 318                                                   context: nil
 319                                               eventNumber: 0
 320                                            trackingNumber: 0
 321                                                  userData: nil
 322                            ];
 323 
 324     [[window contentView] deliverJavaMouseEvent: mouseEvent];
 325 }
 326 
 327 + (void) synthesizeMouseEnteredExitedEventsForAllWindows {
 328 
 329     NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
 330     NSArray *windows = [NSApp windows];
 331     NSWindow *window;
 332 
 333     NSEnumerator *windowEnumerator = [windows objectEnumerator];
 334     while ((window = [windowEnumerator nextObject]) != nil) {
 335         if ([AWTWindow isAWTWindow: window]) {
 336             BOOL isUnderMouse = ([window windowNumber] == topmostWindowUnderMouseID);
 337             BOOL mouseIsOver = [[window contentView] mouseIsOver];
 338             if (isUnderMouse && !mouseIsOver) {
 339                 [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseEntered];
 340             } else if (!isUnderMouse && mouseIsOver) {
 341                 [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseExited];
 342             }
 343         }
 344     }
 345 }
 346 
 347 + (NSNumber *) getNSWindowDisplayID_AppKitThread:(NSWindow *)window {
 348     AWT_ASSERT_APPKIT_THREAD;
 349     NSScreen *screen = [window screen];
 350     NSDictionary *deviceDescription = [screen deviceDescription];
 351     return [deviceDescription objectForKey:@"NSScreenNumber"];
 352 }
 353 
 354 - (void) dealloc {
 355 AWT_ASSERT_APPKIT_THREAD;
 356 
 357     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 358     [self.javaPlatformWindow setJObject:nil withEnv:env];
 359 
 360     self.nsWindow = nil;
 361     self.ownerWindow = nil;
 362     [super dealloc];
 363 }
 364 
 365 // NSWindow overrides
 366 - (BOOL) canBecomeKeyWindow {
 367 AWT_ASSERT_APPKIT_THREAD;
 368     return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_KEY);
 369 }
 370 
 371 - (BOOL) canBecomeMainWindow {
 372 AWT_ASSERT_APPKIT_THREAD;
 373     if (!self.isEnabled) {
 374         // Native system can bring up the NSWindow to
 375         // the top even if the window is not main.
 376         // We should bring up the modal dialog manually
 377         [AWTToolkit eventCountPlusPlus];
 378 
 379         JNIEnv *env = [ThreadUtilities getJNIEnv];
 380         jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 381         if (platformWindow != NULL) {
 382             static JNF_MEMBER_CACHE(jm_checkBlockingAndOrder, jc_CPlatformWindow,
 383                                     "checkBlockingAndOrder", "()Z");
 384             JNFCallBooleanMethod(env, platformWindow, jm_checkBlockingAndOrder);
 385             (*env)->DeleteLocalRef(env, platformWindow);
 386         }
 387     }
 388 
 389     return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_MAIN);
 390 }
 391 
 392 - (BOOL) worksWhenModal {
 393 AWT_ASSERT_APPKIT_THREAD;
 394     return IS(self.styleBits, MODAL_EXCLUDED);
 395 }
 396 
 397 
 398 // Gesture support
 399 - (void)postGesture:(NSEvent *)event as:(jint)type a:(jdouble)a b:(jdouble)b {
 400 AWT_ASSERT_APPKIT_THREAD;
 401 
 402     JNIEnv *env = [ThreadUtilities getJNIEnv];
 403     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 404     if (platformWindow != NULL) {
 405         // extract the target AWT Window object out of the CPlatformWindow
 406         static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
 407         jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
 408         if (awtWindow != NULL) {
 409             // translate the point into Java coordinates
 410             NSPoint loc = [event locationInWindow];
 411             loc.y = [self.nsWindow frame].size.height - loc.y;
 412 
 413             // send up to the GestureHandler to recursively dispatch on the AWT event thread
 414             static JNF_CLASS_CACHE(jc_GestureHandler, "com/apple/eawt/event/GestureHandler");
 415             static JNF_STATIC_MEMBER_CACHE(sjm_handleGestureFromNative, jc_GestureHandler, "handleGestureFromNative", "(Ljava/awt/Window;IDDDD)V");
 416             JNFCallStaticVoidMethod(env, sjm_handleGestureFromNative, awtWindow, type, (jdouble)loc.x, (jdouble)loc.y, (jdouble)a, (jdouble)b);
 417             (*env)->DeleteLocalRef(env, awtWindow);
 418         }
 419         (*env)->DeleteLocalRef(env, platformWindow);
 420     }
 421 }
 422 
 423 - (void)beginGestureWithEvent:(NSEvent *)event {
 424     [self postGesture:event
 425                    as:com_apple_eawt_event_GestureHandler_PHASE
 426                     a:-1.0
 427                     b:0.0];
 428 }
 429 
 430 - (void)endGestureWithEvent:(NSEvent *)event {
 431     [self postGesture:event
 432                    as:com_apple_eawt_event_GestureHandler_PHASE
 433                     a:1.0
 434                     b:0.0];
 435 }
 436 
 437 - (void)magnifyWithEvent:(NSEvent *)event {
 438     [self postGesture:event
 439                    as:com_apple_eawt_event_GestureHandler_MAGNIFY
 440                     a:[event magnification]
 441                     b:0.0];
 442 }
 443 
 444 - (void)rotateWithEvent:(NSEvent *)event {
 445     [self postGesture:event
 446                    as:com_apple_eawt_event_GestureHandler_ROTATE
 447                     a:[event rotation]
 448                     b:0.0];
 449 }
 450 
 451 - (void)swipeWithEvent:(NSEvent *)event {
 452     [self postGesture:event
 453                    as:com_apple_eawt_event_GestureHandler_SWIPE
 454                     a:[event deltaX]
 455                     b:[event deltaY]];
 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 - (void) _deliverIconify:(BOOL)iconify {
 509 AWT_ASSERT_APPKIT_THREAD;
 510 
 511     [AWTToolkit eventCountPlusPlus];
 512     JNIEnv *env = [ThreadUtilities getJNIEnv];
 513     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 514     if (platformWindow != NULL) {
 515         static JNF_MEMBER_CACHE(jm_deliverIconify, jc_CPlatformWindow, "deliverIconify", "(Z)V");
 516         JNFCallVoidMethod(env, platformWindow, jm_deliverIconify, iconify);
 517         (*env)->DeleteLocalRef(env, platformWindow);
 518     }
 519 }
 520 
 521 - (void)windowDidMiniaturize:(NSNotification *)notification {
 522 AWT_ASSERT_APPKIT_THREAD;
 523 
 524     [self _deliverIconify:JNI_TRUE];
 525 }
 526 
 527 - (void)windowDidDeminiaturize:(NSNotification *)notification {
 528 AWT_ASSERT_APPKIT_THREAD;
 529 
 530     [self _deliverIconify:JNI_FALSE];
 531 }
 532 
 533 - (void) _deliverWindowFocusEvent:(BOOL)focused oppositeWindow:(AWTWindow *)opposite {
 534 //AWT_ASSERT_APPKIT_THREAD;
 535     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 536     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 537     if (platformWindow != NULL) {
 538         jobject oppositeWindow = [opposite.javaPlatformWindow jObjectWithEnv:env];
 539 
 540         static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(ZLsun/lwawt/macosx/CPlatformWindow;)V");
 541         JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused, oppositeWindow);
 542         (*env)->DeleteLocalRef(env, platformWindow);
 543         (*env)->DeleteLocalRef(env, oppositeWindow);
 544     }
 545 }
 546 
 547 
 548 - (void) windowDidBecomeKey: (NSNotification *) notification {
 549 AWT_ASSERT_APPKIT_THREAD;
 550     [AWTToolkit eventCountPlusPlus];
 551     AWTWindow *opposite = [AWTWindow lastKeyWindow];
 552 
 553     // Finds appropriate menubar in our hierarchy,
 554     AWTWindow *awtWindow = self;
 555     while (awtWindow.ownerWindow != nil) {
 556         awtWindow = awtWindow.ownerWindow;
 557     }
 558 
 559     CMenuBar *menuBar = nil;
 560     BOOL isDisabled = NO;
 561     if ([awtWindow.nsWindow isVisible]){
 562         menuBar = awtWindow.javaMenuBar;
 563         isDisabled = !awtWindow.isEnabled;
 564     }
 565 
 566     if (menuBar == nil) {
 567         menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
 568         isDisabled = NO;
 569     }
 570 
 571     [CMenuBar activate:menuBar modallyDisabled:isDisabled];
 572 
 573     [AWTWindow setLastKeyWindow:nil];
 574 
 575     [self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
 576 }
 577 
 578 - (void) windowDidResignKey: (NSNotification *) notification {
 579     // TODO: check why sometimes at start is invoked *not* on AppKit main thread.
 580 AWT_ASSERT_APPKIT_THREAD;
 581     [AWTToolkit eventCountPlusPlus];
 582     [self.javaMenuBar deactivate];
 583 
 584     // In theory, this might cause flickering if the window gaining focus
 585     // has its own menu. However, I couldn't reproduce it on practice, so
 586     // perhaps this is a non issue.
 587     CMenuBar* defaultMenu = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
 588     if (defaultMenu != nil) {
 589         [CMenuBar activate:defaultMenu modallyDisabled:NO];
 590     }
 591 
 592     // the new key window
 593     NSWindow *keyWindow = [NSApp keyWindow];
 594     AWTWindow *opposite = nil;
 595     if ([AWTWindow isAWTWindow: keyWindow]) {
 596         opposite = (AWTWindow *)[keyWindow delegate];
 597         [AWTWindow setLastKeyWindow: self];
 598     } else {
 599         [AWTWindow setLastKeyWindow: nil];
 600     }
 601 
 602     [self _deliverWindowFocusEvent:NO oppositeWindow: opposite];
 603 }
 604 
 605 - (void) windowDidBecomeMain: (NSNotification *) notification {
 606 AWT_ASSERT_APPKIT_THREAD;
 607     [AWTToolkit eventCountPlusPlus];
 608 
 609     JNIEnv *env = [ThreadUtilities getJNIEnv];
 610     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 611     if (platformWindow != NULL) {
 612         static JNF_MEMBER_CACHE(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
 613         JNFCallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
 614         (*env)->DeleteLocalRef(env, platformWindow);
 615     }
 616 }
 617 
 618 - (BOOL)windowShouldClose:(id)sender {
 619 AWT_ASSERT_APPKIT_THREAD;
 620     [AWTToolkit eventCountPlusPlus];
 621     JNIEnv *env = [ThreadUtilities getJNIEnv];
 622     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 623     if (platformWindow != NULL) {
 624         static JNF_MEMBER_CACHE(jm_deliverWindowClosingEvent, jc_CPlatformWindow, "deliverWindowClosingEvent", "()V");
 625         JNFCallVoidMethod(env, platformWindow, jm_deliverWindowClosingEvent);
 626         (*env)->DeleteLocalRef(env, platformWindow);
 627     }
 628     // The window will be closed (if allowed) as result of sending Java event
 629     return NO;
 630 }
 631 
 632 
 633 - (void)_notifyFullScreenOp:(jint)op withEnv:(JNIEnv *)env {
 634     static JNF_CLASS_CACHE(jc_FullScreenHandler, "com/apple/eawt/FullScreenHandler");
 635     static JNF_STATIC_MEMBER_CACHE(jm_notifyFullScreenOperation, jc_FullScreenHandler, "handleFullScreenEventFromNative", "(Ljava/awt/Window;I)V");
 636     static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
 637     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 638     if (platformWindow != NULL) {
 639         jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
 640         if (awtWindow != NULL) {
 641             JNFCallStaticVoidMethod(env, jm_notifyFullScreenOperation, awtWindow, op);
 642             (*env)->DeleteLocalRef(env, awtWindow);
 643         }
 644         (*env)->DeleteLocalRef(env, platformWindow);
 645     }
 646 }
 647 
 648 
 649 - (void)windowWillEnterFullScreen:(NSNotification *)notification {
 650     static JNF_MEMBER_CACHE(jm_windowWillEnterFullScreen, jc_CPlatformWindow, "windowWillEnterFullScreen", "()V");
 651     JNIEnv *env = [ThreadUtilities getJNIEnv];
 652     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 653     if (platformWindow != NULL) {
 654         JNFCallVoidMethod(env, platformWindow, jm_windowWillEnterFullScreen);
 655         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_ENTER withEnv:env];
 656         (*env)->DeleteLocalRef(env, platformWindow);
 657     }
 658 }
 659 
 660 - (void)windowDidEnterFullScreen:(NSNotification *)notification {
 661     static JNF_MEMBER_CACHE(jm_windowDidEnterFullScreen, jc_CPlatformWindow, "windowDidEnterFullScreen", "()V");
 662     JNIEnv *env = [ThreadUtilities getJNIEnv];
 663     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 664     if (platformWindow != NULL) {
 665         JNFCallVoidMethod(env, platformWindow, jm_windowDidEnterFullScreen);
 666         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_ENTER withEnv:env];
 667         (*env)->DeleteLocalRef(env, platformWindow);
 668     }
 669     [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
 670 }
 671 
 672 - (void)windowWillExitFullScreen:(NSNotification *)notification {
 673     static JNF_MEMBER_CACHE(jm_windowWillExitFullScreen, jc_CPlatformWindow, "windowWillExitFullScreen", "()V");
 674     JNIEnv *env = [ThreadUtilities getJNIEnv];
 675     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 676     if (platformWindow != NULL) {
 677         JNFCallVoidMethod(env, platformWindow, jm_windowWillExitFullScreen);
 678         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_EXIT withEnv:env];
 679         (*env)->DeleteLocalRef(env, platformWindow);
 680     }
 681 }
 682 
 683 - (void)windowDidExitFullScreen:(NSNotification *)notification {
 684     static JNF_MEMBER_CACHE(jm_windowDidExitFullScreen, jc_CPlatformWindow, "windowDidExitFullScreen", "()V");
 685     JNIEnv *env = [ThreadUtilities getJNIEnv];
 686     jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 687     if (platformWindow != NULL) {
 688         JNFCallVoidMethod(env, platformWindow, jm_windowDidExitFullScreen);
 689         [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_EXIT withEnv:env];
 690         (*env)->DeleteLocalRef(env, platformWindow);
 691     }
 692     [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
 693 }
 694 
 695 - (void)sendEvent:(NSEvent *)event {
 696         if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
 697 
 698             NSPoint p = [NSEvent mouseLocation];
 699             NSRect frame = [self.nsWindow frame];
 700             NSRect contentRect = [self.nsWindow contentRectForFrameRect:frame];
 701 
 702             // Check if the click happened in the non-client area (title bar)
 703             if (p.y >= (frame.origin.y + contentRect.size.height)) {
 704                 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
 705                 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
 706                 // Currently, no need to deliver the whole NSEvent.
 707                 static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
 708                 JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
 709             }
 710         }
 711 }
 712 
 713 - (void)constrainSize:(NSSize*)size {
 714     float minWidth = 0.f, minHeight = 0.f;
 715 
 716     if (IS(self.styleBits, DECORATED)) {
 717         NSRect frame = [self.nsWindow frame];
 718         NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[self.nsWindow styleMask]];
 719 
 720         float top = frame.size.height - contentRect.size.height;
 721         float left = contentRect.origin.x - frame.origin.x;
 722         float bottom = contentRect.origin.y - frame.origin.y;
 723         float right = frame.size.width - (contentRect.size.width + left);
 724 
 725         // Speculative estimation: 80 - enough for window decorations controls
 726         minWidth += left + right + 80;
 727         minHeight += top + bottom;
 728     }
 729 
 730     minWidth = MAX(1.f, minWidth);
 731     minHeight = MAX(1.f, minHeight);
 732 
 733     size->width = MAX(size->width, minWidth);
 734     size->height = MAX(size->height, minHeight);
 735 }
 736 
 737 - (void) setEnabled: (BOOL)flag {
 738     self.isEnabled = flag;
 739 
 740     if (IS(self.styleBits, CLOSEABLE)) {
 741         [[self.nsWindow standardWindowButton:NSWindowCloseButton] setEnabled: flag];
 742     }
 743 
 744     if (IS(self.styleBits, MINIMIZABLE)) {
 745         [[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled: flag];
 746     }
 747 
 748     if (IS(self.styleBits, ZOOMABLE)) {
 749         [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: flag];
 750     }
 751 
 752     if (IS(self.styleBits, RESIZABLE)) {
 753         [self updateMinMaxSize:flag];
 754         [self.nsWindow setShowsResizeIndicator:flag];
 755     }
 756 }
 757 
 758 + (void) setLastKeyWindow:(AWTWindow *)window {
 759     [window retain];
 760     [lastKeyWindow release];
 761     lastKeyWindow = window;
 762 }
 763 
 764 + (AWTWindow *) lastKeyWindow {
 765     return lastKeyWindow;
 766 }
 767 
 768 - (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame {
 769     return !NSEqualSizes(self.nsWindow.frame.size, newFrame.size);
 770 }
 771 
 772 
 773 @end // AWTWindow
 774 
 775 
 776 /*
 777  * Class:     sun_lwawt_macosx_CPlatformWindow
 778  * Method:    nativeCreateNSWindow
 779  * Signature: (JJIIII)J
 780  */
 781 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeCreateNSWindow
 782 (JNIEnv *env, jobject obj, jlong contentViewPtr, jlong ownerPtr, jlong styleBits, jdouble x, jdouble y, jdouble w, jdouble h)
 783 {
 784     __block AWTWindow *window = nil;
 785 
 786 JNF_COCOA_ENTER(env);
 787 
 788     JNFWeakJObjectWrapper *platformWindow = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
 789     NSView *contentView = OBJC(contentViewPtr);
 790     NSRect frameRect = NSMakeRect(x, y, w, h);
 791     AWTWindow *owner = [OBJC(ownerPtr) delegate];
 792     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 793 
 794         window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow
 795                                                ownerWindow:owner
 796                                                  styleBits:styleBits
 797                                                  frameRect:frameRect
 798                                                contentView:contentView];
 799         // the window is released is CPlatformWindow.nativeDispose()
 800 
 801         if (window) [window.nsWindow retain];
 802     }];
 803 
 804 JNF_COCOA_EXIT(env);
 805 
 806     return ptr_to_jlong(window ? window.nsWindow : nil);
 807 }
 808 
 809 /*
 810  * Class:     sun_lwawt_macosx_CPlatformWindow
 811  * Method:    nativeSetNSWindowStyleBits
 812  * Signature: (JII)V
 813  */
 814 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStyleBits
 815 (JNIEnv *env, jclass clazz, jlong windowPtr, jint mask, jint bits)
 816 {
 817 JNF_COCOA_ENTER(env);
 818 
 819     NSWindow *nsWindow = OBJC(windowPtr);
 820     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 821 
 822         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 823 
 824         // scans the bit field, and only updates the values requested by the mask
 825         // (this implicity handles the _CALLBACK_PROP_BITMASK case, since those are passive reads)
 826         jint newBits = window.styleBits & ~mask | bits & mask;
 827 
 828         // resets the NSWindow's style mask if the mask intersects any of those bits
 829         if (mask & MASK(_STYLE_PROP_BITMASK)) {
 830             [nsWindow setStyleMask:[AWTWindow styleMaskForStyleBits:newBits]];
 831         }
 832 
 833         // calls methods on NSWindow to change other properties, based on the mask
 834         if (mask & MASK(_METHOD_PROP_BITMASK)) {
 835             [window setPropertiesForStyleBits:newBits mask:mask];
 836         }
 837 
 838         window.styleBits = newBits;
 839     }];
 840 
 841 JNF_COCOA_EXIT(env);
 842 }
 843 
 844 /*
 845  * Class:     sun_lwawt_macosx_CPlatformWindow
 846  * Method:    nativeSetNSWindowMenuBar
 847  * Signature: (JJ)V
 848  */
 849 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMenuBar
 850 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong menuBarPtr)
 851 {
 852 JNF_COCOA_ENTER(env);
 853 
 854     NSWindow *nsWindow = OBJC(windowPtr);
 855     CMenuBar *menuBar = OBJC(menuBarPtr);
 856     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 857 
 858         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 859 
 860         if ([nsWindow isKeyWindow]) {
 861             [window.javaMenuBar deactivate];
 862         }
 863 
 864         window.javaMenuBar = menuBar;
 865 
 866         CMenuBar* actualMenuBar = menuBar;
 867         if (actualMenuBar == nil) {
 868             actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
 869         }
 870 
 871         if ([nsWindow isKeyWindow]) {
 872             [CMenuBar activate:actualMenuBar modallyDisabled:NO];
 873         }
 874     }];
 875 
 876 JNF_COCOA_EXIT(env);
 877 }
 878 
 879 /*
 880  * Class:     sun_lwawt_macosx_CPlatformWindow
 881  * Method:    nativeGetNSWindowInsets
 882  * Signature: (J)Ljava/awt/Insets;
 883  */
 884 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowInsets
 885 (JNIEnv *env, jclass clazz, jlong windowPtr)
 886 {
 887     jobject ret = NULL;
 888 
 889 JNF_COCOA_ENTER(env);
 890 
 891     NSWindow *nsWindow = OBJC(windowPtr);
 892     __block NSRect contentRect = NSZeroRect;
 893     __block NSRect frame = NSZeroRect;
 894 
 895     [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 896 
 897         frame = [nsWindow frame];
 898         contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[nsWindow styleMask]];
 899     }];
 900 
 901     jint top = (jint)(frame.size.height - contentRect.size.height);
 902     jint left = (jint)(contentRect.origin.x - frame.origin.x);
 903     jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
 904     jint right = (jint)(frame.size.width - (contentRect.size.width + left));
 905 
 906     static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
 907     static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
 908     ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right);
 909 
 910 JNF_COCOA_EXIT(env);
 911     return ret;
 912 }
 913 
 914 /*
 915  * Class:     sun_lwawt_macosx_CPlatformWindow
 916  * Method:    nativeSetNSWindowBounds
 917  * Signature: (JDDDD)V
 918  */
 919 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowBounds
 920 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY, jdouble width, jdouble height)
 921 {
 922 JNF_COCOA_ENTER(env);
 923 
 924     NSRect jrect = NSMakeRect(originX, originY, width, height);
 925 
 926     // TODO: not sure we need displayIfNeeded message in our view
 927     NSWindow *nsWindow = OBJC(windowPtr);
 928     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 929 
 930         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 931 
 932         NSRect rect = ConvertNSScreenRect(NULL, jrect);
 933         [window constrainSize:&rect.size];
 934 
 935         [nsWindow setFrame:rect display:YES];
 936 
 937         // only start tracking events if pointer is above the toplevel
 938         // TODO: should post an Entered event if YES.
 939         NSPoint mLocation = [NSEvent mouseLocation];
 940         [nsWindow setAcceptsMouseMovedEvents:NSPointInRect(mLocation, rect)];
 941 
 942         // ensure we repaint the whole window after the resize operation
 943         // (this will also re-enable screen updates, which were disabled above)
 944         // TODO: send PaintEvent
 945     }];
 946 
 947 JNF_COCOA_EXIT(env);
 948 }
 949 
 950 /*
 951  * Class:     sun_lwawt_macosx_CPlatformWindow
 952  * Method:    nativeSetNSWindowMinMax
 953  * Signature: (JDDDD)V
 954  */
 955 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinMax
 956 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble minW, jdouble minH, jdouble maxW, jdouble maxH)
 957 {
 958 JNF_COCOA_ENTER(env);
 959 
 960     if (minW < 1) minW = 1;
 961     if (minH < 1) minH = 1;
 962     if (maxW < 1) maxW = 1;
 963     if (maxH < 1) maxH = 1;
 964 
 965     NSWindow *nsWindow = OBJC(windowPtr);
 966     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 967 
 968         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
 969 
 970         NSSize min = { minW, minH };
 971         NSSize max = { maxW, maxH };
 972 
 973         [window constrainSize:&min];
 974         [window constrainSize:&max];
 975 
 976         window.javaMinSize = min;
 977         window.javaMaxSize = max;
 978         [window updateMinMaxSize:IS(window.styleBits, RESIZABLE)];
 979     }];
 980 
 981 JNF_COCOA_EXIT(env);
 982 }
 983 
 984 /*
 985  * Class:     sun_lwawt_macosx_CPlatformWindow
 986  * Method:    nativePushNSWindowToBack
 987  * Signature: (J)V
 988  */
 989 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToBack
 990 (JNIEnv *env, jclass clazz, jlong windowPtr)
 991 {
 992 JNF_COCOA_ENTER(env);
 993 
 994     NSWindow *nsWindow = OBJC(windowPtr);
 995     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
 996         [nsWindow orderBack:nil];
 997     }];
 998 
 999 JNF_COCOA_EXIT(env);
1000 }
1001 
1002 /*
1003  * Class:     sun_lwawt_macosx_CPlatformWindow
1004  * Method:    nativePushNSWindowToFront
1005  * Signature: (J)V
1006  */
1007 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToFront
1008 (JNIEnv *env, jclass clazz, jlong windowPtr)
1009 {
1010 JNF_COCOA_ENTER(env);
1011 
1012     NSWindow *nsWindow = OBJC(windowPtr);
1013     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1014 
1015         if (![nsWindow isKeyWindow]) {
1016             [nsWindow makeKeyAndOrderFront:nsWindow];
1017         } else {
1018             [nsWindow orderFront:nsWindow];
1019         }
1020     }];
1021 
1022 JNF_COCOA_EXIT(env);
1023 }
1024 
1025 /*
1026  * Class:     sun_lwawt_macosx_CPlatformWindow
1027  * Method:    nativeSetNSWindowTitle
1028  * Signature: (JLjava/lang/String;)V
1029  */
1030 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTitle
1031 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring jtitle)
1032 {
1033 JNF_COCOA_ENTER(env);
1034 
1035     NSWindow *nsWindow = OBJC(windowPtr);
1036     [nsWindow performSelectorOnMainThread:@selector(setTitle:)
1037                               withObject:JNFJavaToNSString(env, jtitle)
1038                            waitUntilDone:NO];
1039 
1040 JNF_COCOA_EXIT(env);
1041 }
1042 
1043 /*
1044  * Class:     sun_lwawt_macosx_CPlatformWindow
1045  * Method:    nativeRevalidateNSWindowShadow
1046  * Signature: (J)V
1047  */
1048 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeRevalidateNSWindowShadow
1049 (JNIEnv *env, jclass clazz, jlong windowPtr)
1050 {
1051 JNF_COCOA_ENTER(env);
1052 
1053     NSWindow *nsWindow = OBJC(windowPtr);
1054     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1055         [nsWindow invalidateShadow];
1056     }];
1057 
1058 JNF_COCOA_EXIT(env);
1059 }
1060 
1061 /*
1062  * Class:     sun_lwawt_macosx_CPlatformWindow
1063  * Method:    nativeScreenOn_AppKitThread
1064  * Signature: (J)I
1065  */
1066 JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeScreenOn_1AppKitThread
1067 (JNIEnv *env, jclass clazz, jlong windowPtr)
1068 {
1069     jint ret = 0;
1070 
1071 JNF_COCOA_ENTER(env);
1072 AWT_ASSERT_APPKIT_THREAD;
1073 
1074     NSWindow *nsWindow = OBJC(windowPtr);
1075     NSDictionary *props = [[nsWindow screen] deviceDescription];
1076     ret = [[props objectForKey:@"NSScreenNumber"] intValue];
1077 
1078 JNF_COCOA_EXIT(env);
1079 
1080     return ret;
1081 }
1082 
1083 /*
1084  * Class:     sun_lwawt_macosx_CPlatformWindow
1085  * Method:    nativeSetNSWindowMinimizedIcon
1086  * Signature: (JJ)V
1087  */
1088 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinimizedIcon
1089 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong nsImagePtr)
1090 {
1091 JNF_COCOA_ENTER(env);
1092 
1093     NSWindow *nsWindow = OBJC(windowPtr);
1094     NSImage *image = OBJC(nsImagePtr);
1095     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1096         [nsWindow setMiniwindowImage:image];
1097     }];
1098 
1099 JNF_COCOA_EXIT(env);
1100 }
1101 
1102 /*
1103  * Class:     sun_lwawt_macosx_CPlatformWindow
1104  * Method:    nativeSetNSWindowRepresentedFilename
1105  * Signature: (JLjava/lang/String;)V
1106  */
1107 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowRepresentedFilename
1108 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring filename)
1109 {
1110 JNF_COCOA_ENTER(env);
1111 
1112     NSWindow *nsWindow = OBJC(windowPtr);
1113     NSURL *url = (filename == NULL) ? nil : [NSURL fileURLWithPath:JNFNormalizedNSStringForPath(env, filename)];
1114     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1115         [nsWindow setRepresentedURL:url];
1116     }];
1117 
1118 JNF_COCOA_EXIT(env);
1119 }
1120 
1121 /*
1122  * Class:     sun_lwawt_macosx_CPlatformWindow
1123  * Method:    nativeGetTopmostPlatformWindowUnderMouse
1124  * Signature: (J)V
1125  */
1126 JNIEXPORT jobject
1127 JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetTopmostPlatformWindowUnderMouse
1128 (JNIEnv *env, jclass clazz)
1129 {
1130     jobject topmostWindowUnderMouse = nil;
1131 
1132     JNF_COCOA_ENTER(env);
1133     AWT_ASSERT_APPKIT_THREAD;
1134 
1135     AWTWindow *awtWindow = [AWTWindow getTopmostWindowUnderMouse];
1136     if (awtWindow != nil) {
1137         topmostWindowUnderMouse = [awtWindow.javaPlatformWindow jObject];
1138     }
1139 
1140     JNF_COCOA_EXIT(env);
1141 
1142     return topmostWindowUnderMouse;
1143 }
1144 
1145 /*
1146  * Class:     sun_lwawt_macosx_CPlatformWindow
1147  * Method:    nativeSynthesizeMouseEnteredExitedEvents
1148  * Signature: (J)V
1149  */
1150 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMouseEnteredExitedEvents
1151 (JNIEnv *env, jclass clazz)
1152 {
1153     JNF_COCOA_ENTER(env);
1154 
1155     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1156         [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
1157     }];
1158 
1159     JNF_COCOA_EXIT(env);
1160 }
1161 
1162 /*
1163  * Class:     sun_lwawt_macosx_CPlatformWindow
1164  * Method:    _toggleFullScreenMode
1165  * Signature: (J)V
1166  */
1167 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow__1toggleFullScreenMode
1168 (JNIEnv *env, jobject peer, jlong windowPtr)
1169 {
1170 JNF_COCOA_ENTER(env);
1171 
1172     NSWindow *nsWindow = OBJC(windowPtr);
1173     SEL toggleFullScreenSelector = @selector(toggleFullScreen:);
1174     if (![nsWindow respondsToSelector:toggleFullScreenSelector]) return;
1175 
1176     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1177         [nsWindow performSelector:toggleFullScreenSelector withObject:nil];
1178     }];
1179 
1180 JNF_COCOA_EXIT(env);
1181 }
1182 
1183 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetEnabled
1184 (JNIEnv *env, jclass clazz, jlong windowPtr, jboolean isEnabled)
1185 {
1186 JNF_COCOA_ENTER(env);
1187 
1188     NSWindow *nsWindow = OBJC(windowPtr);
1189     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1190         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1191 
1192         [window setEnabled: isEnabled];
1193     }];
1194 
1195 JNF_COCOA_EXIT(env);
1196 }
1197 
1198 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeDispose
1199 (JNIEnv *env, jclass clazz, jlong windowPtr)
1200 {
1201 JNF_COCOA_ENTER(env);
1202 
1203     NSWindow *nsWindow = OBJC(windowPtr);
1204     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1205         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1206 
1207         if ([AWTWindow lastKeyWindow] == window) {
1208             [AWTWindow setLastKeyWindow: nil];
1209         }
1210 
1211         // AWTWindow holds a reference to the NSWindow in its nsWindow
1212         // property. Unsetting the delegate allows it to be deallocated
1213         // which releases the reference. This, in turn, allows the window
1214         // itself be deallocated.
1215         [nsWindow setDelegate: nil];
1216 
1217         [window release];
1218     }];
1219 
1220 JNF_COCOA_EXIT(env);
1221 }
1222 
1223 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeEnterFullScreenMode
1224 (JNIEnv *env, jclass clazz, jlong windowPtr)
1225 {
1226 JNF_COCOA_ENTER(env);
1227 
1228     NSWindow *nsWindow = OBJC(windowPtr);
1229     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1230         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1231         NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1232         CGDirectDisplayID aID = [screenID intValue];
1233 
1234         if (CGDisplayCapture(aID) == kCGErrorSuccess) {
1235             // remove window decoration
1236             NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1237             [nsWindow setStyleMask:(styleMask & ~NSTitledWindowMask) | NSBorderlessWindowMask];
1238 
1239             int shieldLevel = CGShieldingWindowLevel();
1240             window.preFullScreenLevel = [nsWindow level];
1241             [nsWindow setLevel: shieldLevel];
1242 
1243             NSRect screenRect = [[nsWindow screen] frame];
1244             [nsWindow setFrame:screenRect display:YES];
1245         } else {
1246             [JNFException raise:[ThreadUtilities getJNIEnv]
1247                              as:kRuntimeException
1248                          reason:"Failed to enter full screen."];
1249         }
1250     }];
1251 
1252 JNF_COCOA_EXIT(env);
1253 }
1254 
1255 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeExitFullScreenMode
1256 (JNIEnv *env, jclass clazz, jlong windowPtr)
1257 {
1258 JNF_COCOA_ENTER(env);
1259 
1260     NSWindow *nsWindow = OBJC(windowPtr);
1261     [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1262         AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1263         NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1264         CGDirectDisplayID aID = [screenID intValue];
1265 
1266         if (CGDisplayRelease(aID) == kCGErrorSuccess) {
1267             NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1268             [nsWindow setStyleMask:styleMask]; 
1269             [nsWindow setLevel: window.preFullScreenLevel];
1270 
1271             // GraphicsDevice takes care of restoring pre full screen bounds
1272         } else {
1273             [JNFException raise:[ThreadUtilities getJNIEnv]
1274                              as:kRuntimeException
1275                          reason:"Failed to exit full screen."];
1276         }
1277     }];
1278 
1279 JNF_COCOA_EXIT(env);
1280 }
1281