1 /*
2 * Copyright (c) 2011, 2016, 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
269 - (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)platformWindow
270 ownerWindow:owner
271 styleBits:(jint)bits
272 frameRect:(NSRect)rect
273 contentView:(NSView *)view
274 {
275 AWT_ASSERT_APPKIT_THREAD;
276
277 NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:bits];
278 NSRect contentRect = rect; //[NSWindow contentRectForFrameRect:rect styleMask:styleMask];
279 if (contentRect.size.width <= 0.0) {
280 contentRect.size.width = 1.0;
281 }
282 if (contentRect.size.height <= 0.0) {
283 contentRect.size.height = 1.0;
284 }
285
286 self = [super init];
287
288 if (self == nil) return nil; // no hope
289
290 if (IS(bits, UTILITY) ||
291 IS(bits, NONACTIVATING) ||
292 IS(bits, HUD) ||
293 IS(bits, HIDES_ON_DEACTIVATE))
294 {
295 self.nsWindow = [[AWTWindow_Panel alloc] initWithDelegate:self
296 frameRect:contentRect
297 styleMask:styleMask
298 contentView:view];
299 }
300 else
301 {
302 // These windows will appear in the window list in the dock icon menu
303 self.nsWindow = [[AWTWindow_Normal alloc] initWithDelegate:self
304 frameRect:contentRect
305 styleMask:styleMask
306 contentView:view];
307 }
308
309 if (self.nsWindow == nil) return nil; // no hope either
310 [self.nsWindow release]; // the property retains the object already
311
312 self.isEnabled = YES;
313 self.isMinimizing = NO;
314 self.javaPlatformWindow = platformWindow;
315 self.styleBits = bits;
316 self.ownerWindow = owner;
317 [self setPropertiesForStyleBits:styleBits mask:MASK(_METHOD_PROP_BITMASK)];
318
319 if (IS(self.styleBits, IS_POPUP)) {
320 [self.nsWindow setCollectionBehavior:(1 << 8) /*NSWindowCollectionBehaviorFullScreenAuxiliary*/];
321 }
322
323 return self;
324 }
325
326 + (BOOL) isAWTWindow:(NSWindow *)window {
327 return [window isKindOfClass: [AWTWindow_Panel class]] || [window isKindOfClass: [AWTWindow_Normal class]];
328 }
329
330 // Retrieves the list of possible window layers (levels)
331 + (NSArray*) getWindowLayers {
332 static NSArray *windowLayers;
333 static dispatch_once_t token;
334
335 // Initialize the list of possible window layers
336 dispatch_once(&token, ^{
337 // The layers are ordered from front to back, (i.e. the toppest one is the first)
338 windowLayers = [NSArray arrayWithObjects:
339 [NSNumber numberWithInt:CGWindowLevelForKey(kCGPopUpMenuWindowLevelKey)],
340 [NSNumber numberWithInt:CGWindowLevelForKey(kCGFloatingWindowLevelKey)],
341 [NSNumber numberWithInt:CGWindowLevelForKey(kCGNormalWindowLevelKey)],
342 nil
343 ];
344 [windowLayers retain];
345 });
346 return windowLayers;
347 }
348
349 // returns id for the topmost window under mouse
350 + (NSInteger) getTopmostWindowUnderMouseID {
351 NSInteger result = -1;
352
353 NSArray *windowLayers = [AWTWindow getWindowLayers];
354 // Looking for the window under mouse starting from the toppest layer
355 for (NSNumber *layer in windowLayers) {
356 result = [AWTWindow getTopmostWindowUnderMouseIDImpl:[layer integerValue]];
357 if (result != -1) {
358 break;
359 }
360 }
361 return result;
362 }
363
364 + (NSInteger) getTopmostWindowUnderMouseIDImpl:(NSInteger)windowLayer {
365 NSInteger result = -1;
366
367 NSRect screenRect = [[NSScreen mainScreen] frame];
368 NSPoint nsMouseLocation = [NSEvent mouseLocation];
369 CGPoint cgMouseLocation = CGPointMake(nsMouseLocation.x, screenRect.size.height - nsMouseLocation.y);
370
371 NSMutableArray *windows = (NSMutableArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
372
373 for (NSDictionary *window in windows) {
374 NSInteger layer = [[window objectForKey:(id)kCGWindowLayer] integerValue];
375 if (layer == windowLayer) {
376 CGRect rect;
377 CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[window objectForKey:(id)kCGWindowBounds], &rect);
378 if (CGRectContainsPoint(rect, cgMouseLocation)) {
379 result = [[window objectForKey:(id)kCGWindowNumber] integerValue];
380 break;
381 }
382 }
383 }
384 [windows release];
385 return result;
386 }
387
388 // checks that this window is under the mouse cursor and this point is not overlapped by others windows
389 - (BOOL) isTopmostWindowUnderMouse {
390 return [self.nsWindow windowNumber] == [AWTWindow getTopmostWindowUnderMouseID];
391 }
392
393 + (AWTWindow *) getTopmostWindowUnderMouse {
394 NSEnumerator *windowEnumerator = [[NSApp windows] objectEnumerator];
395 NSWindow *window;
396
397 NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
398
399 while ((window = [windowEnumerator nextObject]) != nil) {
400 if ([window windowNumber] == topmostWindowUnderMouseID) {
401 BOOL isAWTWindow = [AWTWindow isAWTWindow: window];
402 return isAWTWindow ? (AWTWindow *) [window delegate] : nil;
403 }
404 }
405 return nil;
406 }
407
408 + (void) synthesizeMouseEnteredExitedEvents:(NSWindow*)window withType:(NSEventType)eventType {
409
410 NSPoint screenLocation = [NSEvent mouseLocation];
411 NSPoint windowLocation = [window convertScreenToBase: screenLocation];
412 int modifierFlags = (eventType == NSMouseEntered) ? NSMouseEnteredMask : NSMouseExitedMask;
413
414 NSEvent *mouseEvent = [NSEvent enterExitEventWithType: eventType
415 location: windowLocation
416 modifierFlags: modifierFlags
417 timestamp: 0
418 windowNumber: [window windowNumber]
419 context: nil
420 eventNumber: 0
421 trackingNumber: 0
422 userData: nil
423 ];
424
425 [[window contentView] deliverJavaMouseEvent: mouseEvent];
426 }
427
428 + (void) synthesizeMouseEnteredExitedEventsForAllWindows {
429
430 NSInteger topmostWindowUnderMouseID = [AWTWindow getTopmostWindowUnderMouseID];
431 NSArray *windows = [NSApp windows];
432 NSWindow *window;
433
434 NSEnumerator *windowEnumerator = [windows objectEnumerator];
435 while ((window = [windowEnumerator nextObject]) != nil) {
436 if ([AWTWindow isAWTWindow: window]) {
437 BOOL isUnderMouse = ([window windowNumber] == topmostWindowUnderMouseID);
438 BOOL mouseIsOver = [[window contentView] mouseIsOver];
439 if (isUnderMouse && !mouseIsOver) {
440 [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseEntered];
441 } else if (!isUnderMouse && mouseIsOver) {
442 [AWTWindow synthesizeMouseEnteredExitedEvents:window withType:NSMouseExited];
443 }
444 }
445 }
446 }
447
448 + (NSNumber *) getNSWindowDisplayID_AppKitThread:(NSWindow *)window {
449 AWT_ASSERT_APPKIT_THREAD;
450 NSScreen *screen = [window screen];
451 NSDictionary *deviceDescription = [screen deviceDescription];
452 return [deviceDescription objectForKey:@"NSScreenNumber"];
453 }
454
455 - (void) dealloc {
456 AWT_ASSERT_APPKIT_THREAD;
457
458 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
459 [self.javaPlatformWindow setJObject:nil withEnv:env];
460
461 self.nsWindow = nil;
462 self.ownerWindow = nil;
463 [super dealloc];
464 }
465
466 // Tests whether window is blocked by modal dialog/window
467 - (BOOL) isBlocked {
468 BOOL isBlocked = NO;
469
470 JNIEnv *env = [ThreadUtilities getJNIEnv];
471 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
472 if (platformWindow != NULL) {
473 static JNF_MEMBER_CACHE(jm_isBlocked, jc_CPlatformWindow, "isBlocked", "()Z");
474 isBlocked = JNFCallBooleanMethod(env, platformWindow, jm_isBlocked) == JNI_TRUE ? YES : NO;
475 (*env)->DeleteLocalRef(env, platformWindow);
476 }
477
478 return isBlocked;
479 }
480
481 // Tests whether the corresponding Java platform window is visible or not
482 + (BOOL) isJavaPlatformWindowVisible:(NSWindow *)window {
483 BOOL isVisible = NO;
484
485 if ([AWTWindow isAWTWindow:window] && [window delegate] != nil) {
486 AWTWindow *awtWindow = (AWTWindow *)[window delegate];
487 [AWTToolkit eventCountPlusPlus];
488
489 JNIEnv *env = [ThreadUtilities getJNIEnv];
490 jobject platformWindow = [awtWindow.javaPlatformWindow jObjectWithEnv:env];
491 if (platformWindow != NULL) {
492 static JNF_MEMBER_CACHE(jm_isVisible, jc_CPlatformWindow, "isVisible", "()Z");
493 isVisible = JNFCallBooleanMethod(env, platformWindow, jm_isVisible) == JNI_TRUE ? YES : NO;
494 (*env)->DeleteLocalRef(env, platformWindow);
495
496 }
497 }
498 return isVisible;
499 }
500
501 // Orders window's childs based on the current focus state
502 - (void) orderChildWindows:(BOOL)focus {
503 AWT_ASSERT_APPKIT_THREAD;
504
505 if (self.isMinimizing || [self isBlocked]) {
506 // Do not perform any ordering, if iconify is in progress
507 // or the window is blocked by a modal window
508 return;
509 }
510
511 NSEnumerator *windowEnumerator = [[NSApp windows]objectEnumerator];
512 NSWindow *window;
513 while ((window = [windowEnumerator nextObject]) != nil) {
514 if ([AWTWindow isJavaPlatformWindowVisible:window]) {
515 AWTWindow *awtWindow = (AWTWindow *)[window delegate];
516 AWTWindow *owner = awtWindow.ownerWindow;
517 if (IS(awtWindow.styleBits, ALWAYS_ON_TOP)) {
518 // Do not order 'always on top' windows
519 continue;
520 }
521 while (awtWindow.ownerWindow != nil) {
522 if (awtWindow.ownerWindow == self) {
523 if (focus) {
524 // Move the childWindow to floating level
525 // so it will appear in front of its
526 // parent which owns the focus
527 [window setLevel:NSFloatingWindowLevel];
528 } else {
529 // Focus owner has changed, move the childWindow
530 // back to normal window level
531 [window setLevel:NSNormalWindowLevel];
532 }
533 // The childWindow should be displayed in front of
534 // its nearest parentWindow
535 [window orderWindow:NSWindowAbove relativeTo:[owner.nsWindow windowNumber]];
536 break;
537 }
538 awtWindow = awtWindow.ownerWindow;
539 }
540 }
541 }
542 }
543
544 // NSWindow overrides
545 - (BOOL) canBecomeKeyWindow {
546 AWT_ASSERT_APPKIT_THREAD;
547 return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_KEY);
548 }
549
550 - (BOOL) canBecomeMainWindow {
551 AWT_ASSERT_APPKIT_THREAD;
552 if (!self.isEnabled) {
553 // Native system can bring up the NSWindow to
554 // the top even if the window is not main.
555 // We should bring up the modal dialog manually
556 [AWTToolkit eventCountPlusPlus];
557
558 JNIEnv *env = [ThreadUtilities getJNIEnv];
559 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
560 if (platformWindow != NULL) {
561 static JNF_MEMBER_CACHE(jm_checkBlockingAndOrder, jc_CPlatformWindow,
562 "checkBlockingAndOrder", "()Z");
563 JNFCallBooleanMethod(env, platformWindow, jm_checkBlockingAndOrder);
564 (*env)->DeleteLocalRef(env, platformWindow);
565 }
566 }
567
568 return self.isEnabled && IS(self.styleBits, SHOULD_BECOME_MAIN);
569 }
570
571 - (BOOL) worksWhenModal {
572 AWT_ASSERT_APPKIT_THREAD;
573 return IS(self.styleBits, MODAL_EXCLUDED);
574 }
575
576
577 // NSWindowDelegate methods
578
579 - (void) _deliverMoveResizeEvent {
580 AWT_ASSERT_APPKIT_THREAD;
581
582 // deliver the event if this is a user-initiated live resize or as a side-effect
583 // of a Java initiated resize, because AppKit can override the bounds and force
584 // the bounds of the window to avoid the Dock or remain on screen.
585 [AWTToolkit eventCountPlusPlus];
586 JNIEnv *env = [ThreadUtilities getJNIEnv];
587 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
588 if (platformWindow == NULL) {
589 // TODO: create generic AWT assert
590 }
591
592 NSRect frame = ConvertNSScreenRect(env, [self.nsWindow frame]);
593
594 static JNF_MEMBER_CACHE(jm_deliverMoveResizeEvent, jc_CPlatformWindow, "deliverMoveResizeEvent", "(IIIIZ)V");
595 JNFCallVoidMethod(env, platformWindow, jm_deliverMoveResizeEvent,
596 (jint)frame.origin.x,
597 (jint)frame.origin.y,
598 (jint)frame.size.width,
599 (jint)frame.size.height,
600 (jboolean)[self.nsWindow inLiveResize]);
601 (*env)->DeleteLocalRef(env, platformWindow);
602
603 [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
604 }
605
606 - (void)windowDidMove:(NSNotification *)notification {
607 AWT_ASSERT_APPKIT_THREAD;
608
609 [self _deliverMoveResizeEvent];
610 }
611
612 - (void)windowDidResize:(NSNotification *)notification {
613 AWT_ASSERT_APPKIT_THREAD;
614
615 [self _deliverMoveResizeEvent];
616 }
617
618 - (void)windowDidExpose:(NSNotification *)notification {
619 AWT_ASSERT_APPKIT_THREAD;
620
621 [AWTToolkit eventCountPlusPlus];
622 // TODO: don't see this callback invoked anytime so we track
623 // window exposing in _setVisible:(BOOL)
624 }
625
626 - (NSRect)windowWillUseStandardFrame:(NSWindow *)window
627 defaultFrame:(NSRect)newFrame {
628
629 return NSEqualSizes(NSZeroSize, [self standardFrame].size)
630 ? newFrame
631 : [self standardFrame];
632 }
633
634 // Hides/shows window's childs during iconify/de-iconify operation
635 - (void) iconifyChildWindows:(BOOL)iconify {
636 AWT_ASSERT_APPKIT_THREAD;
637
638 NSEnumerator *windowEnumerator = [[NSApp windows]objectEnumerator];
639 NSWindow *window;
640 while ((window = [windowEnumerator nextObject]) != nil) {
641 if ([AWTWindow isJavaPlatformWindowVisible:window]) {
642 AWTWindow *awtWindow = (AWTWindow *)[window delegate];
643 while (awtWindow.ownerWindow != nil) {
644 if (awtWindow.ownerWindow == self) {
645 if (iconify) {
646 [window orderOut:window];
647 } else {
648 [window orderFront:window];
649 }
650 break;
651 }
652 awtWindow = awtWindow.ownerWindow;
653 }
654 }
655 }
656 }
657
658 - (void) _deliverIconify:(BOOL)iconify {
659 AWT_ASSERT_APPKIT_THREAD;
660
661 [AWTToolkit eventCountPlusPlus];
662 JNIEnv *env = [ThreadUtilities getJNIEnv];
663 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
664 if (platformWindow != NULL) {
665 static JNF_MEMBER_CACHE(jm_deliverIconify, jc_CPlatformWindow, "deliverIconify", "(Z)V");
666 JNFCallVoidMethod(env, platformWindow, jm_deliverIconify, iconify);
667 (*env)->DeleteLocalRef(env, platformWindow);
668 }
669 }
670
671 - (void)windowWillMiniaturize:(NSNotification *)notification {
672 AWT_ASSERT_APPKIT_THREAD;
673
674 self.isMinimizing = YES;
675
676 JNIEnv *env = [ThreadUtilities getJNIEnv];
677 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
678 if (platformWindow != NULL) {
679 static JNF_MEMBER_CACHE(jm_windowWillMiniaturize, jc_CPlatformWindow, "windowWillMiniaturize", "()V");
680 JNFCallVoidMethod(env, platformWindow, jm_windowWillMiniaturize);
681 (*env)->DeleteLocalRef(env, platformWindow);
682 }
683 // Excplicitly make myself a key window to avoid possible
684 // negative visual effects during iconify operation
685 [self.nsWindow makeKeyAndOrderFront:self.nsWindow];
686 [self iconifyChildWindows:YES];
687 }
688
689 - (void)windowDidMiniaturize:(NSNotification *)notification {
690 AWT_ASSERT_APPKIT_THREAD;
691
692 [self _deliverIconify:JNI_TRUE];
693 self.isMinimizing = NO;
694 }
695
696 - (void)windowDidDeminiaturize:(NSNotification *)notification {
697 AWT_ASSERT_APPKIT_THREAD;
698
699 [self _deliverIconify:JNI_FALSE];
700 [self iconifyChildWindows:NO];
701 }
702
703 - (void) _deliverWindowFocusEvent:(BOOL)focused oppositeWindow:(AWTWindow *)opposite {
704 //AWT_ASSERT_APPKIT_THREAD;
705 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
706 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
707 if (platformWindow != NULL) {
708 jobject oppositeWindow = [opposite.javaPlatformWindow jObjectWithEnv:env];
709
710 static JNF_MEMBER_CACHE(jm_deliverWindowFocusEvent, jc_CPlatformWindow, "deliverWindowFocusEvent", "(ZLsun/lwawt/macosx/CPlatformWindow;)V");
711 JNFCallVoidMethod(env, platformWindow, jm_deliverWindowFocusEvent, (jboolean)focused, oppositeWindow);
712 (*env)->DeleteLocalRef(env, platformWindow);
713 (*env)->DeleteLocalRef(env, oppositeWindow);
714 }
715 }
716
717
718 - (void) windowDidBecomeKey: (NSNotification *) notification {
719 AWT_ASSERT_APPKIT_THREAD;
720 [AWTToolkit eventCountPlusPlus];
721 AWTWindow *opposite = [AWTWindow lastKeyWindow];
722
723 // Finds appropriate menubar in our hierarchy,
724 AWTWindow *awtWindow = self;
725 while (awtWindow.ownerWindow != nil) {
726 awtWindow = awtWindow.ownerWindow;
727 }
728
729 CMenuBar *menuBar = nil;
730 BOOL isDisabled = NO;
731 if ([awtWindow.nsWindow isVisible]){
732 menuBar = awtWindow.javaMenuBar;
733 isDisabled = !awtWindow.isEnabled;
734 }
735
736 if (menuBar == nil) {
737 menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
738 isDisabled = NO;
739 }
740
741 [CMenuBar activate:menuBar modallyDisabled:isDisabled];
742
743 [AWTWindow setLastKeyWindow:nil];
744
745 [self _deliverWindowFocusEvent:YES oppositeWindow: opposite];
746 [self orderChildWindows:YES];
747 }
748
749 - (void) windowDidResignKey: (NSNotification *) notification {
750 // TODO: check why sometimes at start is invoked *not* on AppKit main thread.
751 AWT_ASSERT_APPKIT_THREAD;
752 [AWTToolkit eventCountPlusPlus];
753 [self.javaMenuBar deactivate];
754
755 // In theory, this might cause flickering if the window gaining focus
756 // has its own menu. However, I couldn't reproduce it on practice, so
757 // perhaps this is a non issue.
758 CMenuBar* defaultMenu = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
759 if (defaultMenu != nil) {
760 [CMenuBar activate:defaultMenu modallyDisabled:NO];
761 }
762
763 // the new key window
764 NSWindow *keyWindow = [NSApp keyWindow];
765 AWTWindow *opposite = nil;
766 if ([AWTWindow isAWTWindow: keyWindow]) {
767 opposite = (AWTWindow *)[keyWindow delegate];
768 [AWTWindow setLastKeyWindow: self];
769 } else {
770 [AWTWindow setLastKeyWindow: nil];
771 }
772
773 [self _deliverWindowFocusEvent:NO oppositeWindow: opposite];
774 [self orderChildWindows:NO];
775 }
776
777 - (void) windowDidBecomeMain: (NSNotification *) notification {
778 AWT_ASSERT_APPKIT_THREAD;
779 [AWTToolkit eventCountPlusPlus];
780
781 JNIEnv *env = [ThreadUtilities getJNIEnv];
782 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
783 if (platformWindow != NULL) {
784 static JNF_MEMBER_CACHE(jm_windowDidBecomeMain, jc_CPlatformWindow, "windowDidBecomeMain", "()V");
785 JNFCallVoidMethod(env, platformWindow, jm_windowDidBecomeMain);
786 (*env)->DeleteLocalRef(env, platformWindow);
787 }
788 }
789
790 - (BOOL)windowShouldClose:(id)sender {
791 AWT_ASSERT_APPKIT_THREAD;
792 [AWTToolkit eventCountPlusPlus];
793 JNIEnv *env = [ThreadUtilities getJNIEnv];
794 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
795 if (platformWindow != NULL) {
796 static JNF_MEMBER_CACHE(jm_deliverWindowClosingEvent, jc_CPlatformWindow, "deliverWindowClosingEvent", "()V");
797 JNFCallVoidMethod(env, platformWindow, jm_deliverWindowClosingEvent);
798 (*env)->DeleteLocalRef(env, platformWindow);
799 }
800 // The window will be closed (if allowed) as result of sending Java event
801 return NO;
802 }
803
804
805 - (void)_notifyFullScreenOp:(jint)op withEnv:(JNIEnv *)env {
806 static JNF_CLASS_CACHE(jc_FullScreenHandler, "com/apple/eawt/FullScreenHandler");
807 static JNF_STATIC_MEMBER_CACHE(jm_notifyFullScreenOperation, jc_FullScreenHandler, "handleFullScreenEventFromNative", "(Ljava/awt/Window;I)V");
808 static JNF_MEMBER_CACHE(jf_target, jc_CPlatformWindow, "target", "Ljava/awt/Window;");
809 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
810 if (platformWindow != NULL) {
811 jobject awtWindow = JNFGetObjectField(env, platformWindow, jf_target);
812 if (awtWindow != NULL) {
813 JNFCallStaticVoidMethod(env, jm_notifyFullScreenOperation, awtWindow, op);
814 (*env)->DeleteLocalRef(env, awtWindow);
815 }
816 (*env)->DeleteLocalRef(env, platformWindow);
817 }
818 }
819
820
821 - (void)windowWillEnterFullScreen:(NSNotification *)notification {
822 static JNF_MEMBER_CACHE(jm_windowWillEnterFullScreen, jc_CPlatformWindow, "windowWillEnterFullScreen", "()V");
823 JNIEnv *env = [ThreadUtilities getJNIEnv];
824 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
825 if (platformWindow != NULL) {
826 JNFCallVoidMethod(env, platformWindow, jm_windowWillEnterFullScreen);
827 [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_ENTER withEnv:env];
828 (*env)->DeleteLocalRef(env, platformWindow);
829 }
830 }
831
832 - (void)windowDidEnterFullScreen:(NSNotification *)notification {
833 static JNF_MEMBER_CACHE(jm_windowDidEnterFullScreen, jc_CPlatformWindow, "windowDidEnterFullScreen", "()V");
834 JNIEnv *env = [ThreadUtilities getJNIEnv];
835 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
836 if (platformWindow != NULL) {
837 JNFCallVoidMethod(env, platformWindow, jm_windowDidEnterFullScreen);
838 [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_ENTER withEnv:env];
839 (*env)->DeleteLocalRef(env, platformWindow);
840 }
841 [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
842 }
843
844 - (void)windowWillExitFullScreen:(NSNotification *)notification {
845 static JNF_MEMBER_CACHE(jm_windowWillExitFullScreen, jc_CPlatformWindow, "windowWillExitFullScreen", "()V");
846 JNIEnv *env = [ThreadUtilities getJNIEnv];
847 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
848 if (platformWindow != NULL) {
849 JNFCallVoidMethod(env, platformWindow, jm_windowWillExitFullScreen);
850 [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_WILL_EXIT withEnv:env];
851 (*env)->DeleteLocalRef(env, platformWindow);
852 }
853 }
854
855 - (void)windowDidExitFullScreen:(NSNotification *)notification {
856 static JNF_MEMBER_CACHE(jm_windowDidExitFullScreen, jc_CPlatformWindow, "windowDidExitFullScreen", "()V");
857 JNIEnv *env = [ThreadUtilities getJNIEnv];
858 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
859 if (platformWindow != NULL) {
860 JNFCallVoidMethod(env, platformWindow, jm_windowDidExitFullScreen);
861 [self _notifyFullScreenOp:com_apple_eawt_FullScreenHandler_FULLSCREEN_DID_EXIT withEnv:env];
862 (*env)->DeleteLocalRef(env, platformWindow);
863 }
864 [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
865 }
866
867 - (void)sendEvent:(NSEvent *)event {
868 if ([event type] == NSLeftMouseDown || [event type] == NSRightMouseDown || [event type] == NSOtherMouseDown) {
869 if ([self isBlocked]) {
870 // Move parent windows to front and make sure that a child window is displayed
871 // in front of its nearest parent.
872 if (self.ownerWindow != nil) {
873 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
874 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
875 if (platformWindow != NULL) {
876 static JNF_MEMBER_CACHE(jm_orderAboveSiblings, jc_CPlatformWindow, "orderAboveSiblings", "()V");
877 JNFCallVoidMethod(env,platformWindow, jm_orderAboveSiblings);
878 (*env)->DeleteLocalRef(env, platformWindow);
879 }
880 }
881 [self orderChildWindows:YES];
882 }
883
884 NSPoint p = [NSEvent mouseLocation];
885 NSRect frame = [self.nsWindow frame];
886 NSRect contentRect = [self.nsWindow contentRectForFrameRect:frame];
887
888 // Check if the click happened in the non-client area (title bar)
889 if (p.y >= (frame.origin.y + contentRect.size.height)) {
890 JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
891 jobject platformWindow = [self.javaPlatformWindow jObjectWithEnv:env];
892 if (platformWindow != NULL) {
893 // Currently, no need to deliver the whole NSEvent.
894 static JNF_MEMBER_CACHE(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
895 JNFCallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
896 (*env)->DeleteLocalRef(env, platformWindow);
897 }
898 }
899 }
900 }
901
902 - (void)constrainSize:(NSSize*)size {
903 float minWidth = 0.f, minHeight = 0.f;
904
905 if (IS(self.styleBits, DECORATED)) {
906 NSRect frame = [self.nsWindow frame];
907 NSRect contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[self.nsWindow styleMask]];
908
909 float top = frame.size.height - contentRect.size.height;
910 float left = contentRect.origin.x - frame.origin.x;
911 float bottom = contentRect.origin.y - frame.origin.y;
912 float right = frame.size.width - (contentRect.size.width + left);
913
914 // Speculative estimation: 80 - enough for window decorations controls
915 minWidth += left + right + 80;
916 minHeight += top + bottom;
917 }
918
919 minWidth = MAX(1.f, minWidth);
920 minHeight = MAX(1.f, minHeight);
921
922 size->width = MAX(size->width, minWidth);
923 size->height = MAX(size->height, minHeight);
924 }
925
926 - (void) setEnabled: (BOOL)flag {
927 self.isEnabled = flag;
928
929 if (IS(self.styleBits, CLOSEABLE)) {
930 [[self.nsWindow standardWindowButton:NSWindowCloseButton] setEnabled: flag];
931 }
932
933 if (IS(self.styleBits, MINIMIZABLE)) {
934 [[self.nsWindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled: flag];
935 }
936
937 if (IS(self.styleBits, ZOOMABLE)) {
938 [[self.nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: flag];
939 }
940
941 if (IS(self.styleBits, RESIZABLE)) {
942 [self updateMinMaxSize:flag];
943 [self.nsWindow setShowsResizeIndicator:flag];
944 }
945 }
946
947 + (void) setLastKeyWindow:(AWTWindow *)window {
948 [window retain];
949 [lastKeyWindow release];
950 lastKeyWindow = window;
951 }
952
953 + (AWTWindow *) lastKeyWindow {
954 return lastKeyWindow;
955 }
956
957 @end // AWTWindow
958
959
960 /*
961 * Class: sun_lwawt_macosx_CPlatformWindow
962 * Method: nativeCreateNSWindow
963 * Signature: (JJIIII)J
964 */
965 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeCreateNSWindow
966 (JNIEnv *env, jobject obj, jlong contentViewPtr, jlong ownerPtr, jlong styleBits, jdouble x, jdouble y, jdouble w, jdouble h)
967 {
968 __block AWTWindow *window = nil;
969
970 JNF_COCOA_ENTER(env);
971
972 JNFWeakJObjectWrapper *platformWindow = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
973 NSView *contentView = OBJC(contentViewPtr);
974 NSRect frameRect = NSMakeRect(x, y, w, h);
975 AWTWindow *owner = [OBJC(ownerPtr) delegate];
976 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
977
978 window = [[AWTWindow alloc] initWithPlatformWindow:platformWindow
979 ownerWindow:owner
980 styleBits:styleBits
981 frameRect:frameRect
982 contentView:contentView];
983 // the window is released is CPlatformWindow.nativeDispose()
984
985 if (window) [window.nsWindow retain];
986 }];
987
988 JNF_COCOA_EXIT(env);
989
990 return ptr_to_jlong(window ? window.nsWindow : nil);
991 }
992
993 /*
994 * Class: sun_lwawt_macosx_CPlatformWindow
995 * Method: nativeSetNSWindowStyleBits
996 * Signature: (JII)V
997 */
998 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStyleBits
999 (JNIEnv *env, jclass clazz, jlong windowPtr, jint mask, jint bits)
1000 {
1001 JNF_COCOA_ENTER(env);
1002
1003 NSWindow *nsWindow = OBJC(windowPtr);
1004 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1005
1006 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1007
1008 // scans the bit field, and only updates the values requested by the mask
1009 // (this implicity handles the _CALLBACK_PROP_BITMASK case, since those are passive reads)
1010 jint newBits = window.styleBits & ~mask | bits & mask;
1011
1012 // resets the NSWindow's style mask if the mask intersects any of those bits
1013 if (mask & MASK(_STYLE_PROP_BITMASK)) {
1014 [nsWindow setStyleMask:[AWTWindow styleMaskForStyleBits:newBits]];
1015 }
1016
1017 // calls methods on NSWindow to change other properties, based on the mask
1018 if (mask & MASK(_METHOD_PROP_BITMASK)) {
1019 [window setPropertiesForStyleBits:newBits mask:mask];
1020 }
1021
1022 window.styleBits = newBits;
1023 }];
1024
1025 JNF_COCOA_EXIT(env);
1026 }
1027
1028 /*
1029 * Class: sun_lwawt_macosx_CPlatformWindow
1030 * Method: nativeSetNSWindowMenuBar
1031 * Signature: (JJ)V
1032 */
1033 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMenuBar
1034 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong menuBarPtr)
1035 {
1036 JNF_COCOA_ENTER(env);
1037
1038 NSWindow *nsWindow = OBJC(windowPtr);
1039 CMenuBar *menuBar = OBJC(menuBarPtr);
1040 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1041
1042 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1043
1044 if ([nsWindow isKeyWindow]) {
1045 [window.javaMenuBar deactivate];
1046 }
1047
1048 window.javaMenuBar = menuBar;
1049
1050 CMenuBar* actualMenuBar = menuBar;
1051 if (actualMenuBar == nil) {
1052 actualMenuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
1053 }
1054
1055 if ([nsWindow isKeyWindow]) {
1056 [CMenuBar activate:actualMenuBar modallyDisabled:NO];
1057 }
1058 }];
1059
1060 JNF_COCOA_EXIT(env);
1061 }
1062
1063 /*
1064 * Class: sun_lwawt_macosx_CPlatformWindow
1065 * Method: nativeGetNSWindowInsets
1066 * Signature: (J)Ljava/awt/Insets;
1067 */
1068 JNIEXPORT jobject JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetNSWindowInsets
1069 (JNIEnv *env, jclass clazz, jlong windowPtr)
1070 {
1071 jobject ret = NULL;
1072
1073 JNF_COCOA_ENTER(env);
1074
1075 NSWindow *nsWindow = OBJC(windowPtr);
1076 __block NSRect contentRect = NSZeroRect;
1077 __block NSRect frame = NSZeroRect;
1078
1079 [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
1080
1081 frame = [nsWindow frame];
1082 contentRect = [NSWindow contentRectForFrameRect:frame styleMask:[nsWindow styleMask]];
1083 }];
1084
1085 jint top = (jint)(frame.size.height - contentRect.size.height);
1086 jint left = (jint)(contentRect.origin.x - frame.origin.x);
1087 jint bottom = (jint)(contentRect.origin.y - frame.origin.y);
1088 jint right = (jint)(frame.size.width - (contentRect.size.width + left));
1089
1090 static JNF_CLASS_CACHE(jc_Insets, "java/awt/Insets");
1091 static JNF_CTOR_CACHE(jc_Insets_ctor, jc_Insets, "(IIII)V");
1092 ret = JNFNewObject(env, jc_Insets_ctor, top, left, bottom, right);
1093
1094 JNF_COCOA_EXIT(env);
1095 return ret;
1096 }
1097
1098 /*
1099 * Class: sun_lwawt_macosx_CPlatformWindow
1100 * Method: nativeSetNSWindowBounds
1101 * Signature: (JDDDD)V
1102 */
1103 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowBounds
1104 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY, jdouble width, jdouble height)
1105 {
1106 JNF_COCOA_ENTER(env);
1107
1108 NSRect jrect = NSMakeRect(originX, originY, width, height);
1109
1110 // TODO: not sure we need displayIfNeeded message in our view
1111 NSWindow *nsWindow = OBJC(windowPtr);
1112 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1113
1114 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1115
1116 NSRect rect = ConvertNSScreenRect(NULL, jrect);
1117 [window constrainSize:&rect.size];
1118
1119 [nsWindow setFrame:rect display:YES];
1120
1121 // only start tracking events if pointer is above the toplevel
1122 // TODO: should post an Entered event if YES.
1123 NSPoint mLocation = [NSEvent mouseLocation];
1124 [nsWindow setAcceptsMouseMovedEvents:NSPointInRect(mLocation, rect)];
1125
1126 // ensure we repaint the whole window after the resize operation
1127 // (this will also re-enable screen updates, which were disabled above)
1128 // TODO: send PaintEvent
1129 }];
1130
1131 JNF_COCOA_EXIT(env);
1132 }
1133
1134 /*
1135 * Class: sun_lwawt_macosx_CPlatformWindow
1136 * Method: nativeSetNSWindowStandardFrame
1137 * Signature: (JDDDD)V
1138 */
1139 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStandardFrame
1140 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY,
1141 jdouble width, jdouble height)
1142 {
1143 JNF_COCOA_ENTER(env);
1144
1145 NSRect jrect = NSMakeRect(originX, originY, width, height);
1146
1147 NSWindow *nsWindow = OBJC(windowPtr);
1148 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1149
1150 NSRect rect = ConvertNSScreenRect(NULL, jrect);
1151 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1152 window.standardFrame = rect;
1153 }];
1154
1155 JNF_COCOA_EXIT(env);
1156 }
1157
1158 /*
1159 * Class: sun_lwawt_macosx_CPlatformWindow
1160 * Method: nativeSetNSWindowLocationByPlatform
1161 * Signature: (J)V
1162 */
1163 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowLocationByPlatform
1164 (JNIEnv *env, jclass clazz, jlong windowPtr)
1165 {
1166 JNF_COCOA_ENTER(env);
1167
1168 NSWindow *nsWindow = OBJC(windowPtr);
1169 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1170
1171 if (NSEqualPoints(lastTopLeftPoint, NSZeroPoint)) {
1172 // This is the first usage of lastTopLeftPoint. So invoke cascadeTopLeftFromPoint
1173 // twice to avoid positioning the window's top left to zero-point, since it may
1174 // cause negative user experience.
1175 lastTopLeftPoint = [nsWindow cascadeTopLeftFromPoint:lastTopLeftPoint];
1176 }
1177 lastTopLeftPoint = [nsWindow cascadeTopLeftFromPoint:lastTopLeftPoint];
1178 }];
1179
1180 JNF_COCOA_EXIT(env);
1181 }
1182
1183 /*
1184 * Class: sun_lwawt_macosx_CPlatformWindow
1185 * Method: nativeSetNSWindowMinMax
1186 * Signature: (JDDDD)V
1187 */
1188 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinMax
1189 (JNIEnv *env, jclass clazz, jlong windowPtr, jdouble minW, jdouble minH, jdouble maxW, jdouble maxH)
1190 {
1191 JNF_COCOA_ENTER(env);
1192
1193 if (minW < 1) minW = 1;
1194 if (minH < 1) minH = 1;
1195 if (maxW < 1) maxW = 1;
1196 if (maxH < 1) maxH = 1;
1197
1198 NSWindow *nsWindow = OBJC(windowPtr);
1199 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1200
1201 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1202
1203 NSSize min = { minW, minH };
1204 NSSize max = { maxW, maxH };
1205
1206 [window constrainSize:&min];
1207 [window constrainSize:&max];
1208
1209 window.javaMinSize = min;
1210 window.javaMaxSize = max;
1211 [window updateMinMaxSize:IS(window.styleBits, RESIZABLE)];
1212 }];
1213
1214 JNF_COCOA_EXIT(env);
1215 }
1216
1217 /*
1218 * Class: sun_lwawt_macosx_CPlatformWindow
1219 * Method: nativePushNSWindowToBack
1220 * Signature: (J)V
1221 */
1222 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToBack
1223 (JNIEnv *env, jclass clazz, jlong windowPtr)
1224 {
1225 JNF_COCOA_ENTER(env);
1226
1227 NSWindow *nsWindow = OBJC(windowPtr);
1228 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1229 [nsWindow orderBack:nil];
1230 // Order parent windows
1231 AWTWindow *awtWindow = (AWTWindow*)[nsWindow delegate];
1232 while (awtWindow.ownerWindow != nil) {
1233 awtWindow = awtWindow.ownerWindow;
1234 if ([AWTWindow isJavaPlatformWindowVisible:awtWindow.nsWindow]) {
1235 [awtWindow.nsWindow orderBack:nil];
1236 }
1237 }
1238 // Order child windows
1239 [(AWTWindow*)[nsWindow delegate] orderChildWindows:NO];
1240 }];
1241
1242 JNF_COCOA_EXIT(env);
1243 }
1244
1245 /*
1246 * Class: sun_lwawt_macosx_CPlatformWindow
1247 * Method: nativePushNSWindowToFront
1248 * Signature: (J)V
1249 */
1250 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativePushNSWindowToFront
1251 (JNIEnv *env, jclass clazz, jlong windowPtr)
1252 {
1253 JNF_COCOA_ENTER(env);
1254
1255 NSWindow *nsWindow = OBJC(windowPtr);
1256 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1257
1258 if (![nsWindow isKeyWindow]) {
1259 [nsWindow makeKeyAndOrderFront:nsWindow];
1260 } else {
1261 [nsWindow orderFront:nsWindow];
1262 }
1263 }];
1264
1265 JNF_COCOA_EXIT(env);
1266 }
1267
1268 /*
1269 * Class: sun_lwawt_macosx_CPlatformWindow
1270 * Method: nativeSetNSWindowTitle
1271 * Signature: (JLjava/lang/String;)V
1272 */
1273 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowTitle
1274 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring jtitle)
1275 {
1276 JNF_COCOA_ENTER(env);
1277
1278 NSWindow *nsWindow = OBJC(windowPtr);
1279 [nsWindow performSelectorOnMainThread:@selector(setTitle:)
1280 withObject:JNFJavaToNSString(env, jtitle)
1281 waitUntilDone:NO];
1282
1283 JNF_COCOA_EXIT(env);
1284 }
1285
1286 /*
1287 * Class: sun_lwawt_macosx_CPlatformWindow
1288 * Method: nativeRevalidateNSWindowShadow
1289 * Signature: (J)V
1290 */
1291 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeRevalidateNSWindowShadow
1292 (JNIEnv *env, jclass clazz, jlong windowPtr)
1293 {
1294 JNF_COCOA_ENTER(env);
1295
1296 NSWindow *nsWindow = OBJC(windowPtr);
1297 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1298 [nsWindow invalidateShadow];
1299 }];
1300
1301 JNF_COCOA_EXIT(env);
1302 }
1303
1304 /*
1305 * Class: sun_lwawt_macosx_CPlatformWindow
1306 * Method: nativeScreenOn_AppKitThread
1307 * Signature: (J)I
1308 */
1309 JNIEXPORT jint JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeScreenOn_1AppKitThread
1310 (JNIEnv *env, jclass clazz, jlong windowPtr)
1311 {
1312 jint ret = 0;
1313
1314 JNF_COCOA_ENTER(env);
1315 AWT_ASSERT_APPKIT_THREAD;
1316
1317 NSWindow *nsWindow = OBJC(windowPtr);
1318 NSDictionary *props = [[nsWindow screen] deviceDescription];
1319 ret = [[props objectForKey:@"NSScreenNumber"] intValue];
1320
1321 JNF_COCOA_EXIT(env);
1322
1323 return ret;
1324 }
1325
1326 /*
1327 * Class: sun_lwawt_macosx_CPlatformWindow
1328 * Method: nativeSetNSWindowMinimizedIcon
1329 * Signature: (JJ)V
1330 */
1331 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowMinimizedIcon
1332 (JNIEnv *env, jclass clazz, jlong windowPtr, jlong nsImagePtr)
1333 {
1334 JNF_COCOA_ENTER(env);
1335
1336 NSWindow *nsWindow = OBJC(windowPtr);
1337 NSImage *image = OBJC(nsImagePtr);
1338 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1339 [nsWindow setMiniwindowImage:image];
1340 }];
1341
1342 JNF_COCOA_EXIT(env);
1343 }
1344
1345 /*
1346 * Class: sun_lwawt_macosx_CPlatformWindow
1347 * Method: nativeSetNSWindowRepresentedFilename
1348 * Signature: (JLjava/lang/String;)V
1349 */
1350 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowRepresentedFilename
1351 (JNIEnv *env, jclass clazz, jlong windowPtr, jstring filename)
1352 {
1353 JNF_COCOA_ENTER(env);
1354
1355 NSWindow *nsWindow = OBJC(windowPtr);
1356 NSURL *url = (filename == NULL) ? nil : [NSURL fileURLWithPath:JNFNormalizedNSStringForPath(env, filename)];
1357 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1358 [nsWindow setRepresentedURL:url];
1359 }];
1360
1361 JNF_COCOA_EXIT(env);
1362 }
1363
1364 /*
1365 * Class: sun_lwawt_macosx_CPlatformWindow
1366 * Method: nativeGetTopmostPlatformWindowUnderMouse
1367 * Signature: (J)V
1368 */
1369 JNIEXPORT jobject
1370 JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetTopmostPlatformWindowUnderMouse
1371 (JNIEnv *env, jclass clazz)
1372 {
1373 __block jobject topmostWindowUnderMouse = nil;
1374
1375 JNF_COCOA_ENTER(env);
1376
1377 [ThreadUtilities performOnMainThreadWaiting:YES block:^{
1378 AWTWindow *awtWindow = [AWTWindow getTopmostWindowUnderMouse];
1379 if (awtWindow != nil) {
1380 topmostWindowUnderMouse = [awtWindow.javaPlatformWindow jObject];
1381 }
1382 }];
1383
1384 JNF_COCOA_EXIT(env);
1385
1386 return topmostWindowUnderMouse;
1387 }
1388
1389 /*
1390 * Class: sun_lwawt_macosx_CPlatformWindow
1391 * Method: nativeSynthesizeMouseEnteredExitedEvents
1392 * Signature: ()V
1393 */
1394 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMouseEnteredExitedEvents__
1395 (JNIEnv *env, jclass clazz)
1396 {
1397 JNF_COCOA_ENTER(env);
1398
1399 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1400 [AWTWindow synthesizeMouseEnteredExitedEventsForAllWindows];
1401 }];
1402
1403 JNF_COCOA_EXIT(env);
1404 }
1405
1406 /*
1407 * Class: sun_lwawt_macosx_CPlatformWindow
1408 * Method: nativeSynthesizeMouseEnteredExitedEvents
1409 * Signature: (JI)V
1410 */
1411 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSynthesizeMouseEnteredExitedEvents__JI
1412 (JNIEnv *env, jclass clazz, jlong windowPtr, jint eventType)
1413 {
1414 JNF_COCOA_ENTER(env);
1415
1416 if (eventType == NSMouseEntered || eventType == NSMouseExited) {
1417 NSWindow *nsWindow = OBJC(windowPtr);
1418
1419 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1420 [AWTWindow synthesizeMouseEnteredExitedEvents:nsWindow withType:eventType];
1421 }];
1422 } else {
1423 [JNFException raise:env as:kIllegalArgumentException reason:"unknown event type"];
1424 }
1425
1426 JNF_COCOA_EXIT(env);
1427 }
1428
1429 /*
1430 * Class: sun_lwawt_macosx_CPlatformWindow
1431 * Method: _toggleFullScreenMode
1432 * Signature: (J)V
1433 */
1434 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow__1toggleFullScreenMode
1435 (JNIEnv *env, jobject peer, jlong windowPtr)
1436 {
1437 JNF_COCOA_ENTER(env);
1438
1439 NSWindow *nsWindow = OBJC(windowPtr);
1440 SEL toggleFullScreenSelector = @selector(toggleFullScreen:);
1441 if (![nsWindow respondsToSelector:toggleFullScreenSelector]) return;
1442
1443 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1444 [nsWindow performSelector:toggleFullScreenSelector withObject:nil];
1445 }];
1446
1447 JNF_COCOA_EXIT(env);
1448 }
1449
1450 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetEnabled
1451 (JNIEnv *env, jclass clazz, jlong windowPtr, jboolean isEnabled)
1452 {
1453 JNF_COCOA_ENTER(env);
1454
1455 NSWindow *nsWindow = OBJC(windowPtr);
1456 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1457 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1458
1459 [window setEnabled: isEnabled];
1460 }];
1461
1462 JNF_COCOA_EXIT(env);
1463 }
1464
1465 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeDispose
1466 (JNIEnv *env, jclass clazz, jlong windowPtr)
1467 {
1468 JNF_COCOA_ENTER(env);
1469
1470 NSWindow *nsWindow = OBJC(windowPtr);
1471 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1472 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1473
1474 if ([AWTWindow lastKeyWindow] == window) {
1475 [AWTWindow setLastKeyWindow: nil];
1476 }
1477
1478 // AWTWindow holds a reference to the NSWindow in its nsWindow
1479 // property. Unsetting the delegate allows it to be deallocated
1480 // which releases the reference. This, in turn, allows the window
1481 // itself be deallocated.
1482 [nsWindow setDelegate: nil];
1483
1484 [window release];
1485 }];
1486
1487 JNF_COCOA_EXIT(env);
1488 }
1489
1490 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeEnterFullScreenMode
1491 (JNIEnv *env, jclass clazz, jlong windowPtr)
1492 {
1493 JNF_COCOA_ENTER(env);
1494
1495 NSWindow *nsWindow = OBJC(windowPtr);
1496 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1497 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1498 NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1499 CGDirectDisplayID aID = [screenID intValue];
1500
1501 if (CGDisplayCapture(aID) == kCGErrorSuccess) {
1502 // remove window decoration
1503 NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1504 [nsWindow setStyleMask:(styleMask & ~NSTitledWindowMask) | NSBorderlessWindowMask];
1505
1506 int shieldLevel = CGShieldingWindowLevel();
1507 window.preFullScreenLevel = [nsWindow level];
1508 [nsWindow setLevel: shieldLevel];
1509
1510 NSRect screenRect = [[nsWindow screen] frame];
1511 [nsWindow setFrame:screenRect display:YES];
1512 } else {
1513 [JNFException raise:[ThreadUtilities getJNIEnv]
1514 as:kRuntimeException
1515 reason:"Failed to enter full screen."];
1516 }
1517 }];
1518
1519 JNF_COCOA_EXIT(env);
1520 }
1521
1522 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeExitFullScreenMode
1523 (JNIEnv *env, jclass clazz, jlong windowPtr)
1524 {
1525 JNF_COCOA_ENTER(env);
1526
1527 NSWindow *nsWindow = OBJC(windowPtr);
1528 [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
1529 AWTWindow *window = (AWTWindow*)[nsWindow delegate];
1530 NSNumber* screenID = [AWTWindow getNSWindowDisplayID_AppKitThread: nsWindow];
1531 CGDirectDisplayID aID = [screenID intValue];
1532
1533 if (CGDisplayRelease(aID) == kCGErrorSuccess) {
1534 NSUInteger styleMask = [AWTWindow styleMaskForStyleBits:window.styleBits];
1535 [nsWindow setStyleMask:styleMask];
1536 [nsWindow setLevel: window.preFullScreenLevel];
1537
1538 // GraphicsDevice takes care of restoring pre full screen bounds
1539 } else {
1540 [JNFException raise:[ThreadUtilities getJNIEnv]
1541 as:kRuntimeException
1542 reason:"Failed to exit full screen."];
1543 }
1544 }];
1545
1546 JNF_COCOA_EXIT(env);
1547 }
1548
--- EOF ---