darwin, fixed. Cocoa_GL_GetCurrentDisplayID returns an ID, not a CGDisplayModeRef
[vuplus_xbmc] / xbmc / osx / CocoaInterface.mm
1 /*
2  *      Copyright (C) 2005-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 #if !defined(__arm__)
21 #import <unistd.h>
22 #import <sys/mount.h>
23
24 #define BOOL XBMC_BOOL 
25 #include "utils/log.h"
26 #undef BOOL
27
28 #import <Cocoa/Cocoa.h>
29 #import <QuartzCore/QuartzCore.h>
30 #import <OpenGL/OpenGL.h>
31 #import <OpenGL/gl.h>
32 #import <AudioUnit/AudioUnit.h>
33 #import <AudioToolbox/AudioToolbox.h>
34 #import <CoreServices/CoreServices.h>
35
36 #import "CocoaInterface.h"
37 #import "DllPaths_generated.h"
38
39 #import "AutoPool.h"
40
41
42 // hack for Cocoa_GL_ResizeWindow
43 //extern "C" void SDL_SetWidthHeight(int w, int h);
44
45 //#define MAX_DISPLAYS 32
46 //static NSWindow* blankingWindows[MAX_DISPLAYS];
47
48 //display link for display managment
49 static CVDisplayLinkRef displayLink = NULL; 
50
51 CGDirectDisplayID Cocoa_GetDisplayIDFromScreen(NSScreen *screen);
52
53 uint32_t Cocoa_GL_GetCurrentDisplayID(void)
54 {
55   // Find which display we are on from the current context (default to main display)
56   CGDirectDisplayID display_id = kCGDirectMainDisplay;
57   
58   NSOpenGLContext* context = [NSOpenGLContext currentContext];
59   if (context)
60   {
61     NSView* view;
62   
63     view = [context view];
64     if (view)
65     {
66       NSWindow* window;
67       window = [view window];
68       if (window)
69       {
70         NSDictionary* screenInfo = [[window screen] deviceDescription];
71         NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
72         display_id = (CGDirectDisplayID)[screenID longValue];
73       }
74     }
75   }
76   
77   return((uint32_t)display_id);
78 }
79
80 bool Cocoa_CVDisplayLinkCreate(void *displayLinkcallback, void *displayLinkContext)
81 {
82   CVReturn status = kCVReturnError;
83   CGDirectDisplayID display_id;
84     
85   // OpenGL Flush synchronised with vertical retrace                       
86   GLint swapInterval = 1;
87   [[NSOpenGLContext currentContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
88
89   display_id = (CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID();
90   if (!displayLink)
91   {
92     // Create a display link capable of being used with all active displays
93     status = CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
94
95     // Set the renderer output callback function
96     status = CVDisplayLinkSetOutputCallback(displayLink, (CVDisplayLinkOutputCallback)displayLinkcallback, displayLinkContext);
97   }
98
99   if (status == kCVReturnSuccess)
100   {
101     // Set the display link for the current display
102     status = CVDisplayLinkSetCurrentCGDisplay(displayLink, display_id);
103
104     // Activate the display link
105     status = CVDisplayLinkStart(displayLink);
106   }
107   
108   return(status == kCVReturnSuccess);
109 }
110
111 void Cocoa_CVDisplayLinkRelease(void)
112 {
113   if (displayLink)
114   {
115     if (CVDisplayLinkIsRunning(displayLink))
116       CVDisplayLinkStop(displayLink);
117     // Release the display link
118     CVDisplayLinkRelease(displayLink);
119     displayLink = NULL;
120   }
121 }
122
123 void Cocoa_CVDisplayLinkUpdate(void)
124 {
125   if (displayLink)
126   {
127     CGDirectDisplayID display_id;
128     
129     display_id = (CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID();
130     // Set the display link to the current display
131     CVDisplayLinkSetCurrentCGDisplay(displayLink, display_id);
132   }
133 }
134
135 double Cocoa_GetCVDisplayLinkRefreshPeriod(void)
136 {
137   double fps = 60.0;
138
139   if (displayLink && CVDisplayLinkIsRunning(displayLink) )
140   {
141     CVTime cvtime;
142     cvtime = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink);
143     if (cvtime.timeValue > 0)
144       fps = (double)cvtime.timeScale / (double)cvtime.timeValue;
145     
146     fps = CVDisplayLinkGetActualOutputVideoRefreshPeriod(displayLink);
147     if (fps > 0.0)
148       fps = 1.0 / fps;
149     else
150       fps = 60.0;
151   }
152   else
153   {
154     
155     CGDisplayModeRef display_mode;
156     display_mode = CGDisplayCopyDisplayMode((CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID());
157     fps = CGDisplayModeGetRefreshRate(display_mode);
158     CGDisplayModeRelease(display_mode);
159     if (fps <= 0.0)
160       fps = 60.0;
161   }
162   
163   return(fps);
164 }
165
166 void Cocoa_DoAppleScript(const char* scriptSource)
167 {
168   CCocoaAutoPool pool;
169
170   NSDictionary* errorDict;
171   NSAppleEventDescriptor* returnDescriptor = NULL;
172   NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
173     [NSString stringWithUTF8String:scriptSource]];
174   returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
175   [scriptObject release];
176 }
177   
178 void Cocoa_DoAppleScriptFile(const char* filePath)
179 {
180   NSString* scriptFile = [NSString stringWithUTF8String:filePath];
181   NSString* userScriptsPath = [@"~/Library/Application Support/XBMC/scripts" stringByExpandingTildeInPath];
182   NSString* bundleScriptsPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Resources/XBMC/scripts"];
183   NSString* bundleSysScriptsPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Resources/XBMC/system/AppleScripts"];
184
185   // Check whether a script exists in the app bundle's AppleScripts folder
186   if ([[NSFileManager defaultManager] fileExistsAtPath:[bundleSysScriptsPath stringByAppendingPathComponent:scriptFile]])
187     scriptFile = [bundleSysScriptsPath stringByAppendingPathComponent:scriptFile];
188
189   // Check whether a script exists in app support
190   else if ([[NSFileManager defaultManager] fileExistsAtPath:[userScriptsPath stringByAppendingPathComponent:scriptFile]]) // Check whether a script exists in the app bundle
191     scriptFile = [userScriptsPath stringByAppendingPathComponent:scriptFile];
192
193   // Check whether a script exists in the app bundle's Scripts folder
194   else if ([[NSFileManager defaultManager] fileExistsAtPath:[bundleScriptsPath stringByAppendingPathComponent:scriptFile]])
195     scriptFile = [bundleScriptsPath stringByAppendingPathComponent:scriptFile];
196
197   // If no script could be found, check if we were given a full path
198   else if (![[NSFileManager defaultManager] fileExistsAtPath:scriptFile])
199     return;
200
201   NSAppleScript* appleScript = [[NSAppleScript alloc] initWithContentsOfURL:[NSURL fileURLWithPath:scriptFile] error:nil];
202   [appleScript executeAndReturnError:nil];
203   [appleScript release];
204 }
205
206 const char* Cocoa_GetIconFromBundle(const char *_bundlePath, const char* _iconName)
207 {
208   NSString* bundlePath = [NSString stringWithUTF8String:_bundlePath];
209   NSString* iconName = [NSString stringWithUTF8String:_iconName];
210   NSBundle* bundle = [NSBundle bundleWithPath:bundlePath];
211   NSString* iconPath = [bundle pathForResource:iconName ofType:@"icns"];
212   NSString* bundleIdentifier = [bundle bundleIdentifier];
213
214   if (![[NSFileManager defaultManager] fileExistsAtPath:iconPath]) return NULL;
215
216   // Get the path to the target PNG icon
217   NSString* pngFile = [[NSString stringWithFormat:@"~/Library/Application Support/XBMC/userdata/Thumbnails/%@-%@.png",
218     bundleIdentifier, iconName] stringByExpandingTildeInPath];
219
220   // If no PNG has been created, open the ICNS file & convert
221   if (![[NSFileManager defaultManager] fileExistsAtPath:pngFile])
222   {
223     NSImage* icon = [[NSImage alloc] initWithContentsOfFile:iconPath];
224     if (!icon) return NULL;
225     NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithData:[icon TIFFRepresentation]];
226     NSData* png = [rep representationUsingType:NSPNGFileType properties:nil];
227     [png writeToFile:pngFile atomically:YES];
228     [png release];
229     [rep release];
230     [icon release];
231   }
232   return [pngFile UTF8String];
233 }
234
235 char* Cocoa_MountPoint2DeviceName(char *path)
236 {
237   CCocoaAutoPool pool;
238   // if physical DVDs, libdvdnav wants "/dev/rdiskN" device name for OSX,
239   // path will get realloc'ed and replaced IF this is a physical DVD.
240   char* strDVDDevice;
241   strDVDDevice = strdup(path);
242   if (strncasecmp(strDVDDevice, "/Volumes/", 9) == 0)
243   {
244     struct statfs *mntbufp;
245     int i, mounts;
246     
247     // find a match for /Volumes/<disk name>
248     mounts = getmntinfo(&mntbufp, MNT_WAIT);  // NOT THREAD SAFE!
249     for (i = 0; i < mounts; i++)
250     {
251       if( !strcasecmp(mntbufp[i].f_mntonname, strDVDDevice) )
252       {
253         // Replace "/dev/" with "/dev/r"
254         path = (char*)realloc(path, strlen(mntbufp[i].f_mntfromname) + 2 );
255         strcpy( path, "/dev/r" );
256         strcat( path, mntbufp[i].f_mntfromname + strlen( "/dev/" ) );
257         break;
258       }
259     }
260   }
261   free(strDVDDevice);
262   return path;
263 }
264
265 bool Cocoa_GetVolumeNameFromMountPoint(const char *mountPoint, CStdString &volumeName)
266 {
267   CCocoaAutoPool pool;
268   unsigned i, count = 0;
269   struct statfs *buf = NULL;
270   CStdString mountpoint, devicepath;
271
272   count = getmntinfo(&buf, 0);
273   for (i=0; i<count; i++)
274   {
275     mountpoint = buf[i].f_mntonname;
276     if (mountpoint == mountPoint)
277     {
278       devicepath = buf[i].f_mntfromname;
279       break;
280     }
281   }
282   if (devicepath.empty())
283   {
284     return false;
285   }
286
287   DASessionRef session = DASessionCreate(kCFAllocatorDefault);
288   if (!session)
289   {
290       return false;
291   }
292
293   DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, devicepath.c_str());
294   if (!disk)
295   {
296       CFRelease(session);
297       return false;
298   }
299
300   NSDictionary *dd = (NSDictionary*) DADiskCopyDescription(disk);
301   if (!dd)
302   {
303       CFRelease(session);
304       CFRelease(disk);
305       return false;
306   }
307
308   NSString *volumename = [dd objectForKey:(NSString*)kDADiskDescriptionVolumeNameKey];
309   volumeName = [volumename UTF8String];
310
311   CFRelease(session);                   
312   CFRelease(disk);                      
313   [dd release];
314
315   return true ;
316 }
317
318 /*
319 void SetPIDFrontProcess(pid_t pid) {
320     ProcessSerialNumber psn;
321
322     GetProcessForPID(pid, &psn );
323     SetFrontProcess(&psn);
324 }
325 */
326
327 /*
328 // Synchronize buffer swaps with vertical refresh rate (NSTimer)
329 - (void)prepareOpenGL
330 {
331     GLint swapInt = 1;
332     [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
333 }
334
335 // Put our timer in -awakeFromNib, so it can start up right from the beginning
336 -(void)awakeFromNib
337 {
338     renderTimer = [[NSTimer timerWithTimeInterval:0.001   //a 1ms time interval
339                                 target:self
340                                 selector:@selector(timerFired:)
341                                 userInfo:nil
342                                 repeats:YES];
343
344     [[NSRunLoop currentRunLoop] addTimer:renderTimer 
345                                 forMode:NSDefaultRunLoopMode];
346     [[NSRunLoop currentRunLoop] addTimer:renderTimer 
347                                 forMode:NSEventTrackingRunLoopMode]; //Ensure timer fires during resize
348 }
349
350 // Timer callback method
351 - (void)timerFired:(id)sender
352 {
353     // It is good practice in a Cocoa application to allow the system to send the -drawRect:
354     // message when it needs to draw, and not to invoke it directly from the timer. 
355     // All we do here is tell the display it needs a refresh
356     [self setNeedsDisplay:YES];
357 }
358
359 [newWindow setFrameAutosaveName:@"some name"] 
360
361 and the window's frame is automatically saved for you in the application 
362 defaults each time its location changes. 
363 */
364
365
366 void Cocoa_HideMouse()
367 {
368   [NSCursor hide];
369 }
370
371 void Cocoa_ShowMouse()
372 {
373   [NSCursor unhide];
374 }
375
376 //---------------------------------------------------------------------------------
377 bool Cocoa_GPUForDisplayIsNvidiaPureVideo3()
378 {
379   bool result = false;
380   std::string str;
381   const char *cstr;
382   CGDirectDisplayID display_id;
383
384   // try for display we are running on
385   display_id = (CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID();
386  
387   io_registry_entry_t dspPort = CGDisplayIOServicePort(display_id);
388   // if fails, go for main display
389   if (dspPort == MACH_PORT_NULL)
390     dspPort = CGDisplayIOServicePort(kCGDirectMainDisplay);
391
392   CFDataRef model;
393   model = (CFDataRef)IORegistryEntrySearchCFProperty(dspPort, kIOServicePlane, CFSTR("model"),
394     kCFAllocatorDefault,kIORegistryIterateRecursively | kIORegistryIterateParents);
395
396   if (model)
397   {
398     cstr = (const char*)CFDataGetBytePtr(model);
399     if (cstr && std::string(cstr).find("NVIDIA GeForce 9400") != std::string::npos)
400       result = true;
401
402     CFRelease(model);
403   }
404
405   return(result);
406 }
407
408 int Cocoa_GetOSVersion()
409 {
410   static SInt32 version = -1;
411
412   if (version == -1)
413     Gestalt(gestaltSystemVersion, &version);
414   
415   return(version);
416 }
417
418
419 NSWindow* childWindow = nil;
420 NSWindow* mainWindow = nil;
421
422
423 void Cocoa_MakeChildWindow()
424 {
425   NSOpenGLContext* context = [NSOpenGLContext currentContext];
426   NSView* view = [context view];
427   NSWindow* window = [view window];
428
429   // Create a child window.
430   childWindow = [[NSWindow alloc] initWithContentRect:[window frame]
431                                             styleMask:NSBorderlessWindowMask
432                                               backing:NSBackingStoreBuffered
433                                                 defer:NO];
434                                           
435   [childWindow setContentSize:[view frame].size];
436   [childWindow setBackgroundColor:[NSColor blackColor]];
437   [window addChildWindow:childWindow ordered:NSWindowAbove];
438   mainWindow = window;
439   //childWindow.alphaValue = 0.5; 
440 }
441
442 void Cocoa_DestroyChildWindow()
443 {
444   if (childWindow != nil)
445   {
446     [mainWindow removeChildWindow:childWindow];
447     [childWindow close];
448     childWindow = nil;
449   }
450 }
451 const char *Cocoa_Paste() 
452 {
453   NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
454   NSString *type = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
455   if (type != nil) {
456     NSString *contents = [pasteboard stringForType:type];
457     if (contents != nil) {
458       return [contents UTF8String];
459     }
460   }
461   
462   return NULL;
463 }
464
465 #endif