2 * Copyright (C) 2010-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_IOS)
22 //hack around problem with xbmc's typedef int BOOL
23 // and obj-c's typedef unsigned char BOOL
24 #define BOOL XBMC_BOOL
29 #define BOOL XBMC_BOOL
30 #include "WinSystemIOS.h"
31 #include "utils/log.h"
32 #include "filesystem/SpecialProtocol.h"
33 #include "settings/DisplaySettings.h"
34 #include "guilib/GraphicContext.h"
35 #include "guilib/Texture.h"
36 #include "utils/StringUtils.h"
37 #include "guilib/DispResource.h"
38 #include "threads/SingleLock.h"
42 #import <Foundation/Foundation.h>
43 #import <OpenGLES/ES2/gl.h>
44 #import <OpenGLES/ES2/glext.h>
45 #if defined(TARGET_DARWIN_IOS_ATV2)
46 #import "atv2/XBMCController.h"
48 #import "ios/XBMCController.h"
50 #import "osx/IOSScreenManager.h"
51 #include "osx/DarwinUtils.h"
54 CWinSystemIOS::CWinSystemIOS() : CWinSystemBase()
56 m_eWindowSystem = WINDOW_SYSTEM_IOS;
59 m_bIsBackgrounded = false;
62 CWinSystemIOS::~CWinSystemIOS()
66 bool CWinSystemIOS::InitWindowSystem()
68 return CWinSystemBase::InitWindowSystem();
71 bool CWinSystemIOS::DestroyWindowSystem()
76 bool CWinSystemIOS::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
78 //NSLog(@"%s", __PRETTY_FUNCTION__);
80 if(!SetFullScreen(fullScreen, res, false))
83 [g_xbmcController setFramebuffer];
85 m_bWindowCreated = true;
88 m_eglext += (const char*) glGetString(GL_EXTENSIONS);
91 CLog::Log(LOGDEBUG, "EGL_EXTENSIONS:%s", m_eglext.c_str());
95 bool CWinSystemIOS::DestroyWindow()
100 bool CWinSystemIOS::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
102 //NSLog(@"%s", __PRETTY_FUNCTION__);
104 if (m_nWidth != newWidth || m_nHeight != newHeight)
107 m_nHeight = newHeight;
110 CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight, false, 0);
115 bool CWinSystemIOS::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
117 //NSLog(@"%s", __PRETTY_FUNCTION__);
119 m_nWidth = res.iWidth;
120 m_nHeight = res.iHeight;
121 m_bFullScreen = fullScreen;
123 CLog::Log(LOGDEBUG, "About to switch to %i x %i on screen %i",m_nWidth, m_nHeight, res.iScreen);
124 #ifndef TARGET_DARWIN_IOS_ATV2
125 SwitchToVideoMode(res.iWidth, res.iHeight, res.fRefreshRate, res.iScreen);
126 #endif//TARGET_DARWIN_IOS_ATV2
127 CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
132 UIScreenMode *getModeForResolution(int width, int height, unsigned int screenIdx)
134 if( screenIdx >= [[UIScreen screens] count])
137 UIScreen *aScreen = [[UIScreen screens]objectAtIndex:screenIdx];
138 for ( UIScreenMode *mode in [aScreen availableModes] )
140 //for main screen also find modes where width and height are
141 //exchanged (because of the 90°degree rotated buildinscreens)
142 if((mode.size.width == width && mode.size.height == height) ||
143 (screenIdx == 0 && mode.size.width == height && mode.size.height == width))
145 CLog::Log(LOGDEBUG,"Found matching mode");
149 CLog::Log(LOGERROR,"No matching mode found!");
153 bool CWinSystemIOS::SwitchToVideoMode(int width, int height, double refreshrate, int screenIdx)
156 // SwitchToVideoMode will not return until the display has actually switched over.
157 // This can take several seconds.
158 if( screenIdx >= GetNumScreens())
161 //get the mode to pass to the controller
162 UIScreenMode *newMode = getModeForResolution(width, height, screenIdx);
166 ret = [g_xbmcController changeScreen:screenIdx withMode:newMode];
171 int CWinSystemIOS::GetNumScreens()
173 return [[UIScreen screens] count];
176 int CWinSystemIOS::GetCurrentScreen()
179 if ([[IOSScreenManager sharedInstance] isExternalScreen])
186 bool CWinSystemIOS::GetScreenResolution(int* w, int* h, double* fps, int screenIdx)
188 // Figure out the screen size. (default to main screen)
189 if(screenIdx >= GetNumScreens())
191 UIScreen *screen = [[UIScreen screens] objectAtIndex:screenIdx];
192 CGSize screenSize = [screen currentMode].size;
193 *w = screenSize.width;
194 *h = screenSize.height;
196 //if current mode is 0x0 (happens with external screens which arn't active)
197 //then use the preferred mode
198 if(*h == 0 || *w ==0)
200 UIScreenMode *firstMode = [screen preferredMode];
201 *w = firstMode.size.width;
202 *h = firstMode.size.height;
205 //for mainscreen use the eagl bounds
206 //because mainscreen is build in
210 *w = [g_xbmcController getScreenSize].width;
211 *h = [g_xbmcController getScreenSize].height;
213 CLog::Log(LOGDEBUG,"Current resolution Screen: %i with %i x %i",screenIdx, *w, *h);
217 void CWinSystemIOS::UpdateResolutions()
219 // Add display resolution
222 CWinSystemBase::UpdateResolutions();
224 //first screen goes into the current desktop mode
225 if(GetScreenResolution(&w, &h, &fps, 0))
227 UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, fps);
230 #ifndef TARGET_DARWIN_IOS_ATV2
231 //see resolution.h enum RESOLUTION for how the resolutions
232 //have to appear in the resolution info vector in CDisplaySettings
233 //add the desktop resolutions of the other screens
234 for(int i = 1; i < GetNumScreens(); i++)
237 //get current resolution of screen i
238 if(GetScreenResolution(&w, &h, &fps, i))
240 UpdateDesktopResolution(res, i, w, h, fps);
241 CDisplaySettings::Get().AddResolutionInfo(res);
245 //now just fill in the possible reolutions for the attached screens
246 //and push to the resolution info vector
248 #endif //TARGET_DARWIN_IOS_ATV2
251 void CWinSystemIOS::FillInVideoModes()
253 // Add full screen settings for additional monitors
254 int numDisplays = GetNumScreens();
256 for (int disp = 0; disp < numDisplays; disp++)
260 // atm we don't get refreshrate info from iOS
261 // but this may change in the future. In that case
262 // we will adapt this code for filling some
263 // usefull info into this local var :)
264 double refreshrate = 0.0;
265 //screen 0 is mainscreen - 1 has to be the external one...
266 UIScreen *aScreen = [[UIScreen screens]objectAtIndex:disp];
267 //found external screen
268 for ( UIScreenMode *mode in [aScreen availableModes] )
271 h = mode.size.height;
272 UpdateDesktopResolution(res, disp, w, h, refreshrate);
273 CLog::Log(LOGNOTICE, "Found possible resolution for display %d with %d x %d\n", disp, w, h);
275 //overwrite the mode str because UpdateDesktopResolution adds a
276 //"Full Screen". Since the current resolution is there twice
277 //this would lead to 2 identical resolution entrys in the guisettings.xml.
278 //That would cause problems with saving screen overscan calibration
279 //because the wrong entry is picked on load.
280 //So we just use UpdateDesktopResolutions for the current DESKTOP_RESOLUTIONS
281 //in UpdateResolutions. And on all othere resolutions make a unique
282 //mode str by doing it without appending "Full Screen".
283 //this is what linux does - though it feels that there shouldn't be
284 //the same resolution twice... - thats why i add a FIXME here.
285 res.strMode = StringUtils::Format("%dx%d @ %.2f", w, h, refreshrate);
286 g_graphicsContext.ResetOverscan(res);
287 CDisplaySettings::Get().AddResolutionInfo(res);
292 bool CWinSystemIOS::IsExtSupported(const char* extension)
294 if(strncmp(extension, "EGL_", 4) != 0)
295 return CRenderSystemGLES::IsExtSupported(extension);
303 return m_eglext.find(name) != string::npos;
306 bool CWinSystemIOS::BeginRender()
310 [g_xbmcController setFramebuffer];
312 rtn = CRenderSystemGLES::BeginRender();
316 bool CWinSystemIOS::EndRender()
320 rtn = CRenderSystemGLES::EndRender();
324 void CWinSystemIOS::Register(IDispResource *resource)
326 CSingleLock lock(m_resourceSection);
327 m_resources.push_back(resource);
330 void CWinSystemIOS::Unregister(IDispResource* resource)
332 CSingleLock lock(m_resourceSection);
333 std::vector<IDispResource*>::iterator i = find(m_resources.begin(), m_resources.end(), resource);
334 if (i != m_resources.end())
335 m_resources.erase(i);
338 void CWinSystemIOS::OnAppFocusChange(bool focus)
340 CSingleLock lock(m_resourceSection);
341 m_bIsBackgrounded = !focus;
342 CLog::Log(LOGDEBUG, "CWinSystemIOS::OnAppFocusChange: %d", focus ? 1 : 0);
343 for (std::vector<IDispResource *>::iterator i = m_resources.begin(); i != m_resources.end(); i++)
344 (*i)->OnAppFocusChange(focus);
347 void CWinSystemIOS::InitDisplayLink(void)
350 void CWinSystemIOS::DeinitDisplayLink(void)
353 double CWinSystemIOS::GetDisplayLinkFPS(void)
357 fps = [g_xbmcController getDisplayLinkFPS];
361 bool CWinSystemIOS::PresentRenderImpl(const CDirtyRegionList &dirty)
364 [g_xbmcController presentFramebuffer];
368 void CWinSystemIOS::SetVSyncImpl(bool enable)
371 // set swapinterval if possible
372 void *eglSwapInterval;
373 eglSwapInterval = dlsym( RTLD_DEFAULT, "eglSwapInterval" );
374 if ( eglSwapInterval )
376 ((void(*)(int))eglSwapInterval)( 1 ) ;
382 void CWinSystemIOS::ShowOSMouse(bool show)
386 bool CWinSystemIOS::HasCursor()
388 if( DarwinIsAppleTV2() )
392 else//apple touch devices
398 void CWinSystemIOS::NotifyAppActiveChange(bool bActivated)
400 if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot())
401 g_graphicsContext.ToggleFullScreenRoot();
404 bool CWinSystemIOS::Minimize()
406 m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot();
407 if (m_bWasFullScreenBeforeMinimize)
408 g_graphicsContext.ToggleFullScreenRoot();
413 bool CWinSystemIOS::Restore()
418 bool CWinSystemIOS::Hide()
423 bool CWinSystemIOS::Show(bool raise)