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