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