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