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