Merge pull request #4314 from MartijnKaijser/beta1
[vuplus_xbmc] / xbmc / windowing / osx / WinSystemIOS.mm
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
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 
25 #include "system.h"
26 #undef BOOL
27
28 #ifdef HAS_EGL
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 <vector>
38 #undef BOOL
39
40 #import <Foundation/Foundation.h>
41 #import <OpenGLES/ES2/gl.h>
42 #import <OpenGLES/ES2/glext.h>
43 #if defined(TARGET_DARWIN_IOS_ATV2)
44 #import "atv2/XBMCController.h"
45 #else
46 #import "ios/XBMCController.h"
47 #endif
48 #import "osx/IOSScreenManager.h"
49 #include "osx/DarwinUtils.h"
50 #import <dlfcn.h>
51
52 CWinSystemIOS::CWinSystemIOS() : CWinSystemBase()
53 {
54   m_eWindowSystem = WINDOW_SYSTEM_IOS;
55
56   m_iVSyncErrors = 0;
57 }
58
59 CWinSystemIOS::~CWinSystemIOS()
60 {
61 }
62
63 bool CWinSystemIOS::InitWindowSystem()
64 {
65         return CWinSystemBase::InitWindowSystem();
66 }
67
68 bool CWinSystemIOS::DestroyWindowSystem()
69 {
70   return true;
71 }
72
73 bool CWinSystemIOS::CreateNewWindow(const CStdString& name, bool fullScreen, RESOLUTION_INFO& res, PHANDLE_EVENT_FUNC userFunction)
74 {
75   //NSLog(@"%s", __PRETTY_FUNCTION__);
76         
77   if(!SetFullScreen(fullScreen, res, false))
78     return false;
79
80   [g_xbmcController setFramebuffer];
81
82   m_bWindowCreated = true;
83
84   m_eglext  = " ";
85   m_eglext += (const char*) glGetString(GL_EXTENSIONS);
86   m_eglext += " ";
87
88   CLog::Log(LOGDEBUG, "EGL_EXTENSIONS:%s", m_eglext.c_str());
89   return true;
90 }
91
92 bool CWinSystemIOS::DestroyWindow()
93 {
94   return true;
95 }
96
97 bool CWinSystemIOS::ResizeWindow(int newWidth, int newHeight, int newLeft, int newTop)
98 {
99   //NSLog(@"%s", __PRETTY_FUNCTION__);
100         
101   if (m_nWidth != newWidth || m_nHeight != newHeight)
102   {
103     m_nWidth  = newWidth;
104     m_nHeight = newHeight;
105   }
106
107   CRenderSystemGLES::ResetRenderSystem(newWidth, newHeight, false, 0);
108
109   return true;
110 }
111
112 bool CWinSystemIOS::SetFullScreen(bool fullScreen, RESOLUTION_INFO& res, bool blankOtherDisplays)
113 {
114   //NSLog(@"%s", __PRETTY_FUNCTION__);
115         
116   m_nWidth      = res.iWidth;
117   m_nHeight     = res.iHeight;
118   m_bFullScreen = fullScreen;
119
120   CLog::Log(LOGDEBUG, "About to switch to %i x %i on screen %i",m_nWidth, m_nHeight, res.iScreen);
121 #ifndef TARGET_DARWIN_IOS_ATV2
122   SwitchToVideoMode(res.iWidth, res.iHeight, res.fRefreshRate, res.iScreen);
123 #endif//TARGET_DARWIN_IOS_ATV2
124   CRenderSystemGLES::ResetRenderSystem(res.iWidth, res.iHeight, fullScreen, res.fRefreshRate);
125   
126   return true;
127 }
128
129 UIScreenMode *getModeForResolution(int width, int height, unsigned int screenIdx)
130 {
131   if( screenIdx >= [[UIScreen screens] count])
132     return NULL;
133     
134   UIScreen *aScreen = [[UIScreen screens]objectAtIndex:screenIdx];
135   for ( UIScreenMode *mode in [aScreen availableModes] )
136   {
137     //for main screen also find modes where width and height are
138     //exchanged (because of the 90°degree rotated buildinscreens)
139     if((mode.size.width == width && mode.size.height == height) || 
140         (screenIdx == 0 && mode.size.width == height && mode.size.height == width))
141     {
142       CLog::Log(LOGDEBUG,"Found matching mode");
143       return mode;
144     }
145   }
146   CLog::Log(LOGERROR,"No matching mode found!");
147   return NULL;
148 }
149
150 bool CWinSystemIOS::SwitchToVideoMode(int width, int height, double refreshrate, int screenIdx)
151 {
152   bool ret = false;
153   // SwitchToVideoMode will not return until the display has actually switched over.
154   // This can take several seconds.
155   if( screenIdx >= GetNumScreens())
156     return false;
157   
158   //get the mode to pass to the controller
159   UIScreenMode *newMode = getModeForResolution(width, height, screenIdx);
160
161   if(newMode)
162   {
163     ret = [g_xbmcController changeScreen:screenIdx withMode:newMode];
164   }
165   return ret;
166 }
167
168 int CWinSystemIOS::GetNumScreens()
169 {
170   return [[UIScreen screens] count];
171 }
172
173 int CWinSystemIOS::GetCurrentScreen()
174 {
175   int idx = 0;
176   if ([[IOSScreenManager sharedInstance] isExternalScreen])
177   {
178     idx = 1;
179   }
180   return idx;
181 }
182
183 bool CWinSystemIOS::GetScreenResolution(int* w, int* h, double* fps, int screenIdx)
184 {
185   // Figure out the screen size. (default to main screen)
186   if(screenIdx >= GetNumScreens())
187     return false;
188   UIScreen *screen = [[UIScreen screens] objectAtIndex:screenIdx];
189   CGSize screenSize = [screen currentMode].size;
190   *w = screenSize.width;
191   *h = screenSize.height;
192   *fps = 0.0;
193   //if current mode is 0x0 (happens with external screens which arn't active)
194   //then use the preferred mode
195   if(*h == 0 || *w ==0)
196   {
197     UIScreenMode *firstMode = [screen preferredMode];
198     *w = firstMode.size.width;
199     *h = firstMode.size.height;
200   }
201   
202   //for mainscreen use the eagl bounds
203   //because mainscreen is build in
204   //in 90° rotated
205   if(screenIdx == 0)
206   {
207     *w = [g_xbmcController getScreenSize].width;
208     *h = [g_xbmcController getScreenSize].height;
209   }
210   CLog::Log(LOGDEBUG,"Current resolution Screen: %i with %i x %i",screenIdx, *w, *h);  
211   return true;
212 }
213
214 void CWinSystemIOS::UpdateResolutions()
215 {
216   // Add display resolution
217   int w, h;
218   double fps;
219   CWinSystemBase::UpdateResolutions();
220
221   //first screen goes into the current desktop mode
222   if(GetScreenResolution(&w, &h, &fps, 0))
223   {
224     UpdateDesktopResolution(CDisplaySettings::Get().GetResolutionInfo(RES_DESKTOP), 0, w, h, fps);
225   }
226
227 #ifndef TARGET_DARWIN_IOS_ATV2
228   //see resolution.h enum RESOLUTION for how the resolutions
229   //have to appear in the resolution info vector in CDisplaySettings
230   //add the desktop resolutions of the other screens
231   for(int i = 1; i < GetNumScreens(); i++)
232   {
233     RESOLUTION_INFO res;      
234     //get current resolution of screen i
235     if(GetScreenResolution(&w, &h, &fps, i))
236     {
237       UpdateDesktopResolution(res, i, w, h, fps);
238       CDisplaySettings::Get().AddResolutionInfo(res);
239     }
240   }
241   
242   //now just fill in the possible reolutions for the attached screens
243   //and push to the resolution info vector
244   FillInVideoModes();
245 #endif //TARGET_DARWIN_IOS_ATV2
246 }
247
248 void CWinSystemIOS::FillInVideoModes()
249 {
250   // Add full screen settings for additional monitors
251   int numDisplays = GetNumScreens();
252
253   for (int disp = 0; disp < numDisplays; disp++)
254   {
255     RESOLUTION_INFO res;
256     int w, h;
257     // atm we don't get refreshrate info from iOS
258     // but this may change in the future. In that case
259     // we will adapt this code for filling some
260     // usefull info into this local var :)
261     double refreshrate = 0.0;
262     //screen 0 is mainscreen - 1 has to be the external one...
263     UIScreen *aScreen = [[UIScreen screens]objectAtIndex:disp];
264     //found external screen
265     for ( UIScreenMode *mode in [aScreen availableModes] )
266     {
267       w = mode.size.width;
268       h = mode.size.height;
269       UpdateDesktopResolution(res, disp, w, h, refreshrate);
270       CLog::Log(LOGNOTICE, "Found possible resolution for display %d with %d x %d\n", disp, w, h);      
271
272       //overwrite the mode str because  UpdateDesktopResolution adds a
273       //"Full Screen". Since the current resolution is there twice
274       //this would lead to 2 identical resolution entrys in the guisettings.xml.
275       //That would cause problems with saving screen overscan calibration
276       //because the wrong entry is picked on load.
277       //So we just use UpdateDesktopResolutions for the current DESKTOP_RESOLUTIONS
278       //in UpdateResolutions. And on all othere resolutions make a unique
279       //mode str by doing it without appending "Full Screen".
280       //this is what linux does - though it feels that there shouldn't be
281       //the same resolution twice... - thats why i add a FIXME here.
282       res.strMode = StringUtils::Format("%dx%d @ %.2f", w, h, refreshrate);
283       g_graphicsContext.ResetOverscan(res);
284       CDisplaySettings::Get().AddResolutionInfo(res);
285     }
286   }
287 }
288
289 bool CWinSystemIOS::IsExtSupported(const char* extension)
290 {
291   if(strncmp(extension, "EGL_", 4) != 0)
292     return CRenderSystemGLES::IsExtSupported(extension);
293
294   CStdString name;
295
296   name  = " ";
297   name += extension;
298   name += " ";
299
300   return m_eglext.find(name) != string::npos;
301 }
302
303 bool CWinSystemIOS::BeginRender()
304 {
305   bool rtn;
306
307   [g_xbmcController setFramebuffer];
308
309   rtn = CRenderSystemGLES::BeginRender();
310   return rtn;
311 }
312
313 bool CWinSystemIOS::EndRender()
314 {
315   bool rtn;
316
317   rtn = CRenderSystemGLES::EndRender();
318   return rtn;
319 }
320
321 void CWinSystemIOS::InitDisplayLink(void)
322 {
323 }
324 void CWinSystemIOS::DeinitDisplayLink(void)
325 {
326 }
327 double CWinSystemIOS::GetDisplayLinkFPS(void)
328 {
329   double fps;
330
331   fps = [g_xbmcController getDisplayLinkFPS];
332   return fps;
333 }
334
335 bool CWinSystemIOS::PresentRenderImpl(const CDirtyRegionList &dirty)
336 {
337   //glFlush;
338   [g_xbmcController presentFramebuffer];
339   return true;
340 }
341
342 void CWinSystemIOS::SetVSyncImpl(bool enable)
343 {
344   #if 0 
345     // set swapinterval if possible
346     void *eglSwapInterval;      
347     eglSwapInterval = dlsym( RTLD_DEFAULT, "eglSwapInterval" );
348     if ( eglSwapInterval )
349     {
350       ((void(*)(int))eglSwapInterval)( 1 ) ;
351     }
352   #endif
353   m_iVSyncMode = 10;
354 }
355
356 void CWinSystemIOS::ShowOSMouse(bool show)
357 {
358 }
359
360 bool CWinSystemIOS::HasCursor()
361 {
362   if( DarwinIsAppleTV2() )
363   {
364     return true;
365   }
366   else//apple touch devices
367   {
368     return false;
369   }
370 }
371
372 void CWinSystemIOS::NotifyAppActiveChange(bool bActivated)
373 {
374   if (bActivated && m_bWasFullScreenBeforeMinimize && !g_graphicsContext.IsFullScreenRoot())
375     g_graphicsContext.ToggleFullScreenRoot();
376 }
377
378 bool CWinSystemIOS::Minimize()
379 {
380   m_bWasFullScreenBeforeMinimize = g_graphicsContext.IsFullScreenRoot();
381   if (m_bWasFullScreenBeforeMinimize)
382     g_graphicsContext.ToggleFullScreenRoot();
383
384   return true;
385 }
386
387 bool CWinSystemIOS::Restore()
388 {
389   return false;
390 }
391
392 bool CWinSystemIOS::Hide()
393 {
394   return true;
395 }
396
397 bool CWinSystemIOS::Show(bool raise)
398 {
399   return true;
400 }
401 #endif
402
403 #endif