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/DisplaySettings.h"
32 #include "settings/Settings.h"
33 #include "settings/DisplaySettings.h"
34 #include "input/KeyboardStat.h"
35 #include "threads/SingleLock.h"
36 #include "utils/log.h"
37 #include "utils/StringUtils.h"
38 #include "osx/XBMCHelper.h"
39 #include "utils/SystemInfo.h"
40 #include "osx/CocoaInterface.h"
41 #include "osx/DarwinUtils.h"
44 #import <SDL/SDL_video.h>
45 #import <SDL/SDL_events.h>
47 #import <Cocoa/Cocoa.h>
48 #import <QuartzCore/QuartzCore.h>
49 #import <IOKit/pwr_mgt/IOPMLib.h>
50 #import <IOKit/graphics/IOGraphicsLib.h>
51 #import "osx/OSXTextInputResponder.h"
53 // turn off deprecated warning spew.
54 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
56 //------------------------------------------------------------------------------------------
57 // special object-c class for handling the inhibit display NSTimer callback.
58 @interface windowInhibitScreenSaverClass : NSObject
59 - (void) updateSystemActivity: (NSTimer*)timer;
62 @implementation windowInhibitScreenSaverClass
63 -(void) updateSystemActivity: (NSTimer*)timer
65 UpdateSystemActivity(UsrActivity);
69 //------------------------------------------------------------------------------------------
70 // special object-c class for handling the NSWindowDidMoveNotification callback.
71 @interface windowDidMoveNoteClass : NSObject
75 + initWith: (void*) userdata;
76 - (void) windowDidMoveNotification:(NSNotification*) note;
79 @implementation windowDidMoveNoteClass
80 + initWith: (void*) userdata;
82 windowDidMoveNoteClass *windowDidMove = [windowDidMoveNoteClass new];
83 windowDidMove->m_userdata = userdata;
84 return [windowDidMove autorelease];
86 - (void) windowDidMoveNotification:(NSNotification*) note;
88 CWinSystemOSX *winsys = (CWinSystemOSX*)m_userdata;
92 NSOpenGLContext* context = [NSOpenGLContext currentContext];
97 NSPoint window_origin = [[[context view] window] frame].origin;
99 memset(&newEvent, 0, sizeof(newEvent));
100 newEvent.type = XBMC_VIDEOMOVE;
101 newEvent.move.x = window_origin.x;
102 newEvent.move.y = window_origin.y;
103 g_application.OnEvent(newEvent);
108 //------------------------------------------------------------------------------------------
109 // special object-c class for handling the NSWindowDidReSizeNotification callback.
110 @interface windowDidReSizeNoteClass : NSObject
114 + initWith: (void*) userdata;
115 - (void) windowDidReSizeNotification:(NSNotification*) note;
117 @implementation windowDidReSizeNoteClass
118 + initWith: (void*) userdata;
120 windowDidReSizeNoteClass *windowDidReSize = [windowDidReSizeNoteClass new];
121 windowDidReSize->m_userdata = userdata;
122 return [windowDidReSize autorelease];
124 - (void) windowDidReSizeNotification:(NSNotification*) note;
126 CWinSystemOSX *winsys = (CWinSystemOSX*)m_userdata;
129 /* placeholder, do not uncomment or you will SDL recurse into death
130 NSOpenGLContext* context = [NSOpenGLContext currentContext];
135 NSSize view_size = [[context view] frame].size;
137 memset(&newEvent, 0, sizeof(newEvent));
138 newEvent.type = XBMC_VIDEORESIZE;
139 newEvent.resize.w = view_size.width;
140 newEvent.resize.h = view_size.height;
141 if (newEvent.resize.w * newEvent.resize.h)
143 g_application.OnEvent(newEvent);
144 g_windowManager.MarkDirty();
152 //------------------------------------------------------------------------------------------
153 // special object-c class for handling the NSWindowDidChangeScreenNotification callback.
154 @interface windowDidChangeScreenNoteClass : NSObject
158 + initWith: (void*) userdata;
159 - (void) windowDidChangeScreenNotification:(NSNotification*) note;
161 @implementation windowDidChangeScreenNoteClass
162 + initWith: (void*) userdata;
164 windowDidChangeScreenNoteClass *windowDidChangeScreen = [windowDidChangeScreenNoteClass new];
165 windowDidChangeScreen->m_userdata = userdata;
166 return [windowDidChangeScreen autorelease];
168 - (void) windowDidChangeScreenNotification:(NSNotification*) note;
170 CWinSystemOSX *winsys = (CWinSystemOSX*)m_userdata;
173 winsys->WindowChangedScreen();
176 //------------------------------------------------------------------------------------------
179 #define MAX_DISPLAYS 32
180 static NSWindow* blankingWindows[MAX_DISPLAYS];
182 void* CWinSystemOSX::m_lastOwnedContext = 0;
184 //------------------------------------------------------------------------------------------
185 CRect CGRectToCRect(CGRect cgrect)
190 cgrect.origin.x + cgrect.size.width,
191 cgrect.origin.y + cgrect.size.height);
195 //------------------------------------------------------------------------------------------
196 Boolean GetDictionaryBoolean(CFDictionaryRef theDict, const void* key)
198 // get a boolean from the dictionary
199 Boolean value = false;
200 CFBooleanRef boolRef;
201 boolRef = (CFBooleanRef)CFDictionaryGetValue(theDict, key);
203 value = CFBooleanGetValue(boolRef);
206 //------------------------------------------------------------------------------------------
207 long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
209 // get a long from the dictionary
212 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
214 CFNumberGetValue(numRef, kCFNumberLongType, &value);
217 //------------------------------------------------------------------------------------------
218 int GetDictionaryInt(CFDictionaryRef theDict, const void* key)
220 // get a long from the dictionary
223 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
225 CFNumberGetValue(numRef, kCFNumberIntType, &value);
228 //------------------------------------------------------------------------------------------
229 float GetDictionaryFloat(CFDictionaryRef theDict, const void* key)
231 // get a long from the dictionary
234 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
236 CFNumberGetValue(numRef, kCFNumberFloatType, &value);
239 //------------------------------------------------------------------------------------------
240 double GetDictionaryDouble(CFDictionaryRef theDict, const void* key)
242 // get a long from the dictionary
245 numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
247 CFNumberGetValue(numRef, kCFNumberDoubleType, &value);
251 //---------------------------------------------------------------------------------
252 void SetMenuBarVisible(bool visible)
256 [[NSApplication sharedApplication]
257 setPresentationOptions: NSApplicationPresentationDefault];
261 [[NSApplication sharedApplication]
262 setPresentationOptions: NSApplicationPresentationHideMenuBar |
263 NSApplicationPresentationHideDock];
266 //---------------------------------------------------------------------------------
267 CGDirectDisplayID GetDisplayID(int screen_index)
269 CGDirectDisplayID displayArray[MAX_DISPLAYS];
270 CGDisplayCount numDisplays;
272 // Get the list of displays.
273 CGGetActiveDisplayList(MAX_DISPLAYS, displayArray, &numDisplays);
274 return(displayArray[screen_index]);
277 CGDirectDisplayID GetDisplayIDFromScreen(NSScreen *screen)
279 NSDictionary* screenInfo = [screen deviceDescription];
280 NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
282 return (CGDirectDisplayID)[screenID longValue];
285 int GetDisplayIndex(CGDirectDisplayID display)
287 CGDirectDisplayID displayArray[MAX_DISPLAYS];
288 CGDisplayCount numDisplays;
290 // Get the list of displays.
291 CGGetActiveDisplayList(MAX_DISPLAYS, displayArray, &numDisplays);
292 while (numDisplays > 0)
294 if (display == displayArray[--numDisplays])
300 void BlankOtherDisplays(int screen_index)
303 int numDisplays = [[NSScreen screens] count];
305 // zero out blankingWindows for debugging
306 for (i=0; i<MAX_DISPLAYS; i++)
308 blankingWindows[i] = 0;
312 for (i=0; i<numDisplays; i++)
314 if (i != screen_index)
317 NSScreen* pScreen = [[NSScreen screens] objectAtIndex:i];
318 NSRect screenRect = [pScreen frame];
320 // Build a blanking window.
321 screenRect.origin = NSZeroPoint;
322 blankingWindows[i] = [[NSWindow alloc] initWithContentRect:screenRect
323 styleMask:NSBorderlessWindowMask
324 backing:NSBackingStoreBuffered
328 [blankingWindows[i] setBackgroundColor:[NSColor blackColor]];
329 [blankingWindows[i] setLevel:CGShieldingWindowLevel()];
330 [blankingWindows[i] makeKeyAndOrderFront:nil];
335 void UnblankDisplays(void)
337 int numDisplays = [[NSScreen screens] count];
340 for (i=0; i<numDisplays; i++)
342 if (blankingWindows[i] != 0)
344 // Get rid of the blanking windows we created.
345 [blankingWindows[i] close];
346 if ([blankingWindows[i] isReleasedWhenClosed] == NO)
347 [blankingWindows[i] release];
348 blankingWindows[i] = 0;
353 CGDisplayFadeReservationToken DisplayFadeToBlack(bool fade)
355 // Fade to black to hide resolution-switching flicker and garbage.
356 CGDisplayFadeReservationToken fade_token = kCGDisplayFadeReservationInvalidToken;
357 if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess && fade)
358 CGDisplayFade(fade_token, 0.3, kCGDisplayBlendNormal, kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
363 void DisplayFadeFromBlack(CGDisplayFadeReservationToken fade_token, bool fade)
365 if (fade_token != kCGDisplayFadeReservationInvalidToken)
368 CGDisplayFade(fade_token, 0.5, kCGDisplayBlendSolidColor, kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
369 CGReleaseDisplayFadeReservation(fade_token);
373 NSString* screenNameForDisplay(CGDirectDisplayID displayID)
375 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
377 NSString *screenName = nil;
379 NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(displayID), kIODisplayOnlyPreferredName);
380 NSDictionary *localizedNames = [deviceInfo objectForKey:[NSString stringWithUTF8String:kDisplayProductName]];
382 if ([localizedNames count] > 0) {
383 screenName = [[localizedNames objectForKey:[[localizedNames allKeys] objectAtIndex:0]] retain];
386 [deviceInfo release];
389 return [screenName autorelease];
392 void ShowHideNSWindow(NSWindow *wind, bool show)
395 [wind orderFront:nil];
400 static NSWindow *curtainWindow;
401 void fadeInDisplay(NSScreen *theScreen, double fadeTime)
404 double fadeInterval = (fadeTime / (double) fadeSteps);
406 if (curtainWindow != nil)
408 for (int step = 0; step < fadeSteps; step++)
410 double fade = 1.0 - (step * fadeInterval);
411 [curtainWindow setAlphaValue:fade];
413 NSDate *nextDate = [NSDate dateWithTimeIntervalSinceNow:fadeInterval];
414 [[NSRunLoop currentRunLoop] runUntilDate:nextDate];
417 [curtainWindow close];
423 void fadeOutDisplay(NSScreen *theScreen, double fadeTime)
426 double fadeInterval = (fadeTime / (double) fadeSteps);
430 curtainWindow = [[NSWindow alloc]
431 initWithContentRect:[theScreen frame]
432 styleMask:NSBorderlessWindowMask
433 backing:NSBackingStoreBuffered
437 [curtainWindow setAlphaValue:0.0];
438 [curtainWindow setBackgroundColor:[NSColor blackColor]];
439 [curtainWindow setLevel:NSScreenSaverWindowLevel];
441 [curtainWindow makeKeyAndOrderFront:nil];
442 [curtainWindow setFrame:[curtainWindow
443 frameRectForContentRect:[theScreen frame]]
447 for (int step = 0; step < fadeSteps; step++)
449 double fade = step * fadeInterval;
450 [curtainWindow setAlphaValue:fade];
452 NSDate *nextDate = [NSDate dateWithTimeIntervalSinceNow:fadeInterval];
453 [[NSRunLoop currentRunLoop] runUntilDate:nextDate];
457 // try to find mode that matches the desired size, refreshrate
458 // non interlaced, nonstretched, safe for hardware
459 CFDictionaryRef GetMode(int width, int height, double refreshrate, int screenIdx)
461 if ( screenIdx >= (signed)[[NSScreen screens] count])
466 Boolean safeForHardware;
467 Boolean televisionoutput;
468 int w, h, bitsperpixel;
472 CLog::Log(LOGDEBUG, "GetMode looking for suitable mode with %d x %d @ %f Hz on display %d\n", width, height, refreshrate, screenIdx);
474 CFArrayRef displayModes = CGDisplayAvailableModes(GetDisplayID(screenIdx));
476 if (NULL == displayModes)
478 CLog::Log(LOGERROR, "GetMode - no displaymodes found!");
482 for (int i=0; i < CFArrayGetCount(displayModes); ++i)
484 CFDictionaryRef displayMode = (CFDictionaryRef)CFArrayGetValueAtIndex(displayModes, i);
486 stretched = GetDictionaryBoolean(displayMode, kCGDisplayModeIsStretched);
487 interlaced = GetDictionaryBoolean(displayMode, kCGDisplayModeIsInterlaced);
488 bitsperpixel = GetDictionaryInt(displayMode, kCGDisplayBitsPerPixel);
489 safeForHardware = GetDictionaryBoolean(displayMode, kCGDisplayModeIsSafeForHardware);
490 televisionoutput = GetDictionaryBoolean(displayMode, kCGDisplayModeIsTelevisionOutput);
491 w = GetDictionaryInt(displayMode, kCGDisplayWidth);
492 h = GetDictionaryInt(displayMode, kCGDisplayHeight);
493 rate = GetDictionaryDouble(displayMode, kCGDisplayRefreshRate);
496 if ((bitsperpixel == 32) &&
497 (safeForHardware == YES) &&
499 (interlaced == NO) &&
502 (rate == refreshrate || rate == 0))
504 CLog::Log(LOGDEBUG, "GetMode found a match!");
508 CLog::Log(LOGERROR, "GetMode - no match found!");
512 //---------------------------------------------------------------------------------
513 static void DisplayReconfigured(CGDirectDisplayID display,
514 CGDisplayChangeSummaryFlags flags, void* userData)
516 CWinSystemOSX *winsys = (CWinSystemOSX*)userData;
520 if (flags & kCGDisplaySetModeFlag || flags & kCGDisplayBeginConfigurationFlag)
522 // pre/post-reconfiguration changes
523 RESOLUTION res = g_graphicsContext.GetVideoResolution();
524 if (res == RES_INVALID)
527 NSScreen* pScreen = nil;
528 unsigned int screenIdx = CDisplaySettings::Get().GetResolutionInfo(res).iScreen;
530 if ( screenIdx < [[NSScreen screens] count] )
532 pScreen = [[NSScreen screens] objectAtIndex:screenIdx];
537 CGDirectDisplayID xbmc_display = GetDisplayIDFromScreen(pScreen);
538 if (xbmc_display == display)
540 // we only respond to changes on the display we are running on.
541 CLog::Log(LOGDEBUG, "CWinSystemOSX::DisplayReconfigured");
542 winsys->CheckDisplayChanging(flags);
548 //---------------------------------------------------------------------------------
549 //---------------------------------------------------------------------------------
550 CWinSystemOSX::CWinSystemOSX() : CWinSystemBase()
552 m_eWindowSystem = WINDOW_SYSTEM_OSX;
557 m_obscured_timecheck = XbmcThreads::SystemClockMillis() + 1000;
558 m_use_system_screensaver = true;
559 // check runtime, we only allow this on 10.5+
560 m_can_display_switch = (floor(NSAppKitVersionNumber) >= 949);
561 m_lastDisplayNr = -1;
562 m_movedToOtherScreen = false;
565 CWinSystemOSX::~CWinSystemOSX()
569 bool CWinSystemOSX::InitWindowSystem()
571 SDL_EnableUNICODE(1);
573 // set repeat to 10ms to ensure repeat time < frame time
574 // so that hold times can be reliably detected
575 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, 10);
577 if (!CWinSystemBase::InitWindowSystem())
580 m_osx_events = new CWinEventsOSX();
582 if (m_can_display_switch)
583 CGDisplayRegisterReconfigurationCallback(DisplayReconfigured, (void*)this);
585 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
586 windowDidMoveNoteClass *windowDidMove;
587 windowDidMove = [windowDidMoveNoteClass initWith: this];
588 [center addObserver:windowDidMove
589 selector:@selector(windowDidMoveNotification:)
590 name:NSWindowDidMoveNotification object:nil];
591 m_windowDidMove = windowDidMove;
594 windowDidReSizeNoteClass *windowDidReSize;
595 windowDidReSize = [windowDidReSizeNoteClass initWith: this];
596 [center addObserver:windowDidReSize
597 selector:@selector(windowDidReSizeNotification:)
598 name:NSWindowDidResizeNotification object:nil];
599 m_windowDidReSize = windowDidReSize;
601 windowDidChangeScreenNoteClass *windowDidChangeScreen;
602 windowDidChangeScreen = [windowDidChangeScreenNoteClass initWith: this];
603 [center addObserver:windowDidChangeScreen
604 selector:@selector(windowDidChangeScreenNotification:)
605 name:NSWindowDidChangeScreenNotification object:nil];
606 m_windowChangedScreen = windowDidChangeScreen;
611 bool CWinSystemOSX::DestroyWindowSystem()
613 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
614 [center removeObserver:(windowDidMoveNoteClass*)m_windowDidMove name:NSWindowDidMoveNotification object:nil];
615 [center removeObserver:(windowDidReSizeNoteClass*)m_windowDidReSize name:NSWindowDidResizeNotification object:nil];
616 [center removeObserver:(windowDidChangeScreenNoteClass*)m_windowChangedScreen name:NSWindowDidChangeScreenNotification object:nil];
618 if (m_can_display_switch)
619 CGDisplayRemoveReconfigurationCallback(DisplayReconfigured, (void*)this);
627 NSOpenGLContext* oldContext = (NSOpenGLContext*)m_glContext;
628 [oldContext release];
634 bool CWinSystemOSX::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
636 m_nWidth = res.iWidth;
637 m_nHeight = res.iHeight;
638 m_bFullScreen = fullScreen;
640 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
641 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
642 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
643 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
644 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
646 // Enable vertical sync to avoid any tearing.
647 SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1);
649 m_SDLSurface = SDL_SetVideoMode(m_nWidth, m_nHeight, 0, SDL_OPENGL | SDL_RESIZABLE);
653 // the context SDL creates isn't full screen compatible, so we create new one
654 // first, find the current contect and make sure a view is attached
655 NSOpenGLContext* cur_context = [NSOpenGLContext currentContext];
656 NSView* view = [cur_context view];
660 // if we are not starting up windowed, then hide the initial SDL window
661 // so we do not see it flash before the fade-out and switch to fullscreen.
662 if (CDisplaySettings::Get().GetCurrentResolution() != RES_WINDOW)
663 ShowHideNSWindow([view window], false);
665 // disassociate view from context
666 [cur_context clearDrawable];
668 // release the context
669 if (m_lastOwnedContext == cur_context)
671 [ NSOpenGLContext clearCurrentContext ];
672 [ cur_context clearDrawable ];
673 [ cur_context release ];
676 // create a new context
677 NSOpenGLContext* new_context = (NSOpenGLContext*)CreateWindowedContext(nil);
681 // associate with current view
682 [new_context setView:view];
683 [new_context makeCurrentContext];
685 // set the window title
687 string = [ [ NSString alloc ] initWithUTF8String:"XBMC Media Center" ];
688 [ [ [new_context view] window] setTitle:string ];
691 m_glContext = new_context;
692 m_lastOwnedContext = new_context;
693 m_bWindowCreated = true;
698 bool CWinSystemOSX::DestroyWindow()
703 extern "C" void SDL_SetWidthHeight(int w, int h);
704 bool CWinSystemOSX::ResizeWindowInternal(int newWidth, int newHeight, int newLeft, int newTop, void *additional)
706 bool ret = ResizeWindow(newWidth, newHeight, newLeft, newTop);
708 if( DarwinIsMavericks() )
710 NSView * last_view = (NSView *)additional;
711 if (last_view && [last_view window])
713 NSWindow* lastWindow = [last_view window];
714 [lastWindow setContentSize:NSMakeSize(m_nWidth, m_nHeight)];
716 [last_view setFrameSize:NSMakeSize(m_nWidth, m_nHeight)];
721 bool CWinSystemOSX::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
726 NSOpenGLContext* context = [NSOpenGLContext currentContext];
730 view = [context view];
731 if (view && (newWidth > 0) && (newHeight > 0))
733 window = [view window];
736 [window setContentSize:NSMakeSize(newWidth, newHeight)];
738 [view setFrameSize:NSMakeSize(newWidth, newHeight)];
743 // HACK: resize SDL's view manually so that mouse bounds are correctly updated.
744 // there are two parts to this, the internal SDL (current_video->screen) and
745 // the cocoa view ( handled in SetFullScreen).
746 SDL_SetWidthHeight(newWidth, newHeight);
748 [context makeCurrentContext];
751 m_nHeight = newHeight;
752 m_glContext = context;
757 static bool needtoshowme = true;
759 bool CWinSystemOSX::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
761 static NSWindow* windowedFullScreenwindow = NULL;
762 static NSScreen* last_window_screen = NULL;
763 static NSPoint last_window_origin;
764 static NSView* last_view = NULL;
765 static NSSize last_view_size;
766 static NSPoint last_view_origin;
767 static NSInteger last_window_level = NSNormalWindowLevel;
768 bool was_fullscreen = m_bFullScreen;
769 NSOpenGLContext* cur_context;
771 if (m_lastDisplayNr == -1)
772 m_lastDisplayNr = res.iScreen;
774 // Fade to black to hide resolution-switching flicker and garbage.
775 CGDisplayFadeReservationToken fade_token = DisplayFadeToBlack(needtoshowme);
777 // If we're already fullscreen then we must be moving to a different display.
778 // or if we are still on the same display - it might be only a refreshrate/resolution
780 // Recurse to reset fullscreen mode and then continue.
781 if (was_fullscreen && fullScreen)
783 needtoshowme = false;
784 ShowHideNSWindow([last_view window], needtoshowme);
785 RESOLUTION_INFO& window = CDisplaySettings::Get().GetResolutionInfo(RES_WINDOW);
786 CWinSystemOSX::SetFullScreen(false, window, blankOtherDisplays);
790 m_nWidth = res.iWidth;
791 m_nHeight = res.iHeight;
792 m_bFullScreen = fullScreen;
794 cur_context = [NSOpenGLContext currentContext];
796 //handle resolution/refreshrate switching early here
799 if (m_can_display_switch)
802 SwitchToVideoMode(res.iWidth, res.iHeight, res.fRefreshRate, res.iScreen);
803 m_lastDisplayNr = res.iScreen;
810 DisplayFadeFromBlack(fade_token, needtoshowme);
814 if (windowedFullScreenwindow != NULL)
816 [windowedFullScreenwindow close];
817 if ([windowedFullScreenwindow isReleasedWhenClosed] == NO)
818 [windowedFullScreenwindow release];
819 windowedFullScreenwindow = NULL;
825 NSOpenGLContext* newContext = NULL;
827 // Save info about the windowed context so we can restore it when returning to windowed.
828 last_view = [cur_context view];
829 last_view_size = [last_view frame].size;
830 last_view_origin = [last_view frame].origin;
831 last_window_screen = [[last_view window] screen];
832 last_window_origin = [[last_view window] frame].origin;
833 last_window_level = [[last_view window] level];
835 if (CSettings::Get().GetBool("videoscreen.fakefullscreen"))
837 // This is Cocca Windowed FullScreen Mode
838 // Get the screen rect of our current display
839 NSScreen* pScreen = [[NSScreen screens] objectAtIndex:res.iScreen];
840 NSRect screenRect = [pScreen frame];
842 // remove frame origin offset of orginal display
843 screenRect.origin = NSZeroPoint;
845 // make a new window to act as the windowedFullScreen
846 windowedFullScreenwindow = [[NSWindow alloc] initWithContentRect:screenRect
847 styleMask:NSBorderlessWindowMask
848 backing:NSBackingStoreBuffered
852 [windowedFullScreenwindow setBackgroundColor:[NSColor blackColor]];
853 [windowedFullScreenwindow makeKeyAndOrderFront:nil];
855 // make our window the same level as the rest to enable cmd+tab switching
856 [windowedFullScreenwindow setLevel:NSNormalWindowLevel];
857 // this will make our window topmost and hide all system messages
858 //[windowedFullScreenwindow setLevel:CGShieldingWindowLevel()];
860 // ...and the original one beneath it and on the same screen.
861 [[last_view window] setLevel:NSNormalWindowLevel-1];
862 [[last_view window] setFrameOrigin:[pScreen frame].origin];
863 // expand the mouse bounds in SDL view to fullscreen
864 [ last_view setFrameOrigin:NSMakePoint(0.0, 0.0)];
865 [ last_view setFrameSize:NSMakeSize(m_nWidth, m_nHeight) ];
867 NSView* blankView = [[NSView alloc] init];
868 [windowedFullScreenwindow setContentView:blankView];
869 [windowedFullScreenwindow setContentSize:NSMakeSize(m_nWidth, m_nHeight)];
870 [windowedFullScreenwindow update];
871 [blankView setFrameSize:NSMakeSize(m_nWidth, m_nHeight)];
873 // Obtain windowed pixel format and create a new context.
874 newContext = (NSOpenGLContext*)CreateWindowedContext((void* )cur_context);
875 [newContext setView:blankView];
877 // Hide the menu bar.
878 if (GetDisplayID(res.iScreen) == kCGDirectMainDisplay || DarwinIsMavericks() )
879 SetMenuBarVisible(false);
881 // Blank other displays if requested.
882 if (blankOtherDisplays)
883 BlankOtherDisplays(res.iScreen);
888 [[last_view window] setFrameOrigin:[last_window_screen frame].origin];
889 // expand the mouse bounds in SDL view to fullscreen
890 [ last_view setFrameOrigin:NSMakePoint(0.0, 0.0)];
891 [ last_view setFrameSize:NSMakeSize(m_nWidth, m_nHeight) ];
893 // This is OpenGL FullScreen Mode
894 // create our new context (sharing with the current one)
895 newContext = (NSOpenGLContext*)CreateFullScreenContext(res.iScreen, (void*)cur_context);
899 // clear the current context
900 [NSOpenGLContext clearCurrentContext];
903 [newContext setFullScreen];
905 // Capture the display before going fullscreen.
906 if (blankOtherDisplays == true)
907 CGCaptureAllDisplays();
909 CGDisplayCapture(GetDisplayID(res.iScreen));
911 // If we don't hide menu bar, it will get events and interrupt the program.
912 if (GetDisplayID(res.iScreen) == kCGDirectMainDisplay || DarwinIsMavericks() )
913 SetMenuBarVisible(false);
919 // Release old context if we created it.
920 if (m_lastOwnedContext == cur_context)
922 [ NSOpenGLContext clearCurrentContext ];
923 [ cur_context clearDrawable ];
924 [ cur_context release ];
928 [newContext makeCurrentContext];
929 m_lastOwnedContext = newContext;
935 [cur_context clearDrawable];
940 if (GetDisplayID(res.iScreen) == kCGDirectMainDisplay || DarwinIsMavericks() )
941 SetMenuBarVisible(true);
943 if (CSettings::Get().GetBool("videoscreen.fakefullscreen"))
945 // restore the windowed window level
946 [[last_view window] setLevel:last_window_level];
948 // Get rid of the new window we created.
949 if (windowedFullScreenwindow != NULL)
951 [windowedFullScreenwindow close];
952 if ([windowedFullScreenwindow isReleasedWhenClosed] == NO)
953 [windowedFullScreenwindow release];
954 windowedFullScreenwindow = NULL;
958 // Force the unblank when returning from fullscreen, we get called with blankOtherDisplays set false.
959 //if (blankOtherDisplays)
965 CGReleaseAllDisplays();
968 // create our new context (sharing with the current one)
969 NSOpenGLContext* newContext = (NSOpenGLContext*)CreateWindowedContext((void* )cur_context);
973 // Assign view from old context, move back to original screen.
974 [newContext setView:last_view];
975 [[last_view window] setFrameOrigin:last_window_origin];
976 // return the mouse bounds in SDL view to prevous size
977 [ last_view setFrameSize:last_view_size ];
978 [ last_view setFrameOrigin:last_view_origin ];
979 // done with restoring windowed window, don't set last_view to NULL as we can lose it under dual displays.
980 //last_window_screen = NULL;
982 // Release the fullscreen context.
983 if (m_lastOwnedContext == cur_context)
985 [ NSOpenGLContext clearCurrentContext ];
986 [ cur_context clearDrawable ];
987 [ cur_context release ];
991 [newContext makeCurrentContext];
992 m_lastOwnedContext = newContext;
995 DisplayFadeFromBlack(fade_token, needtoshowme);
997 ShowHideNSWindow([last_view window], needtoshowme);
998 // need to make sure SDL tracks any window size changes
999 ResizeWindowInternal(m_nWidth, m_nHeight, -1, -1, last_view);
1004 void CWinSystemOSX::UpdateResolutions()
1006 CWinSystemBase::UpdateResolutions();
1008 // Add desktop resolution
1012 // first screen goes into the current desktop mode
1013 GetScreenResolution(&w, &h, &fps, 0);
1014 UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, fps);
1016 // see resolution.h enum RESOLUTION for how the resolutions
1017 // have to appear in the resolution info vector in CDisplaySettings
1018 // add the desktop resolutions of the other screens
1019 for(int i = 1; i < GetNumScreens(); i++)
1021 RESOLUTION_INFO res;
1022 // get current resolution of screen i
1023 GetScreenResolution(&w, &h, &fps, i);
1024 UpdateDesktopResolution(res, i, w, h, fps);
1025 CDisplaySettings::Get().AddResolutionInfo(res);
1028 if (m_can_display_switch)
1030 // now just fill in the possible reolutions for the attached screens
1031 // and push to the resolution info vector
1037 void* Cocoa_GL_CreateContext(void* pixFmt, void* shareCtx)
1042 NSOpenGLContext* newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1043 shareContext:(NSOpenGLContext*)shareCtx];
1045 // snipit from SDL_cocoaopengl.m
1047 // Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
1048 // "You are blowing a couple of the internal OpenGL function caches. This
1049 // appears to be happening in the VAO case. You can tell OpenGL to up
1050 // the cache size by issuing the following calls right after you create
1051 // the OpenGL context. The default cache size is 16." --ryan.
1054 #ifndef GLI_ARRAY_FUNC_CACHE_MAX
1055 #define GLI_ARRAY_FUNC_CACHE_MAX 284
1058 #ifndef GLI_SUBMIT_FUNC_CACHE_MAX
1059 #define GLI_SUBMIT_FUNC_CACHE_MAX 280
1063 long cache_max = 64;
1064 CGLContextObj ctx = (CGLContextObj)[newContext CGLContextObj];
1065 CGLSetParameter(ctx, (CGLContextParameter)GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
1066 CGLSetParameter(ctx, (CGLContextParameter)GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
1069 // End Wisdom from Apple Engineer section. --ryan.
1074 void* CWinSystemOSX::CreateWindowedContext(void* shareCtx)
1076 NSOpenGLContext* newContext = NULL;
1078 NSOpenGLPixelFormatAttribute wattrs[] =
1080 NSOpenGLPFADoubleBuffer,
1082 NSOpenGLPFANoRecovery,
1083 NSOpenGLPFAAccelerated,
1084 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)8,
1085 (NSOpenGLPixelFormatAttribute)0
1088 NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:wattrs];
1090 newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1091 shareContext:(NSOpenGLContext*)shareCtx];
1096 // bah, try again for non-accelerated renderer
1097 NSOpenGLPixelFormatAttribute wattrs2[] =
1099 NSOpenGLPFADoubleBuffer,
1101 NSOpenGLPFANoRecovery,
1102 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)8,
1103 (NSOpenGLPixelFormatAttribute)0
1105 NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:wattrs2];
1107 newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1108 shareContext:(NSOpenGLContext*)shareCtx];
1115 void* CWinSystemOSX::CreateFullScreenContext(int screen_index, void* shareCtx)
1117 CGDirectDisplayID displayArray[MAX_DISPLAYS];
1118 CGDisplayCount numDisplays;
1119 CGDirectDisplayID displayID;
1121 // Get the list of displays.
1122 CGGetActiveDisplayList(MAX_DISPLAYS, displayArray, &numDisplays);
1123 displayID = displayArray[screen_index];
1125 NSOpenGLPixelFormatAttribute fsattrs[] =
1127 NSOpenGLPFADoubleBuffer,
1128 NSOpenGLPFAFullScreen,
1129 NSOpenGLPFANoRecovery,
1130 NSOpenGLPFAAccelerated,
1131 NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute)8,
1132 NSOpenGLPFAScreenMask, (NSOpenGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(displayID),
1133 (NSOpenGLPixelFormatAttribute)0
1136 NSOpenGLPixelFormat* pixFmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:fsattrs];
1140 NSOpenGLContext* newContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)pixFmt
1141 shareContext:(NSOpenGLContext*)shareCtx];
1147 void CWinSystemOSX::GetScreenResolution(int* w, int* h, double* fps, int screenIdx)
1149 // Figure out the screen size. (default to main screen)
1150 if (screenIdx >= GetNumScreens())
1152 CGDirectDisplayID display_id = (CGDirectDisplayID)GetDisplayID(screenIdx);
1154 NSOpenGLContext* context = [NSOpenGLContext currentContext];
1159 view = [context view];
1163 window = [view window];
1165 display_id = GetDisplayIDFromScreen( [window screen] );
1168 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(display_id);
1169 *w = CGDisplayModeGetWidth(mode);
1170 *h = CGDisplayModeGetHeight(mode);
1171 *fps = CGDisplayModeGetRefreshRate(mode);
1172 CGDisplayModeRelease(mode);
1175 // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays.
1180 void CWinSystemOSX::EnableVSync(bool enable)
1182 // OpenGL Flush synchronised with vertical retrace
1183 GLint swapInterval = enable ? 1 : 0;
1184 [[NSOpenGLContext currentContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
1187 bool CWinSystemOSX::SwitchToVideoMode(int width, int height, double refreshrate, int screenIdx)
1189 // SwitchToVideoMode will not return until the display has actually switched over.
1190 // This can take several seconds.
1191 if( screenIdx >= GetNumScreens())
1194 boolean_t match = false;
1195 CFDictionaryRef dispMode = NULL;
1196 // Figure out the screen size. (default to main screen)
1197 CGDirectDisplayID display_id = GetDisplayID(screenIdx);
1199 // find mode that matches the desired size, refreshrate
1200 // non interlaced, nonstretched, safe for hardware
1201 dispMode = GetMode(width, height, refreshrate, screenIdx);
1203 //not found - fallback to bestemdeforparameters
1206 dispMode = CGDisplayBestModeForParameters(display_id, 32, width, height, &match);
1209 dispMode = CGDisplayBestModeForParameters(display_id, 16, width, height, &match);
1215 // switch mode and return success
1216 CGDisplayCapture(display_id);
1217 CGDisplayConfigRef cfg;
1218 CGBeginDisplayConfiguration(&cfg);
1219 // we don't need to do this, we are already faded.
1220 //CGConfigureDisplayFadeEffect(cfg, 0.3f, 0.5f, 0, 0, 0);
1221 CGConfigureDisplayMode(cfg, display_id, dispMode);
1222 CGError err = CGCompleteDisplayConfiguration(cfg, kCGConfigureForAppOnly);
1223 CGDisplayRelease(display_id);
1225 Cocoa_CVDisplayLinkUpdate();
1227 return (err == kCGErrorSuccess);
1230 void CWinSystemOSX::FillInVideoModes()
1232 // Add full screen settings for additional monitors
1233 int numDisplays = [[NSScreen screens] count];
1235 for (int disp = 0; disp < numDisplays; disp++)
1239 Boolean safeForHardware;
1240 Boolean televisionoutput;
1241 int w, h, bitsperpixel;
1243 RESOLUTION_INFO res;
1245 CFArrayRef displayModes = CGDisplayAvailableModes(GetDisplayID(disp));
1246 NSString *dispName = screenNameForDisplay(GetDisplayID(disp));
1247 CLog::Log(LOGNOTICE, "Display %i has name %s", disp, [dispName UTF8String]);
1249 if (NULL == displayModes)
1252 for (int i=0; i < CFArrayGetCount(displayModes); ++i)
1254 CFDictionaryRef displayMode = (CFDictionaryRef)CFArrayGetValueAtIndex(displayModes, i);
1256 stretched = GetDictionaryBoolean(displayMode, kCGDisplayModeIsStretched);
1257 interlaced = GetDictionaryBoolean(displayMode, kCGDisplayModeIsInterlaced);
1258 bitsperpixel = GetDictionaryInt(displayMode, kCGDisplayBitsPerPixel);
1259 safeForHardware = GetDictionaryBoolean(displayMode, kCGDisplayModeIsSafeForHardware);
1260 televisionoutput = GetDictionaryBoolean(displayMode, kCGDisplayModeIsTelevisionOutput);
1262 if ((bitsperpixel == 32) &&
1263 (safeForHardware == YES) &&
1264 (stretched == NO) &&
1267 w = GetDictionaryInt(displayMode, kCGDisplayWidth);
1268 h = GetDictionaryInt(displayMode, kCGDisplayHeight);
1269 refreshrate = GetDictionaryDouble(displayMode, kCGDisplayRefreshRate);
1270 if ((int)refreshrate == 0) // LCD display?
1272 // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays.
1275 CLog::Log(LOGNOTICE, "Found possible resolution for display %d with %d x %d @ %f Hz\n", disp, w, h, refreshrate);
1277 UpdateDesktopResolution(res, disp, w, h, refreshrate);
1279 // overwrite the mode str because UpdateDesktopResolution adds a
1280 // "Full Screen". Since the current resolution is there twice
1281 // this would lead to 2 identical resolution entrys in the guisettings.xml.
1282 // That would cause problems with saving screen overscan calibration
1283 // because the wrong entry is picked on load.
1284 // So we just use UpdateDesktopResolutions for the current DESKTOP_RESOLUTIONS
1285 // in UpdateResolutions. And on all othere resolutions make a unique
1286 // mode str by doing it without appending "Full Screen".
1287 // this is what linux does - though it feels that there shouldn't be
1288 // the same resolution twice... - thats why i add a FIXME here.
1289 res.strMode = StringUtils::Format("%dx%d @ %.2f", w, h, refreshrate);
1290 g_graphicsContext.ResetOverscan(res);
1291 CDisplaySettings::Get().AddResolutionInfo(res);
1297 bool CWinSystemOSX::FlushBuffer(void)
1299 [ (NSOpenGLContext*)m_glContext flushBuffer ];
1304 bool CWinSystemOSX::IsObscured(void)
1306 // check once a second if we are obscured.
1307 unsigned int now_time = XbmcThreads::SystemClockMillis();
1308 if (m_obscured_timecheck > now_time)
1311 m_obscured_timecheck = now_time + 1000;
1313 NSOpenGLContext* cur_context = [NSOpenGLContext currentContext];
1314 NSView* view = [cur_context view];
1317 // sanity check, we should always have a view
1322 NSWindow *window = [view window];
1325 // sanity check, we should always have a window
1330 if ([window isVisible] == NO)
1332 // not visable means the window is not showing.
1333 // this should never really happen as we are always visable
1334 // even when minimized in dock.
1339 // check if we are minimized (to an icon in the Dock).
1340 if ([window isMiniaturized] == YES)
1346 // check if we are showing on the active workspace.
1347 if ([window isOnActiveSpace] == NO)
1353 // default to false before we start parsing though the windows.
1354 // if we are are obscured by any windows, then set true.
1356 static bool obscureLogged = false;
1358 CGWindowListOption opts;
1359 opts = kCGWindowListOptionOnScreenAboveWindow | kCGWindowListExcludeDesktopElements;
1360 CFArrayRef windowIDs =CGWindowListCreate(opts, (CGWindowID)[window windowNumber]);
1365 CFArrayRef windowDescs = CGWindowListCreateDescriptionFromArray(windowIDs);
1368 CFRelease(windowIDs);
1372 CGRect bounds = NSRectToCGRect([window frame]);
1373 // kCGWindowBounds measures the origin as the top-left corner of the rectangle
1374 // relative to the top-left corner of the screen.
1375 // NSWindow’s frame property measures the origin as the bottom-left corner
1376 // of the rectangle relative to the bottom-left corner of the screen.
1377 // convert bounds from NSWindow to CGWindowBounds here.
1378 bounds.origin.y = [[window screen] frame].size.height - bounds.origin.y - bounds.size.height;
1380 std::vector<CRect> partialOverlaps;
1381 CRect ourBounds = CGRectToCRect(bounds);
1383 for (CFIndex idx=0; idx < CFArrayGetCount(windowDescs); idx++)
1385 // walk the window list of windows that are above us and are not desktop elements
1386 CFDictionaryRef windowDictionary = (CFDictionaryRef)CFArrayGetValueAtIndex(windowDescs, idx);
1388 // skip the Dock window, it actually covers the entire screen.
1389 CFStringRef ownerName = (CFStringRef)CFDictionaryGetValue(windowDictionary, kCGWindowOwnerName);
1390 if (CFStringCompare(ownerName, CFSTR("Dock"), 0) == kCFCompareEqualTo)
1393 // Ignore known brightness tools for dimming the screen. They claim to cover
1394 // the whole XBMC window and therefore would make the framerate limiter
1395 // kicking in. Unfortunatly even the alpha of these windows is 1.0 so
1396 // we have to check the ownerName.
1397 if (CFStringCompare(ownerName, CFSTR("Shades"), 0) == kCFCompareEqualTo ||
1398 CFStringCompare(ownerName, CFSTR("SmartSaver"), 0) == kCFCompareEqualTo ||
1399 CFStringCompare(ownerName, CFSTR("Brightness Slider"), 0) == kCFCompareEqualTo ||
1400 CFStringCompare(ownerName, CFSTR("Displaperture"), 0) == kCFCompareEqualTo ||
1401 CFStringCompare(ownerName, CFSTR("Dreamweaver"), 0) == kCFCompareEqualTo)
1404 CFDictionaryRef rectDictionary = (CFDictionaryRef)CFDictionaryGetValue(windowDictionary, kCGWindowBounds);
1405 if (!rectDictionary)
1408 CGRect windowBounds;
1409 if (CGRectMakeWithDictionaryRepresentation(rectDictionary, &windowBounds))
1411 if (CGRectContainsRect(windowBounds, bounds))
1413 // if the windowBounds completely encloses our bounds, we are obscured.
1416 std::string appName;
1417 if (DarwinCFStringRefToUTF8String(ownerName, appName))
1418 CLog::Log(LOGDEBUG, "WinSystemOSX: Fullscreen window %s obscures XBMC!", appName.c_str());
1419 obscureLogged = true;
1425 // handle overlaping windows above us that combine
1426 // to obscure by collecting any partial overlaps,
1427 // then subtract them from our bounds and check
1428 // for any remaining area.
1429 CRect intersection = CGRectToCRect(windowBounds);
1430 intersection.Intersect(ourBounds);
1431 if (!intersection.IsEmpty())
1432 partialOverlaps.push_back(intersection);
1438 // if we are here we are not obscured by any fullscreen window - reset flag
1439 // for allowing the logmessage above to show again if this changes.
1441 obscureLogged = false;
1442 std::vector<CRect> rects = ourBounds.SubtractRects(partialOverlaps);
1443 // they got us covered
1444 if (rects.size() == 0)
1448 CFRelease(windowDescs);
1449 CFRelease(windowIDs);
1454 void CWinSystemOSX::NotifyAppFocusChange(bool bGaining)
1456 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1458 if (m_bFullScreen && bGaining)
1461 NSOpenGLContext* context = [NSOpenGLContext currentContext];
1466 view = [context view];
1470 window = [view window];
1473 // find the screenID
1474 NSDictionary* screenInfo = [[window screen] deviceDescription];
1475 NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
1476 if ((CGDirectDisplayID)[screenID longValue] == kCGDirectMainDisplay || DarwinIsMavericks() )
1478 SetMenuBarVisible(false);
1480 [window orderFront:nil];
1488 void CWinSystemOSX::ShowOSMouse(bool show)
1490 SDL_ShowCursor(show ? 1 : 0);
1493 bool CWinSystemOSX::Minimize()
1495 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1497 [[NSApplication sharedApplication] miniaturizeAll:nil];
1503 bool CWinSystemOSX::Restore()
1505 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1507 [[NSApplication sharedApplication] unhide:nil];
1513 bool CWinSystemOSX::Hide()
1515 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1517 [[NSApplication sharedApplication] hide:nil];
1523 void CWinSystemOSX::OnMove(int x, int y)
1525 Cocoa_CVDisplayLinkUpdate();
1528 void CWinSystemOSX::EnableSystemScreenSaver(bool bEnable)
1530 // see Technical Q&A QA1340
1531 static IOPMAssertionID assertionID = 0;
1535 if (assertionID == 0)
1537 CFStringRef reasonForActivity= CFSTR("XBMC requested disable system screen saver");
1538 IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
1539 kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
1541 UpdateSystemActivity(UsrActivity);
1543 else if (assertionID != 0)
1545 IOPMAssertionRelease(assertionID);
1549 m_use_system_screensaver = bEnable;
1552 bool CWinSystemOSX::IsSystemScreenSaverEnabled()
1554 return m_use_system_screensaver;
1557 void CWinSystemOSX::ResetOSScreensaver()
1559 // allow os screensaver only if we are fullscreen
1560 EnableSystemScreenSaver(!m_bFullScreen);
1563 bool CWinSystemOSX::EnableFrameLimiter()
1565 return IsObscured();
1568 void CWinSystemOSX::EnableTextInput(bool bEnable)
1576 OSXTextInputResponder *g_textInputResponder = nil;
1578 bool CWinSystemOSX::IsTextInputEnabled()
1580 return g_textInputResponder != nil && [[g_textInputResponder superview] isEqual: [[NSApp keyWindow] contentView]];
1583 void CWinSystemOSX::StartTextInput()
1585 NSView *parentView = [[NSApp keyWindow] contentView];
1587 /* We only keep one field editor per process, since only the front most
1588 * window can receive text input events, so it make no sense to keep more
1589 * than one copy. When we switched to another window and requesting for
1590 * text input, simply remove the field editor from its superview then add
1591 * it to the front most window's content view */
1592 if (!g_textInputResponder) {
1593 g_textInputResponder =
1594 [[OSXTextInputResponder alloc] initWithFrame: NSMakeRect(0.0, 0.0, 0.0, 0.0)];
1597 if (![[g_textInputResponder superview] isEqual: parentView])
1599 // DLOG(@"add fieldEdit to window contentView");
1600 [g_textInputResponder removeFromSuperview];
1601 [parentView addSubview: g_textInputResponder];
1602 [[NSApp keyWindow] makeFirstResponder: g_textInputResponder];
1605 void CWinSystemOSX::StopTextInput()
1607 if (g_textInputResponder) {
1608 [g_textInputResponder removeFromSuperview];
1609 [g_textInputResponder release];
1610 g_textInputResponder = nil;
1614 void CWinSystemOSX::Register(IDispResource *resource)
1616 CSingleLock lock(m_resourceSection);
1617 m_resources.push_back(resource);
1620 void CWinSystemOSX::Unregister(IDispResource* resource)
1622 CSingleLock lock(m_resourceSection);
1623 std::vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
1624 if (i != m_resources.end())
1625 m_resources.erase(i);
1628 bool CWinSystemOSX::Show(bool raise)
1630 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
1634 [[NSApplication sharedApplication] unhide:nil];
1635 [[NSApplication sharedApplication] activateIgnoringOtherApps: YES];
1636 [[NSApplication sharedApplication] arrangeInFront:nil];
1640 [[NSApplication sharedApplication] unhideWithoutActivation];
1647 int CWinSystemOSX::GetNumScreens()
1649 int numDisplays = [[NSScreen screens] count];
1650 return(numDisplays);
1653 int CWinSystemOSX::GetCurrentScreen()
1655 NSOpenGLContext* context = [NSOpenGLContext currentContext];
1657 // if user hasn't moved us in windowed mode - return the
1658 // last display we were fullscreened at
1659 if (!m_movedToOtherScreen)
1660 return m_lastDisplayNr;
1662 // if we are here the user dragged the window to a different
1663 // screen and we return the screen of the window
1668 view = [context view];
1672 window = [view window];
1675 m_movedToOtherScreen = false;
1676 return GetDisplayIndex(GetDisplayIDFromScreen( [window screen] ));
1684 void CWinSystemOSX::WindowChangedScreen()
1686 // user has moved the window to a
1688 m_movedToOtherScreen = true;
1691 void CWinSystemOSX::CheckDisplayChanging(u_int32_t flags)
1695 CSingleLock lock(m_resourceSection);
1696 // tell any shared resources
1697 if (flags & kCGDisplayBeginConfigurationFlag)
1699 CLog::Log(LOGDEBUG, "CWinSystemOSX::CheckDisplayChanging:OnLostDevice");
1700 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
1701 (*i)->OnLostDevice();
1703 if (flags & kCGDisplaySetModeFlag)
1705 CLog::Log(LOGDEBUG, "CWinSystemOSX::CheckDisplayChanging:OnResetDevice");
1706 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
1707 (*i)->OnResetDevice();
1712 void* CWinSystemOSX::GetCGLContextObj()
1714 return [(NSOpenGLContext*)m_glContext CGLContextObj];
1717 std::string CWinSystemOSX::GetClipboardText(void)
1719 std::string utf8_text;
1721 const char *szStr = Cocoa_Paste();