1 /* 2 * Copyright (c) 2011, 2015, 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 "common.h" 27 #import "com_sun_glass_events_ViewEvent.h" 28 #import "com_sun_glass_events_WindowEvent.h" 29 #import "com_sun_glass_ui_Window.h" 30 #import "com_sun_glass_ui_Window_Level.h" 31 #import "com_sun_glass_ui_mac_MacWindow.h" 32 33 #import "GlassMacros.h" 34 #import "GlassWindow+Java.h" 35 #import "GlassScreen.h" 36 37 //#define VERBOSE 38 #ifndef VERBOSE 39 #define LOG(MSG, ...) 40 #else 41 #define LOG(MSG, ...) GLASS_LOG(MSG, ## __VA_ARGS__); 42 #endif 43 44 static NSWindow *s_grabWindow = nil; 45 46 @interface NSWindow (External) 47 48 - (void)_startLiveResize; 49 - (void)_endLiveResize; 50 51 @end 52 53 @implementation GlassWindow (Java) 54 55 #pragma mark --- Callbacks 56 57 - (void)_sendJavaWindowMoveToAnotherScreenEventIfNeeded 58 { 59 NSScreen *newScreen = [self->nsWindow screen]; 60 61 // Update only if the newScreen isn't nil 62 if (self->currentScreen != newScreen && newScreen != nil) 63 { 64 self->currentScreen = newScreen; 65 66 GET_MAIN_JENV; 67 (*env)->CallVoidMethod(env, jWindow, jWindowNotifyMoveToAnotherScreen, createJavaScreen(env, newScreen)); 68 } 69 } 70 71 - (void)_sendJavaWindowMoveEventForFrame:(NSRect)frame 72 { 73 if (self->suppressWindowMoveEvent == NO) 74 { 75 self->lastReportedLocation = frame.origin; 76 77 GET_MAIN_JENV; 78 (*env)->CallVoidMethod(env, jWindow, jWindowNotifyMove, (int)frame.origin.x, (int)frame.origin.y); 79 [self _sendJavaWindowMoveToAnotherScreenEventIfNeeded]; 80 } 81 } 82 83 - (void)_sendJavaWindowResizeEvent:(int)type forFrame:(NSRect)frame 84 { 85 if (self->suppressWindowResizeEvent == NO) 86 { 87 GET_MAIN_JENV; 88 (*env)->CallVoidMethod(env, jWindow, jWindowNotifyResize, type, (int)frame.size.width, (int)frame.size.height); 89 [self _sendJavaWindowMoveToAnotherScreenEventIfNeeded]; 90 } 91 } 92 93 #pragma mark --- Additions 94 95 - (id)_initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle screen:(NSScreen *)screen jwindow:(jobject)jwindow jIsChild:(jboolean)jIsChild 96 { 97 self = [super init]; 98 if (self == nil) { 99 return nil; 100 } 101 102 if (jIsChild == JNI_FALSE) { 103 if (windowStyle & (NSUtilityWindowMask | NSNonactivatingPanelMask)) { 104 self->nsWindow = [[GlassWindow_Panel alloc] initWithDelegate:self 105 frameRect:contentRect 106 styleMask:windowStyle 107 screen:screen]; 108 } else { 109 self->nsWindow = [[GlassWindow_Normal alloc] initWithDelegate:self 110 frameRect:contentRect 111 styleMask:windowStyle 112 screen:screen]; 113 } 114 } else { 115 GlassEmbeddedWindow *ewindow = [[GlassEmbeddedWindow alloc] initWithDelegate:self 116 frameRect:contentRect 117 styleMask:windowStyle 118 screen:screen]; 119 if (ewindow) { 120 ewindow->parent = nil; 121 ewindow->child = nil; 122 123 self->nsWindow = ewindow; 124 } 125 } 126 127 if (self->nsWindow == nil) { 128 NSLog(@"Unable to create GlassWindow_Normal or GlassWindow_Panel"); 129 return nil; 130 } 131 132 self->jWindow = jwindow; 133 134 self->isFocusable = YES; 135 self->isEnabled = YES; 136 self->currentScreen = screen; 137 138 self->suppressWindowMoveEvent = NO; 139 self->suppressWindowResizeEvent = NO; 140 141 self->isClosed = NO; 142 143 // This is surely can't be a real location, which indicates 144 // we've never sent a MOVE event to Java yet. 145 self->lastReportedLocation.x = self->lastReportedLocation.y = FLT_MAX; 146 147 CGFloat x = 0.0f; 148 CGFloat y = [screen frame].size.height - [screen visibleFrame].size.height; 149 CGFloat w = [self->nsWindow frame].size.width; 150 CGFloat h = [self->nsWindow frame].size.height; 151 [self _setFlipFrame:NSMakeRect(x, y, w, h) display:YES animate:NO]; 152 153 //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:nil]; 154 //[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidMiniaturizeNotification object:nil]; 155 156 return self; 157 } 158 159 - (NSWindow*)_getCurrentWindow 160 { 161 return self->fullscreenWindow ? self->fullscreenWindow : self->nsWindow; 162 } 163 164 - (void)_ungrabFocus 165 { 166 NSWindow *window = [self _getCurrentWindow]; 167 168 if (s_grabWindow != window) { 169 return; 170 } 171 172 GET_MAIN_JENV; 173 (*env)->CallVoidMethod(env, self->jWindow, jWindowNotifyFocusUngrab); 174 175 s_grabWindow = nil; 176 } 177 178 + (void)_resetGrab 179 { 180 if (s_grabWindow && [[s_grabWindow delegate] isKindOfClass:[GlassWindow class]]) { 181 GlassWindow * window = (GlassWindow*)[s_grabWindow delegate]; 182 [window _ungrabFocus]; 183 } 184 s_grabWindow = nil; // unconditionally 185 } 186 187 - (void)_checkUngrab 188 { 189 if (!s_grabWindow) { 190 return; 191 } 192 193 // If this window doesn't belong to an owned windows hierarchy that 194 // holds the grab currently, then the grab should be released. 195 for (NSWindow * window = self->nsWindow; window; window = [window parentWindow]) { 196 if (window == s_grabWindow) { 197 return; 198 } 199 } 200 201 [GlassWindow _resetGrab]; 202 } 203 204 - (void)_grabFocus 205 { 206 NSWindow *window = [self _getCurrentWindow]; 207 208 if (s_grabWindow == window) { 209 return; 210 } 211 212 [GlassWindow _resetGrab]; 213 s_grabWindow = window; 214 } 215 216 - (void)_setResizable 217 { 218 NSUInteger mask = [self->nsWindow styleMask]; 219 if ((mask & NSResizableWindowMask) != 0) 220 { 221 if (self->isDecorated == YES) 222 { 223 mask &= ~(NSUInteger)NSResizableWindowMask; 224 [self->nsWindow setStyleMask: mask]; 225 [self->nsWindow setShowsResizeIndicator:NO]; 226 227 NSButton *zoomButton = [self->nsWindow standardWindowButton:NSWindowZoomButton]; 228 [zoomButton setEnabled:NO]; 229 } 230 self->isResizable = NO; 231 } 232 else 233 { 234 if (self->isDecorated == YES) 235 { 236 mask |= NSResizableWindowMask; 237 [self->nsWindow setStyleMask: mask]; 238 [self->nsWindow setShowsResizeIndicator:YES]; 239 240 NSButton *zoomButton = [self->nsWindow standardWindowButton:NSWindowZoomButton]; 241 [zoomButton setEnabled:YES]; 242 } 243 self->isResizable = YES; 244 } 245 } 246 247 - (NSRect)_constrainFrame:(NSRect)frame 248 { 249 NSSize minSize = [self->nsWindow minSize]; 250 NSSize maxSize = [self->nsWindow maxSize]; 251 NSSize size = frame.size; 252 253 NSRect constrained = frame; 254 { 255 if (size.width < minSize.width) 256 { 257 constrained.size.width = minSize.width; 258 } 259 else if (size.width > maxSize.width) 260 { 261 constrained.size.width = maxSize.width; 262 } 263 264 if (size.height < minSize.height) 265 { 266 constrained.size.height = minSize.height; 267 } 268 else if (size.height > maxSize.height) 269 { 270 constrained.size.height = maxSize.height; 271 } 272 } 273 return constrained; 274 } 275 276 - (void)_setVisible 277 { 278 LOG("_setVisible: focusable %d enabled %d", self->isFocusable, self->isEnabled); 279 280 if (self->isFocusable == YES && self->isEnabled == YES) 281 { 282 [self->nsWindow makeMainWindow]; 283 [self->nsWindow makeKeyAndOrderFront:nil]; 284 } 285 else 286 { 287 [self->nsWindow orderFront:nil]; 288 } 289 290 if ((self->owner != nil) && ([self->nsWindow parentWindow] == nil)) 291 { 292 [self->owner addChildWindow:self->nsWindow ordered:NSWindowAbove]; 293 } 294 // Make sure we synchronize scale factors which could have changed while 295 // we were not visible without invoking the overrides we watch. 296 if ([self->nsWindow screen]) { 297 [self->view notifyScaleFactorChanged:GetScreenScaleFactor([self->nsWindow screen])]; 298 } 299 } 300 301 - (void)_setWindowFrameWithRect:(NSRect)rect withDisplay:(jboolean)display withAnimate:(jboolean)animate 302 { 303 NSRect frame = [self _constrainFrame:rect]; 304 [self _setFlipFrame:frame display:(BOOL)display animate:(BOOL)animate]; 305 306 } 307 308 - (void)_setBounds:(jint)x y:(jint)y xSet:(jboolean)xSet ySet:(jboolean)ySet w:(jint)w h:(jint)h cw:(jint)cw ch:(jint)ch 309 { 310 NSPoint origin = [self _flipFrame].origin; 311 NSSize size = [self->nsWindow frame].size; 312 NSSize sizeForClient = [NSWindow frameRectForContentRect:NSMakeRect(0.0, 0.0, cw > 0 ? cw : 0.0, ch > 0 ? ch : 0.0) styleMask:[self->nsWindow styleMask]].size; 313 314 jint newX = xSet == JNI_TRUE ? x : (jint)origin.x; 315 jint newY = ySet == JNI_TRUE ? y : (jint)origin.y; 316 317 jint newW = (w > 0) ? w : (cw > 0) ? (jint)sizeForClient.width : (jint)size.width; 318 jint newH = (h > 0) ? h : (ch > 0) ? (jint)sizeForClient.height : (jint)size.height; 319 320 [self _setWindowFrameWithRect:NSMakeRect(newX, newY, newW, newH) withDisplay:JNI_TRUE withAnimate:JNI_FALSE]; 321 } 322 323 - (void)_restorePreZoomedRect 324 { 325 [self _setWindowFrameWithRect:NSMakeRect(self->preZoomedRect.origin.x, self->preZoomedRect.origin.y, self->preZoomedRect.size.width, self->preZoomedRect.size.height) withDisplay:JNI_TRUE withAnimate:JNI_TRUE]; 326 [self _sendJavaWindowMoveEventForFrame:[self _flipFrame]]; 327 [self _sendJavaWindowResizeEvent:com_sun_glass_events_WindowEvent_RESTORE forFrame:[self _flipFrame]]; 328 } 329 330 - (NSScreen*)_getScreen 331 { 332 NSScreen *screen = [self->nsWindow screen]; 333 if (screen == nil) 334 { 335 screen = self->currentScreen; 336 } 337 if (screen == nil) 338 { 339 screen = [[NSScreen screens] objectAtIndex: 0]; 340 } 341 return screen; 342 } 343 344 #pragma mark --- Flip 345 346 - (void)_setFlipFrame:(NSRect)frameRect display:(BOOL)displayFlag animate:(BOOL)animateFlag 347 { 348 //NSLog(@"_setFlipFrame: %.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); 349 NSScreen * screen = [[NSScreen screens] objectAtIndex: 0]; 350 NSRect screenFrame = screen.frame; 351 //NSLog(@" screenFrame: %.2f,%.2f %.2fx%.2f", screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height); 352 353 frameRect.origin.y = screenFrame.size.height - frameRect.size.height - frameRect.origin.y; 354 //NSLog(@" set to frameRect:%.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); 355 356 [self->nsWindow setFrame:frameRect display:displayFlag animate:animateFlag]; 357 358 //frameRect = [self _flipFrame]; 359 //NSLog(@" _flipFrame:%.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); 360 //frameRect = [super frame]; 361 //NSLog(@" frame:%.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height); 362 } 363 364 - (NSRect)_flipFrame 365 { 366 NSScreen * screen = [[NSScreen screens] objectAtIndex: 0]; 367 NSRect screenFrame = screen.frame; 368 369 NSRect frame = [self->nsWindow frame]; 370 //NSLog(@"_flipFrame: v.s.h=%.2f f.s.h=%.2f f.o.y=%.2f", screenFrame.size.height, frame.size.height, frame.origin.y); 371 frame.origin.y = screenFrame.size.height - frame.size.height - frame.origin.y; 372 //NSLog(@" result: f.o.y=%.2f", frame.origin.y); 373 374 //NSLog(@"_flipFrame: %.2f,%.2f %.2fx%.2f", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height); 375 return frame; 376 } 377 378 @end