2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #if defined(TARGET_DARWIN_OSX)
23 //hack around problem with xbmc's typedef int BOOL
24 // and obj-c's typedef unsigned char BOOL
25 #define BOOL XBMC_BOOL
26 #include "WinSystemOSX.h"
27 #include "WinEventsOSX.h"
28 #include "Application.h"
29 #include "guilib/DispResource.h"
30 #include "guilib/GUIWindowManager.h"
31 #include "settings/Settings.h"
32 #include "settings/GUISettings.h"
33 #include "input/KeyboardStat.h"
34 #include "threads/SingleLock.h"
35 #include "utils/log.h"
36 #include "osx/XBMCHelper.h"
37 #include "utils/SystemInfo.h"
38 #include "osx/CocoaInterface.h"
39 #include "osx/DarwinUtils.h"
42 #import <SDL/SDL_video.h>
43 #import <SDL/SDL_events.h>
45 #import <Cocoa/Cocoa.h>
46 #import <QuartzCore/QuartzCore.h>
47 #import <IOKit/pwr_mgt/IOPMLib.h>
48 #import <IOKit/graphics/IOGraphicsLib.h>
50 // turn off deprecated warning spew.
51 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
53 //------------------------------------------------------------------------------------------
54 // special object-c class for handling the inhibit display NSTimer callback.
55 @interface windowInhibitScreenSaverClass : NSObject
56 - (void) updateSystemActivity: (NSTimer*)timer;
59 @implementation windowInhibitScreenSaverClass
60 -(void) updateSystemActivity: (NSTimer*)timer
62 UpdateSystemActivity(UsrActivity);
66 //------------------------------------------------------------------------------------------
67 // special object-c class for handling the NSWindowDidMoveNotification callback.
68 @interface windowDidMoveNoteClass : NSObject
72 + initWith: (void*) userdata;
73 - (void) windowDidMoveNotification:(NSNotification*) note;
76 @implementation windowDidMoveNoteClass
77 + initWith: (void*) userdata;
79 windowDidMoveNoteClass *windowDidMove = [windowDidMoveNoteClass new];
80 windowDidMove->m_userdata = userdata;
81 return [windowDidMove autorelease];
83 - (void) windowDidMoveNotification:(NSNotification*) note;
85 CWinSystemOSX *winsys = (CWinSystemOSX*)m_userdata;
89 NSOpenGLContext* context = [NSOpenGLContext currentContext];
94 NSPoint window_origin = [[[context view] window] frame].origin;
96 memset(&newEvent, 0, sizeof(newEvent));
97 newEvent.type = XBMC_VIDEOMOVE;
98 newEvent.move.x = window_origin.x;
99 newEvent.move.y = window_origin.y;
100 g_application.OnEvent(newEvent);
105 //------------------------------------------------------------------------------------------
106 // special object-c class for handling the NSWindowDidReSizeNotification callback.
107 @interface windowDidReSizeNoteClass : NSObject
111 + initWith: (void*) userdata;
112 - (void) windowDidReSizeNotification:(NSNotification*) note;
114 @implementation windowDidReSizeNoteClass
115 + initWith: (void*) userdata;
117 windowDidReSizeNoteClass *windowDidReSize = [windowDidReSizeNoteClass new];
118 windowDidReSize->m_userdata = userdata;
119 return [windowDidReSize autorelease];
121 - (void) windowDidReSizeNotification:(NSNotification*) note;
123 CWinSystemOSX *winsys = (CWinSystemOSX*)m_userdata;
126 /* placeholder, do not uncomment or you will SDL recurse into death
127 NSOpenGLContext* context = [NSOpenGLContext currentContext];
132 NSSize view_size = [[context view] frame].size;
134 memset(&newEvent, 0, sizeof(newEvent));
135 newEvent.type = XBMC_VIDEORESIZE;
136 newEvent.resize.w = view_size.width;
137 newEvent.resize.h = view_size.height;
138 if (newEvent.resize.w * newEvent.resize.h)
140 g_application.OnEvent(newEvent);
141 g_windowManager.MarkDirty();
148 //------------------------------------------------------------------------------------------
151 #define MAX_DISPLAYS 32
152 static NSWindow* blankingWindows[MAX_DISPLAYS];
154 void* CWinSystemOSX::m_lastOwnedContext = 0;
156 //------------------------------------------------------------------------------------------
157 CRect CGRectToCRect(CGRect cgrect)
162 cgrect.origin.x + cgrect.size.width,
163 cgrect.origin.y + cgrect.size.height);
167 //------------------------------------------------------------------------------------------
168 Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key)
170 // get a boolean from the dictionary
171 Boolean value = false;
172 CFBooleanRef boolRef;
173 boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
175 value = CFBooleanGetValue(boolRef);
178 //------------------------------------------------------------------------------------------
179 long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
181 // get a long from the dictionary
184 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
186 CFNumberGetValue(numRef, kCFNumberLongType, &value);
189 //------------------------------------------------------------------------------------------
190 int GetDictionaryInt(CFDictionaryRef theDict, const void* key)
192 // get a long from the dictionary
195 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
197 CFNumberGetValue(numRef, kCFNumberIntType, &value);
200 //------------------------------------------------------------------------------------------
201 float GetDictionaryFloat(CFDictionaryRef theDict, const void* key)
203 // get a long from the dictionary
206 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
208 CFNumberGetValue(numRef, kCFNumberFloatType, &value);
211 //------------------------------------------------------------------------------------------
212 double GetDictionaryDouble(CFDictionaryRef theDict, const void* key)
214 // get a long from the dictionary
217 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
219 CFNumberGetValue(numRef, kCFNumberDoubleType, &value);
223 //---------------------------------------------------------------------------------
224 void SetMenuBarVisible(bool visible)
228 [[NSApplication sharedApplication]
229 setPresentationOptions: NSApplicationPresentationDefault];
233 [[NSApplication sharedApplication]
234 setPresentationOptions: NSApplicationPresentationHideMenuBar |
235 NSApplicationPresentationHideDock];
238 //---------------------------------------------------------------------------------
239 CGDirectDisplayID GetDisplayID(int screen_index)
241 CGDirectDisplayID displayArray[MAX_DISPLAYS];
242 CGDisplayCount numDisplays;
244 // Get the list of displays.
245 CGGetActiveDisplayList(MAX_DISPLAYS, displayArray, &numDisplays);
246 return(displayArray[screen_index]);
249 CGDirectDisplayID GetDisplayIDFromScreen(NSScreen *screen)
251 NSDictionary* screenInfo = [screen deviceDescription];
252 NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
254 return (CGDirectDisplayID)[screenID longValue];
257 int GetDisplayIndex(CGDirectDisplayID display)
259 CGDirectDisplayID displayArray[MAX_DISPLAYS];
260 CGDisplayCount numDisplays;
262 // Get the list of displays.
263 CGGetActiveDisplayList(MAX_DISPLAYS, displayArray, &numDisplays);
264 while (numDisplays > 0)
266 if (display == displayArray[--numDisplays])
272 void BlankOtherDisplays(int screen_index)
275 int numDisplays = [[NSScreen screens] count];
277 // zero out blankingWindows for debugging
278 for (i=0; i<MAX_DISPLAYS; i++)
280 blankingWindows[i] = 0;
284 for (i=0; i<numDisplays; i++)
286 if (i != screen_index)
289 NSScreen* pScreen = [[NSScreen screens] objectAtIndex:i];
290 NSRect screenRect = [pScreen frame];
292 // Build a blanking window.
293 screenRect.origin = NSZeroPoint;
294 blankingWindows[i] = [[NSWindow alloc] initWithContentRect:screenRect
295 styleMask:NSBorderlessWindowMask
296 backing:NSBackingStoreBuffered
300 [blankingWindows[i] setBackgroundColor:[NSColor blackColor]];
301 [blankingWindows[i] setLevel:CGShieldingWindowLevel()];
302 [blankingWindows[i] makeKeyAndOrderFront:nil];
307 void UnblankDisplays(void)
309 int numDisplays = [[NSScreen screens] count];
312 for (i=0; i<numDisplays; i++)
314 if (blankingWindows[i] != 0)
316 // Get rid of the blanking windows we created.
317 [blankingWindows[i] close];
318 if ([blankingWindows[i] isReleasedWhenClosed] == NO)
319 [blankingWindows[i] release];
320 blankingWindows[i] = 0;
325 CGDisplayFadeReservationToken DisplayFadeToBlack(bool fade)
327 // Fade to black to hide resolution-switching flicker and garbage.
328 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
329 if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess && fade)
330 CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
335 void DisplayFadeFromBlack(CGDisplayFadeReservationToken fade_token, bool fade)
337 if (fade_token != kCGDisplayFadeReservationInvalidToken)
340 CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
341 CGReleaseDisplayFadeReservation(fade_token);
345 NSString* screenNameForDisplay(CGDirectDisplayID displayID)
347 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
349 NSString *screenName = nil;
351 NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), kIODisplayOnlyPreferredName);
352 NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
354 if ([localizedNames count] > 0) {
355 screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain];
358 [deviceInfo release];
361 return [screenName autorelease];
364 void ShowHideNSWindow(NSWindow *wind, bool show)
367 [wind orderFront:nil];
372 static NSWindow *curtainWindow;
373 void fadeInDisplay(NSScreen *theScreen, double fadeTime)
376 double fadeInterval = (fadeTime / (double) fadeSteps);
378 if (curtainWindow != nil)
380 for (int step = 0; step < fadeSteps; step++)
382 double fade = 1.0 - (step * fadeInterval);
383 [curtainWindow setAlphaValue:fade];
385 NSDate *nextDate = [NSDate dateWithTimeIntervalSinceNow:fadeInterval];
386 [[NSRunLoop currentRunLoop] runUntilDate:nextDate];
389 [curtainWindow close];
395 void fadeOutDisplay(NSScreen *theScreen, double fadeTime)
398 double fadeInterval = (fadeTime / (double) fadeSteps);
402 curtainWindow = [[NSWindow alloc]
403 initWithContentRect:[theScreen frame]
404 styleMask:NSBorderlessWindowMask
405 backing:NSBackingStoreBuffered
409 [curtainWindow setAlphaValue:0.0];
410 [curtainWindow setBackgroundColor:[NSColor blackColor]];
411 [curtainWindow setLevel:NSScreenSaverWindowLevel];
413 [curtainWindow makeKeyAndOrderFront:nil];
414 [curtainWindow setFrame:[curtainWindow
415 frameRectForContentRect:[theScreen frame]]
419 for (int step = 0; step < fadeSteps; step++)
421 double fade = step * fadeInterval;
422 [curtainWindow setAlphaValue:fade];
424 NSDate *nextDate = [NSDate dateWithTimeIntervalSinceNow:fadeInterval];
425 [[NSRunLoop currentRunLoop] runUntilDate:nextDate];
429 // try to find mode that matches the desired size, refreshrate
430 // non interlaced, nonstretched, safe for hardware
431 CFDictionaryRef GetMode(int width, int height, double refreshrate, int screenIdx)
433 if ( screenIdx >= (signed)[[NSScreen screens] count])
438 Boolean safeForHardware;
439 Boolean televisionoutput;
440 int w, h, bitsperpixel;
444 CLog::Log(LOGDEBUG, "GetMode looking for suitable mode with %d x %d @ %f Hz on display %d\n", width, height, refreshrate, screenIdx);
446 CFArrayRef displayModes = CGDisplayAvailableModes(GetDisplayID(screenIdx));
448 if (NULL == displayModes)
450 CLog::Log(LOGERROR, "GetMode - no displaymodes found!");
454 for (int i=0; i < CFArrayGetCount(displayModes); ++i)
456 CFDictionaryRef displayMode = (CFDictionaryRef)CFArrayGetValueAtIndex(displayModes, i);
458 stretched = GetDictionaryBoolean(displayMode, kCGDisplayModeIsStretched);
459 interlaced = GetDictionaryBoolean(displayMode, kCGDisplayModeIsInterlaced);
460 bitsperpixel = GetDictionaryInt(displayMode, kCGDisplayBitsPerPixel);
461 safeForHardware = GetDictionaryBoolean(displayMode, kCGDisplayModeIsSafeForHardware);
462 televisionoutput = GetDictionaryBoolean(displayMode, kCGDisplayModeIsTelevisionOutput);
463 w = GetDictionaryInt(displayMode, kCGDisplayWidth);
464 h = GetDictionaryInt(displayMode, kCGDisplayHeight);
465 rate = GetDictionaryDouble(displayMode, kCGDisplayRefreshRate);
468 if ((bitsperpixel == 32) &&
469 (safeForHardware == YES) &&
471 (interlaced == NO) &&
474 (rate == refreshrate || rate == 0))
476 CLog::Log(LOGDEBUG, "GetMode found a match!");
480 CLog::Log(LOGERROR, "GetMode - no match found!");
484 //---------------------------------------------------------------------------------
485 static void DisplayReconfigured(CGDirectDisplayID display,
486 CGDisplayChangeSummaryFlags flags, void* userData)
488 CWinSystemOSX *winsys = (CWinSystemOSX*)userData;
492 if (flags & kCGDisplaySetModeFlag || flags & kCGDisplayBeginConfigurationFlag)
494 // pre/post-reconfiguration changes
495 RESOLUTION res = g_graphicsContext.GetVideoResolution();
496 if (res == RES_INVALID)
499 NSScreen* pScreen = nil;
500 unsigned int screenIdx = g_settings.m_ResInfo[res].iScreen;
502 if ( screenIdx < [[NSScreen screens] count] )
504 pScreen = [[NSScreen screens] objectAtIndex:screenIdx];
509 CGDirectDisplayID xbmc_display = GetDisplayIDFromScreen(pScreen);
510 if (xbmc_display == display)
512 // we only respond to changes on the display we are running on.
513 CLog::Log(LOGDEBUG, "CWinSystemOSX::DisplayReconfigured");
514 winsys->CheckDisplayChanging(flags);
520 //---------------------------------------------------------------------------------
521 //---------------------------------------------------------------------------------
522 CWinSystemOSX::CWinSystemOSX() : CWinSystemBase()
524 m_eWindowSystem = WINDOW_SYSTEM_OSX;
529 m_obscured_timecheck = XbmcThreads::SystemClockMillis() + 1000;
530 m_use_system_screensaver = true;
531 // check runtime, we only allow this on 10.5+
532 m_can_display_switch = (floor(NSAppKitVersionNumber) >= 949);
535 CWinSystemOSX::~CWinSystemOSX()
539 bool CWinSystemOSX::InitWindowSystem()
541 SDL_EnableUNICODE(1);
543 // set repeat to 10ms to ensure repeat time < frame time
544 // so that hold times can be reliably detected
545 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10);
547 if (!CWinSystemBase::InitWindowSystem())
550 m_osx_events = new CWinEventsOSX();
552 if (m_can_display_switch)
553 CGDisplayRegisterReconfigurationCallback(DisplayReconfigured, (void*)this);
555 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
556 windowDidMoveNoteClass *windowDidMove;
557 windowDidMove = [windowDidMoveNoteClass initWith: this];
558 [center addObserver:windowDidMove
559 selector:@selector(windowDidMoveNotification:)
560 name:NSWindowDidMoveNotification object:nil];
561 m_windowDidMove = windowDidMove;
564 windowDidReSizeNoteClass *windowDidReSize;
565 windowDidReSize = [windowDidReSizeNoteClass initWith: this];
566 [center addObserver:windowDidReSize
567 selector:@selector(windowDidReSizeNotification:)
568 name:NSWindowDidResizeNotification object:nil];
569 m_windowDidReSize = windowDidReSize;
574 bool CWinSystemOSX::DestroyWindowSystem()
576 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
577 [center removeObserver:(windowDidMoveNoteClass*)m_windowDidMove name:NSWindowDidMoveNotification object:nil];
578 [center removeObserver:(windowDidReSizeNoteClass*)m_windowDidReSize name:NSWindowDidResizeNotification object:nil];
580 if (m_can_display_switch)
581 CGDisplayRemoveReconfigurationCallback(DisplayReconfigured, (void*)this);
589 NSOpenGLContext* oldContext = (NSOpenGLContext*)m_glContext;
590 [oldContext release];
596 bool CWinSystemOSX::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
598 m_nWidth = res.iWidth;
599 m_nHeight = res.iHeight;
600 m_bFullScreen = fullScreen;
602 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
603 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
604 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
605 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
606 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
608 // Enable vertical sync to avoid any tearing.
609 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
611 m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, SDL_OPENGL | SDL_RESIZABLE);
615 // the context SDL creates isn't full screen compatible, so we create new one
616 // first, find the current contect and make sure a view is attached
617 NSOpenGLContext* cur_context = [NSOpenGLContext currentContext];
618 NSView* view = [cur_context view];
622 // if we are not starting up windowed, then hide the initial SDL window
623 // so we do not see it flash before the fade-out and switch to fullscreen.
624 if (g_guiSettings.m_LookAndFeelResolution != RES_WINDOW)
625 ShowHideNSWindow([view window], false);
627 // disassociate view from context
628 [cur_context clearDrawable];
630 // release the context
631 if (m_lastOwnedContext == cur_context)
633 [ NSOpenGLContext clearCurrentContext ];
634 [ cur_context clearDrawable ];
635 [ cur_context release ];
638 // create a new context
639 NSOpenGLContext* new_context = (NSOpenGLContext*)CreateWindowedContext(nil);
643 // associate with current view
644 [new_context setView:view];
645 [new_context makeCurrentContext];
647 // set the window title
649 string = [ [ NSString alloc ] initWithUTF8String:"XBMC Media Center" ];
650 [ [ [new_context view] window] setTitle:string ];
653 m_glContext = new_context;
654 m_lastOwnedContext = new_context;
655 m_bWindowCreated = true;
660 bool CWinSystemOSX::DestroyWindow()
665 extern "C" void SDL_SetWidthHeight(int w, int h);
666 bool CWinSystemOSX::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
671 NSOpenGLContext* context = [NSOpenGLContext currentContext];
675 view = [context view];
676 if (view && (newWidth > 0) && (newHeight > 0))
678 window = [view window];
681 [window setContentSize:NSMakeSize(newWidth, newHeight)];
683 [view setFrameSize:NSMakeSize(newWidth, newHeight)];
688 // HACK: resize SDL's view manually so that mouse bounds are correctly updated.
689 // there are two parts to this, the internal SDL (current_video->screen) and
690 // the cocoa view ( handled in SetFullScreen).
691 SDL_SetWidthHeight(newWidth, newHeight);
693 [context makeCurrentContext];
696 m_nHeight = newHeight;
697 m_glContext = context;
702 static bool needtoshowme = true;
704 bool CWinSystemOSX::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
706 static NSWindow* windowedFullScreenwindow = NULL;
707 static NSScreen* last_window_screen = NULL;
708 static NSPoint last_window_origin;
709 static NSView* last_view = NULL;
710 static NSSize last_view_size;
711 static NSPoint last_view_origin;
712 bool was_fullscreen = m_bFullScreen;
713 static int lastDisplayNr = res.iScreen;
714 NSOpenGLContext* cur_context;
716 // Fade to black to hide resolution-switching flicker and garbage.
717 CGDisplayFadeReservationToken fade_token = DisplayFadeToBlack(needtoshowme);
719 // If we're already fullscreen then we must be moving to a different display.
720 // or if we are still on the same display - it might be only a refreshrate/resolution
722 // Recurse to reset fullscreen mode and then continue.
723 if (was_fullscreen && fullScreen && lastDisplayNr != res.iScreen)
725 needtoshowme = false;
726 ShowHideNSWindow([last_view window], needtoshowme);
727 RESOLUTION_INFO& window = g_settings.m_ResInfo[RES_WINDOW];
728 CWinSystemOSX::SetFullScreen(false, window, blankOtherDisplays);
732 m_nWidth = res.iWidth;
733 m_nHeight = res.iHeight;
734 m_bFullScreen = fullScreen;
736 cur_context = [NSOpenGLContext currentContext];
738 //handle resolution/refreshrate switching early here
741 if (m_can_display_switch)
743 // send pre-configuration change now and do not
744 // wait for switch videomode callback. This gives just
745 // a little more advanced notice of the display pre-change.
746 if (g_guiSettings.GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF)
747 CheckDisplayChanging(kCGDisplayBeginConfigurationFlag);
750 SwitchToVideoMode(res.iWidth, res.iHeight, res.fRefreshRate, res.iScreen);
751 lastDisplayNr = res.iScreen;
758 DisplayFadeFromBlack(fade_token, needtoshowme);
762 if (windowedFullScreenwindow != NULL)
764 [windowedFullScreenwindow close];
765 if ([windowedFullScreenwindow isReleasedWhenClosed] == NO)
766 [windowedFullScreenwindow release];
767 windowedFullScreenwindow = NULL;
773 NSOpenGLContext* newContext = NULL;
775 // Save info about the windowed context so we can restore it when returning to windowed.
776 last_view = [cur_context view];
777 last_view_size = [last_view frame].size;
778 last_view_origin = [last_view frame].origin;
779 last_window_screen = [[last_view window] screen];
780 last_window_origin = [[last_view window] frame].origin;
782 if (g_guiSettings.GetBool("videoscreen.fakefullscreen"))
784 // This is Cocca Windowed FullScreen Mode
785 // Get the screen rect of our current display
786 NSScreen* pScreen = [[NSScreen screens] objectAtIndex:res.iScreen];
787 NSRect screenRect = [pScreen frame];
789 // remove frame origin offset of orginal display
790 screenRect.origin = NSZeroPoint;
792 // make a new window to act as the windowedFullScreen
793 windowedFullScreenwindow = [[NSWindow alloc] initWithContentRect:screenRect
794 styleMask:NSBorderlessWindowMask
795 backing:NSBackingStoreBuffered
799 [windowedFullScreenwindow setBackgroundColor:[NSColor blackColor]];
800 [windowedFullScreenwindow makeKeyAndOrderFront:nil];
802 // make our window the same level as the rest to enable cmd+tab switching
803 [windowedFullScreenwindow setLevel:NSNormalWindowLevel];
804 // this will make our window topmost and hide all system messages
805 //[windowedFullScreenwindow setLevel:CGShieldingWindowLevel()];
807 // ...and the original one beneath it and on the same screen.
808 [[last_view window] setLevel:NSNormalWindowLevel-1];
809 [[last_view window] setFrameOrigin:[pScreen frame].origin];
810 // expand the mouse bounds in SDL view to fullscreen
811 [ last_view setFrameOrigin:NSMakePoint(0.0, 0.0)];
812 [ last_view setFrameSize:NSMakeSize(m_nWidth, m_nHeight) ];
814 NSView* blankView = [[NSView alloc] init];
815 [windowedFullScreenwindow setContentView:blankView];
816 [windowedFullScreenwindow setContentSize:NSMakeSize(m_nWidth, m_nHeight)];
817 [windowedFullScreenwindow update];
818 [blankView setFrameSize:NSMakeSize(m_nWidth, m_nHeight)];
820 // Obtain windowed pixel format and create a new context.
821 newContext = (NSOpenGLContext*)CreateWindowedContext((void* )cur_context);
822 [newContext setView:blankView];
824 // Hide the menu bar.
825 if (GetDisplayID(res.iScreen) == kCGDirectMainDisplay)
826 SetMenuBarVisible(false);
828 // Blank other displays if requested.
829 if (blankOtherDisplays)
830 BlankOtherDisplays(res.iScreen);
835 [[last_view window] setFrameOrigin:[last_window_screen frame].origin];
836 // expand the mouse bounds in SDL view to fullscreen
837 [ last_view setFrameOrigin:NSMakePoint(0.0, 0.0)];
838 [ last_view setFrameSize:NSMakeSize(m_nWidth, m_nHeight) ];
840 // This is OpenGL FullScreen Mode
841 // create our new context (sharing with the current one)
842 newContext = (NSOpenGLContext*)CreateFullScreenContext(res.iScreen, (void*)cur_context);
846 // clear the current context
847 [NSOpenGLContext clearCurrentContext];
850 [newContext setFullScreen];
852 // Capture the display before going fullscreen.
853 if (blankOtherDisplays == true)
854 CGCaptureAllDisplays();
856 CGDisplayCapture(GetDisplayID(res.iScreen));
858 // If we don't hide menu bar, it will get events and interrupt the program.
859 if (GetDisplayID(res.iScreen) == kCGDirectMainDisplay)
860 SetMenuBarVisible(false);
866 // Release old context if we created it.
867 if (m_lastOwnedContext == cur_context)
869 [ NSOpenGLContext clearCurrentContext ];
870 [ cur_context clearDrawable ];
871 [ cur_context release ];
875 [newContext makeCurrentContext];
876 m_lastOwnedContext = newContext;
882 [cur_context clearDrawable];
887 if (GetDisplayID(res.iScreen) == kCGDirectMainDisplay)
888 SetMenuBarVisible(true);
890 if (g_guiSettings.GetBool("videoscreen.fakefullscreen"))
892 // restore the windowed window level
893 [[last_view window] setLevel:NSNormalWindowLevel];
895 // Get rid of the new window we created.
896 if (windowedFullScreenwindow != NULL)
898 [windowedFullScreenwindow close];
899 if ([windowedFullScreenwindow isReleasedWhenClosed] == NO)
900 [windowedFullScreenwindow release];
901 windowedFullScreenwindow = NULL;
905 // Force the unblank when returning from fullscreen, we get called with blankOtherDisplays set false.
906 //if (blankOtherDisplays)
912 CGReleaseAllDisplays();
915 // create our new context (sharing with the current one)
916 NSOpenGLContext* newContext = (NSOpenGLContext*)CreateWindowedContext((void* )cur_context);
920 // Assign view from old context, move back to original screen.
921 [newContext setView:last_view];
922 [[last_view window] setFrameOrigin:last_window_origin];
923 // return the mouse bounds in SDL view to prevous size
924 [ last_view setFrameSize:last_view_size ];
925 [ last_view setFrameOrigin:last_view_origin ];
926 // done with restoring windowed window, don't set last_view to NULL as we can lose it under dual displays.
927 //last_window_screen = NULL;
929 // Release the fullscreen context.
930 if (m_lastOwnedContext == cur_context)
932 [ NSOpenGLContext clearCurrentContext ];
933 [ cur_context clearDrawable ];
934 [ cur_context release ];
938 [newContext makeCurrentContext];
939 m_lastOwnedContext = newContext;
942 DisplayFadeFromBlack(fade_token, needtoshowme);
944 ShowHideNSWindow([last_view window], needtoshowme);
945 // need to make sure SDL tracks any window size changes
946 ResizeWindow(m_nWidth, m_nHeight, -1, -1);
951 void CWinSystemOSX::UpdateResolutions()
953 CWinSystemBase::UpdateResolutions();
955 // Add desktop resolution
959 // first screen goes into the current desktop mode
960 GetScreenResolution(&w, &h, &fps, 0);
961 UpdateDesktopResolution(g_settings.m_ResInfo[RES_DESKTOP], 0, w, h, fps);
963 // see resolution.h enum RESOLUTION for how the resolutions
964 // have to appear in the g_settings.m_ResInfo vector
965 // add the desktop resolutions of the other screens
966 for(int i = 1; i < GetNumScreens(); i++)
969 // get current resolution of screen i
970 GetScreenResolution(&w, &h, &fps, i);
971 UpdateDesktopResolution(res, i, w, h, fps);
972 g_settings.m_ResInfo.push_back(res);
975 if (m_can_display_switch)
977 // now just fill in the possible reolutions for the attached screens
978 // and push to the m_ResInfo vector
984 void* Cocoa_GL_CreateContext(void* pixFmt, void* shareCtx)
989 NSOpenGLContext* newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
990 shareContext:(NSOpenGLContext*)shareCtx];
992 // snipit from SDL_cocoaopengl.m
994 // Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
995 // "You are blowing a couple of the internal OpenGL function caches. This
996 // appears to be happening in the VAO case. You can tell OpenGL to up
997 // the cache size by issuing the following calls right after you create
998 // the OpenGL context. The default cache size is 16." --ryan.
1001 #ifndef GLI_ARRAY_FUNC_CACHE_MAX
1002 #define GLI_ARRAY_FUNC_CACHE_MAX 284
1005 #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
1006 #define GLI_SUBMIT_FUNC_CACHE_MAX 280
1010 long cache_max = 64;
1011 CGLContextObj ctx = (CGLContextObj)[newContext CGLContextObj];
1012 CGLSetParameter(ctx, (CGLContextParameter)GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
1013 CGLSetParameter(ctx, (CGLContextParameter)GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
1016 // End Wisdom from Apple Engineer section. --ryan.
1021 void* CWinSystemOSX::CreateWindowedContext(void* shareCtx)
1023 NSOpenGLContext* newContext = NULL;
1025 NSOpenGLPixelFormatAttribute wattrs[] =
1027 NSOpenGLPFADoubleBuffer,
1029 NSOpenGLPFANoRecovery,
1030 NSOpenGLPFAAccelerated,
1031 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)8,
1032 (NSOpenGLPixelFormatAttribute)0
1035 NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:wattrs];
1037 newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1038 shareContext:(NSOpenGLContext*)shareCtx];
1043 // bah, try again for non-accelerated renderer
1044 NSOpenGLPixelFormatAttribute wattrs2[] =
1046 NSOpenGLPFADoubleBuffer,
1048 NSOpenGLPFANoRecovery,
1049 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)8,
1050 (NSOpenGLPixelFormatAttribute)0
1052 NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:wattrs2];
1054 newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1055 shareContext:(NSOpenGLContext*)shareCtx];
1062 void* CWinSystemOSX::CreateFullScreenContext(int screen_index, void* shareCtx)
1064 CGDirectDisplayID displayArray[MAX_DISPLAYS];
1065 CGDisplayCount numDisplays;
1066 CGDirectDisplayID displayID;
1068 // Get the list of displays.
1069 CGGetActiveDisplayList(MAX_DISPLAYS, displayArray, &numDisplays);
1070 displayID = displayArray[screen_index];
1072 NSOpenGLPixelFormatAttribute fsattrs[] =
1074 NSOpenGLPFADoubleBuffer,
1075 NSOpenGLPFAFullScreen,
1076 NSOpenGLPFANoRecovery,
1077 NSOpenGLPFAAccelerated,
1078 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)8,
1079 NSOpenGLPFAScreenMask, (NSOpenGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(displayID),
1080 (NSOpenGLPixelFormatAttribute)0
1083 NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:fsattrs];
1087 NSOpenGLContext* newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1088 shareContext:(NSOpenGLContext*)shareCtx];
1094 void CWinSystemOSX::GetScreenResolution(int* w, int* h, double* fps, int screenIdx)
1096 // Figure out the screen size. (default to main screen)
1097 if (screenIdx >= GetNumScreens())
1099 CGDirectDisplayID display_id = (CGDirectDisplayID)GetDisplayID(screenIdx);
1101 NSOpenGLContext* context = [NSOpenGLContext currentContext];
1106 view = [context view];
1110 window = [view window];
1112 display_id = GetDisplayIDFromScreen( [window screen] );
1115 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
1116 *w = CGDisplayModeGetWidth(mode);
1117 *h = CGDisplayModeGetHeight(mode);
1118 *fps = CGDisplayModeGetRefreshRate(mode);
1119 CGDisplayModeRelease(mode);
1122 // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays.
1127 void CWinSystemOSX::EnableVSync(bool enable)
1129 // OpenGL Flush synchronised with vertical retrace
1130 GLint swapInterval = enable ? 1 : 0;
1131 [[NSOpenGLContext currentContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
1134 bool CWinSystemOSX::SwitchToVideoMode(int width, int height, double refreshrate, int screenIdx)
1136 // SwitchToVideoMode will not return until the display has actually switched over.
1137 // This can take several seconds.
1138 if( screenIdx >= GetNumScreens())
1141 boolean_t match = false;
1142 CFDictionaryRef dispMode = NULL;
1143 // Figure out the screen size. (default to main screen)
1144 CGDirectDisplayID display_id = GetDisplayID(screenIdx);
1146 // find mode that matches the desired size, refreshrate
1147 // non interlaced, nonstretched, safe for hardware
1148 dispMode = GetMode(width, height, refreshrate, screenIdx);
1150 //not found - fallback to bestemdeforparameters
1153 dispMode = CGDisplayBestModeForParameters(display_id, 32, width, height, &match);
1156 dispMode = CGDisplayBestModeForParameters(display_id, 16, width, height, &match);
1162 // switch mode and return success
1163 CGDisplayCapture(display_id);
1164 CGDisplayConfigRef cfg;
1165 CGBeginDisplayConfiguration(&cfg);
1166 // we don't need to do this, we are already faded.
1167 //CGConfigureDisplayFadeEffect(cfg, 0.3f, 0.5f, 0, 0, 0);
1168 CGConfigureDisplayMode(cfg, display_id, dispMode);
1169 CGError err = CGCompleteDisplayConfiguration(cfg, kCGConfigureForAppOnly);
1170 CGDisplayRelease(display_id);
1172 Cocoa_CVDisplayLinkUpdate();
1174 return (err == kCGErrorSuccess);
1177 void CWinSystemOSX::FillInVideoModes()
1179 // Add full screen settings for additional monitors
1180 int numDisplays = [[NSScreen screens] count];
1182 for (int disp = 0; disp < numDisplays; disp++)
1186 Boolean safeForHardware;
1187 Boolean televisionoutput;
1188 int w, h, bitsperpixel;
1190 RESOLUTION_INFO res;
1192 CFArrayRef displayModes = CGDisplayAvailableModes(GetDisplayID(disp));
1193 NSString *dispName = screenNameForDisplay(GetDisplayID(disp));
1194 CLog::Log(LOGNOTICE, "Display %i has name %s", disp, [dispName UTF8String]);
1196 if (NULL == displayModes)
1199 for (int i=0; i < CFArrayGetCount(displayModes); ++i)
1201 CFDictionaryRef displayMode = (CFDictionaryRef)CFArrayGetValueAtIndex(displayModes, i);
1203 stretched = GetDictionaryBoolean(displayMode, kCGDisplayModeIsStretched);
1204 interlaced = GetDictionaryBoolean(displayMode, kCGDisplayModeIsInterlaced);
1205 bitsperpixel = GetDictionaryInt(displayMode, kCGDisplayBitsPerPixel);
1206 safeForHardware = GetDictionaryBoolean(displayMode, kCGDisplayModeIsSafeForHardware);
1207 televisionoutput = GetDictionaryBoolean(displayMode, kCGDisplayModeIsTelevisionOutput);
1209 if ((bitsperpixel == 32) &&
1210 (safeForHardware == YES) &&
1211 (stretched == NO) &&
1214 w = GetDictionaryInt(displayMode, kCGDisplayWidth);
1215 h = GetDictionaryInt(displayMode, kCGDisplayHeight);
1216 refreshrate = GetDictionaryDouble(displayMode, kCGDisplayRefreshRate);
1217 if ((int)refreshrate == 0) // LCD display?
1219 // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays.
1222 CLog::Log(LOGNOTICE, "Found possible resolution for display %d with %d x %d @ %f Hz\n", disp, w, h, refreshrate);
1224 UpdateDesktopResolution(res, disp, w, h, refreshrate);
1226 // overwrite the mode str because UpdateDesktopResolution adds a
1227 // "Full Screen". Since the current resolution is there twice
1228 // this would lead to 2 identical resolution entrys in the guisettings.xml.
1229 // That would cause problems with saving screen overscan calibration
1230 // because the wrong entry is picked on load.
1231 // So we just use UpdateDesktopResolutions for the current DESKTOP_RESOLUTIONS
1232 // in UpdateResolutions. And on all othere resolutions make a unique
1233 // mode str by doing it without appending "Full Screen".
1234 // this is what linux does - though it feels that there shouldn't be
1235 // the same resolution twice... - thats why i add a FIXME here.
1236 res.strMode.Format("%dx%d @ %.2f", w, h, refreshrate);
1237 g_graphicsContext.ResetOverscan(res);
1238 g_settings.m_ResInfo.push_back(res);
1244 bool CWinSystemOSX::FlushBuffer(void)
1246 [ (NSOpenGLContext*)m_glContext flushBuffer ];
1251 bool CWinSystemOSX::IsObscured(void)
1253 // check once a second if we are obscured.
1254 unsigned int now_time = XbmcThreads::SystemClockMillis();
1255 if (m_obscured_timecheck > now_time)
1258 m_obscured_timecheck = now_time + 1000;
1260 NSOpenGLContext* cur_context = [NSOpenGLContext currentContext];
1261 NSView* view = [cur_context view];
1264 // sanity check, we should always have a view
1269 NSWindow *window = [view window];
1272 // sanity check, we should always have a window
1277 if ([window isVisible] == NO)
1279 // not visable means the window is not showing.
1280 // this should never really happen as we are always visable
1281 // even when minimized in dock.
1286 // check if we are minimized (to an icon in the Dock).
1287 if ([window isMiniaturized] == YES)
1293 // check if we are showing on the active workspace.
1294 if ([window isOnActiveSpace] == NO)
1300 // default to false before we start parsing though the windows.
1301 // if we are are obscured by any windows, then set true.
1303 static bool obscureLogged = false;
1305 CGWindowListOption opts;
1306 opts = kCGWindowListOptionOnScreenAboveWindow | kCGWindowListExcludeDesktopElements;
1307 CFArrayRef windowIDs =CGWindowListCreate(opts, (CGWindowID)[window windowNumber]);
1312 CFArrayRef windowDescs = CGWindowListCreateDescriptionFromArray(windowIDs);
1315 CFRelease(windowIDs);
1319 CGRect bounds = NSRectToCGRect([window frame]);
1320 // kCGWindowBounds measures the origin as the top-left corner of the rectangle
1321 // relative to the top-left corner of the screen.
1322 // NSWindow’s frame property measures the origin as the bottom-left corner
1323 // of the rectangle relative to the bottom-left corner of the screen.
1324 // convert bounds from NSWindow to CGWindowBounds here.
1325 bounds.origin.y = [[window screen] frame].size.height - bounds.origin.y - bounds.size.height;
1327 std::vector<CRect> partialOverlaps;
1328 CRect ourBounds = CGRectToCRect(bounds);
1330 for (CFIndex idx=0; idx < CFArrayGetCount(windowDescs); idx++)
1332 // walk the window list of windows that are above us and are not desktop elements
1333 CFDictionaryRef windowDictionary = (CFDictionaryRef)CFArrayGetValueAtIndex(windowDescs, idx);
1335 // skip the Dock window, it actually covers the entire screen.
1336 CFStringRef ownerName = (CFStringRef)CFDictionaryGetValue(windowDictionary, kCGWindowOwnerName);
1337 if (CFStringCompare(ownerName, CFSTR("Dock"), 0) == kCFCompareEqualTo)
1340 // Ignore known brightness tools for dimming the screen. They claim to cover
1341 // the whole XBMC window and therefore would make the framerate limiter
1342 // kicking in. Unfortunatly even the alpha of these windows is 1.0 so
1343 // we have to check the ownerName.
1344 if (CFStringCompare(ownerName, CFSTR("Shades"), 0) == kCFCompareEqualTo ||
1345 CFStringCompare(ownerName, CFSTR("SmartSaver"), 0) == kCFCompareEqualTo ||
1346 CFStringCompare(ownerName, CFSTR("Brightness Slider"), 0) == kCFCompareEqualTo ||
1347 CFStringCompare(ownerName, CFSTR("Displaperture"), 0) == kCFCompareEqualTo ||
1348 CFStringCompare(ownerName, CFSTR("Dreamweaver"), 0) == kCFCompareEqualTo)
1351 CFDictionaryRef rectDictionary = (CFDictionaryRef)CFDictionaryGetValue(windowDictionary, kCGWindowBounds);
1352 if (!rectDictionary)
1355 CGRect windowBounds;
1356 if (CGRectMakeWithDictionaryRepresentation(rectDictionary, &windowBounds))
1358 if (CGRectContainsRect(windowBounds, bounds))
1360 // if the windowBounds completely encloses our bounds, we are obscured.
1363 std::string appName;
1364 if (DarwinCFStringRefToString(ownerName, appName))
1365 CLog::Log(LOGDEBUG, "WinSystemOSX: Fullscreen window %s obscures XBMC!", appName.c_str());
1366 obscureLogged = true;
1372 // handle overlaping windows above us that combine
1373 // to obscure by collecting any partial overlaps,
1374 // then subtract them from our bounds and check
1375 // for any remaining area.
1376 CRect intersection = CGRectToCRect(windowBounds);
1377 intersection.Intersect(ourBounds);
1378 if (!intersection.IsEmpty())
1379 partialOverlaps.push_back(intersection);
1385 // if we are here we are not obscured by any fullscreen window - reset flag
1386 // for allowing the logmessage above to show again if this changes.
1388 obscureLogged = false;
1389 std::vector<CRect> rects = ourBounds.SubtractRects(partialOverlaps);
1390 // they got us covered
1391 if (rects.size() == 0)
1395 CFRelease(windowDescs);
1396 CFRelease(windowIDs);
1401 void CWinSystemOSX::NotifyAppFocusChange(bool bGaining)
1403 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1405 if (m_bFullScreen && bGaining)
1408 NSOpenGLContext* context = [NSOpenGLContext currentContext];
1413 view = [context view];
1417 window = [view window];
1420 // find the screenID
1421 NSDictionary* screenInfo = [[window screen] deviceDescription];
1422 NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
1423 if ((CGDirectDisplayID)[screenID longValue] == kCGDirectMainDisplay)
1425 SetMenuBarVisible(false);
1427 [window orderFront:nil];
1435 void CWinSystemOSX::ShowOSMouse(bool show)
1437 SDL_ShowCursor(show ? 1 : 0);
1440 bool CWinSystemOSX::Minimize()
1442 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1444 [[NSApplication sharedApplication] miniaturizeAll:nil];
1450 bool CWinSystemOSX::Restore()
1452 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1454 [[NSApplication sharedApplication] unhide:nil];
1460 bool CWinSystemOSX::Hide()
1462 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1464 [[NSApplication sharedApplication] hide:nil];
1470 void CWinSystemOSX::OnMove(int x, int y)
1472 Cocoa_CVDisplayLinkUpdate();
1475 void CWinSystemOSX::EnableSystemScreenSaver(bool bEnable)
1477 // see Technical Q&A QA1340
1478 static IOPMAssertionID assertionID = 0;
1482 if (assertionID == 0)
1484 CFStringRef reasonForActivity= CFSTR("XBMC requested disable system screen saver");
1485 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
1486 kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
1489 else if (assertionID != 0)
1491 IOPMAssertionRelease(assertionID);
1495 m_use_system_screensaver = bEnable;
1498 bool CWinSystemOSX::IsSystemScreenSaverEnabled()
1500 return m_use_system_screensaver;
1503 void CWinSystemOSX::ResetOSScreensaver()
1505 // allow os screensaver only if we are fullscreen
1506 EnableSystemScreenSaver(!m_bFullScreen);
1509 bool CWinSystemOSX::EnableFrameLimiter()
1511 return IsObscured();
1514 void CWinSystemOSX::Register(IDispResource *resource)
1516 CSingleLock lock(m_resourceSection);
1517 m_resources.push_back(resource);
1520 void CWinSystemOSX::Unregister(IDispResource* resource)
1522 CSingleLock lock(m_resourceSection);
1523 std::vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
1524 if (i != m_resources.end())
1525 m_resources.erase(i);
1528 bool CWinSystemOSX::Show(bool raise)
1530 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1534 [[NSApplication sharedApplication] unhide:nil];
1535 [[NSApplication sharedApplication] activateIgnoringOtherApps: YES];
1536 [[NSApplication sharedApplication] arrangeInFront:nil];
1540 [[NSApplication sharedApplication] unhideWithoutActivation];
1547 int CWinSystemOSX::GetNumScreens()
1549 int numDisplays = [[NSScreen screens] count];
1550 return(numDisplays);
1553 void CWinSystemOSX::CheckDisplayChanging(u_int32_t flags)
1557 CSingleLock lock(m_resourceSection);
1558 // tell any shared resources
1559 if (flags & kCGDisplayBeginConfigurationFlag)
1561 CLog::Log(LOGDEBUG, "CWinSystemOSX::CheckDisplayChanging:OnLostDevice");
1562 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
1563 (*i)->OnLostDevice();
1565 if (flags & kCGDisplaySetModeFlag)
1567 CLog::Log(LOGDEBUG, "CWinSystemOSX::CheckDisplayChanging:OnResetDevice");
1568 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
1569 (*i)->OnResetDevice();
1574 void* CWinSystemOSX::GetCGLContextObj()
1576 return [(NSOpenGLContext*)m_glContext CGLContextObj];