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