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/>.
24 #define BOOL XBMC_BOOL
25 #include "utils/log.h"
28 #import <Cocoa/Cocoa.h>
29 #import <QuartzCore/QuartzCore.h>
30 #import <OpenGL/OpenGL.h>
32 #import <AudioUnit/AudioUnit.h>
33 #import <AudioToolbox/AudioToolbox.h>
34 #import <CoreServices/CoreServices.h>
36 #import "CocoaInterface.h"
37 #import "DllPaths_generated.h"
42 // hack for Cocoa_GL_ResizeWindow
43 //extern "C" void SDL_SetWidthHeight(int w, int h);
45 //#define MAX_DISPLAYS 32
46 //static NSWindow* blankingWindows[MAX_DISPLAYS];
48 //display link for display managment
49 static CVDisplayLinkRef displayLink = NULL;
51 CGDirectDisplayID Cocoa_GetDisplayIDFromScreen(NSScreen *screen);
53 uint32_t Cocoa_GL_GetCurrentDisplayID(void)
55 // Find which display we are on from the current context (default to main display)
56 CGDirectDisplayID display_id = kCGDirectMainDisplay;
58 NSOpenGLContext* context = [NSOpenGLContext currentContext];
63 view = [context view];
67 window = [view window];
70 NSDictionary* screenInfo = [[window screen] deviceDescription];
71 NSNumber* screenID = [screenInfo objectForKey:@"NSScreenNumber"];
72 display_id = (CGDirectDisplayID)[screenID longValue];
77 return((uint32_t)display_id);
80 bool Cocoa_CVDisplayLinkCreate(void *displayLinkcallback, void *displayLinkContext)
82 CVReturn status = kCVReturnError;
83 CGDirectDisplayID display_id;
85 // OpenGL Flush synchronised with vertical retrace
86 GLint swapInterval = 1;
87 [[NSOpenGLContext currentContext] setValues:&swapInterval forParameter:NSOpenGLCPSwapInterval];
89 display_id = (CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID();
92 // Create a display link capable of being used with all active displays
93 status = CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
95 // Set the renderer output callback function
96 status = CVDisplayLinkSetOutputCallback(displayLink, (CVDisplayLinkOutputCallback)displayLinkcallback, displayLinkContext);
99 if (status == kCVReturnSuccess)
101 // Set the display link for the current display
102 status = CVDisplayLinkSetCurrentCGDisplay(displayLink, display_id);
104 // Activate the display link
105 status = CVDisplayLinkStart(displayLink);
108 return(status == kCVReturnSuccess);
111 void Cocoa_CVDisplayLinkRelease(void)
115 if (CVDisplayLinkIsRunning(displayLink))
116 CVDisplayLinkStop(displayLink);
117 // Release the display link
118 CVDisplayLinkRelease(displayLink);
123 void Cocoa_CVDisplayLinkUpdate(void)
127 CGDirectDisplayID display_id;
129 display_id = (CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID();
130 // Set the display link to the current display
131 CVDisplayLinkSetCurrentCGDisplay(displayLink, display_id);
135 double Cocoa_GetCVDisplayLinkRefreshPeriod(void)
139 if (displayLink && CVDisplayLinkIsRunning(displayLink) )
142 cvtime = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink);
143 if (cvtime.timeValue > 0)
144 fps = (double)cvtime.timeScale / (double)cvtime.timeValue;
146 fps = CVDisplayLinkGetActualOutputVideoRefreshPeriod(displayLink);
155 CGDisplayModeRef display_mode;
156 display_mode = CGDisplayCopyDisplayMode((CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID());
157 fps = CGDisplayModeGetRefreshRate(display_mode);
158 CGDisplayModeRelease(display_mode);
166 void Cocoa_DoAppleScript(const char* scriptSource)
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];
178 void Cocoa_DoAppleScriptFile(const char* filePath)
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"];
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];
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];
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];
197 // If no script could be found, check if we were given a full path
198 else if (![[NSFileManager defaultManager] fileExistsAtPath:scriptFile])
201 NSAppleScript* appleScript = [[NSAppleScript alloc] initWithContentsOfURL:[NSURL fileURLWithPath:scriptFile] error:nil];
202 [appleScript executeAndReturnError:nil];
203 [appleScript release];
206 const char* Cocoa_GetIconFromBundle(const char *_bundlePath, const char* _iconName)
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];
214 if (![[NSFileManager defaultManager] fileExistsAtPath:iconPath]) return NULL;
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];
220 // If no PNG has been created, open the ICNS file & convert
221 if (![[NSFileManager defaultManager] fileExistsAtPath:pngFile])
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];
232 return [pngFile UTF8String];
235 char* Cocoa_MountPoint2DeviceName(char *path)
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.
241 strDVDDevice = strdup(path);
242 if (strncasecmp(strDVDDevice, "/Volumes/", 9) == 0)
244 struct statfs *mntbufp;
247 // find a match for /Volumes/<disk name>
248 mounts = getmntinfo(&mntbufp, MNT_WAIT); // NOT THREAD SAFE!
249 for (i = 0; i < mounts; i++)
251 if( !strcasecmp(mntbufp[i].f_mntonname, strDVDDevice) )
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/" ) );
265 bool Cocoa_GetVolumeNameFromMountPoint(const char *mountPoint, CStdString &volumeName)
268 unsigned i, count = 0;
269 struct statfs *buf = NULL;
270 CStdString mountpoint, devicepath;
272 count = getmntinfo(&buf, 0);
273 for (i=0; i<count; i++)
275 mountpoint = buf[i].f_mntonname;
276 if (mountpoint == mountPoint)
278 devicepath = buf[i].f_mntfromname;
282 if (devicepath.empty())
287 DASessionRef session = DASessionCreate(kCFAllocatorDefault);
293 DADiskRef disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, devicepath.c_str());
300 NSDictionary *dd = (NSDictionary*) DADiskCopyDescription(disk);
308 NSString *volumename = [dd objectForKey:(NSString*)kDADiskDescriptionVolumeNameKey];
309 volumeName = [volumename UTF8String];
319 void SetPIDFrontProcess(pid_t pid) {
320 ProcessSerialNumber psn;
322 GetProcessForPID(pid, &psn );
323 SetFrontProcess(&psn);
328 // Synchronize buffer swaps with vertical refresh rate (NSTimer)
329 - (void)prepareOpenGL
332 [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
335 // Put our timer in -awakeFromNib, so it can start up right from the beginning
338 renderTimer = [[NSTimer timerWithTimeInterval:0.001 //a 1ms time interval
340 selector:@selector(timerFired:)
344 [[NSRunLoop currentRunLoop] addTimer:renderTimer
345 forMode:NSDefaultRunLoopMode];
346 [[NSRunLoop currentRunLoop] addTimer:renderTimer
347 forMode:NSEventTrackingRunLoopMode]; //Ensure timer fires during resize
350 // Timer callback method
351 - (void)timerFired:(id)sender
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];
359 [newWindow setFrameAutosaveName:@"some name"]
361 and the window's frame is automatically saved for you in the application
362 defaults each time its location changes.
366 void Cocoa_HideMouse()
371 void Cocoa_ShowMouse()
376 //---------------------------------------------------------------------------------
377 bool Cocoa_GPUForDisplayIsNvidiaPureVideo3()
382 CGDirectDisplayID display_id;
384 // try for display we are running on
385 display_id = (CGDirectDisplayID)Cocoa_GL_GetCurrentDisplayID();
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);
393 model = (CFDataRef)IORegistryEntrySearchCFProperty(dspPort, kIOServicePlane, CFSTR("model"),
394 kCFAllocatorDefault,kIORegistryIterateRecursively | kIORegistryIterateParents);
398 cstr = (const char*)CFDataGetBytePtr(model);
399 if (cstr && std::string(cstr).find("NVIDIA GeForce 9400") != std::string::npos)
408 int Cocoa_GetOSVersion()
410 static SInt32 version = -1;
413 Gestalt(gestaltSystemVersion, &version);
419 NSWindow* childWindow = nil;
420 NSWindow* mainWindow = nil;
423 void Cocoa_MakeChildWindow()
425 NSOpenGLContext* context = [NSOpenGLContext currentContext];
426 NSView* view = [context view];
427 NSWindow* window = [view window];
429 // Create a child window.
430 childWindow = [[NSWindow alloc] initWithContentRect:[window frame]
431 styleMask:NSBorderlessWindowMask
432 backing:NSBackingStoreBuffered
435 [childWindow setContentSize:[view frame].size];
436 [childWindow setBackgroundColor:[NSColor blackColor]];
437 [window addChildWindow:childWindow ordered:NSWindowAbove];
439 //childWindow.alphaValue = 0.5;
442 void Cocoa_DestroyChildWindow()
444 if (childWindow != nil)
446 [mainWindow removeChildWindow:childWindow];
451 const char *Cocoa_Paste()
453 NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
454 NSString *type = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
456 NSString *contents = [pasteboard stringForType:type];
457 if (contents != nil) {
458 return [contents UTF8String];