macWindow.mm

Engine/source/windowManager/mac/macWindow.mm

More...

Classes:

Public Functions

torque_setsafariwindow(NSWindow * window, S32 x, S32 y, S32 width, S32 height)

Detailed Description

Public Functions

torque_setsafariwindow(NSWindow * window, S32 x, S32 y, S32 width, S32 height)

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include <Cocoa/Cocoa.h>
 25#include "windowManager/mac/macWindow.h"
 26#include "windowManager/mac/macView.h"
 27
 28#include "console/console.h"
 29
 30MacWindow::SafariWindowInfo* MacWindow::sSafariWindowInfo = NULL;
 31MacWindow* MacWindow::sInstance = NULL;
 32
 33@interface SafariBrowserWindow : NSWindow
 34{
 35}
 36@end
 37
 38@implementation SafariBrowserWindow
 39
 40// Windows created with NSBorderlessWindowMask normally can't be key, but we want ours to be
 41- (BOOL) canBecomeKeyWindow
 42{
 43    return YES;
 44}
 45
 46@end
 47
 48
 49MacWindow::MacWindow(U32 windowId, const char* windowText, Point2I clientExtent)
 50{
 51   mMouseLocked      = false;
 52   mShouldMouseLock  = false;
 53   mTitle            = NULL;
 54   mMouseCaptured    = false;
 55   
 56   mCocoaWindow      = NULL;
 57   mCursorController = new MacCursorController( this );
 58   mOwningWindowManager = NULL;
 59   
 60   mFullscreen = false;
 61   mShouldFullscreen = false;
 62   mDefaultDisplayMode = NULL;
 63   
 64   mSkipMouseEvents = 0;
 65   
 66   mDisplay = kCGDirectMainDisplay;
 67   mMainDisplayBounds = mDisplayBounds = CGDisplayBounds(mDisplay);
 68   
 69   mWindowId = windowId;
 70   _initCocoaWindow(windowText, clientExtent);
 71   
 72   appEvent.notify(this, &MacWindow::_onAppEvent);
 73   
 74   sInstance = this;
 75}
 76
 77MacWindow::~MacWindow()
 78{
 79   if(mFullscreen)
 80      _setFullscreen(false);
 81
 82   appEvent.remove(this, &MacWindow::_onAppEvent);
 83
 84   //ensure our view isn't the delegate
 85   [NSApp setDelegate:nil];
 86   
 87   if( mCocoaWindow )
 88   {
 89      NSWindow* window = mCocoaWindow;
 90      _disassociateCocoaWindow();
 91      
 92      [ window close ];
 93   }
 94   
 95   appEvent.trigger(mWindowId, LoseFocus);
 96   appEvent.trigger(mWindowId, WindowDestroy);
 97   
 98   mOwningWindowManager->_removeWindow(this);
 99   
100   setSafariWindow(NULL);
101   
102   sInstance = NULL;
103}
104
105extern "C"
106{
107
108void torque_setsafariwindow( NSWindow *window, S32 x, S32 y, S32 width, S32 height)
109{
110   MacWindow::setSafariWindow(window, x, y, width, height);
111}
112
113}
114
115void MacWindow::hideBrowserWindow(bool hide)
116{
117   if (sSafariWindowInfo && sInstance && sInstance->mCocoaWindow)
118   {
119      if (hide)
120      {
121         if (sSafariWindowInfo && sSafariWindowInfo->safariWindow)
122            [sSafariWindowInfo->safariWindow removeChildWindow: sInstance->mCocoaWindow];
123         
124         sInstance->hide();
125      }
126      else
127      {
128      
129         if (sSafariWindowInfo && sSafariWindowInfo->safariWindow)
130            [sSafariWindowInfo->safariWindow addChildWindow: sInstance->mCocoaWindow ordered:NSWindowAbove];
131         
132         sInstance->show();
133      }
134   }
135}
136
137void MacWindow::setSafariWindow(NSWindow *window, S32 x, S32 y, S32 width, S32 height )
138{
139   if (!window)
140   {
141      hideBrowserWindow(true);
142   
143      if (sSafariWindowInfo)
144         delete sSafariWindowInfo;
145         
146      sSafariWindowInfo = NULL;
147      
148      return;
149   }
150   
151   if (!sSafariWindowInfo)
152   {   
153      sSafariWindowInfo = new SafariWindowInfo;
154      sSafariWindowInfo->safariWindow = window;
155      sSafariWindowInfo->width = width;
156      sSafariWindowInfo->height = height;
157      sSafariWindowInfo->x = x;
158      sSafariWindowInfo->y = y;
159      if (sInstance && sInstance->mCocoaWindow)
160      {
161         [window addChildWindow: sInstance->mCocoaWindow ordered:NSWindowAbove];
162         hideBrowserWindow(false);
163      }
164   }
165   else
166   {
167      sSafariWindowInfo->width = width;
168      sSafariWindowInfo->height = height;
169      sSafariWindowInfo->x = x;
170      sSafariWindowInfo->y = y;   
171   }
172   
173   if (sInstance && sInstance->mCocoaWindow)
174   {
175      //update position
176      
177      NSRect frame = [sSafariWindowInfo->safariWindow frame];
178      
179      NSPoint o = { (float)sSafariWindowInfo->x,  frame.size.height -  sSafariWindowInfo->y  };      
180      NSPoint p = [sSafariWindowInfo->safariWindow convertBaseToScreen: o];
181            
182      NSRect contentRect = NSMakeRect(p.x, p.y - sSafariWindowInfo->height, sSafariWindowInfo->width,sSafariWindowInfo->height);
183      
184      // we have to set display to NO when resizing otherwise get hangs, perhaps add delegate to SafariBrowserWindow class?
185      [sInstance->mCocoaWindow setFrame:contentRect display:NO];
186            
187   }
188   
189}
190   
191void MacWindow::_initCocoaWindow(const char* windowText, Point2I clientExtent)
192{
193   // TODO: cascade windows on screen?
194   
195   // create the window
196   NSRect contentRect;
197   U32 style;
198   
199   if (sSafariWindowInfo)
200   {
201     
202      NSRect frame = [sSafariWindowInfo->safariWindow frame];
203            
204      NSPoint o = { (float)sSafariWindowInfo->x,  frame.size.height -  sSafariWindowInfo->y  };
205      
206      NSPoint p = [sSafariWindowInfo->safariWindow convertBaseToScreen: o];
207             
208      contentRect = NSMakeRect(0, 0, sSafariWindowInfo->width,sSafariWindowInfo->height);
209      
210      style = NSBorderlessWindowMask; 
211            
212      mCocoaWindow = [[SafariBrowserWindow alloc] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:nil];
213      
214      [mCocoaWindow setFrameTopLeftPoint: p];
215      
216      [sSafariWindowInfo->safariWindow addChildWindow: mCocoaWindow ordered:NSWindowAbove];      
217      
218       // necessary to accept mouseMoved events
219      [mCocoaWindow setAcceptsMouseMovedEvents:YES];
220   }
221   else
222   {
223   
224      contentRect = NSMakeRect(0,0,clientExtent.x, clientExtent.y);
225      
226      style = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;
227   
228      mCocoaWindow = [[NSWindow alloc] initWithContentRect:contentRect styleMask:style backing:NSBackingStoreBuffered defer:YES screen:nil];
229      if(windowText)
230         [mCocoaWindow setTitle: [NSString stringWithUTF8String: windowText]];   
231
232      // necessary to accept mouseMoved events
233      [mCocoaWindow setAcceptsMouseMovedEvents:YES];
234      
235      // correctly position the window on screen
236      [mCocoaWindow center];
237
238   }
239   
240   // create the opengl view. we don't care about its pixel format, because we
241   // will be replacing its context with another one.
242   GGMacView* view = [[GGMacView alloc] initWithFrame:contentRect pixelFormat:[NSOpenGLView defaultPixelFormat]];
243   [view setTorqueWindow:this];
244   [mCocoaWindow setContentView:view];
245   [mCocoaWindow setDelegate:view];
246   
247}
248
249void MacWindow::_disassociateCocoaWindow()
250{
251   if( !mCocoaWindow )
252      return;
253      
254   [mCocoaWindow setContentView:nil];
255   [mCocoaWindow setDelegate:nil];   
256
257   if (sSafariWindowInfo)
258      [sSafariWindowInfo->safariWindow removeChildWindow: mCocoaWindow];
259      
260   mCocoaWindow = NULL;
261}
262
263void MacWindow::_setVideoMode(const GFXVideoMode &mode)
264{
265   mCurrentMode = mode;
266   setSize(mCurrentMode.resolution);
267   
268   if(mTarget.isValid())
269      mTarget->resetMode();
270
271   _setFullscreen(mCurrentMode.fullScreen);
272}
273
274void MacWindow::_onAppEvent(WindowId, S32 evt)
275{
276   if(evt == LoseFocus && isFullscreen())
277   {
278      mShouldFullscreen = true;
279      GFXVideoMode mode = mCurrentMode;
280      mode.fullScreen = false;
281      setVideoMode(mode);
282   }
283   
284   if(evt == GainFocus && !isFullscreen() && mShouldFullscreen)
285   {
286      mShouldFullscreen = false;
287      GFXVideoMode mode = mCurrentMode;
288      mode.fullScreen = true;
289      setVideoMode(mode);
290   }
291}
292
293void MacWindow::_setFullscreen(bool fullScreen)
294{
295   if(mFullscreen == fullScreen)
296      return;
297   
298   mFullscreen = fullScreen;
299   
300   if(mFullscreen)
301   {
302      Con::printf("Capturing display %x", mDisplay);
303      CGDisplayCapture(mDisplay);
304      [mCocoaWindow setAlphaValue:0.0f];
305   }
306   else
307   {
308      if(mDefaultDisplayMode)
309      {
310         Con::printf("Restoring default display mode... width: %i height: %i bpp: %i", [[mDefaultDisplayMode valueForKey:@"Width"] intValue], 
311               [[mDefaultDisplayMode valueForKey:@"Height"] intValue], [[mDefaultDisplayMode valueForKey:@"BitsPerPixel"] intValue]);
312         CGDisplaySwitchToMode(mDisplay, (CFDictionaryRef)mDefaultDisplayMode);
313         mDisplayBounds = CGDisplayBounds(mDisplay);
314         if(mDisplay == kCGDirectMainDisplay)
315            mMainDisplayBounds = mDisplayBounds;
316      }
317      
318      Con::printf("Releasing display %x", mDisplay);
319      CGDisplayRelease(mDisplay);
320      [mCocoaWindow setAlphaValue:1.0f];
321      mDefaultDisplayMode = NULL;
322   }
323}
324
325void* MacWindow::getPlatformDrawable() const
326{
327   return [mCocoaWindow contentView];
328}
329
330void MacWindow::show()
331{
332   [mCocoaWindow makeKeyAndOrderFront:nil];
333   [mCocoaWindow makeFirstResponder:[mCocoaWindow contentView]];
334   appEvent.trigger(getWindowId(), WindowShown);
335   appEvent.trigger(getWindowId(), GainFocus);
336}
337
338void MacWindow::close()
339{
340   [mCocoaWindow close];
341   appEvent.trigger(mWindowId, LoseFocus);
342   appEvent.trigger(mWindowId, WindowDestroy);
343   
344   mOwningWindowManager->_removeWindow(this);
345   
346   delete this;
347}
348
349void MacWindow::hide()
350{
351   [mCocoaWindow orderOut:nil];
352   appEvent.trigger(getWindowId(), WindowHidden);
353}
354
355void MacWindow::setDisplay(CGDirectDisplayID display)
356{
357   mDisplay = display;
358   mDisplayBounds = CGDisplayBounds(mDisplay);
359}
360
361PlatformWindow* MacWindow::getNextWindow() const
362{
363   return mNextWindow;
364}
365
366bool MacWindow::setSize(const Point2I &newSize)
367{
368   if (sSafariWindowInfo)
369      return true;
370      
371   NSSize newExtent = {newSize.x, newSize.y};
372   [mCocoaWindow setContentSize:newExtent];
373   [mCocoaWindow center];
374   return true;
375}
376
377void MacWindow::setClientExtent( const Point2I newExtent )
378{
379   if(!mFullscreen)
380   {
381      // Set the Client Area Extent (Resolution) of this window
382      NSSize newSize = {newExtent.x, newExtent.y};
383      [mCocoaWindow setContentSize:newSize];
384   }
385   else
386   {
387      // In fullscreen we have to resize the monitor (it'll be good to change it back too...)
388      if(!mDefaultDisplayMode)
389         mDefaultDisplayMode = (NSDictionary*)CGDisplayCurrentMode(mDisplay);
390      
391      NSDictionary* newMode = (NSDictionary*)CGDisplayBestModeForParameters(mDisplay, 32, newExtent.x, newExtent.y, NULL);
392      Con::printf("Switching to new display mode... width: %i height: %i bpp: %i", 
393                  [[newMode valueForKey:@"Width"] intValue], [[newMode valueForKey:@"Height"] intValue], [[newMode valueForKey:@"BitsPerPixel"] intValue]); 
394      CGDisplaySwitchToMode(mDisplay, (CFDictionaryRef)newMode);
395      mDisplayBounds = CGDisplayBounds(mDisplay);
396      if(mDisplay == kCGDirectMainDisplay)
397         mMainDisplayBounds = mDisplayBounds;
398   }
399}
400
401const Point2I MacWindow::getClientExtent()
402{
403   if(!mFullscreen)
404   {
405      // Get the Client Area Extent (Resolution) of this window
406      NSSize size = [[mCocoaWindow contentView] frame].size;
407      return Point2I(size.width, size.height);
408   }
409   else
410   {
411      return Point2I(mDisplayBounds.size.width, mDisplayBounds.size.height);
412   }
413}
414
415void MacWindow::setBounds( const RectI &newBounds )
416{
417   NSRect newFrame = NSMakeRect(newBounds.point.x, newBounds.point.y, newBounds.extent.x, newBounds.extent.y);
418   [mCocoaWindow setFrame:newFrame display:YES];
419}
420
421const RectI MacWindow::getBounds() const
422{
423   if(!mFullscreen)
424   {
425      // Get the position and size (fullscreen windows are always at (0,0)).
426      NSRect frame = [mCocoaWindow frame];
427      return RectI(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
428   }
429   else
430   {
431      return RectI(0, 0, mDisplayBounds.size.width, mDisplayBounds.size.height);
432   }
433}
434
435void MacWindow::setPosition( const Point2I newPosition )
436{
437   NSScreen *screen = [mCocoaWindow screen];
438   NSRect screenFrame = [screen frame];
439
440   NSPoint pos = {newPosition.x, newPosition.y + screenFrame.size.height};
441   [mCocoaWindow setFrameTopLeftPoint: pos];
442}
443
444const Point2I MacWindow::getPosition()
445{
446   NSScreen *screen = [mCocoaWindow screen];
447   NSRect screenFrame = [screen frame];
448   NSRect frame = [mCocoaWindow frame];
449
450   return Point2I(frame.origin.x, screenFrame.size.height - (frame.origin.y + frame.size.height));
451}
452
453void MacWindow::centerWindow()
454{
455   [mCocoaWindow center];
456}
457
458Point2I MacWindow::clientToScreen( const Point2I& pos )
459{
460   NSPoint p = { pos.x, pos.y };
461   
462   p = [ mCocoaWindow convertBaseToScreen: p ];
463   return Point2I( p.x, p.y );
464}
465
466Point2I MacWindow::screenToClient( const Point2I& pos )
467{
468   NSPoint p = { pos.x, pos.y };
469   
470   p = [ mCocoaWindow convertScreenToBase: p ];
471   return Point2I( p.x, p.y );
472}
473
474bool MacWindow::isFocused()
475{
476   return [mCocoaWindow isKeyWindow];
477}
478
479bool MacWindow::isOpen()
480{
481   // Maybe check if _window != NULL ?
482   return true;
483}
484
485bool MacWindow::isVisible()
486{
487   return !isMinimized() && ([mCocoaWindow isVisible] == YES);
488}
489   
490void MacWindow::setFocus()
491{
492   [mCocoaWindow makeKeyAndOrderFront:nil];
493}
494
495void MacWindow::signalGainFocus()
496{
497   if(isFocused())
498      [[mCocoaWindow delegate] performSelector:@selector(signalGainFocus)];
499}
500
501void MacWindow::minimize()
502{
503   if(!isVisible())
504      return;
505      
506   [mCocoaWindow miniaturize:nil];
507   appEvent.trigger(getWindowId(), WindowHidden);
508}
509
510void MacWindow::maximize()
511{
512   if(!isVisible())
513      return;
514   
515   // GFX2_RENDER_MERGE 
516   //[mCocoaWindow miniaturize:nil];
517   //appEvent.trigger(getWindowId(), WindowHidden);
518}
519
520void MacWindow::restore()
521{
522   if(!isMinimized())
523      return;
524   
525   [mCocoaWindow deminiaturize:nil];
526   appEvent.trigger(getWindowId(), WindowShown);
527}
528
529bool MacWindow::isMinimized()
530{
531   return [mCocoaWindow isMiniaturized] == YES;
532}
533
534bool MacWindow::isMaximized()
535{
536   return false;
537}
538
539void MacWindow::clearFocus()
540{
541   // Clear the focus state for this Window.  
542   // If the Window does not have focus, nothing happens.
543   // If the Window has focus, it relinquishes it's focus to the Operating System
544   
545   // TODO: find out if we can do anything correct here. We are instructed *not* to call [NSWindow resignKeyWindow], and we don't necessarily have another window to assign as key.
546}
547
548bool MacWindow::setCaption(const char* windowText)
549{
550   mTitle = windowText;
551   [mCocoaWindow setTitle:[NSString stringWithUTF8String:mTitle]];
552   return true;
553}
554
555void MacWindow::_doMouseLockNow()
556{
557   if(!isVisible())
558      return;
559      
560   if(mShouldMouseLock == mMouseLocked && mMouseLocked != isCursorVisible())
561      return;
562   
563   if(mShouldMouseLock)
564      _dissociateMouse();
565   else
566      _associateMouse();
567   
568   // hide the cursor if we're locking, show it if we're unlocking
569   setCursorVisible(!shouldLockMouse());
570
571   mMouseLocked = mShouldMouseLock;
572
573   return;
574}
575
576void MacWindow::_associateMouse()
577{
578   CGAssociateMouseAndMouseCursorPosition(true);
579}
580
581void MacWindow::_dissociateMouse()
582{
583   _centerMouse();
584   CGAssociateMouseAndMouseCursorPosition(false);
585}
586
587void MacWindow::_centerMouse()
588{
589   NSRect frame = [mCocoaWindow frame];
590   
591   // Deal with the y flip (really fun when more than one monitor is involved)
592   F32 offsetY = mMainDisplayBounds.size.height - mDisplayBounds.size.height;
593   frame.origin.y = (mDisplayBounds.size.height + offsetY) - (S32)frame.origin.y - (S32)frame.size.height;
594   mCursorController->setCursorPosition(frame.origin.x + frame.size.width / 2, frame.origin.y + frame.size.height / 2);
595}
596