1/*
2 * Copyright (c) 2011, 2019, 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
28#import "sun_lwawt_macosx_CPlatformWindow.h"
29#import "com_apple_eawt_event_GestureHandler.h"
30#import "com_apple_eawt_FullScreenHandler.h"
31#import "ApplicationDelegate.h"
32
33#import "AWTWindow.h"
34#import "AWTView.h"
35#import "GeomUtilities.h"
36#import "ThreadUtilities.h"
37#import "JNIUtilities.h"
38
39#define MASK(KEY) \
40    (sun_lwawt_macosx_CPlatformWindow_ ## KEY)
41
42#define IS(BITS, KEY) \
43    ((BITS & MASK(KEY)) != 0)
44
45#define SET(BITS, KEY, VALUE) \
46    BITS = VALUE ? BITS | MASK(KEY) : BITS & ~MASK(KEY)
47
48static jclass jc_CPlatformWindow = NULL;
49#define GET_CPLATFORM_WINDOW_CLASS() \
50    GET_CLASS(jc_CPlatformWindow, "sun/lwawt/macosx/CPlatformWindow");
51
52#define GET_CPLATFORM_WINDOW_CLASS_RETURN(ret) \
53    GET_CLASS_RETURN(jc_CPlatformWindow, "sun/lwawt/macosx/CPlatformWindow", ret);
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.
61static AWTWindow* lastKeyWindow = nil;
62
63// This variable contains coordinates of a window's top left
64// which was positioned via java.awt.Window.setLocationByPlatform.
65// It would be NSZeroPoint if 'Location by Platform' is not used.
66static NSPoint lastTopLeftPoint;
67
68// --------------------------------------------------------------
69// NSWindow/NSPanel descendants implementation
70#define AWT_NS_WINDOW_IMPLEMENTATION                            \
71- (id) initWithDelegate:(AWTWindow *)delegate                   \
72              frameRect:(NSRect)contectRect                     \
73              styleMask:(NSUInteger)styleMask                   \
74            contentView:(NSView *)view                          \
75{                                                               \
76    self = [super initWithContentRect:contectRect               \
77                            styleMask:styleMask                 \
78                              backing:NSBackingStoreBuffered    \
79                                defer:NO];                      \
80                                                                \
81    if (self == nil) return nil;                                \
82                                                                \
83    [self setDelegate:delegate];                                \
84    [self setContentView:view];                                 \
85    [self setInitialFirstResponder:view];                       \
86    [self setReleasedWhenClosed:NO];                            \
87    [self setPreservesContentDuringLiveResize:YES];             \
88                                                                \
89    return self;                                                \
90}                                                               \
91                                                                \
92/* NSWindow overrides */                                        \
93- (BOOL) canBecomeKeyWindow {                                   \
94    return [(AWTWindow*)[self delegate] canBecomeKeyWindow];    \
95}                                                               \
96                                                                \
97- (BOOL) canBecomeMainWindow {                                  \
98    return [(AWTWindow*)[self delegate] canBecomeMainWindow];   \
99}                                                               \
100                                                                \
101- (BOOL) worksWhenModal {                                       \
102    return [(AWTWindow*)[self delegate] worksWhenModal];        \
103}                                                               \
104                                                                \
105- (void)sendEvent:(NSEvent *)event {                            \
106    [(AWTWindow*)[self delegate] sendEvent:event];              \
107    [super sendEvent:event];                                    \
108}
109
110@implementation AWTWindow_Normal
111AWT_NS_WINDOW_IMPLEMENTATION
112
113// Gesture support
114- (void)postGesture:(NSEvent *)event as:(jint)type a:(jdouble)a b:(jdouble)b {
115    AWT_ASSERT_APPKIT_THREAD;
116
117    JNIEnv *env = [ThreadUtilities getJNIEnv];
118    jobject platformWindow = (*env)->NewLocalRef(env, ((AWTWindow *)self.delegate).javaPlatformWindow);
119    if (platformWindow != NULL) {
120        // extract the target AWT Window object out of the CPlatformWindow
121        GET_CPLATFORM_WINDOW_CLASS();
122        DECLARE_FIELD(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
123        jobject awtWindow = (*env)->GetObjectField(env, platformWindow, jf_target);
124        if (awtWindow != NULL) {
125            // translate the point into Java coordinates
126            NSPoint loc = [event locationInWindow];
127            loc.y = [self frame].size.height - loc.y;
128
129            // send up to the GestureHandler to recursively dispatch on the AWT event thread
130            DECLARE_CLASS(jc_GestureHandler, "com/apple/eawt/event/GestureHandler");
131            DECLARE_METHOD(sjm_handleGestureFromNative, jc_GestureHandler,
132                            "handleGestureFromNative", "(Ljava/awt/Window;IDDDD)V");
133            (*env)->CallStaticVoidMethod(env, jc_GestureHandler, sjm_handleGestureFromNative,
134                               awtWindow, type, (jdouble)loc.x, (jdouble)loc.y, (jdouble)a, (jdouble)b);
135            CHECK_EXCEPTION();
136            (*env)->DeleteLocalRef(env, awtWindow);
137        }
138        (*env)->DeleteLocalRef(env, platformWindow);
139    }
140}
141
142- (void)beginGestureWithEvent:(NSEvent *)event {
143    [self postGesture:event
144                   as:com_apple_eawt_event_GestureHandler_PHASE
145                    a:-1.0
146                    b:0.0];
147}
148
149- (void)endGestureWithEvent:(NSEvent *)event {
150    [self postGesture:event
151                   as:com_apple_eawt_event_GestureHandler_PHASE
152                    a:1.0
153                    b:0.0];
154}
155
156- (void)magnifyWithEvent:(NSEvent *)event {
157    [self postGesture:event
158                   as:com_apple_eawt_event_GestureHandler_MAGNIFY
159                    a:[event magnification]
160                    b:0.0];
161}
162
163- (void)rotateWithEvent:(NSEvent *)event {
164    [self postGesture:event
165                   as:com_apple_eawt_event_GestureHandler_ROTATE
166                    a:[event rotation]
167                    b:0.0];
168}
169
170- (void)swipeWithEvent:(NSEvent *)event {
171    [self postGesture:event
172                   as:com_apple_eawt_event_GestureHandler_SWIPE
173                    a:[event deltaX]
174                    b:[event deltaY]];
175}
176
177@end
178@implementation AWTWindow_Panel
179AWT_NS_WINDOW_IMPLEMENTATION
180@end
181// END of NSWindow/NSPanel descendants implementation
182// --------------------------------------------------------------
183
184
185@implementation AWTWindow
186
187@synthesize nsWindow;
188@synthesize javaPlatformWindow;
189@synthesize javaMenuBar;
190@synthesize javaMinSize;
191@synthesize javaMaxSize;
192@synthesize styleBits;
193@synthesize isEnabled;
194@synthesize ownerWindow;
195@synthesize preFullScreenLevel;
196@synthesize standardFrame;
197@synthesize isMinimizing;
198@synthesize keyNotificationRecd;
199
200- (void) updateMinMaxSize:(BOOL)resizable {
201    if (resizable) {
202        [self.nsWindow setMinSize:self.javaMinSize];
203        [self.nsWindow setMaxSize:self.javaMaxSize];
204    } else {
205        NSRect currentFrame = [self.nsWindow frame];
206        [self.nsWindow setMinSize:currentFrame.size];
207        [self.nsWindow setMaxSize:currentFrame.size];
208    }
209}
210
211// creates a new NSWindow style mask based on the _STYLE_PROP_BITMASK bits
212+ (NSUInteger) styleMaskForStyleBits:(jint)styleBits {
213    NSUInteger type = 0;
214    if (IS(styleBits, DECORATED)) {
215        type |= NSTitledWindowMask;
216        if (IS(styleBits, CLOSEABLE))            type |= NSClosableWindowMask;
217        if (IS(styleBits, RESIZABLE))            type |= NSResizableWindowMask;
218        if (IS(styleBits, FULL_WINDOW_CONTENT))  type |= NSFullSizeContentViewWindowMask;
219    } else {
220        type |= NSBorderlessWindowMask;
221    }
222
223    if (IS(styleBits, MINIMIZABLE))   type |= NSMiniaturizableWindowMask;
224    if (IS(styleBits, TEXTURED))      type |= NSTexturedBackgroundWindowMask;
225    if (IS(styleBits, UNIFIED))       type |= NSUnifiedTitleAndToolbarWindowMask;
226    if (IS(styleBits, UTILITY))       type |= NSUtilityWindowMask;
227    if (IS(styleBits, HUD))           type |= NSHUDWindowMask;
228    if (IS(styleBits, SHEET))         type |= NSWindowStyleMaskDocModalWindow;
229    if (IS(styleBits, NONACTIVATING)) type |= NSNonactivatingPanelMask;
230
231    return type;
232}
233
234// updates _METHOD_PROP_BITMASK based properties on the window
235- (void) setPropertiesForStyleBits:(jint)bits mask:(jint)mask {
236    if (IS(mask, RESIZABLE)) {
237        BOOL resizable = IS(bits, RESIZABLE);
238        [self updateMinMaxSize:resizable];
239        [self.nsWindow setShowsResizeIndicator:resizable];
240        // Zoom button should be disabled, if the window is not resizable,
241        // otherwise button should be restored to initial state.
242        BOOL zoom = resizable && IS(bits, ZOOMABLE);
243        [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:zoom];
244    }
245
246    if (IS(mask, HAS_SHADOW)) {
247        [self.nsWindow setHasShadow:IS(bits, HAS_SHADOW)];
248    }
249
250    if (IS(mask, ZOOMABLE)) {
251        [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:IS(bits, ZOOMABLE)];
252    }
253
254    if (IS(mask, ALWAYS_ON_TOP)) {
255        [self.nsWindow setLevel:IS(bits, ALWAYS_ON_TOP) ? NSFloatingWindowLevel : NSNormalWindowLevel];
256    }
257
258    if (IS(mask, HIDES_ON_DEACTIVATE)) {
259        [self.nsWindow setHidesOnDeactivate:IS(bits, HIDES_ON_DEACTIVATE)];
260    }
261
262    if (IS(mask, DRAGGABLE_BACKGROUND)) {
263        [self.nsWindow setMovableByWindowBackground:IS(bits, DRAGGABLE_BACKGROUND)];
264    }
265
266    if (IS(mask, DOCUMENT_MODIFIED)) {
267        [self.nsWindow setDocumentEdited:IS(bits, DOCUMENT_MODIFIED)];
268    }
269
270    if (IS(mask, FULLSCREENABLE) && [self.nsWindow respondsToSelector:@selector(toggleFullScreen:)]) {
271        if (IS(bits, FULLSCREENABLE)) {
272            [self.nsWindow setCollectionBehavior:(1 << 7) /*NSWindowCollectionBehaviorFullScreenPrimary*/];
273        } else {
274            [self.nsWindow setCollectionBehavior:NSWindowCollectionBehaviorDefault];
275        }
276    }
277
278    if (IS(mask, TRANSPARENT_TITLE_BAR) && [self.nsWindow respondsToSelector:@selector(setTitlebarAppearsTransparent:)]) {
279        [self.nsWindow setTitlebarAppearsTransparent:IS(bits, TRANSPARENT_TITLE_BAR)];
280    }
281}
282
283- (id) initWithPlatformWindow:(jobject)platformWindow
284                  ownerWindow:owner
285                    styleBits:(jint)bits
286                    frameRect:(NSRect)rect
287                  contentView:(NSView *)view
288{
289AWT_ASSERT_APPKIT_THREAD;
290
291    NSUInteger newBits = bits;
292    if (IS(bits, SHEET) && owner == nil) {
293        newBits = bits & ~NSWindowStyleMaskDocModalWindow;
294    }
295    NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:newBits];
296
297    NSRect contentRect = rect; //[NSWindow contentRectForFrameRect:rect styleMask:styleMask];
298    if (contentRect.size.width <= 0.0) {
299        contentRect.size.width = 1.0;
300    }
301    if (contentRect.size.height <= 0.0) {
302        contentRect.size.height = 1.0;
303    }
304
305    self = [super init];
306
307    if (self == nil) return nil; // no hope
308
309    if (IS(bits, UTILITY) ||
310        IS(bits, NONACTIVATING) ||
311        IS(bits, HUD) ||
312        IS(bits, HIDES_ON_DEACTIVATE) ||
313        IS(bits, SHEET))
314    {
315        self.nsWindow = [[AWTWindow_Panel alloc] initWithDelegate:self
316                            frameRect:contentRect
317                            styleMask:styleMask
318                          contentView:view];
319    }
320    else
321    {
322        // These windows will appear in the window list in the dock icon menu
323        self.nsWindow = [[AWTWindow_Normal alloc] initWithDelegate:self
324                            frameRect:contentRect
325                            styleMask:styleMask
326                          contentView:view];
327    }
328
329    if (self.nsWindow == nil) return nil; // no hope either
330    [self.nsWindow release]; // the property retains the object already
331
332    self.keyNotificationRecd = NO;
333    self.isEnabled = YES;
334    self.isMinimizing = NO;
335    self.javaPlatformWindow = platformWindow;
336    self.styleBits = bits;
337    self.ownerWindow = owner;
338    [self setPropertiesForStyleBits:styleBits mask:MASK(_METHOD_PROP_BITMASK)];
339
340    if (IS(self.styleBits, IS_POPUP)) {
341        [self.nsWindow setCollectionBehavior:(1 << 8) /*NSWindowCollectionBehaviorFullScreenAuxiliary*/];
342    }
343
344    if (IS(bits, SHEET) && owner != nil) {
345        [self.nsWindow setStyleMask: NSWindowStyleMaskDocModalWindow];
346    }
347
348    return self;
349}
350
351+ (BOOL) isAWTWindow:(NSWindow *)window {
352    return [window isKindOfClass: [AWTWindow_Panel class]] || [window isKindOfClass: [AWTWindow_Normal class]];
353}
354
355// Retrieves the list of possible window layers (levels)
356+ (NSArray*) getWindowLayers {
357    static NSArray *windowLayers;
358    static dispatch_once_t token;
359
360    // Initialize the list of possible window layers
361    dispatch_once(&token, ^{
362        // The layers are ordered from front to back, (i.e. the toppest one is the first)
363        windowLayers = [NSArray arrayWithObjects:
364                            [NSNumber numberWithInt:CGWindowLevelForKey(kCGPopUpMenuWindowLevelKey)],
365                            [NSNumber numberWithInt:CGWindowLevelForKey(kCGFloatingWindowLevelKey)],
366                            [NSNumber numberWithInt:CGWindowLevelForKey(kCGNormalWindowLevelKey)],
367                            nil
368                        ];
369        [windowLayers retain];
370    });
371    return windowLayers;
372}
373
374// returns id for the topmost window under mouse
375+ (NSInteger) getTopmostWindowUnderMouseID {
376    NSInteger result = -1;
377
378    NSArray *windowLayers = [AWTWindow getWindowLayers];
379    // Looking for the window under mouse starting from the toppest layer
380    for (NSNumber *layer in windowLayers) {
381        result = [AWTWindow getTopmostWindowUnderMouseIDImpl:[layer integerValue]];
382        if (result != -1) {
383            break;
384        }
385    }
386    return result;
387}
388
389+ (NSInteger) getTopmostWindowUnderMouseIDImpl:(NSInteger)windowLayer {
390    NSInteger result = -1;
391
392    NSRect screenRect = [[NSScreen mainScreen] frame];
393    NSPoint nsMouseLocation = [NSEvent mouseLocation];
394    CGPoint cgMouseLocation = CGPointMake(nsMouseLocation.x, screenRect.size.height - nsMouseLocation.y);
395
396    NSMutableArray *windows = (NSMutableArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
397
398    for (NSDictionary *window in windows) {
399        NSInteger layer = [[window objectForKey:(id)kCGWindowLayer] integerValue];
400        if (layer == windowLayer) {
401            CGRect rect;
402            CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[window objectForKey:(id)kCGWindowBounds], &rect);
403            if (CGRectContainsPoint(rect, cgMouseLocation)) {
404                result = [[window objectForKey:(id)kCGWindowNumber] integerValue];
405                break;
406            }
407        }
408    }
409    [windows release];
410    return result;
411}
412
413// checks that this window is under the mouse cursor and this point is not overlapped by others windows
414- (BOOL) isTopmostWindowUnderMouse {
415    return [self.nsWindow windowNumber] == [AWTWindow getTopmostWindowUnderMouseID];
416}
417
418+ (AWTWindow *) getTopmostWindowUnderMouse {
419    NSEnumerator *windowEnumerator = [[NSApp windows] objectEnumerator];
420    NSWindow *window;
421
422    NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
423
424    while ((window = [windowEnumerator nextObject]) != nil) {
425        if ([window windowNumber] == topmostWindowUnderMouseID) {
426            BOOL isAWTWindow = [AWTWindow isAWTWindow: window];
427            return isAWTWindow ? (AWTWindow *) [window delegate] : nil;
428        }
429    }
430    return nil;
431}
432
433+ (void) synthesizeMouseEnteredExitedEvents:(NSWindow*)window withType:(NSEventType)eventType {
434
435    NSPoint screenLocation = [NSEvent mouseLocation];
436    NSPoint windowLocation = [window convertScreenToBase: screenLocation];
437    int modifierFlags = (eventType == NSMouseEntered) ? NSMouseEnteredMask : NSMouseExitedMask;
438
439    NSEvent *mouseEvent = [NSEvent enterExitEventWithType: eventType
440                                                 location: windowLocation
441                                            modifierFlags: modifierFlags
442                                                timestamp: 0
443                                             windowNumber: [window windowNumber]
444                                                  context: nil
445                                              eventNumber: 0
446                                           trackingNumber: 0
447                                                 userData: nil
448                           ];
449
450    [[window contentView] deliverJavaMouseEvent: mouseEvent];
451}
452
453+ (void) synthesizeMouseEnteredExitedEventsForAllWindows {
454
455    NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
456    NSArray *windows = [NSApp windows];
457    NSWindow *window;
458
459    NSEnumerator *windowEnumerator = [windows objectEnumerator];
460    while ((window = [windowEnumerator nextObject]) != nil) {
461        if ([AWTWindow isAWTWindow: window]) {
462            BOOL isUnderMouse = ([window windowNumber] == topmostWindowUnderMouseID);
463            BOOL mouseIsOver = [[window contentView] mouseIsOver];
464            if (isUnderMouse && !mouseIsOver) {
465                [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseEntered];
466            } else if (!isUnderMouse && mouseIsOver) {
467                [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseExited];
468            }
469        }
470    }
471}
472
473+ (NSNumber *) getNSWindowDisplayID_AppKitThread:(NSWindow *)window {
474    AWT_ASSERT_APPKIT_THREAD;
475    NSScreen *screen = [window screen];
476    NSDictionary *deviceDescription = [screen deviceDescription];
477    return [deviceDescription objectForKey:@"NSScreenNumber"];
478}
479
480- (void) dealloc {
481AWT_ASSERT_APPKIT_THREAD;
482
483    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
484    (*env)->DeleteWeakGlobalRef(env, self.javaPlatformWindow);
485    self.javaPlatformWindow = nil;
486    self.nsWindow = nil;
487    self.ownerWindow = nil;
488    [super dealloc];
489}
490
491// Tests whether window is blocked by modal dialog/window
492- (BOOL) isBlocked {
493    BOOL isBlocked = NO;
494
495    JNIEnv *env = [ThreadUtilities getJNIEnv];
496    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
497    if (platformWindow != NULL) {
498        GET_CPLATFORM_WINDOW_CLASS_RETURN(isBlocked);
499        DECLARE_METHOD_RETURN(jm_isBlocked, jc_CPlatformWindow, "isBlocked", "()Z", isBlocked);
500        isBlocked = (*env)->CallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
501        CHECK_EXCEPTION();
502        (*env)->DeleteLocalRef(env, platformWindow);
503    }
504
505    return isBlocked;
506}
507
508// Test whether window is simple window and owned by embedded frame
509- (BOOL) isSimpleWindowOwnedByEmbeddedFrame {
510    BOOL isSimpleWindowOwnedByEmbeddedFrame = NO;
511
512    JNIEnv *env = [ThreadUtilities getJNIEnv];
513    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
514    if (platformWindow != NULL) {
515        GET_CPLATFORM_WINDOW_CLASS_RETURN(NO);
516        DECLARE_METHOD_RETURN(jm_isBlocked, jc_CPlatformWindow, "isSimpleWindowOwnedByEmbeddedFrame", "()Z", NO);
517        isSimpleWindowOwnedByEmbeddedFrame = (*env)->CallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
518        CHECK_EXCEPTION();
519        (*env)->DeleteLocalRef(env, platformWindow);
520    }
521
522    return isSimpleWindowOwnedByEmbeddedFrame;
523}
524
525// Tests whether the corresponding Java platform window is visible or not
526+ (BOOL) isJavaPlatformWindowVisible:(NSWindow *)window {
527    BOOL isVisible = NO;
528
529    if ([AWTWindow isAWTWindow:window] && [window delegate] != nil) {
530        AWTWindow *awtWindow = (AWTWindow *)[window delegate];
531        [AWTToolkit eventCountPlusPlus];
532
533        JNIEnv *env = [ThreadUtilities getJNIEnv];
534        jobject platformWindow = (*env)->NewLocalRef(env, awtWindow.javaPlatformWindow);
535        if (platformWindow != NULL) {
536            GET_CPLATFORM_WINDOW_CLASS_RETURN(isVisible);
537            DECLARE_METHOD_RETURN(jm_isVisible, jc_CPlatformWindow, "isVisible", "()Z", isVisible)
538            isVisible = (*env)->CallBooleanMethod(env, platformWindow, jm_isVisible) == JNI_TRUE ? YES : NO;
539            CHECK_EXCEPTION();
540            (*env)->DeleteLocalRef(env, platformWindow);
541
542        }
543    }
544    return isVisible;
545}
546
547// Orders window's childs based on the current focus state
548- (void) orderChildWindows:(BOOL)focus {
549AWT_ASSERT_APPKIT_THREAD;
550
551    if (self.isMinimizing || [self isBlocked]) {
552        // Do not perform any ordering, if iconify is in progress
553        // or the window is blocked by a modal window
554        return;
555    }
556
557    NSEnumerator *windowEnumerator = [[NSApp windows]objectEnumerator];
558    NSWindow *window;
559    while ((window = [windowEnumerator nextObject]) != nil) {
560        if ([AWTWindow isJavaPlatformWindowVisible:window]) {
561            AWTWindow *awtWindow = (AWTWindow *)[window delegate];
562            AWTWindow *owner = awtWindow.ownerWindow;
563            if (IS(awtWindow.styleBits, ALWAYS_ON_TOP)) {
564                // Do not order 'always on top' windows
565                continue;
566            }
567            while (awtWindow.ownerWindow != nil) {
568                if (awtWindow.ownerWindow == self) {
569                    if (focus) {
570                        // Move the childWindow to floating level
571                        // so it will appear in front of its
572                        // parent which owns the focus
573                        [window setLevel:NSFloatingWindowLevel];
574                    } else {
575                        // Focus owner has changed, move the childWindow
576                        // back to normal window level
577                        [window setLevel:NSNormalWindowLevel];
578                    }
579                    // The childWindow should be displayed in front of
580                    // its nearest parentWindow
581                    [window orderWindow:NSWindowAbove relativeTo:[owner.nsWindow windowNumber]];
582                    break;
583                }
584                awtWindow = awtWindow.ownerWindow;
585            }
586        }
587    }
588}
589
590// NSWindow overrides
591- (BOOL) canBecomeKeyWindow {
592AWT_ASSERT_APPKIT_THREAD;
593    return self.isEnabled && (IS(self.styleBits, SHOULD_BECOME_KEY) || [self isSimpleWindowOwnedByEmbeddedFrame]);
594}
595
596- (BOOL) canBecomeMainWindow {
597AWT_ASSERT_APPKIT_THREAD;
598    if (!self.isEnabled) {
599        // Native system can bring up the NSWindow to
600        // the top even if the window is not main.
601        // We should bring up the modal dialog manually
602        [AWTToolkit eventCountPlusPlus];
603
604        JNIEnv *env = [ThreadUtilities getJNIEnv];
605        jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
606        if (platformWindow != NULL) {
607            GET_CPLATFORM_WINDOW_CLASS_RETURN(NO);
608            DECLARE_METHOD_RETURN(jm_checkBlockingAndOrder, jc_CPlatformWindow, "checkBlockingAndOrder", "()Z", NO);
609            (*env)->CallBooleanMethod(env, platformWindow, jm_checkBlockingAndOrder);
610            CHECK_EXCEPTION();
611            (*env)->DeleteLocalRef(env, platformWindow);
612        }
613    }
614
615    return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_MAIN);
616}
617
618- (BOOL) worksWhenModal {
619AWT_ASSERT_APPKIT_THREAD;
620    return IS(self.styleBits, MODAL_EXCLUDED);
621}
622
623
624// NSWindowDelegate methods
625
626- (void) _deliverMoveResizeEvent {
627AWT_ASSERT_APPKIT_THREAD;
628
629    // deliver the event if this is a user-initiated live resize or as a side-effect
630    // of a Java initiated resize, because AppKit can override the bounds and force
631    // the bounds of the window to avoid the Dock or remain on screen.
632    [AWTToolkit eventCountPlusPlus];
633    JNIEnv *env = [ThreadUtilities getJNIEnv];
634    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
635    if (platformWindow == NULL) {
636        // TODO: create generic AWT assert
637    }
638
639    NSRect frame = ConvertNSScreenRect(env, [self.nsWindow frame]);
640
641    GET_CPLATFORM_WINDOW_CLASS();
642    DECLARE_METHOD(jm_deliverMoveResizeEvent, jc_CPlatformWindow, "deliverMoveResizeEvent", "(IIIIZ)V");
643    (*env)->CallVoidMethod(env, platformWindow, jm_deliverMoveResizeEvent,
644                      (jint)frame.origin.x,
645                      (jint)frame.origin.y,
646                      (jint)frame.size.width,
647                      (jint)frame.size.height,
648                      (jboolean)[self.nsWindow inLiveResize]);
649    CHECK_EXCEPTION();
650    (*env)->DeleteLocalRef(env, platformWindow);
651
652    [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
653}
654
655- (void)windowDidMove:(NSNotification *)notification {
656AWT_ASSERT_APPKIT_THREAD;
657
658    [self _deliverMoveResizeEvent];
659}
660
661- (void)windowDidResize:(NSNotification *)notification {
662AWT_ASSERT_APPKIT_THREAD;
663
664    [self _deliverMoveResizeEvent];
665}
666
667- (void)windowDidExpose:(NSNotification *)notification {
668AWT_ASSERT_APPKIT_THREAD;
669
670    [AWTToolkit eventCountPlusPlus];
671    // TODO: don't see this callback invoked anytime so we track
672    // window exposing in _setVisible:(BOOL)
673}
674
675- (NSRect)windowWillUseStandardFrame:(NSWindow *)window
676                        defaultFrame:(NSRect)newFrame {
677
678    return NSEqualSizes(NSZeroSize, [self standardFrame].size)
679                ? newFrame
680                : [self standardFrame];
681}
682
683// Hides/shows window's childs during iconify/de-iconify operation
684- (void) iconifyChildWindows:(BOOL)iconify {
685AWT_ASSERT_APPKIT_THREAD;
686
687    NSEnumerator *windowEnumerator = [[NSApp windows]objectEnumerator];
688    NSWindow *window;
689    while ((window = [windowEnumerator nextObject]) != nil) {
690        if ([AWTWindow isJavaPlatformWindowVisible:window]) {
691            AWTWindow *awtWindow = (AWTWindow *)[window delegate];
692            while (awtWindow.ownerWindow != nil) {
693                if (awtWindow.ownerWindow == self) {
694                    if (iconify) {
695                        [window orderOut:window];
696                    } else {
697                        [window orderFront:window];
698                    }
699                    break;
700                }
701                awtWindow = awtWindow.ownerWindow;
702            }
703        }
704    }
705}
706
707- (void) _deliverIconify:(BOOL)iconify {
708AWT_ASSERT_APPKIT_THREAD;
709
710    [AWTToolkit eventCountPlusPlus];
711    JNIEnv *env = [ThreadUtilities getJNIEnv];
712    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
713    if (platformWindow != NULL) {
714        GET_CPLATFORM_WINDOW_CLASS();
715        DECLARE_METHOD(jm_deliverIconify, jc_CPlatformWindow, "deliverIconify", "(Z)V");
716        (*env)->CallVoidMethod(env, platformWindow, jm_deliverIconify, iconify);
717        CHECK_EXCEPTION();
718        (*env)->DeleteLocalRef(env, platformWindow);
719    }
720}
721
722- (void)windowWillMiniaturize:(NSNotification *)notification {
723AWT_ASSERT_APPKIT_THREAD;
724
725    self.isMinimizing = YES;
726
727    JNIEnv *env = [ThreadUtilities getJNIEnv];
728    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
729    if (platformWindow != NULL) {
730        GET_CPLATFORM_WINDOW_CLASS();
731        DECLARE_METHOD(jm_windowWillMiniaturize, jc_CPlatformWindow, "windowWillMiniaturize", "()V");
732        (*env)->CallVoidMethod(env, platformWindow, jm_windowWillMiniaturize);
733        CHECK_EXCEPTION();
734        (*env)->DeleteLocalRef(env, platformWindow);
735    }
736    // Explicitly make myself a key window to avoid possible
737    // negative visual effects during iconify operation
738    [self.nsWindow makeKeyAndOrderFront:self.nsWindow];
739    [self iconifyChildWindows:YES];
740}
741
742- (void)windowDidMiniaturize:(NSNotification *)notification {
743AWT_ASSERT_APPKIT_THREAD;
744
745    [self _deliverIconify:JNI_TRUE];
746    self.isMinimizing = NO;
747}
748
749- (void)windowDidDeminiaturize:(NSNotification *)notification {
750AWT_ASSERT_APPKIT_THREAD;
751
752    [self _deliverIconify:JNI_FALSE];
753    [self iconifyChildWindows:NO];
754}
755
756- (void) _deliverWindowFocusEvent:(BOOL)focused oppositeWindow:(AWTWindow *)opposite {
757//AWT_ASSERT_APPKIT_THREAD;
758    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
759    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
760    if (platformWindow != NULL) {
761        jobject oppositeWindow = (*env)->NewLocalRef(env, opposite.javaPlatformWindow);
762        GET_CPLATFORM_WINDOW_CLASS();
763        DECLARE_METHOD(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(ZLsun/lwawt/macosx/CPlatformWindow;)V");
764        (*env)->CallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused, oppositeWindow);
765        CHECK_EXCEPTION();
766        (*env)->DeleteLocalRef(env, platformWindow);
767        (*env)->DeleteLocalRef(env, oppositeWindow);
768    }
769}
770
771- (void) windowDidBecomeMain: (NSNotification *) notification {
772AWT_ASSERT_APPKIT_THREAD;
773    [AWTToolkit eventCountPlusPlus];
774#ifdef DEBUG
775    NSLog(@"became main: %d %@ %@ %d", [self.nsWindow isKeyWindow], [self.nsWindow title], [self menuBarForWindow], self.keyNotificationRecd);
776#endif
777
778    // if for some reason, no KEY notification is received but this main window is also a key window
779    // then we need to execute the KEY notification functionality.
780    if(self.keyNotificationRecd != YES && [self.nsWindow isKeyWindow]) {
781        [self doWindowDidBecomeKey];
782    }
783    self.keyNotificationRecd = NO;
784
785    if (![self.nsWindow isKeyWindow]) {
786        [self activateWindowMenuBar];
787    }
788
789    JNIEnv *env = [ThreadUtilities getJNIEnv];
790    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
791    if (platformWindow != NULL) {
792        GET_CPLATFORM_WINDOW_CLASS();
793        DECLARE_METHOD(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
794        (*env)->CallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
795        CHECK_EXCEPTION();
796        (*env)->DeleteLocalRef(env, platformWindow);
797    }
798}
799
800- (void) windowDidBecomeKey: (NSNotification *) notification {
801AWT_ASSERT_APPKIT_THREAD;
802    [AWTToolkit eventCountPlusPlus];
803#ifdef DEBUG
804    NSLog(@"became key: %d %@ %@", [self.nsWindow isMainWindow], [self.nsWindow title], [self menuBarForWindow]);
805#endif
806    [self doWindowDidBecomeKey];
807    self.keyNotificationRecd = YES;
808}
809
810- (void) doWindowDidBecomeKey {
811AWT_ASSERT_APPKIT_THREAD;
812    AWTWindow *opposite = [AWTWindow lastKeyWindow];
813
814    if (![self.nsWindow isMainWindow]) {
815        [self activateWindowMenuBar];
816    }
817
818    [AWTWindow setLastKeyWindow:nil];
819
820    [self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
821    [self orderChildWindows:YES];
822}
823
824- (void) activateWindowMenuBar {
825AWT_ASSERT_APPKIT_THREAD;
826    // Finds appropriate menubar in our hierarchy
827    AWTWindow *awtWindow = self;
828    while (awtWindow.ownerWindow != nil) {
829        awtWindow = awtWindow.ownerWindow;
830    }
831
832    CMenuBar *menuBar = nil;
833    BOOL isDisabled = NO;
834    if ([awtWindow.nsWindow isVisible]){
835        menuBar = awtWindow.javaMenuBar;
836        isDisabled = !awtWindow.isEnabled;
837    }
838
839    if (menuBar == nil) {
840        menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
841        isDisabled = NO;
842    }
843
844    [CMenuBar activate:menuBar modallyDisabled:isDisabled];
845}
846
847#ifdef DEBUG
848- (CMenuBar *) menuBarForWindow {
849AWT_ASSERT_APPKIT_THREAD;
850    AWTWindow *awtWindow = self;
851    while (awtWindow.ownerWindow != nil) {
852        awtWindow = awtWindow.ownerWindow;
853    }
854    return awtWindow.javaMenuBar;
855}
856#endif
857
858- (void) windowDidResignKey: (NSNotification *) notification {
859    // TODO: check why sometimes at start is invoked *not* on AppKit main thread.
860AWT_ASSERT_APPKIT_THREAD;
861    [AWTToolkit eventCountPlusPlus];
862#ifdef DEBUG
863    NSLog(@"resigned key: %d %@ %@", [self.nsWindow isMainWindow], [self.nsWindow title], [self menuBarForWindow]);
864#endif
865    if (![self.nsWindow isMainWindow]) {
866        [self deactivateWindow];
867    }
868}
869
870- (void) windowDidResignMain: (NSNotification *) notification {
871AWT_ASSERT_APPKIT_THREAD;
872    [AWTToolkit eventCountPlusPlus];
873#ifdef DEBUG
874    NSLog(@"resigned main: %d %@ %@", [self.nsWindow isKeyWindow], [self.nsWindow title], [self menuBarForWindow]);
875#endif
876    if (![self.nsWindow isKeyWindow]) {
877        [self deactivateWindow];
878    }
879}
880
881- (void) deactivateWindow {
882AWT_ASSERT_APPKIT_THREAD;
883#ifdef DEBUG
884    NSLog(@"deactivating window: %@", [self.nsWindow title]);
885#endif
886    [self.javaMenuBar deactivate];
887
888    // the new key window
889    NSWindow *keyWindow = [NSApp keyWindow];
890    AWTWindow *opposite = nil;
891    if ([AWTWindow isAWTWindow: keyWindow]) {
892        opposite = (AWTWindow *)[keyWindow delegate];
893        [AWTWindow setLastKeyWindow: self];
894    } else {
895        [AWTWindow setLastKeyWindow: nil];
896    }
897
898    [self _deliverWindowFocusEvent:NO oppositeWindow: opposite];
899    [self orderChildWindows:NO];
900}
901
902- (BOOL)windowShouldClose:(id)sender {
903AWT_ASSERT_APPKIT_THREAD;
904    [AWTToolkit eventCountPlusPlus];
905    JNIEnv *env = [ThreadUtilities getJNIEnv];
906    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
907    if (platformWindow != NULL) {
908        GET_CPLATFORM_WINDOW_CLASS_RETURN(NO);
909        DECLARE_METHOD_RETURN(jm_deliverWindowClosingEvent, jc_CPlatformWindow, "deliverWindowClosingEvent", "()V", NO);
910        (*env)->CallVoidMethod(env, platformWindow, jm_deliverWindowClosingEvent);
911        CHECK_EXCEPTION();
912        (*env)->DeleteLocalRef(env, platformWindow);
913    }
914    // The window will be closed (if allowed) as result of sending Java event
915    return NO;
916}
917
918- (void)_notifyFullScreenOp:(jint)op withEnv:(JNIEnv *)env {
919    DECLARE_CLASS(jc_FullScreenHandler, "com/apple/eawt/FullScreenHandler");
920    DECLARE_STATIC_METHOD(jm_notifyFullScreenOperation, jc_FullScreenHandler,
921                           "handleFullScreenEventFromNative", "(Ljava/awt/Window;I)V");
922    GET_CPLATFORM_WINDOW_CLASS();
923    DECLARE_FIELD(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
924    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
925    if (platformWindow != NULL) {
926        jobject awtWindow = (*env)->GetObjectField(env, platformWindow, jf_target);
927        if (awtWindow != NULL) {
928            (*env)->CallStaticVoidMethod(env, jc_FullScreenHandler, jm_notifyFullScreenOperation, awtWindow, op);
929            CHECK_EXCEPTION();
930            (*env)->DeleteLocalRef(env, awtWindow);
931        }
932        (*env)->DeleteLocalRef(env, platformWindow);
933    }
934}
935
936
937- (void)windowWillEnterFullScreen:(NSNotification *)notification {
938    JNIEnv *env = [ThreadUtilities getJNIEnv];
939    GET_CPLATFORM_WINDOW_CLASS();
940    DECLARE_METHOD(jm_windowWillEnterFullScreen, jc_CPlatformWindow, "windowWillEnterFullScreen", "()V");
941    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
942    if (platformWindow != NULL) {
943        (*env)->CallVoidMethod(env, platformWindow, jm_windowWillEnterFullScreen);
944        CHECK_EXCEPTION();
945        [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_ENTER withEnv:env];
946        (*env)->DeleteLocalRef(env, platformWindow);
947    }
948}
949
950- (void)windowDidEnterFullScreen:(NSNotification *)notification {
951    JNIEnv *env = [ThreadUtilities getJNIEnv];
952    GET_CPLATFORM_WINDOW_CLASS();
953    DECLARE_METHOD(jm_windowDidEnterFullScreen, jc_CPlatformWindow, "windowDidEnterFullScreen", "()V");
954    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
955    if (platformWindow != NULL) {
956        (*env)->CallVoidMethod(env, platformWindow, jm_windowDidEnterFullScreen);
957        CHECK_EXCEPTION();
958        [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_ENTER withEnv:env];
959        (*env)->DeleteLocalRef(env, platformWindow);
960    }
961    [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
962}
963
964- (void)windowWillExitFullScreen:(NSNotification *)notification {
965    JNIEnv *env = [ThreadUtilities getJNIEnv];
966    GET_CPLATFORM_WINDOW_CLASS();
967    DECLARE_METHOD(jm_windowWillExitFullScreen, jc_CPlatformWindow, "windowWillExitFullScreen", "()V");
968    if (jm_windowWillExitFullScreen == NULL) {
969        GET_CPLATFORM_WINDOW_CLASS();
970        jm_windowWillExitFullScreen = (*env)->GetMethodID(env, jc_CPlatformWindow, "windowWillExitFullScreen", "()V");
971    }
972    CHECK_NULL(jm_windowWillExitFullScreen);
973    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
974    if (platformWindow != NULL) {
975        (*env)->CallVoidMethod(env, platformWindow, jm_windowWillExitFullScreen);
976        CHECK_EXCEPTION();
977        [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_EXIT withEnv:env];
978        (*env)->DeleteLocalRef(env, platformWindow);
979    }
980}
981
982- (void)windowDidExitFullScreen:(NSNotification *)notification {
983    JNIEnv *env = [ThreadUtilities getJNIEnv];
984    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
985    if (platformWindow != NULL) {
986        GET_CPLATFORM_WINDOW_CLASS();
987        DECLARE_METHOD(jm_windowDidExitFullScreen, jc_CPlatformWindow, "windowDidExitFullScreen", "()V");
988        (*env)->CallVoidMethod(env, platformWindow, jm_windowDidExitFullScreen);
989        CHECK_EXCEPTION();
990        [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_EXIT withEnv:env];
991        (*env)->DeleteLocalRef(env, platformWindow);
992    }
993    [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
994}
995
996- (void)sendEvent:(NSEvent *)event {
997        if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
998            if ([self isBlocked]) {
999                // Move parent windows to front and make sure that a child window is displayed
1000                // in front of its nearest parent.
1001                if (self.ownerWindow != nil) {
1002                    JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
1003                    jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
1004                    if (platformWindow != NULL) {
1005                        GET_CPLATFORM_WINDOW_CLASS();
1006                        DECLARE_METHOD(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
1007                        (*env)->CallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
1008                        CHECK_EXCEPTION();
1009                        (*env)->DeleteLocalRef(env, platformWindow);
1010                    }
1011                }
1012                [self orderChildWindows:YES];
1013            }
1014
1015            NSPoint p = [NSEvent mouseLocation];
1016            NSRect frame = [self.nsWindow frame];
1017            NSRect contentRect = [self.nsWindow contentRectForFrameRect:frame];
1018
1019            // Check if the click happened in the non-client area (title bar)
1020            if (p.y >= (frame.origin.y + contentRect.size.height)) {
1021                JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
1022                jobject platformWindow = (*env)->NewLocalRef(env, self.javaPlatformWindow);
1023                if (platformWindow != NULL) {
1024                    // Currently, no need to deliver the whole NSEvent.
1025                    GET_CPLATFORM_WINDOW_CLASS();
1026                    DECLARE_METHOD(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
1027                    (*env)->CallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
1028                    CHECK_EXCEPTION();
1029                    (*env)->DeleteLocalRef(env, platformWindow);
1030                }
1031            }
1032        }
1033}
1034
1035- (void)constrainSize:(NSSize*)size {
1036    float minWidth = 0.f, minHeight = 0.f;
1037
1038    if (IS(self.styleBits, DECORATED)) {
1039        NSRect frame = [self.nsWindow frame];
1040        NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[self.nsWindow styleMask]];
1041
1042        float top = frame.size.height - contentRect.size.height;
1043        float left = contentRect.origin.x - frame.origin.x;
1044        float bottom = contentRect.origin.y - frame.origin.y;
1045        float right = frame.size.width - (contentRect.size.width + left);
1046
1047        // Speculative estimation: 80 - enough for window decorations controls
1048        minWidth += left + right + 80;
1049        minHeight += top + bottom;
1050    }
1051
1052    minWidth = MAX(1.f, minWidth);
1053    minHeight = MAX(1.f, minHeight);
1054
1055    size->width = MAX(size->width, minWidth);
1056    size->height = MAX(size->height, minHeight);
1057}
1058
1059- (void) setEnabled: (BOOL)flag {
1060    self.isEnabled = flag;
1061
1062    if (IS(self.styleBits, CLOSEABLE)) {
1063        [[self.nsWindow standardWindowButton:NSWindowCloseButton] setEnabled: flag];
1064    }
1065
1066    if (IS(self.styleBits, MINIMIZABLE)) {
1067        [[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled: flag];
1068    }
1069
1070    if (IS(self.styleBits, ZOOMABLE)) {
1071        [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: flag];
1072    }
1073
1074    if (IS(self.styleBits, RESIZABLE)) {
1075        [self updateMinMaxSize:flag];
1076        [self.nsWindow setShowsResizeIndicator:flag];
1077    }
1078}
1079
1080+ (void) setLastKeyWindow:(AWTWindow *)window {
1081    [window retain];
1082    [lastKeyWindow release];
1083    lastKeyWindow = window;
1084}
1085
1086+ (AWTWindow *) lastKeyWindow {
1087    return lastKeyWindow;
1088}
1089
1090@end // AWTWindow
1091
1092
1093/*
1094 * Class:     sun_lwawt_macosx_CPlatformWindow
1095 * Method:    nativeCreateNSWindow
1096 * Signature: (JJIIII)J
1097 */
1098JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeCreateNSWindow
1099(JNIEnv *env, jobject obj, jlong contentViewPtr, jlong ownerPtr, jlong styleBits, jdouble x, jdouble y, jdouble w, jdouble h)
1100{
1101    __block AWTWindow *window = nil;
1102
1103JNI_COCOA_ENTER(env);
1104
1105    jobject platformWindow = (*env)->NewWeakGlobalRef(env, obj);
1106    NSView *contentView = OBJC(contentViewPtr);
1107    NSRect frameRect = NSMakeRect(x, y, w, h);
1108    AWTWindow *owner = [OBJC(ownerPtr) delegate];
1109    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1110
1111        window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow
1112                                               ownerWindow:owner
1113                                                 styleBits:styleBits
1114                                                 frameRect:frameRect
1115                                               contentView:contentView];
1116        // the window is released is CPlatformWindow.nativeDispose()
1117
1118        if (window) [window.nsWindow retain];
1119    }];
1120
1121JNI_COCOA_EXIT(env);
1122
1123    return ptr_to_jlong(window ? window.nsWindow : nil);
1124}
1125
1126/*
1127 * Class:     sun_lwawt_macosx_CPlatformWindow
1128 * Method:    nativeSetNSWindowStyleBits
1129 * Signature: (JII)V
1130 */
1131JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStyleBits
1132(JNIEnv *env, jclass clazz, jlong windowPtr, jint mask, jint bits)
1133{
1134JNI_COCOA_ENTER(env);
1135
1136    NSWindow *nsWindow = OBJC(windowPtr);
1137
1138    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1139
1140        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1141
1142        // scans the bit field, and only updates the values requested by the mask
1143        // (this implicitly handles the _CALLBACK_PROP_BITMASK case, since those are passive reads)
1144        jint newBits = window.styleBits & ~mask | bits & mask;
1145
1146        BOOL resized = NO;
1147
1148        // Check for a change to the full window content view option.
1149        // The content view must be resized first, otherwise the window will be resized to fit the existing
1150        // content view.
1151        if (IS(mask, FULL_WINDOW_CONTENT)) {
1152            if (IS(newBits, FULL_WINDOW_CONTENT) != IS(window.styleBits, FULL_WINDOW_CONTENT)) {
1153                NSRect frame = [nsWindow frame];
1154                NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:newBits];
1155                NSRect screenContentRect = [NSWindow contentRectForFrameRect:frame styleMask:styleMask];
1156                NSRect contentFrame = NSMakeRect(screenContentRect.origin.x - frame.origin.x,
1157                    screenContentRect.origin.y - frame.origin.y,
1158                    screenContentRect.size.width,
1159                    screenContentRect.size.height);
1160                nsWindow.contentView.frame = contentFrame;
1161                resized = YES;
1162            }
1163        }
1164
1165        // resets the NSWindow's style mask if the mask intersects any of those bits
1166        if (mask & MASK(_STYLE_PROP_BITMASK)) {
1167            [nsWindow setStyleMask:[AWTWindow styleMaskForStyleBits:newBits]];
1168        }
1169
1170        // calls methods on NSWindow to change other properties, based on the mask
1171        if (mask & MASK(_METHOD_PROP_BITMASK)) {
1172            [window setPropertiesForStyleBits:newBits mask:mask];
1173        }
1174
1175        window.styleBits = newBits;
1176
1177        if (resized) {
1178            [window _deliverMoveResizeEvent];
1179        }
1180    }];
1181
1182JNI_COCOA_EXIT(env);
1183}
1184
1185/*
1186 * Class:     sun_lwawt_macosx_CPlatformWindow
1187 * Method:    nativeSetNSWindowMenuBar
1188 * Signature: (JJ)V
1189 */
1190JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMenuBar
1191(JNIEnv *env, jclass clazz, jlong windowPtr, jlong menuBarPtr)
1192{
1193JNI_COCOA_ENTER(env);
1194
1195    NSWindow *nsWindow = OBJC(windowPtr);
1196    CMenuBar *menuBar = OBJC(menuBarPtr);
1197    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1198
1199        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1200
1201        if ([nsWindow isKeyWindow] || [nsWindow isMainWindow]) {
1202            [window.javaMenuBar deactivate];
1203        }
1204
1205        window.javaMenuBar = menuBar;
1206
1207        CMenuBar* actualMenuBar = menuBar;
1208        if (actualMenuBar == nil) {
1209            actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
1210        }
1211
1212        if ([nsWindow isKeyWindow] || [nsWindow isMainWindow]) {
1213            [CMenuBar activate:actualMenuBar modallyDisabled:NO];
1214        }
1215    }];
1216
1217JNI_COCOA_EXIT(env);
1218}
1219
1220/*
1221 * Class:     sun_lwawt_macosx_CPlatformWindow
1222 * Method:    nativeGetNSWindowInsets
1223 * Signature: (J)Ljava/awt/Insets;
1224 */
1225JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowInsets
1226(JNIEnv *env, jclass clazz, jlong windowPtr)
1227{
1228    jobject ret = NULL;
1229
1230JNI_COCOA_ENTER(env);
1231
1232    NSWindow *nsWindow = OBJC(windowPtr);
1233    __block NSRect contentRect = NSZeroRect;
1234    __block NSRect frame = NSZeroRect;
1235
1236    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1237
1238        frame = [nsWindow frame];
1239        contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[nsWindow styleMask]];
1240    }];
1241
1242    jint top = (jint)(frame.size.height - contentRect.size.height);
1243    jint left = (jint)(contentRect.origin.x - frame.origin.x);
1244    jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
1245    jint right = (jint)(frame.size.width - (contentRect.size.width + left));
1246
1247    DECLARE_CLASS_RETURN(jc_Insets, "java/awt/Insets", NULL);
1248    DECLARE_METHOD_RETURN(jc_Insets_ctor, jc_Insets, "<init>", "(IIII)V", NULL);
1249    ret = (*env)->NewObject(env, jc_Insets, jc_Insets_ctor, top, left, bottom, right);
1250
1251JNI_COCOA_EXIT(env);
1252    return ret;
1253}
1254
1255/*
1256 * Class:     sun_lwawt_macosx_CPlatformWindow
1257 * Method:    nativeSetNSWindowBounds
1258 * Signature: (JDDDD)V
1259 */
1260JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowBounds
1261(JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY, jdouble width, jdouble height)
1262{
1263JNI_COCOA_ENTER(env);
1264
1265    NSRect jrect = NSMakeRect(originX, originY, width, height);
1266
1267    // TODO: not sure we need displayIfNeeded message in our view
1268    NSWindow *nsWindow = OBJC(windowPtr);
1269    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1270
1271        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1272
1273        NSRect rect = ConvertNSScreenRect(NULL, jrect);
1274        [window constrainSize:&rect.size];
1275
1276        [nsWindow setFrame:rect display:YES];
1277
1278        // only start tracking events if pointer is above the toplevel
1279        // TODO: should post an Entered event if YES.
1280        NSPoint mLocation = [NSEvent mouseLocation];
1281        [nsWindow setAcceptsMouseMovedEvents:NSPointInRect(mLocation, rect)];
1282
1283        // ensure we repaint the whole window after the resize operation
1284        // (this will also re-enable screen updates, which were disabled above)
1285        // TODO: send PaintEvent
1286
1287        // the macOS may ignore our "setFrame" request, in this, case the
1288        // windowDidMove() will not come and we need to manually resync the
1289        // "java.awt.Window" and NSWindow locations, because "java.awt.Window"
1290        // already uses location ignored by the macOS.
1291        // see sun.lwawt.LWWindowPeer#notifyReshape()
1292        if (!NSEqualRects(rect, [nsWindow frame])) {
1293            [window _deliverMoveResizeEvent];
1294        }
1295    }];
1296
1297JNI_COCOA_EXIT(env);
1298}
1299
1300/*
1301 * Class:     sun_lwawt_macosx_CPlatformWindow
1302 * Method:    nativeSetNSWindowStandardFrame
1303 * Signature: (JDDDD)V
1304 */
1305JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStandardFrame
1306(JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY,
1307     jdouble width, jdouble height)
1308{
1309    JNI_COCOA_ENTER(env);
1310
1311    NSRect jrect = NSMakeRect(originX, originY, width, height);
1312
1313    NSWindow *nsWindow = OBJC(windowPtr);
1314    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1315
1316        NSRect rect = ConvertNSScreenRect(NULL, jrect);
1317        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1318        window.standardFrame = rect;
1319    }];
1320
1321    JNI_COCOA_EXIT(env);
1322}
1323
1324/*
1325 * Class:     sun_lwawt_macosx_CPlatformWindow
1326 * Method:    nativeSetNSWindowLocationByPlatform
1327 * Signature: (J)V
1328 */
1329JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowLocationByPlatform
1330(JNIEnv *env, jclass clazz, jlong windowPtr)
1331{
1332    JNI_COCOA_ENTER(env);
1333
1334    NSWindow *nsWindow = OBJC(windowPtr);
1335    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1336
1337        if (NSEqualPoints(lastTopLeftPoint, NSZeroPoint)) {
1338            // This is the first usage of lastTopLeftPoint. So invoke cascadeTopLeftFromPoint
1339            // twice to avoid positioning the window's top left to zero-point, since it may
1340            // cause negative user experience.
1341            lastTopLeftPoint = [nsWindow cascadeTopLeftFromPoint:lastTopLeftPoint];
1342        }
1343        lastTopLeftPoint = [nsWindow cascadeTopLeftFromPoint:lastTopLeftPoint];
1344    }];
1345
1346    JNI_COCOA_EXIT(env);
1347}
1348
1349/*
1350 * Class:     sun_lwawt_macosx_CPlatformWindow
1351 * Method:    nativeSetNSWindowMinMax
1352 * Signature: (JDDDD)V
1353 */
1354JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinMax
1355(JNIEnv *env, jclass clazz, jlong windowPtr, jdouble minW, jdouble minH, jdouble maxW, jdouble maxH)
1356{
1357JNI_COCOA_ENTER(env);
1358
1359    if (minW < 1) minW = 1;
1360    if (minH < 1) minH = 1;
1361    if (maxW < 1) maxW = 1;
1362    if (maxH < 1) maxH = 1;
1363
1364    NSWindow *nsWindow = OBJC(windowPtr);
1365    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1366
1367        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1368
1369        NSSize min = { minW, minH };
1370        NSSize max = { maxW, maxH };
1371
1372        [window constrainSize:&min];
1373        [window constrainSize:&max];
1374
1375        window.javaMinSize = min;
1376        window.javaMaxSize = max;
1377        [window updateMinMaxSize:IS(window.styleBits, RESIZABLE)];
1378    }];
1379
1380JNI_COCOA_EXIT(env);
1381}
1382
1383/*
1384 * Class:     sun_lwawt_macosx_CPlatformWindow
1385 * Method:    nativePushNSWindowToBack
1386 * Signature: (J)V
1387 */
1388JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToBack
1389(JNIEnv *env, jclass clazz, jlong windowPtr)
1390{
1391JNI_COCOA_ENTER(env);
1392
1393    NSWindow *nsWindow = OBJC(windowPtr);
1394    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1395        [nsWindow orderBack:nil];
1396        // Order parent windows
1397        AWTWindow *awtWindow = (AWTWindow*)[nsWindow delegate];
1398        while (awtWindow.ownerWindow != nil) {
1399            awtWindow = awtWindow.ownerWindow;
1400            if ([AWTWindow isJavaPlatformWindowVisible:awtWindow.nsWindow]) {
1401                [awtWindow.nsWindow orderBack:nil];
1402            }
1403        }
1404        // Order child windows
1405        [(AWTWindow*)[nsWindow delegate] orderChildWindows:NO];
1406    }];
1407
1408JNI_COCOA_EXIT(env);
1409}
1410
1411/*
1412 * Class:     sun_lwawt_macosx_CPlatformWindow
1413 * Method:    nativePushNSWindowToFront
1414 * Signature: (J)V
1415 */
1416JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToFront
1417(JNIEnv *env, jclass clazz, jlong windowPtr)
1418{
1419JNI_COCOA_ENTER(env);
1420
1421    NSWindow *nsWindow = OBJC(windowPtr);
1422    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1423
1424        if (![nsWindow isKeyWindow]) {
1425            [nsWindow makeKeyAndOrderFront:nsWindow];
1426        } else {
1427            [nsWindow orderFront:nsWindow];
1428        }
1429    }];
1430
1431JNI_COCOA_EXIT(env);
1432}
1433
1434/*
1435 * Class:     sun_lwawt_macosx_CPlatformWindow
1436 * Method:    nativeSetNSWindowTitle
1437 * Signature: (JLjava/lang/String;)V
1438 */
1439JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTitle
1440(JNIEnv *env, jclass clazz, jlong windowPtr, jstring jtitle)
1441{
1442JNI_COCOA_ENTER(env);
1443
1444    NSWindow *nsWindow = OBJC(windowPtr);
1445    [nsWindow performSelectorOnMainThread:@selector(setTitle:)
1446                              withObject:JavaStringToNSString(env, jtitle)
1447                           waitUntilDone:NO];
1448
1449JNI_COCOA_EXIT(env);
1450}
1451
1452/*
1453 * Class:     sun_lwawt_macosx_CPlatformWindow
1454 * Method:    nativeRevalidateNSWindowShadow
1455 * Signature: (J)V
1456 */
1457JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeRevalidateNSWindowShadow
1458(JNIEnv *env, jclass clazz, jlong windowPtr)
1459{
1460JNI_COCOA_ENTER(env);
1461
1462    NSWindow *nsWindow = OBJC(windowPtr);
1463    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1464        [nsWindow invalidateShadow];
1465    }];
1466
1467JNI_COCOA_EXIT(env);
1468}
1469
1470/*
1471 * Class:     sun_lwawt_macosx_CPlatformWindow
1472 * Method:    nativeScreenOn_AppKitThread
1473 * Signature: (J)I
1474 */
1475JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeScreenOn_1AppKitThread
1476(JNIEnv *env, jclass clazz, jlong windowPtr)
1477{
1478    jint ret = 0;
1479
1480JNI_COCOA_ENTER(env);
1481AWT_ASSERT_APPKIT_THREAD;
1482
1483    NSWindow *nsWindow = OBJC(windowPtr);
1484    NSDictionary *props = [[nsWindow screen] deviceDescription];
1485    ret = [[props objectForKey:@"NSScreenNumber"] intValue];
1486
1487JNI_COCOA_EXIT(env);
1488
1489    return ret;
1490}
1491
1492/*
1493 * Class:     sun_lwawt_macosx_CPlatformWindow
1494 * Method:    nativeSetNSWindowMinimizedIcon
1495 * Signature: (JJ)V
1496 */
1497JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinimizedIcon
1498(JNIEnv *env, jclass clazz, jlong windowPtr, jlong nsImagePtr)
1499{
1500JNI_COCOA_ENTER(env);
1501
1502    NSWindow *nsWindow = OBJC(windowPtr);
1503    NSImage *image = OBJC(nsImagePtr);
1504    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1505        [nsWindow setMiniwindowImage:image];
1506    }];
1507
1508JNI_COCOA_EXIT(env);
1509}
1510
1511/*
1512 * Class:     sun_lwawt_macosx_CPlatformWindow
1513 * Method:    nativeSetNSWindowRepresentedFilename
1514 * Signature: (JLjava/lang/String;)V
1515 */
1516JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowRepresentedFilename
1517(JNIEnv *env, jclass clazz, jlong windowPtr, jstring filename)
1518{
1519JNI_COCOA_ENTER(env);
1520
1521    NSWindow *nsWindow = OBJC(windowPtr);
1522    NSURL *url = (filename == NULL) ? nil : [NSURL fileURLWithPath:NormalizedPathNSStringFromJavaString(env, filename)];
1523    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1524        [nsWindow setRepresentedURL:url];
1525    }];
1526
1527JNI_COCOA_EXIT(env);
1528}
1529
1530/*
1531 * Class:     sun_lwawt_macosx_CPlatformWindow
1532 * Method:    nativeGetTopmostPlatformWindowUnderMouse
1533 * Signature: (J)V
1534 */
1535JNIEXPORT jobject
1536JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetTopmostPlatformWindowUnderMouse
1537(JNIEnv *env, jclass clazz)
1538{
1539    __block jobject topmostWindowUnderMouse = nil;
1540
1541    JNI_COCOA_ENTER(env);
1542
1543    [ThreadUtilities performOnMainThreadWaiting:YES block:^{
1544        AWTWindow *awtWindow = [AWTWindow getTopmostWindowUnderMouse];
1545        if (awtWindow != nil) {
1546            topmostWindowUnderMouse = awtWindow.javaPlatformWindow;
1547        }
1548    }];
1549
1550    JNI_COCOA_EXIT(env);
1551
1552    return topmostWindowUnderMouse;
1553}
1554
1555/*
1556 * Class:     sun_lwawt_macosx_CPlatformWindow
1557 * Method:    nativeSynthesizeMouseEnteredExitedEvents
1558 * Signature: ()V
1559 */
1560JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMouseEnteredExitedEvents__
1561(JNIEnv *env, jclass clazz)
1562{
1563    JNI_COCOA_ENTER(env);
1564
1565    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1566        [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
1567    }];
1568
1569    JNI_COCOA_EXIT(env);
1570}
1571
1572/*
1573 * Class:     sun_lwawt_macosx_CPlatformWindow
1574 * Method:    nativeSynthesizeMouseEnteredExitedEvents
1575 * Signature: (JI)V
1576 */
1577JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMouseEnteredExitedEvents__JI
1578(JNIEnv *env, jclass clazz, jlong windowPtr, jint eventType)
1579{
1580JNI_COCOA_ENTER(env);
1581
1582    if (eventType == NSMouseEntered || eventType == NSMouseExited) {
1583        NSWindow *nsWindow = OBJC(windowPtr);
1584
1585        [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1586            [AWTWindow synthesizeMouseEnteredExitedEvents:nsWindow withType:eventType];
1587        }];
1588    } else {
1589        JNU_ThrowIllegalArgumentException(env, "unknown event type");
1590    }
1591
1592JNI_COCOA_EXIT(env);
1593}
1594
1595/*
1596 * Class:     sun_lwawt_macosx_CPlatformWindow
1597 * Method:    _toggleFullScreenMode
1598 * Signature: (J)V
1599 */
1600JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow__1toggleFullScreenMode
1601(JNIEnv *env, jobject peer, jlong windowPtr)
1602{
1603JNI_COCOA_ENTER(env);
1604
1605    NSWindow *nsWindow = OBJC(windowPtr);
1606    SEL toggleFullScreenSelector = @selector(toggleFullScreen:);
1607    if (![nsWindow respondsToSelector:toggleFullScreenSelector]) return;
1608
1609    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1610        [nsWindow performSelector:toggleFullScreenSelector withObject:nil];
1611    }];
1612
1613JNI_COCOA_EXIT(env);
1614}
1615
1616JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetEnabled
1617(JNIEnv *env, jclass clazz, jlong windowPtr, jboolean isEnabled)
1618{
1619JNI_COCOA_ENTER(env);
1620
1621    NSWindow *nsWindow = OBJC(windowPtr);
1622    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1623        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1624
1625        [window setEnabled: isEnabled];
1626    }];
1627
1628JNI_COCOA_EXIT(env);
1629}
1630
1631JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeDispose
1632(JNIEnv *env, jclass clazz, jlong windowPtr)
1633{
1634JNI_COCOA_ENTER(env);
1635
1636    NSWindow *nsWindow = OBJC(windowPtr);
1637    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1638        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1639
1640        if ([AWTWindow lastKeyWindow] == window) {
1641            [AWTWindow setLastKeyWindow: nil];
1642        }
1643
1644        // AWTWindow holds a reference to the NSWindow in its nsWindow
1645        // property. Unsetting the delegate allows it to be deallocated
1646        // which releases the reference. This, in turn, allows the window
1647        // itself be deallocated.
1648        [nsWindow setDelegate: nil];
1649
1650        [window release];
1651    }];
1652
1653JNI_COCOA_EXIT(env);
1654}
1655
1656JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeEnterFullScreenMode
1657(JNIEnv *env, jclass clazz, jlong windowPtr)
1658{
1659JNI_COCOA_ENTER(env);
1660
1661    NSWindow *nsWindow = OBJC(windowPtr);
1662    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1663        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1664        NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1665        CGDirectDisplayID aID = [screenID intValue];
1666
1667        if (CGDisplayCapture(aID) == kCGErrorSuccess) {
1668            // remove window decoration
1669            NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1670            [nsWindow setStyleMask:(styleMask & ~NSTitledWindowMask) | NSBorderlessWindowMask];
1671
1672            int shieldLevel = CGShieldingWindowLevel();
1673            window.preFullScreenLevel = [nsWindow level];
1674            [nsWindow setLevel: shieldLevel];
1675
1676            NSRect screenRect = [[nsWindow screen] frame];
1677            [nsWindow setFrame:screenRect display:YES];
1678        } else {
1679            [NSException raise:@"Java Exception" reason:@"Failed to enter full screen." userInfo:nil];
1680        }
1681    }];
1682
1683JNI_COCOA_EXIT(env);
1684}
1685
1686JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeExitFullScreenMode
1687(JNIEnv *env, jclass clazz, jlong windowPtr)
1688{
1689JNI_COCOA_ENTER(env);
1690
1691    NSWindow *nsWindow = OBJC(windowPtr);
1692    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1693        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1694        NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1695        CGDirectDisplayID aID = [screenID intValue];
1696
1697        if (CGDisplayRelease(aID) == kCGErrorSuccess) {
1698            NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1699            [nsWindow setStyleMask:styleMask];
1700            [nsWindow setLevel: window.preFullScreenLevel];
1701
1702            // GraphicsDevice takes care of restoring pre full screen bounds
1703        } else {
1704            [NSException raise:@"Java Exception" reason:@"Failed to exit full screen." userInfo:nil];
1705        }
1706    }];
1707
1708JNI_COCOA_EXIT(env);
1709}
1710
1711