1 /*
   2  * Copyright (c) 2011, 2014, 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 }
 295 
 296 - (void)_setWindowFrameWithRect:(NSRect)rect withDisplay:(jboolean)display withAnimate:(jboolean)animate
 297 {
 298     NSRect frame = [self _constrainFrame:rect];
 299     [self _setFlipFrame:frame display:(BOOL)display animate:(BOOL)animate];
 300 
 301 }
 302 
 303 - (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
 304 {
 305     NSPoint origin = [self _flipFrame].origin;
 306     NSSize size = [self->nsWindow frame].size;
 307     NSSize sizeForClient = [NSWindow frameRectForContentRect:NSMakeRect(0.0, 0.0, cw > 0 ? cw : 0.0, ch > 0 ? ch : 0.0) styleMask:[self->nsWindow styleMask]].size;
 308 
 309     jint newX = xSet == JNI_TRUE ? x : (jint)origin.x;
 310     jint newY = ySet == JNI_TRUE ? y : (jint)origin.y;
 311 
 312     jint newW = (w > 0) ? w : (cw > 0) ? (jint)sizeForClient.width : (jint)size.width;
 313     jint newH = (h > 0) ? h : (ch > 0) ? (jint)sizeForClient.height : (jint)size.height;
 314 
 315     [self _setWindowFrameWithRect:NSMakeRect(newX, newY, newW, newH) withDisplay:JNI_TRUE withAnimate:JNI_FALSE];
 316 }
 317 
 318 - (void)_restorePreZoomedRect
 319 {
 320     [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];
 321     [self _sendJavaWindowMoveEventForFrame:[self _flipFrame]];
 322     [self _sendJavaWindowResizeEvent:com_sun_glass_events_WindowEvent_RESTORE forFrame:[self _flipFrame]];
 323 }
 324 
 325 - (NSScreen*)_getScreen
 326 {
 327     NSScreen *screen = [self->nsWindow screen];
 328     if (screen == nil)
 329     {
 330         screen = self->currentScreen;
 331     }
 332     if (screen == nil)
 333     {
 334         screen = [[NSScreen screens] objectAtIndex: 0];
 335     }
 336     return screen;
 337 }
 338 
 339 #pragma mark --- Flip
 340      
 341 - (void)_setFlipFrame:(NSRect)frameRect display:(BOOL)displayFlag animate:(BOOL)animateFlag
 342 {
 343     //NSLog(@"_setFlipFrame:   %.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
 344     NSScreen * screen = [[NSScreen screens] objectAtIndex: 0];
 345     NSRect screenFrame = screen.frame;
 346     //NSLog(@"            screenFrame: %.2f,%.2f %.2fx%.2f", screenFrame.origin.x, screenFrame.origin.y, screenFrame.size.width, screenFrame.size.height);
 347     
 348     frameRect.origin.y = screenFrame.size.height - frameRect.size.height - frameRect.origin.y;
 349     //NSLog(@"            set to frameRect:%.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
 350     
 351     [self->nsWindow setFrame:frameRect display:displayFlag animate:animateFlag];
 352     
 353     //frameRect = [self _flipFrame];
 354     //NSLog(@"            _flipFrame:%.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
 355     //frameRect = [super frame];
 356     //NSLog(@"            frame:%.2f,%.2f %.2fx%.2f", frameRect.origin.x, frameRect.origin.y, frameRect.size.width, frameRect.size.height);
 357 }
 358 
 359 - (NSRect)_flipFrame
 360 {
 361     NSScreen * screen = [[NSScreen screens] objectAtIndex: 0];
 362     NSRect screenFrame = screen.frame;
 363     
 364     NSRect frame = [self->nsWindow frame];
 365     //NSLog(@"_flipFrame: v.s.h=%.2f f.s.h=%.2f f.o.y=%.2f", screenFrame.size.height, frame.size.height, frame.origin.y);
 366     frame.origin.y = screenFrame.size.height - frame.size.height - frame.origin.y;
 367     //NSLog(@"                            result: f.o.y=%.2f", frame.origin.y);
 368     
 369     //NSLog(@"_flipFrame:   %.2f,%.2f %.2fx%.2f", frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
 370     return frame;
 371 }
 372 
 373 @end