Commit 6822a805 authored by Sam Lantinga's avatar Sam Lantinga

The Mac OS X Cocoa video driver is under construction...

Note that SDLmain is no longer necessary on Mac OS X. :)

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401976
parent d4e887aa
...@@ -1046,36 +1046,11 @@ CheckBWINDOW() ...@@ -1046,36 +1046,11 @@ CheckBWINDOW()
fi fi
} }
dnl Set up the Carbon/QuickDraw video driver for Mac OS X (but not Darwin) dnl Set up the Cocoa video driver for Mac OS X (but not Darwin)
CheckCARBON()
{
AC_ARG_ENABLE(video-carbon,
AC_HELP_STRING([--enable-video-carbon], [use Carbon/QuickDraw video driver [[default=no]]]),
, enable_video_carbon=no)
if test x$enable_video = xyes -a x$enable_video_carbon = xyes; then
AC_MSG_CHECKING(for Carbon framework)
have_carbon=no
AC_TRY_COMPILE([
#include <Carbon/Carbon.h>
],[
],[
have_carbon=yes
])
AC_MSG_RESULT($have_carbon)
if test x$have_carbon = xyes; then
AC_DEFINE(SDL_VIDEO_DRIVER_TOOLBOX)
SOURCES="$SOURCES $srcdir/src/video/maccommon/*.c"
SOURCES="$SOURCES $srcdir/src/video/macrom/*.c"
have_video=yes
fi
fi
}
dnl Set up the Cocoa/Quartz video driver for Mac OS X (but not Darwin)
CheckCOCOA() CheckCOCOA()
{ {
AC_ARG_ENABLE(video-cocoa, AC_ARG_ENABLE(video-cocoa,
AC_HELP_STRING([--enable-video-cocoa], [use Cocoa/Quartz video driver [[default=yes]]]), AC_HELP_STRING([--enable-video-cocoa], [use Cocoa video driver [[default=yes]]]),
, enable_video_cocoa=yes) , enable_video_cocoa=yes)
if test x$enable_video = xyes -a x$enable_video_cocoa = xyes; then if test x$enable_video = xyes -a x$enable_video_cocoa = xyes; then
save_CFLAGS="$CFLAGS" save_CFLAGS="$CFLAGS"
...@@ -1092,8 +1067,8 @@ AC_HELP_STRING([--enable-video-cocoa], [use Cocoa/Quartz video driver [[default= ...@@ -1092,8 +1067,8 @@ AC_HELP_STRING([--enable-video-cocoa], [use Cocoa/Quartz video driver [[default=
AC_MSG_RESULT($have_cocoa) AC_MSG_RESULT($have_cocoa)
CFLAGS="$save_CFLAGS" CFLAGS="$save_CFLAGS"
if test x$have_cocoa = xyes; then if test x$have_cocoa = xyes; then
AC_DEFINE(SDL_VIDEO_DRIVER_QUARTZ) AC_DEFINE(SDL_VIDEO_DRIVER_COCOA)
SOURCES="$SOURCES $srcdir/src/video/quartz/*.m" SOURCES="$SOURCES $srcdir/src/video/cocoa/*.m"
have_video=yes have_video=yes
fi fi
fi fi
...@@ -1526,9 +1501,6 @@ CheckMacGL() ...@@ -1526,9 +1501,6 @@ CheckMacGL()
if test x$enable_video_cocoa = xyes; then if test x$enable_video_cocoa = xyes; then
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,OpenGL" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,OpenGL"
fi fi
if test x$enable_video_carbon = xyes; then
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AGL"
fi
esac esac
fi fi
} }
...@@ -2453,7 +2425,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau ...@@ -2453,7 +2425,6 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
fi fi
CheckCOCOA CheckCOCOA
CheckCARBON
CheckX11 CheckX11
CheckMacGL CheckMacGL
CheckOpenGLX11 CheckOpenGLX11
...@@ -2492,11 +2463,9 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau ...@@ -2492,11 +2463,9 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
have_timers=yes have_timers=yes
fi fi
# The Mac OS X platform requires special setup. # The Mac OS X platform requires special setup.
SDLMAIN_SOURCES="$srcdir/src/main/macosx/*.m"
EXTRA_CFLAGS="$EXTRA_CFLAGS -fpascal-strings" EXTRA_CFLAGS="$EXTRA_CFLAGS -fpascal-strings"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Cocoa" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Cocoa"
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
SDL_LIBS="-lSDLmain $SDL_LIBS"
# If either the audio or CD driver is used, add the AudioUnit framework # If either the audio or CD driver is used, add the AudioUnit framework
if test x$enable_audio = xyes -o x$enable_cdrom = xyes; then if test x$enable_audio = xyes -o x$enable_cdrom = xyes; then
EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit" EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,AudioToolbox -Wl,-framework,AudioUnit"
...@@ -2623,7 +2592,6 @@ OBJECTS=`echo $OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.c,$(objects)/\1.lo,g'` ...@@ -2623,7 +2592,6 @@ OBJECTS=`echo $OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.c,$(objects)/\1.lo,g'`
OBJECTS=`echo $OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.S,$(objects)/\1.lo,g'` OBJECTS=`echo $OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.S,$(objects)/\1.lo,g'`
SDLMAIN_OBJECTS=`echo $SDLMAIN_SOURCES | sed 's,[[^ ]]*/\([[^ ]]*\)\.cc,$(objects)/\1.o,g'` SDLMAIN_OBJECTS=`echo $SDLMAIN_SOURCES | sed 's,[[^ ]]*/\([[^ ]]*\)\.cc,$(objects)/\1.o,g'`
SDLMAIN_OBJECTS=`echo $SDLMAIN_OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.m,$(objects)/\1.o,g'`
SDLMAIN_OBJECTS=`echo $SDLMAIN_OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.c,$(objects)/\1.o,g'` SDLMAIN_OBJECTS=`echo $SDLMAIN_OBJECTS | sed 's,[[^ ]]*/\([[^ ]]*\)\.c,$(objects)/\1.o,g'`
# Set runtime shared library paths as needed # Set runtime shared library paths as needed
...@@ -2642,12 +2610,8 @@ fi ...@@ -2642,12 +2610,8 @@ fi
case "$ARCH" in case "$ARCH" in
macosx) macosx)
SDL_LIBS="$SDL_LIBS -Wl,-framework,Cocoa" SDL_LIBS="$SDL_LIBS -Wl,-framework,Cocoa"
# Is this still needed?
#if test x$enable_video = xyes -a x$enable_video_carbon = xyes; then
# SDL_LIBS="$SDL_LIBS -Wl,-framework,Carbon"
#fi
# Evil hack to allow static linking on Mac OS X # Evil hack to allow static linking on Mac OS X
SDL_STATIC_LIBS="\${exec_prefix}/lib/libSDLmain.a \${exec_prefix}/lib/libSDL.a $EXTRA_LDFLAGS" SDL_STATIC_LIBS="\${exec_prefix}/lib/libSDL.a $EXTRA_LDFLAGS"
;; ;;
*) *)
SDL_STATIC_LIBS="$SDL_LIBS" SDL_STATIC_LIBS="$SDL_LIBS"
......
...@@ -251,6 +251,7 @@ ...@@ -251,6 +251,7 @@
/* Enable various video drivers */ /* Enable various video drivers */
#undef SDL_VIDEO_DRIVER_AALIB #undef SDL_VIDEO_DRIVER_AALIB
#undef SDL_VIDEO_DRIVER_BWINDOW #undef SDL_VIDEO_DRIVER_BWINDOW
#undef SDL_VIDEO_DRIVER_COCOA
#undef SDL_VIDEO_DRIVER_CYBERGRAPHICS #undef SDL_VIDEO_DRIVER_CYBERGRAPHICS
#undef SDL_VIDEO_DRIVER_DC #undef SDL_VIDEO_DRIVER_DC
#undef SDL_VIDEO_DRIVER_DGA #undef SDL_VIDEO_DRIVER_DGA
...@@ -270,7 +271,6 @@ ...@@ -270,7 +271,6 @@
#undef SDL_VIDEO_DRIVER_PICOGUI #undef SDL_VIDEO_DRIVER_PICOGUI
#undef SDL_VIDEO_DRIVER_PS2GS #undef SDL_VIDEO_DRIVER_PS2GS
#undef SDL_VIDEO_DRIVER_QTOPIA #undef SDL_VIDEO_DRIVER_QTOPIA
#undef SDL_VIDEO_DRIVER_QUARTZ
#undef SDL_VIDEO_DRIVER_RISCOS #undef SDL_VIDEO_DRIVER_RISCOS
#undef SDL_VIDEO_DRIVER_SVGALIB #undef SDL_VIDEO_DRIVER_SVGALIB
#undef SDL_VIDEO_DRIVER_TOOLBOX #undef SDL_VIDEO_DRIVER_TOOLBOX
......
...@@ -113,12 +113,8 @@ ...@@ -113,12 +113,8 @@
#define SDL_TIMER_UNIX 1 #define SDL_TIMER_UNIX 1
/* Enable various video drivers */ /* Enable various video drivers */
#define SDL_VIDEO_DRIVER_COCOA 1
#define SDL_VIDEO_DRIVER_DUMMY 1 #define SDL_VIDEO_DRIVER_DUMMY 1
#if TARGET_API_MAC_CARBON
#define SDL_VIDEO_DRIVER_TOOLBOX 1
#else
#define SDL_VIDEO_DRIVER_QUARTZ 1
#endif
/* Enable OpenGL support */ /* Enable OpenGL support */
#define SDL_VIDEO_OPENGL 1 #define SDL_VIDEO_OPENGL 1
......
...@@ -25,11 +25,11 @@ ...@@ -25,11 +25,11 @@
#include "SDL_stdinc.h" #include "SDL_stdinc.h"
/* Redefine main() on Win32 and MacOS so that it is called by winmain.c */ /* Redefine main() on some platforms so that it is called by SDL */
#if defined(__WIN32__) || \ #if defined(__WIN32__) || \
(defined(__MWERKS__) && !defined(__BEOS__)) || \ (defined(__MWERKS__) && !defined(__BEOS__)) || \
defined(__MACOS__) || defined(__MACOSX__) || \ defined(__MACOS__) || \
defined(__SYMBIAN32__) || defined(QWS) defined(__SYMBIAN32__) || defined(QWS)
#ifdef __cplusplus #ifdef __cplusplus
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>@EXECUTABLE_NAME@</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>@PACKAGE@</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>@VERSION@</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>NSMainNibFile</key>
<string>SDLMain.nib</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
Feel free to customize this file to suit your needs
*/
#import <Cocoa/Cocoa.h>
@ interface SDLMain:NSObject @ end
/* vi: set ts=4 sw=4 expandtab: */
/* SDLMain.m - main entry point for our Cocoa-ized SDL app
Initial Version: Darrell Walisser <dwaliss1@purdue.edu>
Non-NIB-Code & other changes: Max Horn <max@quendi.de>
Feel free to customize this file to suit your needs
*/
#import "SDL.h"
#import "SDLMain.h"
#import <sys/param.h> /* for MAXPATHLEN */
#import <unistd.h>
/* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
but the method still is there and works. To avoid warnings, we declare
it ourselves here. */
@interface NSApplication(SDL_Missing_Methods)
- (void)setAppleMenu:(NSMenu *)menu;
@end
/* Use this flag to determine whether we use SDLMain.nib or not */
#define SDL_USE_NIB_FILE 0
/* Use this flag to determine whether we use CPS (docking) or not */
#define SDL_USE_CPS 1
#ifdef SDL_USE_CPS
/* Portions of CPS.h */
typedef struct CPSProcessSerNum
{
UInt32 lo;
UInt32 hi;
} CPSProcessSerNum;
extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
#endif /* SDL_USE_CPS */
static int gArgc;
static char **gArgv;
static BOOL gFinderLaunch;
static BOOL gCalledAppMainline = FALSE;
static NSString *getApplicationName(void)
{
NSDictionary *dict;
NSString *appName = 0;
/* Determine the application name */
dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
if (dict)
appName = [dict objectForKey: @"CFBundleName"];
if (![appName length])
appName = [[NSProcessInfo processInfo] processName];
return appName;
}
#if SDL_USE_NIB_FILE
/* A helper category for NSString */
@interface NSString (ReplaceSubString)
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
@end
#endif
@interface SDLApplication : NSApplication
@end
@implementation SDLApplication
/* Invoked from the Quit menu item */
- (void)terminate:(id)sender
{
/* Post a SDL_QUIT event */
SDL_Event event;
event.type = SDL_QUIT;
SDL_PushEvent(&event);
}
@end
/* The main class of the application, the application's delegate */
@implementation SDLMain
/* Set the working directory to the .app's parent directory */
- (void) setupWorkingDirectory:(BOOL)shouldChdir
{
if (shouldChdir)
{
char parentdir[MAXPATHLEN];
CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url);
if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) {
assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */
}
CFRelease(url);
CFRelease(url2);
}
}
#if SDL_USE_NIB_FILE
/* Fix menu to contain the real app name instead of "SDL App" */
- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
{
NSRange aRange;
NSEnumerator *enumerator;
NSMenuItem *menuItem;
aRange = [[aMenu title] rangeOfString:@"SDL App"];
if (aRange.length != 0)
[aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
enumerator = [[aMenu itemArray] objectEnumerator];
while ((menuItem = [enumerator nextObject]))
{
aRange = [[menuItem title] rangeOfString:@"SDL App"];
if (aRange.length != 0)
[menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
if ([menuItem hasSubmenu])
[self fixMenu:[menuItem submenu] withAppName:appName];
}
[ aMenu sizeToFit ];
}
#else
static void setApplicationMenu(void)
{
/* warning: this code is very odd */
NSMenu *appleMenu;
NSMenuItem *menuItem;
NSString *title;
NSString *appName;
appName = getApplicationName();
appleMenu = [[NSMenu alloc] initWithTitle:@""];
/* Add menu items */
title = [@"About " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
/* Finally give up our references to the objects */
[appleMenu release];
[menuItem release];
}
/* Create a window menu */
static void setupWindowMenu(void)
{
NSMenu *windowMenu;
NSMenuItem *windowMenuItem;
NSMenuItem *menuItem;
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
/* "Minimize" item */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[windowMenu addItem:menuItem];
[menuItem release];
/* Put menu into the menubar */
windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[windowMenuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:windowMenuItem];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
/* Finally give up our references to the objects */
[windowMenu release];
[windowMenuItem release];
}
/* Replacement for NSApplicationMain */
static void CustomApplicationMain (int argc, char **argv)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
SDLMain *sdlMain;
/* Ensure the application object is initialised */
[SDLApplication sharedApplication];
#ifdef SDL_USE_CPS
{
CPSProcessSerNum PSN;
/* Tell the dock about us */
if (!CPSGetCurrentProcess(&PSN))
if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
if (!CPSSetFrontProcess(&PSN))
[SDLApplication sharedApplication];
}
#endif /* SDL_USE_CPS */
/* Set up the menubar */
[NSApp setMainMenu:[[NSMenu alloc] init]];
setApplicationMenu();
setupWindowMenu();
/* Create SDLMain and make it the app delegate */
sdlMain = [[SDLMain alloc] init];
[NSApp setDelegate:sdlMain];
/* Start the main event loop */
[NSApp run];
[sdlMain release];
[pool release];
}
#endif
/*
* Catch document open requests...this lets us notice files when the app
* was launched by double-clicking a document, or when a document was
* dragged/dropped on the app's icon. You need to have a
* CFBundleDocumentsType section in your Info.plist to get this message,
* apparently.
*
* Files are added to gArgv, so to the app, they'll look like command line
* arguments. Previously, apps launched from the finder had nothing but
* an argv[0].
*
* This message may be received multiple times to open several docs on launch.
*
* This message is ignored once the app's mainline has been called.
*/
- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
{
const char *temparg;
size_t arglen;
char *arg;
char **newargv;
if (!gFinderLaunch) /* MacOS is passing command line args. */
return FALSE;
if (gCalledAppMainline) /* app has started, ignore this document. */
return FALSE;
temparg = [filename UTF8String];
arglen = SDL_strlen(temparg) + 1;
arg = (char *) SDL_malloc(arglen);
if (arg == NULL)
return FALSE;
newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
if (newargv == NULL)
{
SDL_free(arg);
return FALSE;
}
gArgv = newargv;
SDL_strlcpy(arg, temparg, arglen);
gArgv[gArgc++] = arg;
gArgv[gArgc] = NULL;
return TRUE;
}
/* Called when the internal event loop has just started running */
- (void) applicationDidFinishLaunching: (NSNotification *) note
{
int status;
/* Set the working directory to the .app's parent directory */
[self setupWorkingDirectory:gFinderLaunch];
#if SDL_USE_NIB_FILE
/* Set the main menu to contain the real app name instead of "SDL App" */
[self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
#endif
/* Hand off to main application code */
gCalledAppMainline = TRUE;
status = SDL_main (gArgc, gArgv);
/* We're done, thank you for playing */
exit(status);
}
@end
@implementation NSString (ReplaceSubString)
- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
{
unsigned int bufferSize;
unsigned int selfLen = [self length];
unsigned int aStringLen = [aString length];
unichar *buffer;
NSRange localRange;
NSString *result;
bufferSize = selfLen + aStringLen - aRange.length;
buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
/* Get first part into buffer */
localRange.location = 0;
localRange.length = aRange.location;
[self getCharacters:buffer range:localRange];
/* Get middle part into buffer */
localRange.location = 0;
localRange.length = aStringLen;
[aString getCharacters:(buffer+aRange.location) range:localRange];
/* Get last part into buffer */
localRange.location = aRange.location + aRange.length;
localRange.length = selfLen - localRange.location;
[self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
/* Build output string */
result = [NSString stringWithCharacters:buffer length:bufferSize];
NSDeallocateMemoryPages(buffer, bufferSize);
return result;
}
@end
#ifdef main
# undef main
#endif
/* Main entry point to executable - should *not* be SDL_main! */
int main (int argc, char **argv)
{
/* Copy the arguments into a global variable */
/* This is passed if we are launched by double-clicking */
if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
gArgv[0] = argv[0];
gArgv[1] = NULL;
gArgc = 1;
gFinderLaunch = YES;
} else {
int i;
gArgc = argc;
gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
for (i = 0; i <= argc; i++)
gArgv[i] = argv[i];
gFinderLaunch = NO;
}
#if SDL_USE_NIB_FILE
[SDLApplication poseAsClass:[NSApplication class]];
NSApplicationMain (argc, argv);
#else
CustomApplicationMain (argc, argv);
#endif
return 0;
}
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
ACTIONS = {makeFullscreen = id; quit = id; };
CLASS = SDLMain;
LANGUAGE = ObjC;
SUPERCLASS = NSObject;
}
);
IBVersion = 1;
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
<plist version="0.9">
<dict>
<key>IBDocumentLocation</key>
<string>49 97 356 240 0 0 987 746 </string>
<key>IBMainMenuLocation</key>
<string>20 515 195 44 0 46 800 532 </string>
<key>IBUserGuides</key>
<dict/>
</dict>
</plist>
// This is just a stub file to force automake to create the install directory
...@@ -296,8 +296,8 @@ typedef struct VideoBootStrap ...@@ -296,8 +296,8 @@ typedef struct VideoBootStrap
SDL_VideoDevice *(*create) (int devindex); SDL_VideoDevice *(*create) (int devindex);
} VideoBootStrap; } VideoBootStrap;
#if SDL_VIDEO_DRIVER_QUARTZ #if SDL_VIDEO_DRIVER_COCOA
extern VideoBootStrap QZ_bootstrap; extern VideoBootStrap COCOA_bootstrap;
#endif #endif
#if SDL_VIDEO_DRIVER_X11 #if SDL_VIDEO_DRIVER_X11
extern VideoBootStrap X11_bootstrap; extern VideoBootStrap X11_bootstrap;
......
...@@ -43,8 +43,8 @@ ...@@ -43,8 +43,8 @@
/* Available video drivers */ /* Available video drivers */
static VideoBootStrap *bootstrap[] = { static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_QUARTZ #if SDL_VIDEO_DRIVER_COCOA
&QZ_bootstrap, &COCOA_bootstrap,
#endif #endif
#if SDL_VIDEO_DRIVER_X11 #if SDL_VIDEO_DRIVER_X11
&X11_bootstrap, &X11_bootstrap,
......
/* /*
SDL - Simple DirectMedia Layer SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Library General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga Sam Lantinga
slouken@libsdl.org slouken@libsdl.org
*/ */
#include "SDL_config.h" #include "SDL_config.h"
/* Subclass of NSWindow to fix genie effect and support resize events */ #ifndef _SDL_cocoaevents_h
@ interface SDL_QuartzWindow: NSWindow - (void) miniaturize:(id) sender; #define _SDL_cocoaevents_h
-(void) display;
-(void) setFrame:(NSRect) extern void Cocoa_RegisterApp(void);
frameRect display:(BOOL) flag; extern void Cocoa_PumpEvents(_THIS);
-(void) appDidHide:(NSNotification *) note;
-(void) appWillUnhide:(NSNotification *) note; #endif /* _SDL_cocoaevents_h */
-(void) appDidUnhide:(NSNotification *) note;
-(id) initWithContentRect:(NSRect)
contentRect styleMask:(unsigned int)
styleMask backing:(NSBackingStoreType)
backingType defer:(BOOL) flag;
@end
/* Delegate for our NSWindow to send SDLQuit() on close */
@ interface SDL_QuartzWindowDelegate: NSObject - (BOOL) windowShouldClose:(id)
sender;
@end
/* vi: set ts=4 sw=4 expandtab: */ /* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_cocoavideo.h"
/* setAppleMenu disappeared from the headers in 10.4 */
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
@interface NSApplication(NSAppleMenu)
- (void)setAppleMenu:(NSMenu *)menu;
@end
#endif
@interface SDLApplication : NSApplication
{
}
- (void)finishLaunching;
@end
@implementation SDLApplication
- (void)finishLaunching
{
[super finishLaunching];
_running = 1;
}
@end
static NSString *
GetApplicationName(void)
{
NSDictionary *dict;
NSString *appName = 0;
/* Determine the application name */
dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
if (dict)
appName = [dict objectForKey: @"CFBundleName"];
if (![appName length])
appName = [[NSProcessInfo processInfo] processName];
return appName;
}
static void
CreateApplicationMenus(void)
{
NSString *appName;
NSString *title;
NSMenu *appleMenu;
NSMenu *windowMenu;
NSMenuItem *menuItem;
/* Create the main menu bar */
[NSApp setMainMenu:[[NSMenu alloc] init]];
/* Create the application menu */
appName = GetApplicationName();
appleMenu = [[NSMenu alloc] initWithTitle:@""];
/* Add menu items */
title = [@"About " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Hide " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
[appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
[appleMenu addItem:[NSMenuItem separatorItem]];
title = [@"Quit " stringByAppendingString:appName];
[appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
[menuItem setSubmenu:appleMenu];
[[NSApp mainMenu] addItem:menuItem];
[menuItem release];
/* Tell the application object that this is now the application menu */
[NSApp setAppleMenu:appleMenu];
[appleMenu release];
/* Create the window menu */
windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
/* "Minimize" item */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[windowMenu addItem:menuItem];
[menuItem release];
/* Put menu into the menubar */
menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
[menuItem setSubmenu:windowMenu];
[[NSApp mainMenu] addItem:menuItem];
[menuItem release];
/* Tell the application object that this is now the window menu */
[NSApp setWindowsMenu:windowMenu];
[windowMenu release];
}
void
Cocoa_RegisterApp(void)
{
ProcessSerialNumber psn;
NSAutoreleasePool *pool;
if (!GetCurrentProcess(&psn)) {
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
SetFrontProcess(&psn);
}
pool = [[NSAutoreleasePool alloc] init];
if (NSApp == nil) {
[SDLApplication sharedApplication];
if ([NSApp mainMenu] == nil) {
CreateApplicationMenus();
}
[NSApp finishLaunching];
}
[pool release];
}
void
Cocoa_PumpEvents(_THIS)
{
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
for ( ; [NSApp isRunning]; ) {
NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES ];
if ( event == nil ) {
break;
}
[NSApp sendEvent:event];
}
[pool release];
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_cocoakeyboard_h
#define _SDL_cocoakeyboard_h
extern void Cocoa_InitKeyboard(_THIS);
extern void Cocoa_QuitKeyboard(_THIS);
#endif /* _SDL_cocoakeyboard_h */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_cocoavideo.h"
#include "../../events/SDL_keyboard_c.h"
void
Cocoa_InitKeyboard(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
SDL_Keyboard keyboard;
SDL_zero(keyboard);
data->keyboard = SDL_AddKeyboard(&keyboard, -1);
}
void
Cocoa_QuitKeyboard(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
SDL_DelKeyboard(data->keyboard);
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_cocoamodes_h
#define _SDL_cocoamodes_h
extern void Cocoa_InitModes(_THIS);
extern void Cocoa_GetDisplayModes(_THIS);
extern int Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode);
extern void Cocoa_QuitModes(_THIS);
#endif /* _SDL_cocoamodes_h */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_cocoavideo.h"
void
Cocoa_InitModes(_THIS)
{
SDL_VideoDisplay display;
SDL_DisplayMode mode;
SDL_zero(display);
SDL_zero(mode);
display.desktop_mode = mode;
display.current_mode = mode;
SDL_AddVideoDisplay(&display);
}
void
Cocoa_GetDisplayModes(_THIS)
{
}
int
Cocoa_SetDisplayMode(_THIS, SDL_DisplayMode * mode)
{
return -1;
}
void
Cocoa_QuitModes(_THIS)
{
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_cocoamouse_h
#define _SDL_cocoamouse_h
extern void Cocoa_InitMouse(_THIS);
extern void Cocoa_QuitMouse(_THIS);
#endif /* _SDL_cocoamouse_h */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_cocoavideo.h"
#include "../../events/SDL_mouse_c.h"
void
Cocoa_InitMouse(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
SDL_Mouse mouse;
SDL_zero(mouse);
data->mouse = SDL_AddMouse(&mouse, -1);
}
void
Cocoa_QuitMouse(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
SDL_DelMouse(data->mouse);
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#ifndef _SDL_cocoavideo_h
#define _SDL_cocoavideo_h
#include <Cocoa/Cocoa.h>
#include "../SDL_sysvideo.h"
#include "SDL_cocoaevents.h"
#include "SDL_cocoakeyboard.h"
#include "SDL_cocoamodes.h"
#include "SDL_cocoamouse.h"
/*
#include "SDL_cocoaopengl.h"
#include "SDL_cocoawindow.h"
*/
/* Private display data */
typedef struct SDL_VideoData
{
int mouse;
int keyboard;
} SDL_VideoData;
#endif /* _SDL_cocoavideo_h */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_cocoavideo.h"
/* Initialization/Query functions */
static int Cocoa_VideoInit(_THIS);
static void Cocoa_VideoQuit(_THIS);
/* Cocoa driver bootstrap functions */
static int
Cocoa_Available(void)
{
return (1);
}
static void
Cocoa_DeleteDevice(SDL_VideoDevice * device)
{
SDL_VideoData *data = (SDL_VideoData *) device->driverdata;
SDL_free(device->driverdata);
SDL_free(device);
}
static SDL_VideoDevice *
Cocoa_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
Cocoa_RegisterApp();
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device) {
data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
}
if (!device || !data) {
SDL_OutOfMemory();
if (device) {
SDL_free(device);
}
return NULL;
}
device->driverdata = data;
/* Set the function pointers */
device->VideoInit = Cocoa_VideoInit;
device->VideoQuit = Cocoa_VideoQuit;
device->GetDisplayModes = Cocoa_GetDisplayModes;
device->SetDisplayMode = Cocoa_SetDisplayMode;
device->PumpEvents = Cocoa_PumpEvents;
/*
device->CreateWindow = Cocoa_CreateWindow;
device->CreateWindowFrom = Cocoa_CreateWindowFrom;
device->SetWindowTitle = Cocoa_SetWindowTitle;
device->SetWindowPosition = Cocoa_SetWindowPosition;
device->SetWindowSize = Cocoa_SetWindowSize;
device->ShowWindow = Cocoa_ShowWindow;
device->HideWindow = Cocoa_HideWindow;
device->RaiseWindow = Cocoa_RaiseWindow;
device->MaximizeWindow = Cocoa_MaximizeWindow;
device->MinimizeWindow = Cocoa_MinimizeWindow;
device->RestoreWindow = Cocoa_RestoreWindow;
device->SetWindowGrab = Cocoa_SetWindowGrab;
device->DestroyWindow = Cocoa_DestroyWindow;
device->GetWindowWMInfo = Cocoa_GetWindowWMInfo;
#ifdef SDL_VIDEO_OPENGL
device->GL_LoadLibrary = Cocoa_GL_LoadLibrary;
device->GL_GetProcAddress = Cocoa_GL_GetProcAddress;
device->GL_GetWindowAttribute = Cocoa_GL_GetWindowAttribute;
device->GL_CreateContext = Cocoa_GL_CreateContext;
device->GL_MakeCurrent = Cocoa_GL_MakeCurrent;
device->GL_SetSwapInterval = Cocoa_GL_SetSwapInterval;
device->GL_GetSwapInterval = Cocoa_GL_GetSwapInterval;
device->GL_SwapWindow = Cocoa_GL_SwapWindow;
device->GL_DeleteContext = Cocoa_GL_DeleteContext;
#endif
*/
device->free = Cocoa_DeleteDevice;
return device;
}
VideoBootStrap COCOA_bootstrap = {
"cocoa", "SDL Cocoa video driver",
Cocoa_Available, Cocoa_CreateDevice
};
int
Cocoa_VideoInit(_THIS)
{
Cocoa_InitModes(_this);
Cocoa_InitKeyboard(_this);
Cocoa_InitMouse(_this);
return 0;
}
void
Cocoa_VideoQuit(_THIS)
{
Cocoa_QuitModes(_this);
Cocoa_QuitKeyboard(_this);
Cocoa_QuitMouse(_this);
}
/* vim: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
Obscuring code: maximum number of windows above ours (inclusive)
Note: this doesn't work too well in practice and should be
phased out when we add OpenGL 2D acceleration. It was never
enabled in the first place, so this shouldn't be a problem ;-)
*/
#define kMaxWindows 256
/* Some of the Core Graphics Server API for obscuring code */
#define kCGSWindowLevelTop 2147483632
#define kCGSWindowLevelDockIconDrag 500
#define kCGSWindowLevelDockMenu 101
#define kCGSWindowLevelMenuIgnore 21
#define kCGSWindowLevelMenu 20
#define kCGSWindowLevelDockLabel 12
#define kCGSWindowLevelDockIcon 11
#define kCGSWindowLevelDock 10
#define kCGSWindowLevelUtility 3
#define kCGSWindowLevelNormal 0
/*
For completeness; We never use these window levels, they are always below us
#define kCGSWindowLevelMBarShadow -20
#define kCGSWindowLevelDesktopPicture -2147483647
#define kCGSWindowLevelDesktop -2147483648
*/
typedef CGError CGSError;
typedef long CGSWindowCount;
typedef void *CGSConnectionID;
typedef int CGSWindowID;
typedef CGSWindowID *CGSWindowIDList;
typedef CGWindowLevel CGSWindowLevel;
typedef NSRect CGSRect;
extern CGSConnectionID _CGSDefaultConnection();
extern CGSError CGSGetOnScreenWindowList(CGSConnectionID cid,
CGSConnectionID owner,
CGSWindowCount listCapacity,
CGSWindowIDList list,
CGSWindowCount * listCount);
extern CGSError CGSGetScreenRectForWindow(CGSConnectionID cid,
CGSWindowID wid, CGSRect * rect);
extern CGWindowLevel CGSGetWindowLevel(CGSConnectionID cid,
CGSWindowID wid,
CGSWindowLevel * level);
extern CGSError CGSDisplayHWFill(CGDirectDisplayID id, unsigned int x,
unsigned int y, unsigned int w,
unsigned int h, unsigned int color);
extern CGSError CGSDisplayCanHWFill(CGDirectDisplayID id);
extern CGSError CGSGetMouseEnabledFlags(CGSConnectionID cid, CGSWindowID wid,
int *flags);
int CGSDisplayHWSync(CGDirectDisplayID id);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_QuartzVideo.h"
#include <IOKit/IOMessage.h> /* For wake from sleep detection */
#include <IOKit/pwr_mgt/IOPMLib.h> /* For wake from sleep detection */
#include "SDL_QuartzKeys.h"
/*
* In Panther, this header defines device dependent masks for
* right side keys. These definitions only exist in Panther, but
* the header seems to exist at least in Jaguar and probably earlier
* versions of the OS, so this should't break anything.
*/
#include <IOKit/hidsystem/IOLLEvent.h>
/*
* These are not defined before Panther. To keep the code compiling
* on systems without these, I will define if they don't exist.
*/
#ifndef NX_DEVICERCTLKEYMASK
#define NX_DEVICELCTLKEYMASK 0x00000001
#endif
#ifndef NX_DEVICELSHIFTKEYMASK
#define NX_DEVICELSHIFTKEYMASK 0x00000002
#endif
#ifndef NX_DEVICERSHIFTKEYMASK
#define NX_DEVICERSHIFTKEYMASK 0x00000004
#endif
#ifndef NX_DEVICELCMDKEYMASK
#define NX_DEVICELCMDKEYMASK 0x00000008
#endif
#ifndef NX_DEVICERCMDKEYMASK
#define NX_DEVICERCMDKEYMASK 0x00000010
#endif
#ifndef NX_DEVICELALTKEYMASK
#define NX_DEVICELALTKEYMASK 0x00000020
#endif
#ifndef NX_DEVICERALTKEYMASK
#define NX_DEVICERALTKEYMASK 0x00000040
#endif
#ifndef NX_DEVICERCTLKEYMASK
#define NX_DEVICERCTLKEYMASK 0x00002000
#endif
void
QZ_InitOSKeymap (_THIS)
{
const void *KCHRPtr;
UInt32 state;
UInt32 value;
int i;
int world = SDLK_WORLD_0;
for (i = 0; i < SDL_TABLESIZE (keymap); ++i)
keymap[i] = SDLK_UNKNOWN;
/* This keymap is almost exactly the same as the OS 9 one */
keymap[QZ_ESCAPE] = SDLK_ESCAPE;
keymap[QZ_F1] = SDLK_F1;
keymap[QZ_F2] = SDLK_F2;
keymap[QZ_F3] = SDLK_F3;
keymap[QZ_F4] = SDLK_F4;
keymap[QZ_F5] = SDLK_F5;
keymap[QZ_F6] = SDLK_F6;
keymap[QZ_F7] = SDLK_F7;
keymap[QZ_F8] = SDLK_F8;
keymap[QZ_F9] = SDLK_F9;
keymap[QZ_F10] = SDLK_F10;
keymap[QZ_F11] = SDLK_F11;
keymap[QZ_F12] = SDLK_F12;
keymap[QZ_PRINT] = SDLK_PRINT;
keymap[QZ_SCROLLOCK] = SDLK_SCROLLOCK;
keymap[QZ_PAUSE] = SDLK_PAUSE;
keymap[QZ_POWER] = SDLK_POWER;
keymap[QZ_BACKQUOTE] = SDLK_BACKQUOTE;
keymap[QZ_1] = SDLK_1;
keymap[QZ_2] = SDLK_2;
keymap[QZ_3] = SDLK_3;
keymap[QZ_4] = SDLK_4;
keymap[QZ_5] = SDLK_5;
keymap[QZ_6] = SDLK_6;
keymap[QZ_7] = SDLK_7;
keymap[QZ_8] = SDLK_8;
keymap[QZ_9] = SDLK_9;
keymap[QZ_0] = SDLK_0;
keymap[QZ_MINUS] = SDLK_MINUS;
keymap[QZ_EQUALS] = SDLK_EQUALS;
keymap[QZ_BACKSPACE] = SDLK_BACKSPACE;
keymap[QZ_INSERT] = SDLK_INSERT;
keymap[QZ_HOME] = SDLK_HOME;
keymap[QZ_PAGEUP] = SDLK_PAGEUP;
keymap[QZ_NUMLOCK] = SDLK_NUMLOCK;
keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
keymap[QZ_TAB] = SDLK_TAB;
keymap[QZ_q] = SDLK_q;
keymap[QZ_w] = SDLK_w;
keymap[QZ_e] = SDLK_e;
keymap[QZ_r] = SDLK_r;
keymap[QZ_t] = SDLK_t;
keymap[QZ_y] = SDLK_y;
keymap[QZ_u] = SDLK_u;
keymap[QZ_i] = SDLK_i;
keymap[QZ_o] = SDLK_o;
keymap[QZ_p] = SDLK_p;
keymap[QZ_LEFTBRACKET] = SDLK_LEFTBRACKET;
keymap[QZ_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
keymap[QZ_BACKSLASH] = SDLK_BACKSLASH;
keymap[QZ_DELETE] = SDLK_DELETE;
keymap[QZ_END] = SDLK_END;
keymap[QZ_PAGEDOWN] = SDLK_PAGEDOWN;
keymap[QZ_KP7] = SDLK_KP7;
keymap[QZ_KP8] = SDLK_KP8;
keymap[QZ_KP9] = SDLK_KP9;
keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
keymap[QZ_CAPSLOCK] = SDLK_CAPSLOCK;
keymap[QZ_a] = SDLK_a;
keymap[QZ_s] = SDLK_s;
keymap[QZ_d] = SDLK_d;
keymap[QZ_f] = SDLK_f;
keymap[QZ_g] = SDLK_g;
keymap[QZ_h] = SDLK_h;
keymap[QZ_j] = SDLK_j;
keymap[QZ_k] = SDLK_k;
keymap[QZ_l] = SDLK_l;
keymap[QZ_SEMICOLON] = SDLK_SEMICOLON;
keymap[QZ_QUOTE] = SDLK_QUOTE;
keymap[QZ_RETURN] = SDLK_RETURN;
keymap[QZ_KP4] = SDLK_KP4;
keymap[QZ_KP5] = SDLK_KP5;
keymap[QZ_KP6] = SDLK_KP6;
keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
keymap[QZ_LSHIFT] = SDLK_LSHIFT;
keymap[QZ_RSHIFT] = SDLK_RSHIFT;
keymap[QZ_z] = SDLK_z;
keymap[QZ_x] = SDLK_x;
keymap[QZ_c] = SDLK_c;
keymap[QZ_v] = SDLK_v;
keymap[QZ_b] = SDLK_b;
keymap[QZ_n] = SDLK_n;
keymap[QZ_m] = SDLK_m;
keymap[QZ_COMMA] = SDLK_COMMA;
keymap[QZ_PERIOD] = SDLK_PERIOD;
keymap[QZ_SLASH] = SDLK_SLASH;
keymap[QZ_UP] = SDLK_UP;
keymap[QZ_KP1] = SDLK_KP1;
keymap[QZ_KP2] = SDLK_KP2;
keymap[QZ_KP3] = SDLK_KP3;
keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
keymap[QZ_LCTRL] = SDLK_LCTRL;
keymap[QZ_LALT] = SDLK_LALT;
keymap[QZ_LMETA] = SDLK_LMETA;
keymap[QZ_RCTRL] = SDLK_RCTRL;
keymap[QZ_RALT] = SDLK_RALT;
keymap[QZ_RMETA] = SDLK_RMETA;
keymap[QZ_SPACE] = SDLK_SPACE;
keymap[QZ_LEFT] = SDLK_LEFT;
keymap[QZ_DOWN] = SDLK_DOWN;
keymap[QZ_RIGHT] = SDLK_RIGHT;
keymap[QZ_KP0] = SDLK_KP0;
keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
keymap[QZ_IBOOK_ENTER] = SDLK_KP_ENTER;
keymap[QZ_IBOOK_RIGHT] = SDLK_RIGHT;
keymap[QZ_IBOOK_DOWN] = SDLK_DOWN;
keymap[QZ_IBOOK_UP] = SDLK_UP;
keymap[QZ_IBOOK_LEFT] = SDLK_LEFT;
/*
Up there we setup a static scancode->keysym map. However, it will not
work very well on international keyboard. Hence we now query MacOS
for its own keymap to adjust our own mapping table. However, this is
basically only useful for ascii char keys. This is also the reason
why we keep the static table, too.
*/
/* Get a pointer to the systems cached KCHR */
KCHRPtr = (void *) GetScriptManagerVariable (smKCHRCache);
if (KCHRPtr) {
/* Loop over all 127 possible scan codes */
for (i = 0; i < 0x7F; i++) {
/* We pretend a clean start to begin with (i.e. no dead keys active */
state = 0;
/* Now translate the key code to a key value */
value = KeyTranslate (KCHRPtr, i, &state) & 0xff;
/* If the state become 0, it was a dead key. We need to translate again,
passing in the new state, to get the actual key value */
if (state != 0)
value = KeyTranslate (KCHRPtr, i, &state) & 0xff;
/* Now we should have an ascii value, or 0. Try to figure out to which SDL symbol it maps */
if (value >= 128) /* Some non-ASCII char, map it to SDLK_WORLD_* */
keymap[i] = world++;
else if (value >= 32) /* non-control ASCII char */
keymap[i] = value;
}
}
/*
The keypad codes are re-setup here, because the loop above cannot
distinguish between a key on the keypad and a regular key. We maybe
could get around this problem in another fashion: NSEvent's flags
include a "NSNumericPadKeyMask" bit; we could check that and modify
the symbol we return on the fly. However, this flag seems to exhibit
some weird behaviour related to the num lock key
*/
keymap[QZ_KP0] = SDLK_KP0;
keymap[QZ_KP1] = SDLK_KP1;
keymap[QZ_KP2] = SDLK_KP2;
keymap[QZ_KP3] = SDLK_KP3;
keymap[QZ_KP4] = SDLK_KP4;
keymap[QZ_KP5] = SDLK_KP5;
keymap[QZ_KP6] = SDLK_KP6;
keymap[QZ_KP7] = SDLK_KP7;
keymap[QZ_KP8] = SDLK_KP8;
keymap[QZ_KP9] = SDLK_KP9;
keymap[QZ_KP_MINUS] = SDLK_KP_MINUS;
keymap[QZ_KP_PLUS] = SDLK_KP_PLUS;
keymap[QZ_KP_PERIOD] = SDLK_KP_PERIOD;
keymap[QZ_KP_EQUALS] = SDLK_KP_EQUALS;
keymap[QZ_KP_DIVIDE] = SDLK_KP_DIVIDE;
keymap[QZ_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
keymap[QZ_KP_ENTER] = SDLK_KP_ENTER;
}
static void
QZ_DoKey (_THIS, int state, NSEvent * event)
{
NSString *chars;
unsigned int numChars;
SDL_keysym key;
/*
A key event can contain multiple characters,
or no characters at all. In most cases, it
will contain a single character. If it contains
0 characters, we'll use 0 as the unicode. If it
contains multiple characters, we'll use 0 as
the scancode/keysym.
*/
chars =[event characters];
numChars =[chars length];
if (numChars == 1) {
key.scancode =[event keyCode];
key.sym = keymap[key.scancode];
key.unicode =[chars characterAtIndex:0];
key.mod = KMOD_NONE;
SDL_PrivateKeyboard (state, &key);
} else if (numChars == 0) {
key.scancode =[event keyCode];
key.sym = keymap[key.scancode];
key.unicode = 0;
key.mod = KMOD_NONE;
SDL_PrivateKeyboard (state, &key);
} else { /* (numChars > 1) */
int i;
for (i = 0; i < numChars; i++) {
key.scancode = 0;
key.sym = 0;
key.unicode =[chars characterAtIndex:i];
key.mod = KMOD_NONE;
SDL_PrivateKeyboard (state, &key);
}
}
if (SDL_getenv ("SDL_ENABLEAPPEVENTS"))
[NSApp sendEvent:event];
}
/* This is the original behavior, before support was added for
* differentiating between left and right versions of the keys.
*/
static void
QZ_DoUnsidedModifiers (_THIS, unsigned int newMods)
{
const int mapping[] =
{ SDLK_CAPSLOCK, SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
int i;
int bit;
SDL_keysym key;
key.scancode = 0;
key.sym = SDLK_UNKNOWN;
key.unicode = 0;
key.mod = KMOD_NONE;
/* Iterate through the bits, testing each against the current modifiers */
for (i = 0, bit = NSAlphaShiftKeyMask; bit <= NSCommandKeyMask;
bit <<= 1, ++i) {
unsigned int currentMask, newMask;
currentMask = current_mods & bit;
newMask = newMods & bit;
if (currentMask && currentMask != newMask) { /* modifier up event */
key.sym = mapping[i];
/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
if (bit == NSAlphaShiftKeyMask)
SDL_PrivateKeyboard (SDL_PRESSED, &key);
SDL_PrivateKeyboard (SDL_RELEASED, &key);
} else if (newMask && currentMask != newMask) { /* modifier down event */
key.sym = mapping[i];
SDL_PrivateKeyboard (SDL_PRESSED, &key);
/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
if (bit == NSAlphaShiftKeyMask)
SDL_PrivateKeyboard (SDL_RELEASED, &key);
}
}
}
/* This is a helper function for QZ_HandleModifierSide. This
* function reverts back to behavior before the distinction between
* sides was made.
*/
static void
QZ_HandleNonDeviceModifier (_THIS, unsigned int device_independent_mask,
unsigned int newMods, unsigned int key_sym)
{
unsigned int currentMask, newMask;
SDL_keysym key;
key.scancode = 0;
key.sym = key_sym;
key.unicode = 0;
key.mod = KMOD_NONE;
/* Isolate just the bits we care about in the depedent bits so we can
* figure out what changed
*/
currentMask = current_mods & device_independent_mask;
newMask = newMods & device_independent_mask;
if (currentMask && currentMask != newMask) { /* modifier up event */
SDL_PrivateKeyboard (SDL_RELEASED, &key);
} else if (newMask && currentMask != newMask) { /* modifier down event */
SDL_PrivateKeyboard (SDL_PRESSED, &key);
}
}
/* This is a helper function for QZ_HandleModifierSide.
* This function sets the actual SDL_PrivateKeyboard event.
*/
static void
QZ_HandleModifierOneSide (_THIS, unsigned int newMods,
unsigned int key_sym,
unsigned int sided_device_dependent_mask)
{
SDL_keysym key;
unsigned int current_dep_mask, new_dep_mask;
key.scancode = 0;
key.sym = key_sym;
key.unicode = 0;
key.mod = KMOD_NONE;
/* Isolate just the bits we care about in the depedent bits so we can
* figure out what changed
*/
current_dep_mask = current_mods & sided_device_dependent_mask;
new_dep_mask = newMods & sided_device_dependent_mask;
/* We now know that this side bit flipped. But we don't know if
* it went pressed to released or released to pressed, so we must
* find out which it is.
*/
if (new_dep_mask && current_dep_mask != new_dep_mask) {
/* Modifier down event */
SDL_PrivateKeyboard (SDL_PRESSED, &key);
} else { /* Modifier up event */
SDL_PrivateKeyboard (SDL_RELEASED, &key);
}
}
/* This is a helper function for QZ_DoSidedModifiers.
* This function will figure out if the modifier key is the left or right side,
* e.g. left-shift vs right-shift.
*/
static void
QZ_HandleModifierSide (_THIS, int device_independent_mask,
unsigned int newMods,
unsigned int left_key_sym,
unsigned int right_key_sym,
unsigned int left_device_dependent_mask,
unsigned int right_device_dependent_mask)
{
unsigned int device_dependent_mask = 0;
unsigned int diff_mod = 0;
device_dependent_mask =
left_device_dependent_mask | right_device_dependent_mask;
/* On the basis that the device independent mask is set, but there are
* no device dependent flags set, we'll assume that we can't detect this
* keyboard and revert to the unsided behavior.
*/
if ((device_dependent_mask & newMods) == 0) {
/* Revert to the old behavior */
QZ_HandleNonDeviceModifier (this, device_independent_mask, newMods,
left_key_sym);
return;
}
/* XOR the previous state against the new state to see if there's a change */
diff_mod = (device_dependent_mask & current_mods)
^ (device_dependent_mask & newMods);
if (diff_mod) {
/* A change in state was found. Isolate the left and right bits
* to handle them separately just in case the values can simulataneously
* change or if the bits don't both exist.
*/
if (left_device_dependent_mask & diff_mod) {
QZ_HandleModifierOneSide (this, newMods, left_key_sym,
left_device_dependent_mask);
}
if (right_device_dependent_mask & diff_mod) {
QZ_HandleModifierOneSide (this, newMods, right_key_sym,
right_device_dependent_mask);
}
}
}
/* This is a helper function for QZ_DoSidedModifiers.
* This function will release a key press in the case that
* it is clear that the modifier has been released (i.e. one side
* can't still be down).
*/
static void
QZ_ReleaseModifierSide (_THIS,
unsigned int device_independent_mask,
unsigned int newMods,
unsigned int left_key_sym,
unsigned int right_key_sym,
unsigned int left_device_dependent_mask,
unsigned int right_device_dependent_mask)
{
unsigned int device_dependent_mask = 0;
SDL_keysym key;
key.scancode = 0;
key.sym = SDLK_UNKNOWN;
key.unicode = 0;
key.mod = KMOD_NONE;
device_dependent_mask =
left_device_dependent_mask | right_device_dependent_mask;
/* On the basis that the device independent mask is set, but there are
* no device dependent flags set, we'll assume that we can't detect this
* keyboard and revert to the unsided behavior.
*/
if ((device_dependent_mask & current_mods) == 0) {
/* In this case, we can't detect the keyboard, so use the left side
* to represent both, and release it.
*/
key.sym = left_key_sym;
SDL_PrivateKeyboard (SDL_RELEASED, &key);
return;
}
/*
* This could have been done in an if-else case because at this point,
* we know that all keys have been released when calling this function.
* But I'm being paranoid so I want to handle each separately,
* so I hope this doesn't cause other problems.
*/
if (left_device_dependent_mask & current_mods) {
key.sym = left_key_sym;
SDL_PrivateKeyboard (SDL_RELEASED, &key);
}
if (right_device_dependent_mask & current_mods) {
key.sym = right_key_sym;
SDL_PrivateKeyboard (SDL_RELEASED, &key);
}
}
/* This is a helper function for QZ_DoSidedModifiers.
* This function handles the CapsLock case.
*/
static void
QZ_HandleCapsLock (_THIS, unsigned int newMods)
{
unsigned int currentMask, newMask;
SDL_keysym key;
key.scancode = 0;
key.sym = SDLK_CAPSLOCK;
key.unicode = 0;
key.mod = KMOD_NONE;
currentMask = current_mods & NSAlphaShiftKeyMask;
newMask = newMods & NSAlphaShiftKeyMask;
if (currentMask && currentMask != newMask) { /* modifier up event */
/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
SDL_PrivateKeyboard (SDL_PRESSED, &key);
SDL_PrivateKeyboard (SDL_RELEASED, &key);
} else if (newMask && currentMask != newMask) { /* modifier down event */
/* If this was Caps Lock, we need some additional voodoo to make SDL happy */
SDL_PrivateKeyboard (SDL_PRESSED, &key);
SDL_PrivateKeyboard (SDL_RELEASED, &key);
}
}
/* This function will handle the modifier keys and also determine the
* correct side of the key.
*/
static void
QZ_DoSidedModifiers (_THIS, unsigned int newMods)
{
/* Set up arrays for the key syms for the left and right side. */
const unsigned int left_mapping[] =
{ SDLK_LSHIFT, SDLK_LCTRL, SDLK_LALT, SDLK_LMETA };
const unsigned int right_mapping[] =
{ SDLK_RSHIFT, SDLK_RCTRL, SDLK_RALT, SDLK_RMETA };
/* Set up arrays for the device dependent masks with indices that
* correspond to the _mapping arrays
*/
const unsigned int left_device_mapping[] =
{ NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK, NX_DEVICELALTKEYMASK,
NX_DEVICELCMDKEYMASK
};
const unsigned int right_device_mapping[] =
{ NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK, NX_DEVICERALTKEYMASK,
NX_DEVICERCMDKEYMASK
};
unsigned int i;
unsigned int bit;
/* Handle CAPSLOCK separately because it doesn't have a left/right side */
QZ_HandleCapsLock (this, newMods);
/* Iterate through the bits, testing each against the current modifiers */
for (i = 0, bit = NSShiftKeyMask; bit <= NSCommandKeyMask; bit <<= 1, ++i) {
unsigned int currentMask, newMask;
currentMask = current_mods & bit;
newMask = newMods & bit;
/* If the bit is set, we must always examine it because the left
* and right side keys may alternate or both may be pressed.
*/
if (newMask) {
QZ_HandleModifierSide (this, bit, newMods,
left_mapping[i],
right_mapping[i],
left_device_mapping[i],
right_device_mapping[i]);
}
/* If the state changed from pressed to unpressed, we must examine
* the device dependent bits to release the correct keys.
*/
else if (currentMask && currentMask != newMask) { /* modifier up event */
QZ_ReleaseModifierSide (this, bit, newMods,
left_mapping[i],
right_mapping[i],
left_device_mapping[i],
right_device_mapping[i]);
}
}
}
/* This function is called to handle the modifiers.
* It will try to distinguish between the left side and right side
* of the keyboard for those modifiers that qualify if the
* operating system version supports it. Otherwise, the code
* will not try to make the distinction.
*/
static void
QZ_DoModifiers (_THIS, unsigned int newMods)
{
if (current_mods == newMods)
return;
/*
* Starting with Panther (10.3.0), the ability to distinguish between
* left side and right side modifiers is available.
*/
if (system_version >= 0x1030) {
QZ_DoSidedModifiers (this, newMods);
} else {
QZ_DoUnsidedModifiers (this, newMods);
}
current_mods = newMods;
}
static void
QZ_GetMouseLocation (_THIS, NSPoint * p)
{
*p =[NSEvent mouseLocation]; /* global coordinates */
if (qz_window)
QZ_PrivateGlobalToLocal (this, p);
QZ_PrivateCocoaToSDL (this, p);
}
void
QZ_DoActivate (_THIS)
{
SDL_PrivateAppActive (1,
SDL_APPINPUTFOCUS | (QZ_IsMouseInWindow (this) ?
SDL_APPMOUSEFOCUS : 0));
/* Hide the cursor if it was hidden by SDL_ShowCursor() */
if (!cursor_should_be_visible)
QZ_HideMouse (this);
/* Regrab input, only if it was previously grabbed */
if (current_grab_mode == SDL_GRAB_ON) {
/* Restore cursor location if input was grabbed */
QZ_PrivateWarpCursor (this, cursor_loc.x, cursor_loc.y);
QZ_ChangeGrabState (this, QZ_ENABLE_GRAB);
} else {
/* Update SDL's mouse location */
NSPoint p;
QZ_GetMouseLocation (this, &p);
SDL_PrivateMouseMotion (0, 0, p.x, p.y);
}
}
void
QZ_DoDeactivate (_THIS)
{
SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS | SDL_APPMOUSEFOCUS);
/* Get the current cursor location, for restore on activate */
QZ_GetMouseLocation (this, &cursor_loc);
/* Reassociate mouse and cursor */
CGAssociateMouseAndMouseCursorPosition (1);
/* Show the cursor if it was hidden by SDL_ShowCursor() */
if (!cursor_should_be_visible)
QZ_ShowMouse (this);
}
void
QZ_SleepNotificationHandler (void *refcon,
io_service_t service,
natural_t messageType, void *messageArgument)
{
SDL_VideoDevice *this = (SDL_VideoDevice *) refcon;
switch (messageType) {
case kIOMessageSystemWillSleep:
IOAllowPowerChange (power_connection, (long) messageArgument);
break;
case kIOMessageCanSystemSleep:
IOAllowPowerChange (power_connection, (long) messageArgument);
break;
case kIOMessageSystemHasPoweredOn:
/* awake */
SDL_PrivateExpose ();
break;
}
}
void
QZ_RegisterForSleepNotifications (_THIS)
{
CFRunLoopSourceRef rls;
IONotificationPortRef thePortRef;
io_object_t notifier;
power_connection =
IORegisterForSystemPower (this, &thePortRef,
QZ_SleepNotificationHandler, &notifier);
if (power_connection == 0)
NSLog
(@"SDL: QZ_SleepNotificationHandler() IORegisterForSystemPower failed.");
rls = IONotificationPortGetRunLoopSource (thePortRef);
CFRunLoopAddSource (CFRunLoopGetCurrent (), rls, kCFRunLoopDefaultMode);
CFRelease (rls);
}
/* Try to map Quartz mouse buttons to SDL's lingo... */
static int
QZ_OtherMouseButtonToSDL (int button)
{
switch (button) {
case 0:
return (SDL_BUTTON_LEFT); /* 1 */
case 1:
return (SDL_BUTTON_RIGHT); /* 3 */
case 2:
return (SDL_BUTTON_MIDDLE); /* 2 */
}
/* >= 3: skip 4 & 5, since those are the SDL mousewheel buttons. */
return (button + 3);
}
void
QZ_PumpEvents (_THIS)
{
static Uint32 screensaverTicks = 0;
Uint32 nowTicks;
int firstMouseEvent;
CGMouseDelta dx, dy;
NSDate *distantPast;
NSEvent *event;
NSRect winRect;
NSAutoreleasePool *pool;
if (!SDL_VideoSurface)
return; /* don't do anything if there's no screen surface. */
/* Update activity every five seconds to prevent screensaver. --ryan. */
nowTicks = SDL_GetTicks ();
if ((nowTicks - screensaverTicks) > 5000) {
UpdateSystemActivity (UsrActivity);
screensaverTicks = nowTicks;
}
pool =[[NSAutoreleasePool alloc] init];
distantPast =[NSDate distantPast];
winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
/* send the first mouse event in absolute coordinates */
firstMouseEvent = 1;
/* accumulate any additional mouse moved events into one SDL mouse event */
dx = 0;
dy = 0;
do {
/* Poll for an event. This will not block */
event =[NSApp nextEventMatchingMask: NSAnyEventMask untilDate: distantPast inMode: NSDefaultRunLoopMode dequeue:YES];
if (event != nil) {
int button;
unsigned int type;
BOOL isInGameWin;
#define DO_MOUSE_DOWN(button) do { \
if ( SDL_GetAppState() & SDL_APPMOUSEFOCUS ) { \
SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0); \
expect_mouse_up |= 1<<button; \
} \
[ NSApp sendEvent:event ]; \
} while(0)
#define DO_MOUSE_UP(button) do { \
if ( expect_mouse_up & (1<<button) ) { \
SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); \
expect_mouse_up &= ~(1<<button); \
} \
[ NSApp sendEvent:event ]; \
} while(0)
type =[event type];
isInGameWin = QZ_IsMouseInWindow (this);
QZ_DoModifiers (this,[event modifierFlags]);
switch (type) {
case NSLeftMouseDown:
if (SDL_getenv ("SDL_HAS3BUTTONMOUSE")) {
DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
} else {
if (NSCommandKeyMask & current_mods) {
last_virtual_button = SDL_BUTTON_RIGHT;
DO_MOUSE_DOWN (SDL_BUTTON_RIGHT);
} else if (NSAlternateKeyMask & current_mods) {
last_virtual_button = SDL_BUTTON_MIDDLE;
DO_MOUSE_DOWN (SDL_BUTTON_MIDDLE);
} else {
DO_MOUSE_DOWN (SDL_BUTTON_LEFT);
}
}
break;
case NSLeftMouseUp:
if (last_virtual_button != 0) {
DO_MOUSE_UP (last_virtual_button);
last_virtual_button = 0;
} else {
DO_MOUSE_UP (SDL_BUTTON_LEFT);
}
break;
case NSOtherMouseDown:
case NSRightMouseDown:
button = QZ_OtherMouseButtonToSDL ([event buttonNumber]);
DO_MOUSE_DOWN (button);
break;
case NSOtherMouseUp:
case NSRightMouseUp:
button = QZ_OtherMouseButtonToSDL ([event buttonNumber]);
DO_MOUSE_UP (button);
break;
case NSSystemDefined:
/*
Future: up to 32 "mouse" buttons can be handled.
if ([event subtype] == 7) {
unsigned int buttons;
buttons = [ event data2 ];
*/
break;
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged: /* usually middle mouse dragged */
case NSMouseMoved:
if (grab_state == QZ_INVISIBLE_GRAB) {
/*
If input is grabbed+hidden, the cursor doesn't move,
so we have to call the lowlevel window server
function. This is less accurate but works OK.
*/
CGMouseDelta dx1, dy1;
CGGetLastMouseDelta (&dx1, &dy1);
dx += dx1;
dy += dy1;
} else if (firstMouseEvent) {
/*
Get the first mouse event in a possible
sequence of mouse moved events. Since we
use absolute coordinates, this serves to
compensate any inaccuracy in deltas, and
provides the first known mouse position,
since everything after this uses deltas
*/
NSPoint p;
QZ_GetMouseLocation (this, &p);
SDL_PrivateMouseMotion (0, 0, p.x, p.y);
firstMouseEvent = 0;
} else {
/*
Get the amount moved since the last drag or move event,
add it on for one big move event at the end.
*/
dx +=[event deltaX];
dy +=[event deltaY];
}
/*
Handle grab input+cursor visible by warping the cursor back
into the game window. This still generates a mouse moved event,
but not as a result of the warp (so it's in the right direction).
*/
if (grab_state == QZ_VISIBLE_GRAB && !isInGameWin) {
NSPoint p;
QZ_GetMouseLocation (this, &p);
if (p.x < 0.0)
p.x = 0.0;
if (p.y < 0.0)
p.y = 0.0;
if (p.x >= winRect.size.width)
p.x = winRect.size.width - 1;
if (p.y >= winRect.size.height)
p.y = winRect.size.height - 1;
QZ_PrivateWarpCursor (this, p.x, p.y);
} else if (!isInGameWin
&& (SDL_GetAppState () & SDL_APPMOUSEFOCUS)) {
SDL_PrivateAppActive (0, SDL_APPMOUSEFOCUS);
if (grab_state == QZ_INVISIBLE_GRAB)
/*The cursor has left the window even though it is
disassociated from the mouse (and therefore
shouldn't move): this can happen with Wacom
tablets, and it effectively breaks the grab, since
mouse down events now go to background
applications. The only possibility to avoid this
seems to be talking to the tablet driver
(AppleEvents) to constrain its mapped area to the
window, which may not be worth the effort. For
now, handle the condition more gracefully than
before by reassociating cursor and mouse until the
cursor enters the window again, making it obvious
to the user that the grab is broken. */
CGAssociateMouseAndMouseCursorPosition (1);
if (!cursor_should_be_visible)
QZ_ShowMouse (this);
} else if (isInGameWin
&& (SDL_GetAppState () &
(SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) ==
SDL_APPINPUTFOCUS) {
SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS);
if (!cursor_should_be_visible)
QZ_HideMouse (this);
if (grab_state == QZ_INVISIBLE_GRAB) { /*see comment above */
QZ_PrivateWarpCursor (this,
SDL_VideoSurface->w /
2, SDL_VideoSurface->h / 2);
CGAssociateMouseAndMouseCursorPosition (0);
}
}
break;
case NSScrollWheel:
if (isInGameWin) {
float dy, dx;
Uint8 button;
dy =[event deltaY];
dx =[event deltaX];
if (dy > 0.0 || dx > 0.0) /* Scroll up */
button = SDL_BUTTON_WHEELUP;
else /* Scroll down */
button = SDL_BUTTON_WHEELDOWN;
/* For now, wheel is sent as a quick down+up */
SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0);
SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0);
}
break;
case NSKeyUp:
QZ_DoKey (this, SDL_RELEASED, event);
break;
case NSKeyDown:
QZ_DoKey (this, SDL_PRESSED, event);
break;
case NSFlagsChanged:
break;
/* case NSAppKitDefined: break; */
/* case NSApplicationDefined: break; */
/* case NSPeriodic: break; */
/* case NSCursorUpdate: break; */
default:
[NSApp sendEvent:event];
}
}
}
while (event != nil);
/* handle accumulated mouse moved events */
if (dx != 0 || dy != 0)
SDL_PrivateMouseMotion (0, 1, dx, dy);
[pool release];
}
void
QZ_UpdateMouse (_THIS)
{
NSPoint p;
QZ_GetMouseLocation (this, &p);
SDL_PrivateAppActive (QZ_IsMouseInWindow (this), SDL_APPMOUSEFOCUS);
SDL_PrivateMouseMotion (0, 0, p.x, p.y);
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_QuartzVideo.h"
/*
* GL_ARB_Multisample is supposed to be available in 10.1, according to Apple:
*
* http://developer.apple.com/opengl/extensions.html#GL_ARB_multisample
*
* ...but it isn't in the system headers, according to Sam:
*
* http://www.libsdl.org/pipermail/sdl/2003-December/058335.html
*
* These are normally enums and not #defines in the system headers.
*
* --ryan.
*/
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1020)
#define NSOpenGLPFASampleBuffers ((NSOpenGLPixelFormatAttribute) 55)
#define NSOpenGLPFASamples ((NSOpenGLPixelFormatAttribute) 56)
#endif
@ implementation NSOpenGLContext (CGLContextAccess)
- (CGLContextObj) cglContext;
{
return _contextAuxiliary;
}
@end
/* OpenGL helper functions (used internally) */
int
QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags)
{
NSOpenGLPixelFormatAttribute attr[32];
NSOpenGLPixelFormat *fmt;
int i = 0;
int colorBits = bpp;
/* if a GL library hasn't been loaded at this point, load the default. */
if (!this->gl_config.driver_loaded) {
if (QZ_GL_LoadLibrary (this, NULL) == -1)
return 0;
}
if (flags & SDL_FULLSCREEN) {
attr[i++] = NSOpenGLPFAFullScreen;
}
/* In windowed mode, the OpenGL pixel depth must match device pixel depth */
else if (colorBits != device_bpp) {
colorBits = device_bpp;
}
attr[i++] = NSOpenGLPFAColorSize;
attr[i++] = colorBits;
attr[i++] = NSOpenGLPFADepthSize;
attr[i++] = this->gl_config.depth_size;
if (this->gl_config.double_buffer) {
attr[i++] = NSOpenGLPFADoubleBuffer;
}
if (this->gl_config.stereo) {
attr[i++] = NSOpenGLPFAStereo;
}
if (this->gl_config.stencil_size != 0) {
attr[i++] = NSOpenGLPFAStencilSize;
attr[i++] = this->gl_config.stencil_size;
}
if ((this->gl_config.accum_red_size +
this->gl_config.accum_green_size +
this->gl_config.accum_blue_size +
this->gl_config.accum_alpha_size) > 0) {
attr[i++] = NSOpenGLPFAAccumSize;
attr[i++] =
this->gl_config.accum_red_size +
this->gl_config.accum_green_size +
this->gl_config.accum_blue_size +
this->gl_config.accum_alpha_size;
}
if (this->gl_config.multisamplebuffers != 0) {
attr[i++] = NSOpenGLPFASampleBuffers;
attr[i++] = this->gl_config.multisamplebuffers;
}
if (this->gl_config.multisamplesamples != 0) {
attr[i++] = NSOpenGLPFASamples;
attr[i++] = this->gl_config.multisamplesamples;
attr[i++] = NSOpenGLPFANoRecovery;
}
if (this->gl_config.accelerated > 0) {
attr[i++] = NSOpenGLPFAAccelerated;
}
attr[i++] = NSOpenGLPFAScreenMask;
attr[i++] = CGDisplayIDToOpenGLDisplayMask (display_id);
attr[i] = 0;
fmt =[[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
if (fmt == nil) {
SDL_SetError ("Failed creating OpenGL pixel format");
return 0;
}
gl_context =[[NSOpenGLContext alloc] initWithFormat: fmt shareContext:nil];
[fmt release];
if (gl_context == nil) {
SDL_SetError ("Failed creating OpenGL context");
return 0;
}
/* Synchronize QZ_GL_SwapBuffers() to vertical retrace.
* (Apple's documentation is not completely clear about what this setting
* exactly does, IMHO - for a detailed explanation see
* http://lists.apple.com/archives/mac-opengl/2006/Jan/msg00080.html )
*/
if (this->gl_config.swap_control >= 0) {
long value;
value = this->gl_config.swap_control;
[gl_context setValues: &value forParameter:NSOpenGLCPSwapInterval];
}
/*
* Wisdom from Apple engineer in reference to UT2003's OpenGL performance:
* "You are blowing a couple of the internal OpenGL function caches. This
* appears to be happening in the VAO case. You can tell OpenGL to up
* the cache size by issuing the following calls right after you create
* the OpenGL context. The default cache size is 16." --ryan.
*/
#ifndef GLI_ARRAY_FUNC_CACHE_MAX
#define GLI_ARRAY_FUNC_CACHE_MAX 284
#endif
#ifndef GLI_SUBMIT_FUNC_CACHE_MAX
#define GLI_SUBMIT_FUNC_CACHE_MAX 280
#endif
{
long cache_max = 64;
CGLContextObj ctx =[gl_context cglContext];
CGLSetParameter (ctx, GLI_SUBMIT_FUNC_CACHE_MAX, &cache_max);
CGLSetParameter (ctx, GLI_ARRAY_FUNC_CACHE_MAX, &cache_max);
}
/* End Wisdom from Apple Engineer section. --ryan. */
return 1;
}
void
QZ_TearDownOpenGL (_THIS)
{
[NSOpenGLContext clearCurrentContext];
[gl_context clearDrawable];
[gl_context release];
}
/* SDL OpenGL functions */
static const char *DEFAULT_OPENGL_LIB_NAME =
"/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib";
int
QZ_GL_LoadLibrary (_THIS, const char *location)
{
if (gl_context != NULL) {
SDL_SetError ("OpenGL context already created");
return -1;
}
if (opengl_library != NULL)
SDL_UnloadObject (opengl_library);
if (location == NULL)
location = DEFAULT_OPENGL_LIB_NAME;
opengl_library = SDL_LoadObject (location);
if (opengl_library != NULL) {
this->gl_config.driver_loaded = 1;
return 0;
}
this->gl_config.driver_loaded = 0;
return -1;
}
void *
QZ_GL_GetProcAddress (_THIS, const char *proc)
{
return SDL_LoadFunction (opengl_library, proc);
}
int
QZ_GL_GetAttribute (_THIS, SDL_GLattr attrib, int *value)
{
GLenum attr = 0;
QZ_GL_MakeCurrent (this);
switch (attrib) {
case SDL_GL_RED_SIZE:
attr = GL_RED_BITS;
break;
case SDL_GL_BLUE_SIZE:
attr = GL_BLUE_BITS;
break;
case SDL_GL_GREEN_SIZE:
attr = GL_GREEN_BITS;
break;
case SDL_GL_ALPHA_SIZE:
attr = GL_ALPHA_BITS;
break;
case SDL_GL_DOUBLEBUFFER:
attr = GL_DOUBLEBUFFER;
break;
case SDL_GL_DEPTH_SIZE:
attr = GL_DEPTH_BITS;
break;
case SDL_GL_STENCIL_SIZE:
attr = GL_STENCIL_BITS;
break;
case SDL_GL_ACCUM_RED_SIZE:
attr = GL_ACCUM_RED_BITS;
break;
case SDL_GL_ACCUM_GREEN_SIZE:
attr = GL_ACCUM_GREEN_BITS;
break;
case SDL_GL_ACCUM_BLUE_SIZE:
attr = GL_ACCUM_BLUE_BITS;
break;
case SDL_GL_ACCUM_ALPHA_SIZE:
attr = GL_ACCUM_ALPHA_BITS;
break;
case SDL_GL_STEREO:
attr = GL_STEREO;
break;
case SDL_GL_MULTISAMPLEBUFFERS:
attr = GL_SAMPLE_BUFFERS_ARB;
break;
case SDL_GL_MULTISAMPLESAMPLES:
attr = GL_SAMPLES_ARB;
break;
case SDL_GL_BUFFER_SIZE:
{
GLint bits = 0;
GLint component;
/* there doesn't seem to be a single flag in OpenGL for this! */
glGetIntegerv (GL_RED_BITS, &component);
bits += component;
glGetIntegerv (GL_GREEN_BITS, &component);
bits += component;
glGetIntegerv (GL_BLUE_BITS, &component);
bits += component;
glGetIntegerv (GL_ALPHA_BITS, &component);
bits += component;
*value = bits;
return 0;
}
case SDL_GL_ACCELERATED_VISUAL:
{
long val;
/* FIXME: How do we get this information here?
[fmt getValues: &val forAttribute: NSOpenGLPFAAccelerated attr forVirtualScreen: 0];
*/
val = (this->gl_config.accelerated != 0);;
*value = val;
return 0;
}
case SDL_GL_SWAP_CONTROL:
{
long val;
[gl_context getValues: &val forParameter:NSOpenGLCPSwapInterval];
*value = val;
return 0;
}
}
glGetIntegerv (attr, (GLint *) value);
return 0;
}
int
QZ_GL_MakeCurrent (_THIS)
{
[gl_context makeCurrentContext];
return 0;
}
void
QZ_GL_SwapBuffers (_THIS)
{
[gl_context flushBuffer];
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/* These are the Macintosh key scancode constants -- from Inside Macintosh */
#define QZ_ESCAPE 0x35
#define QZ_F1 0x7A
#define QZ_F2 0x78
#define QZ_F3 0x63
#define QZ_F4 0x76
#define QZ_F5 0x60
#define QZ_F6 0x61
#define QZ_F7 0x62
#define QZ_F8 0x64
#define QZ_F9 0x65
#define QZ_F10 0x6D
#define QZ_F11 0x67
#define QZ_F12 0x6F
#define QZ_PRINT 0x69
#define QZ_SCROLLOCK 0x6B
#define QZ_PAUSE 0x71
#define QZ_POWER 0x7F
#define QZ_BACKQUOTE 0x32
#define QZ_1 0x12
#define QZ_2 0x13
#define QZ_3 0x14
#define QZ_4 0x15
#define QZ_5 0x17
#define QZ_6 0x16
#define QZ_7 0x1A
#define QZ_8 0x1C
#define QZ_9 0x19
#define QZ_0 0x1D
#define QZ_MINUS 0x1B
#define QZ_EQUALS 0x18
#define QZ_BACKSPACE 0x33
#define QZ_INSERT 0x72
#define QZ_HOME 0x73
#define QZ_PAGEUP 0x74
#define QZ_NUMLOCK 0x47
#define QZ_KP_EQUALS 0x51
#define QZ_KP_DIVIDE 0x4B
#define QZ_KP_MULTIPLY 0x43
#define QZ_TAB 0x30
#define QZ_q 0x0C
#define QZ_w 0x0D
#define QZ_e 0x0E
#define QZ_r 0x0F
#define QZ_t 0x11
#define QZ_y 0x10
#define QZ_u 0x20
#define QZ_i 0x22
#define QZ_o 0x1F
#define QZ_p 0x23
#define QZ_LEFTBRACKET 0x21
#define QZ_RIGHTBRACKET 0x1E
#define QZ_BACKSLASH 0x2A
#define QZ_DELETE 0x75
#define QZ_END 0x77
#define QZ_PAGEDOWN 0x79
#define QZ_KP7 0x59
#define QZ_KP8 0x5B
#define QZ_KP9 0x5C
#define QZ_KP_MINUS 0x4E
#define QZ_CAPSLOCK 0x39
#define QZ_a 0x00
#define QZ_s 0x01
#define QZ_d 0x02
#define QZ_f 0x03
#define QZ_g 0x05
#define QZ_h 0x04
#define QZ_j 0x26
#define QZ_k 0x28
#define QZ_l 0x25
#define QZ_SEMICOLON 0x29
#define QZ_QUOTE 0x27
#define QZ_RETURN 0x24
#define QZ_KP4 0x56
#define QZ_KP5 0x57
#define QZ_KP6 0x58
#define QZ_KP_PLUS 0x45
#define QZ_LSHIFT 0x38
#define QZ_z 0x06
#define QZ_x 0x07
#define QZ_c 0x08
#define QZ_v 0x09
#define QZ_b 0x0B
#define QZ_n 0x2D
#define QZ_m 0x2E
#define QZ_COMMA 0x2B
#define QZ_PERIOD 0x2F
#define QZ_SLASH 0x2C
#if 1 /* Panther now defines right side keys */
#define QZ_RSHIFT 0x3C
#endif
#define QZ_UP 0x7E
#define QZ_KP1 0x53
#define QZ_KP2 0x54
#define QZ_KP3 0x55
#define QZ_KP_ENTER 0x4C
#define QZ_LCTRL 0x3B
#define QZ_LALT 0x3A
#define QZ_LMETA 0x37
#define QZ_SPACE 0x31
#if 1 /* Panther now defines right side keys */
#define QZ_RMETA 0x36
#define QZ_RALT 0x3D
#define QZ_RCTRL 0x3E
#endif
#define QZ_LEFT 0x7B
#define QZ_DOWN 0x7D
#define QZ_RIGHT 0x7C
#define QZ_KP0 0x52
#define QZ_KP_PERIOD 0x41
/* Wierd, these keys are on my iBook under Mac OS X */
#define QZ_IBOOK_ENTER 0x34
#define QZ_IBOOK_LEFT 0x3B
#define QZ_IBOOK_RIGHT 0x3C
#define QZ_IBOOK_DOWN 0x3D
#define QZ_IBOOK_UP 0x3E
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
@file SDL_QuartzVideo.h
@author Darrell Walisser, Max Horn, et al.
@abstract SDL video driver for Mac OS X.
@discussion
TODO
- Hardware Cursor support with NSCursor instead of Carbon
- Keyboard repeat/mouse speed adjust (if needed)
- Multiple monitor support (currently only main display)
- Accelerated blitting support
- Fix white OpenGL window on minimize (fixed) (update: broken again on 10.2)
- Find out what events should be sent/ignored if window is minimized
- Find a way to deal with external resolution/depth switch while app is running
- Check accuracy of QZ_SetGamma()
Problems:
- OGL not working in full screen with software renderer
- SetColors sets palette correctly but clears framebuffer
- Crash in CG after several mode switches (I think this has been fixed)
- Retained windows don't draw their title bar quite right (OS Bug) (not using retained windows)
- Cursor in 8 bit modes is screwy (might just be Radeon PCI bug) (update: not just Radeon)
- Warping cursor delays mouse events for a fraction of a second,
there is a hack around this that helps a bit
*/
/* Needs to be first, so QuickTime.h doesn't include glext.h (10.4) */
#include "SDL_opengl.h"
#include <Cocoa/Cocoa.h>
#include <Carbon/Carbon.h>
#include <QuickTime/QuickTime.h>
#include <OpenGL/CGLTypes.h> /* For CGLContextObj */
#include <IOKit/IOKitLib.h> /* For powersave handling */
#include <pthread.h>
#include "SDL_thread.h"
#include "SDL_video.h"
#include "SDL_error.h"
#include "SDL_timer.h"
#include "SDL_loadso.h"
#include "SDL_syswm.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
/*
This is a workaround to directly access NSOpenGLContext's CGL context
We need this to check for errors NSOpenGLContext doesn't support
*/
@ interface NSOpenGLContext(CGLContextAccess) - (CGLContextObj) cglContext;
@end
/* Main driver structure to store required state information */
typedef struct SDL_PrivateVideoData
{
CGDirectDisplayID
display; /* 0 == main display (only support single display) */
CFDictionaryRef
mode; /* current mode of the display */
CFDictionaryRef
save_mode; /* original mode of the display */
CFArrayRef
mode_list; /* list of available fullscreen modes */
CGDirectPaletteRef
palette; /* palette of an 8-bit display */
NSOpenGLContext *
gl_context; /* OpenGL rendering context */
Uint32
width,
height,
bpp; /* frequently used data about the display */
Uint32
flags; /* flags for current mode, for teardown purposes */
Uint32
video_set; /* boolean; indicates if video was set correctly */
Uint32
warp_flag; /* boolean; notify to event loop that a warp just occured */
Uint32
warp_ticks; /* timestamp when the warp occured */
NSWindow *
window; /* Cocoa window to implement the SDL window */
NSQuickDrawView *
view; /* the window's view; draw 2D and OpenGL into this view */
SDL_Surface *
resize_icon; /* icon for the resize badge, we have to draw it by hand */
SDL_GrabMode
current_grab_mode; /* default value is SDL_GRAB_OFF */
SDL_Rect **
client_mode_list; /* resolution list to pass back to client */
SDLKey
keymap[256]; /* Mac OS X to SDL key mapping */
Uint32
current_mods; /* current keyboard modifiers, to track modifier state */
Uint32
last_virtual_button; /* last virtual mouse button pressed */
io_connect_t
power_connection; /* used with IOKit to detect wake from sleep */
Uint8
expect_mouse_up; /* used to determine when to send mouse up events */
Uint8
grab_state; /* used to manage grab behavior */
NSPoint
cursor_loc; /* saved cursor coords, for activate/deactivate when grabbed */
BOOL
cursor_should_be_visible; /* tells if cursor is supposed to be visible (SDL_ShowCursor) */
BOOL
cursor_visible; /* tells if cursor is *actually* visible or not */
Uint8 *
sw_buffers[2]; /* pointers to the two software buffers for double-buffer emulation */
SDL_Thread *
thread; /* thread for async updates to the screen */
SDL_sem *
sem1, *
sem2; /* synchronization for async screen updates */
Uint8 *
current_buffer; /* the buffer being copied to the screen */
BOOL
quit_thread; /* used to quit the async blitting thread */
SInt32
system_version; /* used to dis-/enable workarounds depending on the system version */
ImageDescriptionHandle
yuv_idh;
MatrixRecordPtr
yuv_matrix;
DecompressorComponent
yuv_codec;
ImageSequence
yuv_seq;
PlanarPixmapInfoYUV420 *
yuv_pixmap;
Sint16
yuv_width,
yuv_height;
CGrafPtr
yuv_port;
void *
opengl_library; /* dynamically loaded OpenGL library. */
} SDL_PrivateVideoData;
#define _THIS SDL_VideoDevice *this
#define display_id (this->hidden->display)
#define mode (this->hidden->mode)
#define save_mode (this->hidden->save_mode)
#define mode_list (this->hidden->mode_list)
#define palette (this->hidden->palette)
#define gl_context (this->hidden->gl_context)
#define device_width (this->hidden->width)
#define device_height (this->hidden->height)
#define device_bpp (this->hidden->bpp)
#define mode_flags (this->hidden->flags)
#define qz_window (this->hidden->window)
#define window_view (this->hidden->view)
#define video_set (this->hidden->video_set)
#define warp_ticks (this->hidden->warp_ticks)
#define warp_flag (this->hidden->warp_flag)
#define resize_icon (this->hidden->resize_icon)
#define current_grab_mode (this->hidden->current_grab_mode)
#define client_mode_list (this->hidden->client_mode_list)
#define keymap (this->hidden->keymap)
#define current_mods (this->hidden->current_mods)
#define last_virtual_button (this->hidden->last_virtual_button)
#define power_connection (this->hidden->power_connection)
#define expect_mouse_up (this->hidden->expect_mouse_up)
#define grab_state (this->hidden->grab_state)
#define cursor_loc (this->hidden->cursor_loc)
#define cursor_should_be_visible (this->hidden->cursor_should_be_visible)
#define cursor_visible (this->hidden->cursor_visible)
#define sw_buffers (this->hidden->sw_buffers)
#define thread (this->hidden->thread)
#define sem1 (this->hidden->sem1)
#define sem2 (this->hidden->sem2)
#define current_buffer (this->hidden->current_buffer)
#define quit_thread (this->hidden->quit_thread)
#define system_version (this->hidden->system_version)
#define opengl_library (this->hidden->opengl_library)
/* grab states - the input is in one of these states */
enum
{
QZ_UNGRABBED = 0,
QZ_VISIBLE_GRAB,
QZ_INVISIBLE_GRAB
};
/* grab actions - these can change the grabbed state */
enum
{
QZ_ENABLE_GRAB = 0,
QZ_DISABLE_GRAB,
QZ_HIDECURSOR,
QZ_SHOWCURSOR
};
/* Gamma Functions */
int
QZ_SetGamma(_THIS, float red, float green, float blue);
int
QZ_GetGamma(_THIS, float *red, float *green, float *blue);
int
QZ_SetGammaRamp(_THIS, Uint16 * ramp);
int
QZ_GetGammaRamp(_THIS, Uint16 * ramp);
/* OpenGL functions */
int
QZ_SetupOpenGL(_THIS, int bpp, Uint32 flags);
void
QZ_TearDownOpenGL(_THIS);
void *
QZ_GL_GetProcAddress(_THIS, const char *proc);
int
QZ_GL_GetAttribute(_THIS, SDL_GLattr attrib, int *value);
int
QZ_GL_MakeCurrent(_THIS);
void
QZ_GL_SwapBuffers(_THIS);
int
QZ_GL_LoadLibrary(_THIS, const char *location);
/* Cursor and Mouse functions */
void
QZ_FreeWMCursor(_THIS, WMcursor * cursor);
WMcursor *
QZ_CreateWMCursor(_THIS, Uint8 * data, Uint8 * mask,
int w, int h, int hot_x, int hot_y);
int
QZ_ShowWMCursor(_THIS, WMcursor * cursor);
void
QZ_WarpWMCursor(_THIS, Uint16 x, Uint16 y);
void
QZ_MoveWMCursor(_THIS, int x, int y);
void
QZ_CheckMouseMode(_THIS);
void
QZ_UpdateMouse(_THIS);
/* Event functions */
void
QZ_InitOSKeymap(_THIS);
void
QZ_PumpEvents(_THIS);
/* Window Manager functions */
void
QZ_SetCaption(_THIS, const char *title, const char *icon);
void
QZ_SetIcon(_THIS, SDL_Surface * icon, Uint8 * mask);
int
QZ_IconifyWindow(_THIS);
SDL_GrabMode
QZ_GrabInput(_THIS, SDL_GrabMode grab_mode);
/*int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info);*/
/* YUV functions */
SDL_Overlay *QZ_CreateYUVOverlay(_THIS, int width, int height,
Uint32 format, SDL_Surface * display);
/* Private functions (used internally) */
void QZ_PrivateWarpCursor(_THIS, int x, int y);
void QZ_ChangeGrabState(_THIS, int action);
void QZ_RegisterForSleepNotifications(_THIS);
void QZ_ShowMouse(_THIS);
void QZ_HideMouse(_THIS);
void QZ_PrivateGlobalToLocal(_THIS, NSPoint * p);
void QZ_PrivateCocoaToSDL(_THIS, NSPoint * p);
BOOL
QZ_IsMouseInWindow(_THIS);
void QZ_DoActivate(_THIS);
void QZ_DoDeactivate(_THIS);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_QuartzVideo.h"
#include "SDL_QuartzWindow.h"
/*
Add methods to get at private members of NSScreen.
Since there is a bug in Apple's screen switching code
that does not update this variable when switching
to fullscreen, we'll set it manually (but only for the
main screen).
*/
@ interface NSScreen (NSScreenAccess) - (void) setFrame:(NSRect) frame;
@end @ implementation NSScreen (NSScreenAccess) - (void) setFrame:(NSRect)
frame;
{
_frame = frame;
}
@end
/*
Structure for rez switch gamma fades
We can hide the monitor flicker by setting the gamma tables to 0
*/
#define QZ_GAMMA_TABLE_SIZE 256
typedef struct
{
CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
} SDL_QuartzGammaTable;
/* Bootstrap functions */
static int QZ_Available ();
static SDL_VideoDevice *QZ_CreateDevice (int device_index);
static void QZ_DeleteDevice (SDL_VideoDevice * device);
/* Initialization, Query, Setup, and Redrawing functions */
static int QZ_VideoInit (_THIS, SDL_PixelFormat * video_format);
static SDL_Rect **QZ_ListModes (_THIS, SDL_PixelFormat * format,
Uint32 flags);
static void QZ_UnsetVideoMode (_THIS, BOOL to_desktop);
static SDL_Surface *QZ_SetVideoMode (_THIS, SDL_Surface * current,
int width, int height, int bpp,
Uint32 flags);
static int QZ_ToggleFullScreen (_THIS, int on);
static int QZ_SetColors (_THIS, int first_color,
int num_colors, SDL_Color * colors);
static int QZ_LockDoubleBuffer (_THIS, SDL_Surface * surface);
static void QZ_UnlockDoubleBuffer (_THIS, SDL_Surface * surface);
static int QZ_ThreadFlip (_THIS);
static int QZ_FlipDoubleBuffer (_THIS, SDL_Surface * surface);
static void QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect * rects);
static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect * rects);
static int QZ_LockWindow (_THIS, SDL_Surface * surface);
static void QZ_UnlockWindow (_THIS, SDL_Surface * surface);
static void QZ_UpdateRects (_THIS, int num_rects, SDL_Rect * rects);
static void QZ_VideoQuit (_THIS);
/* Hardware surface functions (for fullscreen mode only) */
#if 0 /* Not used (apparently, it's really slow) */
static int QZ_FillHWRect (_THIS, SDL_Surface * dst, SDL_Rect * rect,
Uint32 color);
#endif
static int QZ_LockHWSurface (_THIS, SDL_Surface * surface);
static void QZ_UnlockHWSurface (_THIS, SDL_Surface * surface);
static int QZ_AllocHWSurface (_THIS, SDL_Surface * surface);
static void QZ_FreeHWSurface (_THIS, SDL_Surface * surface);
/* static int QZ_FlipHWSurface (_THIS, SDL_Surface *surface); */
/* Bootstrap binding, enables entry point into the driver */
VideoBootStrap QZ_bootstrap = {
"Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice
};
/* Bootstrap functions */
static int
QZ_Available ()
{
return 1;
}
static SDL_VideoDevice *
QZ_CreateDevice (int device_index)
{
#pragma unused (device_index)
SDL_VideoDevice *device;
SDL_PrivateVideoData *hidden;
device = (SDL_VideoDevice *) SDL_malloc (sizeof (*device));
hidden = (SDL_PrivateVideoData *) SDL_malloc (sizeof (*hidden));
if (device == NULL || hidden == NULL)
SDL_OutOfMemory ();
SDL_memset (device, 0, sizeof (*device));
SDL_memset (hidden, 0, sizeof (*hidden));
device->hidden = hidden;
device->VideoInit = QZ_VideoInit;
device->ListModes = QZ_ListModes;
device->SetVideoMode = QZ_SetVideoMode;
device->ToggleFullScreen = QZ_ToggleFullScreen;
device->UpdateMouse = QZ_UpdateMouse;
device->SetColors = QZ_SetColors;
/* device->UpdateRects = QZ_UpdateRects; this is determined by SetVideoMode() */
device->VideoQuit = QZ_VideoQuit;
device->LockHWSurface = QZ_LockHWSurface;
device->UnlockHWSurface = QZ_UnlockHWSurface;
device->AllocHWSurface = QZ_AllocHWSurface;
device->FreeHWSurface = QZ_FreeHWSurface;
/* device->FlipHWSurface = QZ_FlipHWSurface */ ;
device->SetGamma = QZ_SetGamma;
device->GetGamma = QZ_GetGamma;
device->SetGammaRamp = QZ_SetGammaRamp;
device->GetGammaRamp = QZ_GetGammaRamp;
device->GL_GetProcAddress = QZ_GL_GetProcAddress;
device->GL_GetAttribute = QZ_GL_GetAttribute;
device->GL_MakeCurrent = QZ_GL_MakeCurrent;
device->GL_SwapBuffers = QZ_GL_SwapBuffers;
device->GL_LoadLibrary = QZ_GL_LoadLibrary;
device->FreeWMCursor = QZ_FreeWMCursor;
device->CreateWMCursor = QZ_CreateWMCursor;
device->ShowWMCursor = QZ_ShowWMCursor;
device->WarpWMCursor = QZ_WarpWMCursor;
device->MoveWMCursor = QZ_MoveWMCursor;
device->CheckMouseMode = QZ_CheckMouseMode;
device->InitOSKeymap = QZ_InitOSKeymap;
device->PumpEvents = QZ_PumpEvents;
device->SetCaption = QZ_SetCaption;
device->SetIcon = QZ_SetIcon;
device->IconifyWindow = QZ_IconifyWindow;
/*device->GetWMInfo = QZ_GetWMInfo; */
device->GrabInput = QZ_GrabInput;
device->CreateYUVOverlay = QZ_CreateYUVOverlay;
device->free = QZ_DeleteDevice;
return device;
}
static void
QZ_DeleteDevice (SDL_VideoDevice * device)
{
SDL_free (device->hidden);
SDL_free (device);
}
static int
QZ_VideoInit (_THIS, SDL_PixelFormat * video_format)
{
/* Initialize the video settings; this data persists between mode switches */
display_id = kCGDirectMainDisplay;
save_mode = CGDisplayCurrentMode (display_id);
mode_list = CGDisplayAvailableModes (display_id);
palette = CGPaletteCreateDefaultColorPalette ();
/* Gather some information that is useful to know about the display */
CFNumberGetValue (CFDictionaryGetValue
(save_mode, kCGDisplayBitsPerPixel),
kCFNumberSInt32Type, &device_bpp);
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayWidth),
kCFNumberSInt32Type, &device_width);
CFNumberGetValue (CFDictionaryGetValue (save_mode, kCGDisplayHeight),
kCFNumberSInt32Type, &device_height);
/* Determine the current screen size */
this->info.current_w = device_width;
this->info.current_h = device_height;
/* Determine the default screen depth */
video_format->BitsPerPixel = device_bpp;
/* Set misc globals */
current_grab_mode = SDL_GRAB_OFF;
cursor_should_be_visible = YES;
cursor_visible = YES;
current_mods = 0;
if (Gestalt (gestaltSystemVersion, &system_version) != noErr)
system_version = 0;
/* register for sleep notifications so wake from sleep generates SDL_VIDEOEXPOSE */
QZ_RegisterForSleepNotifications (this);
/* Fill in some window manager capabilities */
this->info.wm_available = 1;
return 0;
}
static SDL_Rect **
QZ_ListModes (_THIS, SDL_PixelFormat * format, Uint32 flags)
{
CFIndex num_modes;
CFIndex i;
int list_size = 0;
/* Any windowed mode is acceptable */
if ((flags & SDL_FULLSCREEN) == 0)
return (SDL_Rect **) - 1;
/* Free memory from previous call, if any */
if (client_mode_list != NULL) {
int i;
for (i = 0; client_mode_list[i] != NULL; i++)
SDL_free (client_mode_list[i]);
SDL_free (client_mode_list);
client_mode_list = NULL;
}
num_modes = CFArrayGetCount (mode_list);
/* Build list of modes with the requested bpp */
for (i = 0; i < num_modes; i++) {
CFDictionaryRef onemode;
CFNumberRef number;
int bpp;
onemode = CFArrayGetValueAtIndex (mode_list, i);
number = CFDictionaryGetValue (onemode, kCGDisplayBitsPerPixel);
CFNumberGetValue (number, kCFNumberSInt32Type, &bpp);
if (bpp == format->BitsPerPixel) {
int intvalue;
int hasMode;
int width, height;
number = CFDictionaryGetValue (onemode, kCGDisplayWidth);
CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
width = (Uint16) intvalue;
number = CFDictionaryGetValue (onemode, kCGDisplayHeight);
CFNumberGetValue (number, kCFNumberSInt32Type, &intvalue);
height = (Uint16) intvalue;
/* Check if mode is already in the list */
{
int i;
hasMode = SDL_FALSE;
for (i = 0; i < list_size; i++) {
if (client_mode_list[i]->w == width &&
client_mode_list[i]->h == height) {
hasMode = SDL_TRUE;
break;
}
}
}
/* Grow the list and add mode to the list */
if (!hasMode) {
SDL_Rect *rect;
list_size++;
if (client_mode_list == NULL)
client_mode_list = (SDL_Rect **)
SDL_malloc (sizeof (*client_mode_list) *
(list_size + 1));
else
client_mode_list = (SDL_Rect **)
SDL_realloc (client_mode_list,
sizeof (*client_mode_list) *
(list_size + 1));
rect = (SDL_Rect *)
SDL_malloc (sizeof (**client_mode_list));
if (client_mode_list == NULL || rect == NULL) {
SDL_OutOfMemory ();
return NULL;
}
rect->x = rect->y = 0;
rect->w = width;
rect->h = height;
client_mode_list[list_size - 1] = rect;
client_mode_list[list_size] = NULL;
}
}
}
/* Sort list largest to smallest (by area) */
{
int i, j;
for (i = 0; i < list_size; i++) {
for (j = 0; j < list_size - 1; j++) {
int area1, area2;
area1 = client_mode_list[j]->w * client_mode_list[j]->h;
area2 =
client_mode_list[j + 1]->w * client_mode_list[j + 1]->h;
if (area1 < area2) {
SDL_Rect *tmp = client_mode_list[j];
client_mode_list[j] = client_mode_list[j + 1];
client_mode_list[j + 1] = tmp;
}
}
}
}
return client_mode_list;
}
static SDL_bool
QZ_WindowPosition (_THIS, int *x, int *y)
{
const char *window = getenv ("SDL_VIDEO_WINDOW_POS");
if (window) {
if (sscanf (window, "%d,%d", x, y) == 2) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static void
QZ_UnsetVideoMode (_THIS, BOOL to_desktop)
{
/* Reset values that may change between switches */
this->info.blit_fill = 0;
this->FillHWRect = NULL;
this->UpdateRects = NULL;
this->LockHWSurface = NULL;
this->UnlockHWSurface = NULL;
/* Release fullscreen resources */
if (mode_flags & SDL_FULLSCREEN) {
NSRect screen_rect;
/* Release double buffer stuff */
if (mode_flags & SDL_DOUBLEBUF) {
quit_thread = YES;
SDL_SemPost (sem1);
SDL_WaitThread (thread, NULL);
SDL_DestroySemaphore (sem1);
SDL_DestroySemaphore (sem2);
SDL_free (sw_buffers[0]);
}
/*
Release the OpenGL context
Do this first to avoid trash on the display before fade
*/
if (mode_flags & SDL_INTERNALOPENGL) {
QZ_TearDownOpenGL (this);
CGLSetFullScreen (NULL);
}
if (to_desktop) {
/* Restore original screen resolution/bpp */
CGDisplaySwitchToMode (display_id, save_mode);
CGReleaseAllDisplays ();
ShowMenuBar ();
/*
Reset the main screen's rectangle
See comment in QZ_SetVideoFullscreen for why we do this
*/
screen_rect = NSMakeRect (0, 0, device_width, device_height);
[[NSScreen mainScreen] setFrame:screen_rect];
}
}
/* Release window mode resources */
else {
[qz_window close];
[qz_window release];
qz_window = nil;
window_view = nil;
/* Release the OpenGL context */
if (mode_flags & SDL_INTERNALOPENGL)
QZ_TearDownOpenGL (this);
}
/* Signal successful teardown */
video_set = SDL_FALSE;
}
static SDL_Surface *
QZ_SetVideoFullScreen (_THIS, SDL_Surface * current, int width,
int height, int bpp, Uint32 flags)
{
boolean_t exact_match = 0;
NSRect screen_rect;
CGError error;
CGDisplayFadeReservationToken fade_token =
kCGDisplayFadeReservationInvalidToken;
/* Fade to black to hide resolution-switching flicker (and garbage
that is displayed by a destroyed OpenGL context, if applicable) */
if (CGAcquireDisplayFadeReservation (5, &fade_token) == kCGErrorSuccess) {
CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
}
/* Destroy any previous mode */
if (video_set == SDL_TRUE)
QZ_UnsetVideoMode (this, FALSE);
/* See if requested mode exists */
mode = CGDisplayBestModeForParameters (display_id, bpp, width,
height, &exact_match);
/* Require an exact match to the requested mode */
if (!exact_match) {
SDL_SetError ("Failed to find display resolution: %dx%dx%d", width,
height, bpp);
goto ERR_NO_MATCH;
}
/* Put up the blanking window (a window above all other windows) */
if (getenv ("SDL_SINGLEDISPLAY"))
error = CGDisplayCapture (display_id);
else
error = CGCaptureAllDisplays ();
if (CGDisplayNoErr != error) {
SDL_SetError ("Failed capturing display");
goto ERR_NO_CAPTURE;
}
/* Do the physical switch */
if (CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode)) {
SDL_SetError ("Failed switching display resolution");
goto ERR_NO_SWITCH;
}
current->pixels = (Uint32 *) CGDisplayBaseAddress (display_id);
current->pitch = CGDisplayBytesPerRow (display_id);
current->flags = 0;
current->w = width;
current->h = height;
current->flags |= SDL_FULLSCREEN;
current->flags |= SDL_HWSURFACE;
current->flags |= SDL_PREALLOC;
this->UpdateRects = QZ_DirectUpdate;
this->LockHWSurface = QZ_LockHWSurface;
this->UnlockHWSurface = QZ_UnlockHWSurface;
/* Setup double-buffer emulation */
if (flags & SDL_DOUBLEBUF) {
/*
Setup a software backing store for reasonable results when
double buffering is requested (since a single-buffered hardware
surface looks hideous).
The actual screen blit occurs in a separate thread to allow
other blitting while waiting on the VBL (and hence results in higher framerates).
*/
this->LockHWSurface = NULL;
this->UnlockHWSurface = NULL;
this->UpdateRects = NULL;
current->flags |= (SDL_HWSURFACE | SDL_DOUBLEBUF);
this->UpdateRects = QZ_DoubleBufferUpdate;
this->LockHWSurface = QZ_LockDoubleBuffer;
this->UnlockHWSurface = QZ_UnlockDoubleBuffer;
this->FlipHWSurface = QZ_FlipDoubleBuffer;
current->pixels = SDL_malloc (current->pitch * current->h * 2);
if (current->pixels == NULL) {
SDL_OutOfMemory ();
goto ERR_DOUBLEBUF;
}
sw_buffers[0] = current->pixels;
sw_buffers[1] =
(Uint8 *) current->pixels + current->pitch * current->h;
quit_thread = NO;
sem1 = SDL_CreateSemaphore (0);
sem2 = SDL_CreateSemaphore (1);
thread = SDL_CreateThread ((int (*)(void *)) QZ_ThreadFlip, this);
}
if (CGDisplayCanSetPalette (display_id))
current->flags |= SDL_HWPALETTE;
/* Setup OpenGL for a fullscreen context */
if (flags & SDL_INTERNALOPENGL) {
CGLError err;
CGLContextObj ctx;
if (!QZ_SetupOpenGL (this, bpp, flags)) {
goto ERR_NO_GL;
}
ctx =[gl_context cglContext];
err = CGLSetFullScreen (ctx);
if (err) {
SDL_SetError ("Error setting OpenGL fullscreen: %s",
CGLErrorString (err));
goto ERR_NO_GL;
}
[gl_context makeCurrentContext];
glClear (GL_COLOR_BUFFER_BIT);
[gl_context flushBuffer];
current->flags |= SDL_INTERNALOPENGL;
}
/* If we don't hide menu bar, it will get events and interrupt the program */
HideMenuBar ();
/* Fade in again (asynchronously) */
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
/*
There is a bug in Cocoa where NSScreen doesn't synchronize
with CGDirectDisplay, so the main screen's frame is wrong.
As a result, coordinate translation produces incorrect results.
We can hack around this bug by setting the screen rect
ourselves. This hack should be removed if/when the bug is fixed.
*/
screen_rect = NSMakeRect (0, 0, width, height);
[[NSScreen mainScreen] setFrame:screen_rect];
/* Save the flags to ensure correct tear-down */
mode_flags = current->flags;
/* Set app state, hide cursor if necessary, ... */
QZ_DoActivate (this);
return current;
/* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */
ERR_NO_GL:
ERR_DOUBLEBUF:CGDisplaySwitchToMode (display_id, save_mode);
ERR_NO_SWITCH:CGReleaseAllDisplays ();
ERR_NO_CAPTURE:
ERR_NO_MATCH:if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
return NULL;
}
static SDL_Surface *
QZ_SetVideoWindowed (_THIS, SDL_Surface * current, int width,
int height, int *bpp, Uint32 flags)
{
unsigned int style;
NSRect contentRect;
BOOL isCustom = NO;
int center_window = 1;
int origin_x, origin_y;
CGDisplayFadeReservationToken fade_token =
kCGDisplayFadeReservationInvalidToken;
current->flags = 0;
current->w = width;
current->h = height;
contentRect = NSMakeRect (0, 0, width, height);
/*
Check if we should completely destroy the previous mode
- If it is fullscreen
- If it has different noframe or resizable attribute
- If it is OpenGL (since gl attributes could be different)
- If new mode is OpenGL, but previous mode wasn't
*/
if (video_set == SDL_TRUE) {
if (mode_flags & SDL_FULLSCREEN) {
/* Fade to black to hide resolution-switching flicker (and garbage
that is displayed by a destroyed OpenGL context, if applicable) */
if (CGAcquireDisplayFadeReservation (5, &fade_token) ==
kCGErrorSuccess) {
CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0,
TRUE);
}
QZ_UnsetVideoMode (this, TRUE);
} else if (((mode_flags ^ flags) & (SDL_NOFRAME | SDL_RESIZABLE)) ||
(mode_flags & SDL_INTERNALOPENGL) ||
(flags & SDL_INTERNALOPENGL)) {
QZ_UnsetVideoMode (this, TRUE);
}
}
/* Check for user-specified window and view */
{
char *windowPtrString = getenv ("SDL_NSWindowPointer");
char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer");
if (windowPtrString && viewPtrString) {
/* Release any previous window */
if (qz_window) {
[qz_window release];
qz_window = nil;
}
qz_window = (NSWindow *) atoi (windowPtrString);
window_view = (NSQuickDrawView *) atoi (viewPtrString);
isCustom = YES;
/*
Retain reference to window because we
might release it in QZ_UnsetVideoMode
*/
[qz_window retain];
style =[qz_window styleMask];
/* Check resizability */
if (style & NSResizableWindowMask)
current->flags |= SDL_RESIZABLE;
/* Check frame */
if (style & NSBorderlessWindowMask)
current->flags |= SDL_NOFRAME;
}
}
/* Check if we should recreate the window */
if (qz_window == nil) {
/* Set the window style based on input flags */
if (flags & SDL_NOFRAME) {
style = NSBorderlessWindowMask;
current->flags |= SDL_NOFRAME;
} else {
style = NSTitledWindowMask;
style |= (NSMiniaturizableWindowMask | NSClosableWindowMask);
if (flags & SDL_RESIZABLE) {
style |= NSResizableWindowMask;
current->flags |= SDL_RESIZABLE;
}
}
if (QZ_WindowPosition (this, &origin_x, &origin_y)) {
center_window = 0;
contentRect.origin.x = (float) origin_x;
contentRect.origin.y = (float) origin_y;
}
/* Manually create a window, avoids having a nib file resource */
qz_window =[[SDL_QuartzWindow alloc] initWithContentRect: contentRect styleMask: style backing: NSBackingStoreBuffered defer:NO];
if (qz_window == nil) {
SDL_SetError ("Could not create the Cocoa window");
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5,
kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
return NULL;
}
/*[ qz_window setReleasedWhenClosed:YES ]; */
QZ_SetCaption (this, this->wm_title, this->wm_icon);
[qz_window setAcceptsMouseMovedEvents:YES];
[qz_window setViewsNeedDisplay:NO];
if (center_window) {
[qz_window center];
}
[qz_window setDelegate:
[[[SDL_QuartzWindowDelegate alloc] init] autorelease]];
}
/* We already have a window, just change its size */
else {
if (!isCustom) {
[qz_window setContentSize:contentRect.size];
current->flags |= (SDL_NOFRAME | SDL_RESIZABLE) & mode_flags;
[window_view setFrameSize:contentRect.size];
}
}
/* For OpenGL, we bind the context to a subview */
if (flags & SDL_INTERNALOPENGL) {
if (!QZ_SetupOpenGL (this, *bpp, flags)) {
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5,
kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
return NULL;
}
window_view =[[NSView alloc] initWithFrame:contentRect];
[window_view setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
[[qz_window contentView] addSubview:window_view];
[gl_context setView:window_view];
[window_view release];
[gl_context makeCurrentContext];
[qz_window makeKeyAndOrderFront:nil];
current->flags |= SDL_INTERNALOPENGL;
}
/* For 2D, we set the subview to an NSQuickDrawView */
else {
short qdbpp = 0;
/* Only recreate the view if it doesn't already exist */
if (window_view == nil) {
window_view =[[NSQuickDrawView alloc] initWithFrame:contentRect];
[window_view setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
[[qz_window contentView] addSubview:window_view];
[window_view release];
[qz_window makeKeyAndOrderFront:nil];
}
LockPortBits ([window_view qdPort]);
current->pixels =
GetPixBaseAddr (GetPortPixMap ([window_view qdPort]));
current->pitch =
GetPixRowBytes (GetPortPixMap ([window_view qdPort]));
qdbpp = GetPixDepth (GetPortPixMap ([window_view qdPort]));
UnlockPortBits ([window_view qdPort]);
/* QuickDraw may give a 16-bit shadow surface on 8-bit displays! */
*bpp = qdbpp;
current->flags |= SDL_SWSURFACE;
current->flags |= SDL_PREALLOC;
current->flags |= SDL_ASYNCBLIT;
/*
current->pixels now points to the window's pixels
We want it to point to the *view's* pixels
*/
{
int vOffset =[qz_window frame].size.height -
[window_view frame].size.height -[window_view frame].origin.y;
int hOffset =[window_view frame].origin.x;
current->pixels =
(Uint8 *) current->pixels + (vOffset * current->pitch) +
hOffset * (qdbpp / 8);
}
this->UpdateRects = QZ_UpdateRects;
this->LockHWSurface = QZ_LockWindow;
this->UnlockHWSurface = QZ_UnlockWindow;
}
/* Save flags to ensure correct teardown */
mode_flags = current->flags;
/* Fade in again (asynchronously) if we came from a fullscreen mode and faded to black */
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
return current;
}
static SDL_Surface *
QZ_SetVideoMode (_THIS, SDL_Surface * current, int width,
int height, int bpp, Uint32 flags)
{
current->flags = 0;
current->pixels = NULL;
/* Setup full screen video */
if (flags & SDL_FULLSCREEN) {
current =
QZ_SetVideoFullScreen (this, current, width, height, bpp, flags);
if (current == NULL)
return NULL;
}
/* Setup windowed video */
else {
/* Force bpp to the device's bpp */
bpp = device_bpp;
current =
QZ_SetVideoWindowed (this, current, width, height, &bpp, flags);
if (current == NULL)
return NULL;
}
/* Setup the new pixel format */
{
int amask = 0, rmask = 0, gmask = 0, bmask = 0;
switch (bpp) {
case 16: /* (1)-5-5-5 RGB */
amask = 0;
rmask = 0x7C00;
gmask = 0x03E0;
bmask = 0x001F;
break;
case 24:
SDL_SetError ("24bpp is not available");
return NULL;
case 32: /* (8)-8-8-8 ARGB */
amask = 0x00000000;
rmask = 0x00FF0000;
gmask = 0x0000FF00;
bmask = 0x000000FF;
break;
}
if (!SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, amask)) {
SDL_SetError ("Couldn't reallocate pixel format");
return NULL;
}
}
/* Signal successful completion (used internally) */
video_set = SDL_TRUE;
return current;
}
static int
QZ_ToggleFullScreen (_THIS, int on)
{
return 0;
}
static int
QZ_SetColors (_THIS, int first_color, int num_colors, SDL_Color * colors)
{
CGTableCount index;
CGDeviceColor color;
for (index = first_color; index < first_color + num_colors; index++) {
/* Clamp colors between 0.0 and 1.0 */
color.red = colors->r / 255.0;
color.blue = colors->b / 255.0;
color.green = colors->g / 255.0;
colors++;
CGPaletteSetColorAtIndex (palette, color, index);
}
if (CGDisplayNoErr != CGDisplaySetPalette (display_id, palette))
return 0;
return 1;
}
static int
QZ_LockDoubleBuffer (_THIS, SDL_Surface * surface)
{
return 1;
}
static void
QZ_UnlockDoubleBuffer (_THIS, SDL_Surface * surface)
{
}
/* The VBL delay is based on code by Ian R Ollmann's RezLib <iano@cco.caltech.edu> */
static AbsoluteTime
QZ_SecondsToAbsolute (double seconds)
{
union
{
UInt64 i;
Nanoseconds ns;
} temp;
temp.i = seconds * 1000000000.0;
return NanosecondsToAbsolute (temp.ns);
}
static int
QZ_ThreadFlip (_THIS)
{
Uint8 *src, *dst;
int skip, len, h;
/*
Give this thread the highest scheduling priority possible,
in the hopes that it will immediately run after the VBL delay
*/
{
pthread_t current_thread;
int policy;
struct sched_param param;
current_thread = pthread_self ();
pthread_getschedparam (current_thread, &policy, &param);
policy = SCHED_RR;
param.sched_priority = sched_get_priority_max (policy);
pthread_setschedparam (current_thread, policy, &param);
}
while (1) {
SDL_SemWait (sem1);
if (quit_thread)
return 0;
/*
* We have to add SDL_VideoSurface->offset here, since we might be a
* smaller surface in the center of the framebuffer (you asked for
* a fullscreen resolution smaller than the hardware could supply
* so SDL is centering it in a bigger resolution)...
*/
dst =
(Uint8 *) CGDisplayBaseAddress (display_id) +
SDL_VideoSurface->offset;
src = current_buffer + SDL_VideoSurface->offset;
len = SDL_VideoSurface->w * SDL_VideoSurface->format->BytesPerPixel;
h = SDL_VideoSurface->h;
skip = SDL_VideoSurface->pitch;
/* Wait for the VBL to occur (estimated since we don't have a hardware interrupt) */
{
/* The VBL delay is based on Ian Ollmann's RezLib <iano@cco.caltech.edu> */
double refreshRate;
double linesPerSecond;
double target;
double position;
double adjustment;
AbsoluteTime nextTime;
CFNumberRef refreshRateCFNumber;
refreshRateCFNumber =
CFDictionaryGetValue (mode, kCGDisplayRefreshRate);
if (NULL == refreshRateCFNumber) {
SDL_SetError ("Mode has no refresh rate");
goto ERROR;
}
if (0 ==
CFNumberGetValue (refreshRateCFNumber, kCFNumberDoubleType,
&refreshRate)) {
SDL_SetError ("Error getting refresh rate");
goto ERROR;
}
if (0 == refreshRate) {
SDL_SetError ("Display has no refresh rate, using 60hz");
/* ok, for LCD's we'll emulate a 60hz refresh, which may or may not look right */
refreshRate = 60.0;
}
linesPerSecond = refreshRate * h;
target = h;
/* Figure out the first delay so we start off about right */
position = CGDisplayBeamPosition (display_id);
if (position > target)
position = 0;
adjustment = (target - position) / linesPerSecond;
nextTime =
AddAbsoluteToAbsolute (UpTime (),
QZ_SecondsToAbsolute (adjustment));
MPDelayUntil (&nextTime);
}
/* On error, skip VBL delay */
ERROR:
while (h--) {
SDL_memcpy (dst, src, len);
src += skip;
dst += skip;
}
/* signal flip completion */
SDL_SemPost (sem2);
}
return 0;
}
static int
QZ_FlipDoubleBuffer (_THIS, SDL_Surface * surface)
{
/* wait for previous flip to complete */
SDL_SemWait (sem2);
current_buffer = surface->pixels;
if (surface->pixels == sw_buffers[0])
surface->pixels = sw_buffers[1];
else
surface->pixels = sw_buffers[0];
/* signal worker thread to do the flip */
SDL_SemPost (sem1);
return 0;
}
static void
QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect * rects)
{
/* perform a flip if someone calls updaterects on a doublebuferred surface */
this->FlipHWSurface (this, SDL_VideoSurface);
}
static void
QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect * rects)
{
#pragma unused(this,num_rects,rects)
}
/*
The obscured code is based on work by Matt Slot fprefect@ambrosiasw.com,
who supplied sample code for Carbon.
*/
/*#define TEST_OBSCURED 1*/
#if TEST_OBSCURED
#include "CGS.h"
#endif
static int
QZ_IsWindowObscured (NSWindow * window)
{
#if TEST_OBSCURED
/*
In order to determine if a direct copy to the screen is possible,
we must figure out if there are any windows covering ours (including shadows).
This can be done by querying the window server about the on screen
windows for their screen rectangle and window level.
The procedure used below is puts accuracy before speed; however, it aims to call
the window server the fewest number of times possible to keep things reasonable.
In my testing on a 300mhz G3, this routine typically takes < 2 ms. -DW
Notes:
-Calls into the Window Server involve IPC which is slow.
-Getting a rectangle seems slower than getting the window level
-The window list we get back is in sorted order, top to bottom
-On average, I suspect, most windows above ours are dock icon windows (hence optimization)
-Some windows above ours are always there, and cannot move or obscure us (menu bar)
Bugs:
-no way (yet) to deactivate direct drawing when a window is dragged,
or suddenly obscured, so drawing continues and can produce garbage
We need some kind of locking mechanism on window movement to prevent this
-deactivated normal windows use activated normal
window shadows (slight inaccuraccy)
*/
/* Cache the connection to the window server */
static CGSConnectionID cgsConnection = (CGSConnectionID) - 1;
/* Cache the dock icon windows */
static CGSWindowID dockIcons[kMaxWindows];
static int numCachedDockIcons = 0;
CGSWindowID windows[kMaxWindows];
CGSWindowCount i, count;
CGSWindowLevel winLevel;
CGSRect winRect;
CGSRect contentRect;
int windowNumber;
int firstDockIcon;
int dockIconCacheMiss;
int windowContentOffset;
int obscured = SDL_TRUE;
if ([window isVisible]) {
/*
walk the window list looking for windows over top of
(or casting a shadow on) ours
*/
/*
Get a connection to the window server
Should probably be moved out into SetVideoMode() or InitVideo()
*/
if (cgsConnection == (CGSConnectionID) - 1) {
cgsConnection = (CGSConnectionID) 0;
cgsConnection = _CGSDefaultConnection ();
}
if (cgsConnection) {
if (![window styleMask] & NSBorderlessWindowMask)
windowContentOffset = 22;
else
windowContentOffset = 0;
windowNumber =[window windowNumber];
/* The window list is sorted according to order on the screen */
count = 0;
CGSGetOnScreenWindowList (cgsConnection, 0, kMaxWindows,
windows, &count);
CGSGetScreenRectForWindow (cgsConnection, windowNumber,
&contentRect);
/* adjust rect for window title bar (if present) */
contentRect.origin.y += windowContentOffset;
contentRect.size.height -= windowContentOffset;
firstDockIcon = -1;
dockIconCacheMiss = SDL_FALSE;
/*
The first window is always an empty window with level kCGSWindowLevelTop
so start at index 1
*/
for (i = 1; i < count; i++) {
/* If we reach our window in the list, it cannot be obscured */
if (windows[i] == windowNumber) {
obscured = SDL_FALSE;
break;
} else {
float shadowSide;
float shadowTop;
float shadowBottom;
CGSGetWindowLevel (cgsConnection, windows[i], &winLevel);
if (winLevel == kCGSWindowLevelDockIcon) {
int j;
if (firstDockIcon < 0) {
firstDockIcon = i;
if (numCachedDockIcons > 0) {
for (j = 0; j < numCachedDockIcons; j++) {
if (windows[i] == dockIcons[j])
i++;
else
break;
}
if (j != 0) {
i--;
if (j < numCachedDockIcons) {
dockIconCacheMiss = SDL_TRUE;
}
}
}
}
continue;
} else if (winLevel == kCGSWindowLevelMenuIgnore
/* winLevel == kCGSWindowLevelTop */ ) {
continue; /* cannot obscure window */
} else if (winLevel == kCGSWindowLevelDockMenu ||
winLevel == kCGSWindowLevelMenu) {
shadowSide = 18;
shadowTop = 4;
shadowBottom = 22;
} else if (winLevel == kCGSWindowLevelUtility) {
shadowSide = 8;
shadowTop = 4;
shadowBottom = 12;
} else if (winLevel == kCGSWindowLevelNormal) {
/*
These numbers are for foreground windows,
they are too big (but will work) for background windows
*/
shadowSide = 20;
shadowTop = 10;
shadowBottom = 24;
} else if (winLevel == kCGSWindowLevelDock) {
/* Create dock icon cache */
if (numCachedDockIcons != (i - firstDockIcon)
|| dockIconCacheMiss) {
numCachedDockIcons = i - firstDockIcon;
SDL_memcpy (dockIcons,
&(windows[firstDockIcon]),
numCachedDockIcons *
sizeof (*windows));
}
/* no shadow */
shadowSide = 0;
shadowTop = 0;
shadowBottom = 0;
} else {
/*
kCGSWindowLevelDockLabel,
kCGSWindowLevelDock,
kOther???
*/
/* no shadow */
shadowSide = 0;
shadowTop = 0;
shadowBottom = 0;
}
CGSGetScreenRectForWindow (cgsConnection,
windows[i], &winRect);
winRect.origin.x -= shadowSide;
winRect.origin.y -= shadowTop;
winRect.size.width += shadowSide;
winRect.size.height += shadowBottom;
if (NSIntersectsRect (contentRect, winRect)) {
obscured = SDL_TRUE;
break;
}
} /* window was not our window */
} /* iterate over windows */
}
/* get cgsConnection */
}
/* window is visible */
return obscured;
#else
return SDL_TRUE;
#endif
}
/* Locking functions for the software window buffer */
static int
QZ_LockWindow (_THIS, SDL_Surface * surface)
{
return LockPortBits ([window_view qdPort]);
}
static void
QZ_UnlockWindow (_THIS, SDL_Surface * surface)
{
UnlockPortBits ([window_view qdPort]);
}
/* Resize icon, BMP format */
static const unsigned char QZ_ResizeIcon[] = {
0x42, 0x4d, 0x31, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00,
0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x00,
0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfb, 0x01, 0x00, 0x00, 0x13, 0x0b, 0x00, 0x00, 0x13, 0x0b,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x0b, 0xff, 0xff,
0xff, 0xda, 0xda, 0xda, 0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff, 0xff,
0xff, 0xda, 0xda, 0xda,
0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff, 0xff, 0xff, 0xda, 0xda, 0xda,
0x87, 0x87, 0x87, 0xe8,
0xe8, 0xe8, 0xff, 0xff, 0xff, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xda, 0xda, 0xda, 0x87,
0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff, 0xff, 0xff, 0xda, 0xda, 0xda, 0x87,
0x87, 0x87, 0xe8, 0xe8,
0xe8, 0xff, 0xff, 0xff, 0xda, 0xda, 0xda, 0x87, 0x87, 0x87, 0xff, 0xff,
0xff, 0x0b, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd5, 0xd5, 0xd5, 0x87, 0x87,
0x87, 0xe8, 0xe8, 0xe8,
0xff, 0xff, 0xff, 0xda, 0xda, 0xda, 0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8,
0xff, 0xff, 0xff, 0xda,
0xda, 0xda, 0xff, 0xff, 0xff, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xd7, 0xd7, 0xd7, 0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff,
0xff, 0xff, 0xda, 0xda,
0xda, 0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x0b, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xd7, 0xd7, 0xd7,
0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff, 0xff, 0xff, 0xda, 0xda, 0xda,
0x87, 0x87, 0x87, 0xe8,
0xe8, 0xe8, 0xff, 0xff, 0xff, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd7, 0xd7, 0xd7, 0x87,
0x87, 0x87, 0xe8, 0xe8,
0xe8, 0xff, 0xff, 0xff, 0xdc, 0xdc, 0xdc, 0x87, 0x87, 0x87, 0xff, 0xff,
0xff, 0x0b, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xd9, 0xd9, 0xd9, 0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8,
0xff, 0xff, 0xff, 0xdc,
0xdc, 0xdc, 0xff, 0xff, 0xff, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xdb, 0xdb,
0xdb, 0x87, 0x87, 0x87, 0xe8, 0xe8, 0xe8, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x0b, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdb, 0xdb, 0xdb,
0x87, 0x87, 0x87, 0xe8,
0xe8, 0xe8, 0xff, 0xff, 0xff, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xdc, 0xdc, 0xdc, 0x87, 0x87, 0x87, 0xff, 0xff,
0xff, 0x0b, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xdc,
0xdc, 0xdc, 0xff, 0xff, 0xff, 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x0b
};
static void
QZ_DrawResizeIcon (_THIS, RgnHandle dirtyRegion)
{
/* Check if we should draw the resize icon */
if (SDL_VideoSurface->flags & SDL_RESIZABLE) {
Rect icon;
SetRect (&icon, SDL_VideoSurface->w - 13, SDL_VideoSurface->h - 13,
SDL_VideoSurface->w, SDL_VideoSurface->h);
if (RectInRgn (&icon, dirtyRegion)) {
SDL_Rect icon_rect;
/* Create the icon image */
if (resize_icon == NULL) {
SDL_RWops *rw;
SDL_Surface *tmp;
rw = SDL_RWFromConstMem (QZ_ResizeIcon,
sizeof (QZ_ResizeIcon));
tmp = SDL_LoadBMP_RW (rw, SDL_TRUE);
resize_icon =
SDL_ConvertSurface (tmp, SDL_VideoSurface->format,
SDL_SRCCOLORKEY);
SDL_SetColorKey (resize_icon, SDL_SRCCOLORKEY, 0xFFFFFF);
SDL_FreeSurface (tmp);
}
icon_rect.x = SDL_VideoSurface->w - 13;
icon_rect.y = SDL_VideoSurface->h - 13;
icon_rect.w = 13;
icon_rect.h = 13;
SDL_BlitSurface (resize_icon, NULL, SDL_VideoSurface, &icon_rect);
}
}
}
static void
QZ_UpdateRects (_THIS, int numRects, SDL_Rect * rects)
{
if ([qz_window isMiniaturized]) {
/* Do nothing if miniaturized */
}
else if (!QZ_IsWindowObscured (qz_window)) {
/* Use direct copy to flush contents to the display */
CGrafPtr savePort;
CGrafPtr dstPort, srcPort;
const BitMap *dstBits, *srcBits;
Rect dstRect, srcRect;
Point offset;
int i;
GetPort (&savePort);
dstPort = CreateNewPortForCGDisplayID ((UInt32) display_id);
srcPort =[window_view qdPort];
offset.h = 0;
offset.v = 0;
SetPort (srcPort);
LocalToGlobal (&offset);
SetPort (dstPort);
LockPortBits (dstPort);
LockPortBits (srcPort);
dstBits = GetPortBitMapForCopyBits (dstPort);
srcBits = GetPortBitMapForCopyBits (srcPort);
for (i = 0; i < numRects; i++) {
SetRect (&srcRect, rects[i].x, rects[i].y,
rects[i].x + rects[i].w, rects[i].y + rects[i].h);
SetRect (&dstRect,
rects[i].x + offset.h,
rects[i].y + offset.v,
rects[i].x + rects[i].w + offset.h,
rects[i].y + rects[i].h + offset.v);
CopyBits (srcBits, dstBits, &srcRect, &dstRect, srcCopy, NULL);
}
SetPort (savePort);
} else {
/* Use QDFlushPortBuffer() to flush content to display */
int i;
RgnHandle dirty = NewRgn ();
RgnHandle temp = NewRgn ();
SetEmptyRgn (dirty);
/* Build the region of dirty rectangles */
for (i = 0; i < numRects; i++) {
MacSetRectRgn (temp, rects[i].x, rects[i].y,
rects[i].x + rects[i].w, rects[i].y + rects[i].h);
MacUnionRgn (dirty, temp, dirty);
}
QZ_DrawResizeIcon (this, dirty);
/* Flush the dirty region */
QDFlushPortBuffer ([window_view qdPort], dirty);
DisposeRgn (dirty);
DisposeRgn (temp);
}
}
static void
QZ_VideoQuit (_THIS)
{
CGDisplayFadeReservationToken fade_token =
kCGDisplayFadeReservationInvalidToken;
/* Restore gamma settings */
CGDisplayRestoreColorSyncSettings ();
/* Ensure the cursor will be visible and working when we quit */
CGDisplayShowCursor (display_id);
CGAssociateMouseAndMouseCursorPosition (1);
if (mode_flags & SDL_FULLSCREEN) {
/* Fade to black to hide resolution-switching flicker (and garbage
that is displayed by a destroyed OpenGL context, if applicable) */
if (CGAcquireDisplayFadeReservation (5, &fade_token) ==
kCGErrorSuccess) {
CGDisplayFade (fade_token, 0.3, kCGDisplayBlendNormal,
kCGDisplayBlendSolidColor, 0.0, 0.0, 0.0, TRUE);
}
QZ_UnsetVideoMode (this, TRUE);
if (fade_token != kCGDisplayFadeReservationInvalidToken) {
CGDisplayFade (fade_token, 0.5, kCGDisplayBlendSolidColor,
kCGDisplayBlendNormal, 0.0, 0.0, 0.0, FALSE);
CGReleaseDisplayFadeReservation (fade_token);
}
} else
QZ_UnsetVideoMode (this, TRUE);
CGPaletteRelease (palette);
if (opengl_library) {
SDL_UnloadObject (opengl_library);
opengl_library = NULL;
}
this->gl_config.driver_loaded = 0;
}
#if 0 /* Not used (apparently, it's really slow) */
static int
QZ_FillHWRect (_THIS, SDL_Surface * dst, SDL_Rect * rect, Uint32 color)
{
CGSDisplayHWFill (display_id, rect->x, rect->y, rect->w, rect->h, color);
return 0;
}
#endif
static int
QZ_LockHWSurface (_THIS, SDL_Surface * surface)
{
return 1;
}
static void
QZ_UnlockHWSurface (_THIS, SDL_Surface * surface)
{
}
static int
QZ_AllocHWSurface (_THIS, SDL_Surface * surface)
{
return (-1); /* unallowed (no HWSURFACE support here). */
}
static void
QZ_FreeHWSurface (_THIS, SDL_Surface * surface)
{
}
/*
int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) {
return 0;
}
*/
/* Gamma functions */
int
QZ_SetGamma (_THIS, float red, float green, float blue)
{
const CGGammaValue min = 0.0, max = 1.0;
if (red == 0.0)
red = FLT_MAX;
else
red = 1.0 / red;
if (green == 0.0)
green = FLT_MAX;
else
green = 1.0 / green;
if (blue == 0.0)
blue = FLT_MAX;
else
blue = 1.0 / blue;
if (CGDisplayNoErr == CGSetDisplayTransferByFormula
(display_id, min, max, red, min, max, green, min, max, blue)) {
return 0;
} else {
return -1;
}
}
int
QZ_GetGamma (_THIS, float *red, float *green, float *blue)
{
CGGammaValue dummy;
if (CGDisplayNoErr == CGGetDisplayTransferByFormula
(display_id, &dummy, &dummy, red,
&dummy, &dummy, green, &dummy, &dummy, blue))
return 0;
else
return -1;
}
int
QZ_SetGammaRamp (_THIS, Uint16 * ramp)
{
const CGTableCount tableSize = 255;
CGGammaValue redTable[tableSize];
CGGammaValue greenTable[tableSize];
CGGammaValue blueTable[tableSize];
int i;
/* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
for (i = 0; i < 256; i++)
redTable[i % 256] = ramp[i] / 65535.0;
for (i = 256; i < 512; i++)
greenTable[i % 256] = ramp[i] / 65535.0;
for (i = 512; i < 768; i++)
blueTable[i % 256] = ramp[i] / 65535.0;
if (CGDisplayNoErr == CGSetDisplayTransferByTable
(display_id, tableSize, redTable, greenTable, blueTable))
return 0;
else
return -1;
}
int
QZ_GetGammaRamp (_THIS, Uint16 * ramp)
{
const CGTableCount tableSize = 255;
CGGammaValue redTable[tableSize];
CGGammaValue greenTable[tableSize];
CGGammaValue blueTable[tableSize];
CGTableCount actual;
int i;
if (CGDisplayNoErr != CGGetDisplayTransferByTable
(display_id, tableSize, redTable, greenTable, blueTable, &actual) ||
actual != tableSize)
return -1;
/* Pack tables into one array, with values from 0 to 65535 */
for (i = 0; i < 256; i++)
ramp[i] = redTable[i % 256] * 65535.0;
for (i = 256; i < 512; i++)
ramp[i] = greenTable[i % 256] * 65535.0;
for (i = 512; i < 768; i++)
ramp[i] = blueTable[i % 256] * 65535.0;
return 0;
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_QuartzVideo.h"
struct WMcursor
{
NSCursor *nscursor;
};
void
QZ_FreeWMCursor(_THIS, WMcursor * cursor)
{
if (cursor != NULL) {
[cursor->nscursor release];
free(cursor);
}
}
WMcursor *
QZ_CreateWMCursor(_THIS, Uint8 * data, Uint8 * mask,
int w, int h, int hot_x, int hot_y)
{
WMcursor *cursor;
NSBitmapImageRep *imgrep;
NSImage *img;
unsigned char *planes[5];
int i;
NSAutoreleasePool *pool;
pool =[[NSAutoreleasePool alloc] init];
/* Allocate the cursor memory */
cursor = (WMcursor *) SDL_malloc(sizeof(WMcursor));
if (cursor == NULL)
goto outOfMemory;
/* create the image representation and get the pointers to its storage */
imgrep =[[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: w pixelsHigh: h bitsPerSample: 1 samplesPerPixel: 2 hasAlpha: YES isPlanar: YES colorSpaceName: NSDeviceBlackColorSpace bytesPerRow: (w + 7) / 8 bitsPerPixel:0] autorelease];
if (imgrep == nil)
goto outOfMemory;
[imgrep getBitmapDataPlanes:planes];
/* copy data and mask, extending the mask to all black pixels because the inversion effect doesn't work with Cocoa's alpha-blended cursors */
for (i = 0; i < (w + 7) / 8 * h; i++) {
planes[0][i] = data[i];
planes[1][i] = mask[i] | data[i];
}
/* create image and cursor */
img =[[[NSImage alloc] initWithSize:NSMakeSize(w, h)] autorelease];
if (img == nil)
goto outOfMemory;
[img addRepresentation:imgrep];
if (system_version < 0x1030) { /* on 10.2, cursors must be 16*16 */
if (w > 16 || h > 16) { /* too big: scale it down */
[img setScalesWhenResized:YES];
hot_x = hot_x * 16 / w;
hot_y = hot_y * 16 / h;
} else { /* too small (or just right): extend it (from the bottom left corner, so hot_y must be adjusted) */
hot_y += 16 - h;
}
[img setSize:NSMakeSize(16, 16)];
}
cursor->nscursor =[[NSCursor alloc] initWithImage: img hotSpot:NSMakePoint(hot_x,
hot_y)];
if (cursor->nscursor == nil)
goto outOfMemory;
[pool release];
return (cursor);
outOfMemory:
[pool release];
if (cursor != NULL)
SDL_free(cursor);
SDL_OutOfMemory();
return (NULL);
}
void
QZ_ShowMouse(_THIS)
{
if (!cursor_visible) {
[NSCursor unhide];
cursor_visible = YES;
}
}
void
QZ_HideMouse(_THIS)
{
if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) && cursor_visible) {
[NSCursor hide];
cursor_visible = NO;
}
}
BOOL
QZ_IsMouseInWindow(_THIS)
{
if (qz_window == nil)
return YES; /*fullscreen */
else {
NSPoint p =[qz_window mouseLocationOutsideOfEventStream];
p.y -= 1.0f; /* Apparently y goes from 1 to h, not from 0 to h-1 (i.e. the "location of the mouse" seems to be defined as "the location of the top left corner of the mouse pointer's hot pixel" */
return NSPointInRect(p,[window_view frame]);
}
}
int
QZ_ShowWMCursor(_THIS, WMcursor * cursor)
{
if (cursor == NULL) {
if (cursor_should_be_visible) {
QZ_HideMouse(this);
cursor_should_be_visible = NO;
QZ_ChangeGrabState(this, QZ_HIDECURSOR);
}
} else {
[cursor->nscursor set];
if (!cursor_should_be_visible) {
QZ_ShowMouse(this);
cursor_should_be_visible = YES;
QZ_ChangeGrabState(this, QZ_SHOWCURSOR);
}
}
return 1;
}
/*
Coordinate conversion functions, for convenience
Cocoa sets the origin at the lower left corner of the window/screen
SDL, CoreGraphics/WindowServer, and QuickDraw use the origin at the upper left corner
The routines were written so they could be called before SetVideoMode() has finished;
this might have limited usefulness at the moment, but the extra cost is trivial.
*/
/* Convert Cocoa screen coordinate to Cocoa window coordinate */
void
QZ_PrivateGlobalToLocal(_THIS, NSPoint * p)
{
*p =[qz_window convertScreenToBase:*p];
}
/* Convert Cocoa window coordinate to Cocoa screen coordinate */
void
QZ_PrivateLocalToGlobal(_THIS, NSPoint * p)
{
*p =[qz_window convertBaseToScreen:*p];
}
/* Convert SDL coordinate to Cocoa coordinate */
void
QZ_PrivateSDLToCocoa(_THIS, NSPoint * p)
{
if (CGDisplayIsCaptured(display_id)) { /* capture signals fullscreen */
p->y = CGDisplayPixelsHigh(display_id) - p->y;
} else {
*p =[window_view convertPoint: *p toView:nil];
/* We need a workaround in OpenGL mode */
if (SDL_VideoSurface->flags & SDL_OPENGL) {
p->y =[window_view frame].size.height - p->y;
}
}
}
/* Convert Cocoa coordinate to SDL coordinate */
void
QZ_PrivateCocoaToSDL(_THIS, NSPoint * p)
{
if (CGDisplayIsCaptured(display_id)) { /* capture signals fullscreen */
p->y = CGDisplayPixelsHigh(display_id) - p->y;
} else {
*p =[window_view convertPoint: *p fromView:nil];
/* We need a workaround in OpenGL mode */
if (SDL_VideoSurface != NULL
&& (SDL_VideoSurface->flags & SDL_OPENGL)) {
p->y =[window_view frame].size.height - p->y;
}
}
}
/* Convert SDL coordinate to window server (CoreGraphics) coordinate */
CGPoint
QZ_PrivateSDLToCG(_THIS, NSPoint * p)
{
CGPoint cgp;
if (!CGDisplayIsCaptured(display_id)) { /* not captured => not fullscreen => local coord */
int height;
QZ_PrivateSDLToCocoa(this, p);
QZ_PrivateLocalToGlobal(this, p);
height = CGDisplayPixelsHigh(display_id);
p->y = height - p->y;
}
cgp.x = p->x;
cgp.y = p->y;
return cgp;
}
#if 0 /* Dead code */
/* Convert window server (CoreGraphics) coordinate to SDL coordinate */
void
QZ_PrivateCGToSDL(_THIS, NSPoint * p)
{
if (!CGDisplayIsCaptured(display_id)) { /* not captured => not fullscreen => local coord */
int height;
/* Convert CG Global to Cocoa Global */
height = CGDisplayPixelsHigh(display_id);
p->y = height - p->y;
QZ_PrivateGlobalToLocal(this, p);
QZ_PrivateCocoaToSDL(this, p);
}
}
#endif /* Dead code */
void
QZ_PrivateWarpCursor(_THIS, int x, int y)
{
NSPoint p;
CGPoint cgp;
p = NSMakePoint(x, y);
cgp = QZ_PrivateSDLToCG(this, &p);
/* this is the magic call that fixes cursor "freezing" after warp */
CGSetLocalEventsSuppressionInterval(0.0);
CGWarpMouseCursorPosition(cgp);
}
void
QZ_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
{
/* Only allow warping when in foreground */
if (![NSApp isActive])
return;
/* Do the actual warp */
if (grab_state != QZ_INVISIBLE_GRAB)
QZ_PrivateWarpCursor(this, x, y);
/* Generate the mouse moved event */
SDL_PrivateMouseMotion(0, 0, x, y);
}
void
QZ_MoveWMCursor(_THIS, int x, int y)
{
}
void
QZ_CheckMouseMode(_THIS)
{
}
void
QZ_SetCaption(_THIS, const char *title, const char *icon)
{
if (qz_window != nil) {
NSString *string;
if (title != NULL) {
string =[[NSString alloc] initWithUTF8String:title];
[qz_window setTitle:string];
[string release];
}
if (icon != NULL) {
string =[[NSString alloc] initWithUTF8String:icon];
[qz_window setMiniwindowTitle:string];
[string release];
}
}
}
void
QZ_SetIcon(_THIS, SDL_Surface * icon, Uint8 * mask)
{
NSBitmapImageRep *imgrep;
NSImage *img;
SDL_Surface *mergedSurface;
NSAutoreleasePool *pool;
Uint8 *pixels;
SDL_bool iconSrcAlpha;
Uint8 iconAlphaValue;
int i, j, maskPitch, index;
pool =[[NSAutoreleasePool alloc] init];
imgrep =[[[NSBitmapImageRep alloc] initWithBitmapDataPlanes: NULL pixelsWide: icon->w pixelsHigh: icon->h bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES isPlanar: NO colorSpaceName: NSDeviceRGBColorSpace bytesPerRow: 4 * icon->w bitsPerPixel:32] autorelease];
if (imgrep == nil)
goto freePool;
pixels =[imgrep bitmapData];
SDL_memset(pixels, 0, 4 * icon->w * icon->h); /* make the background, which will survive in colorkeyed areas, completely transparent */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#define BYTEORDER_DEPENDENT_RGBA_MASKS 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
#else
#define BYTEORDER_DEPENDENT_RGBA_MASKS 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
#endif
mergedSurface =
SDL_CreateRGBSurfaceFrom(pixels, icon->w, icon->h, 32, 4 * icon->w,
BYTEORDER_DEPENDENT_RGBA_MASKS);
if (mergedSurface == NULL)
goto freePool;
/* blit, with temporarily cleared SRCALPHA flag because we want to copy, not alpha-blend */
iconSrcAlpha = ((icon->flags & SDL_SRCALPHA) != 0);
iconAlphaValue = icon->format->alpha;
SDL_SetAlpha(icon, 0, 255);
SDL_BlitSurface(icon, NULL, mergedSurface, NULL);
if (iconSrcAlpha)
SDL_SetAlpha(icon, SDL_SRCALPHA, iconAlphaValue);
SDL_FreeSurface(mergedSurface);
/* apply mask, source alpha, and premultiply color values by alpha */
maskPitch = (icon->w + 7) / 8;
for (i = 0; i < icon->h; i++) {
for (j = 0; j < icon->w; j++) {
index = i * 4 * icon->w + j * 4;
if (!(mask[i * maskPitch + j / 8] & (128 >> j % 8))) {
pixels[index + 3] = 0;
} else {
if (iconSrcAlpha) {
if (icon->format->Amask == 0)
pixels[index + 3] = icon->format->alpha;
} else {
pixels[index + 3] = 255;
}
}
if (pixels[index + 3] < 255) {
pixels[index + 0] =
(Uint16) pixels[index + 0] * pixels[index + 3] / 255;
pixels[index + 1] =
(Uint16) pixels[index + 1] * pixels[index + 3] / 255;
pixels[index + 2] =
(Uint16) pixels[index + 2] * pixels[index + 3] / 255;
}
}
}
img =[[[NSImage alloc] initWithSize:NSMakeSize(icon->w,
icon->h)] autorelease];
if (img == nil)
goto freePool;
[img addRepresentation:imgrep];
[NSApp setApplicationIconImage:img];
freePool:
[pool release];
}
int
QZ_IconifyWindow(_THIS)
{
if (![qz_window isMiniaturized]) {
[qz_window miniaturize:nil];
return 1;
} else {
SDL_SetError("window already iconified");
return 0;
}
}
/*
int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) {
info->nsWindowPtr = qz_window;
return 0;
}*/
void
QZ_ChangeGrabState(_THIS, int action)
{
/*
Figure out what the next state should be based on the action.
Ignore actions that can't change the current state.
*/
if (grab_state == QZ_UNGRABBED) {
if (action == QZ_ENABLE_GRAB) {
if (cursor_should_be_visible)
grab_state = QZ_VISIBLE_GRAB;
else
grab_state = QZ_INVISIBLE_GRAB;
}
} else if (grab_state == QZ_VISIBLE_GRAB) {
if (action == QZ_DISABLE_GRAB)
grab_state = QZ_UNGRABBED;
else if (action == QZ_HIDECURSOR)
grab_state = QZ_INVISIBLE_GRAB;
} else {
assert(grab_state == QZ_INVISIBLE_GRAB);
if (action == QZ_DISABLE_GRAB)
grab_state = QZ_UNGRABBED;
else if (action == QZ_SHOWCURSOR)
grab_state = QZ_VISIBLE_GRAB;
}
/* now apply the new state */
if (grab_state == QZ_UNGRABBED) {
CGAssociateMouseAndMouseCursorPosition(1);
} else if (grab_state == QZ_VISIBLE_GRAB) {
CGAssociateMouseAndMouseCursorPosition(1);
} else {
assert(grab_state == QZ_INVISIBLE_GRAB);
QZ_PrivateWarpCursor(this, SDL_VideoSurface->w / 2,
SDL_VideoSurface->h / 2);
CGAssociateMouseAndMouseCursorPosition(0);
}
}
SDL_GrabMode
QZ_GrabInput(_THIS, SDL_GrabMode grab_mode)
{
int doGrab = grab_mode & SDL_GRAB_ON;
/*int fullscreen = grab_mode & SDL_GRAB_FULLSCREEN; */
if (this->screen == NULL) {
SDL_SetError("QZ_GrabInput: screen is NULL");
return SDL_GRAB_OFF;
}
if (!video_set) {
/*SDL_SetError ("QZ_GrabInput: video is not set, grab will take effect on mode switch"); */
current_grab_mode = grab_mode;
return grab_mode; /* Will be set later on mode switch */
}
if (grab_mode != SDL_GRAB_QUERY) {
if (doGrab)
QZ_ChangeGrabState(this, QZ_ENABLE_GRAB);
else
QZ_ChangeGrabState(this, QZ_DISABLE_GRAB);
current_grab_mode = doGrab ? SDL_GRAB_ON : SDL_GRAB_OFF;
}
return current_grab_mode;
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_QuartzVideo.h"
#include "SDL_QuartzWindow.h"
/*
This function makes the *SDL region* of the window 100% opaque.
The genie effect uses the alpha component. Otherwise,
it doesn't seem to matter what value it has.
*/
static void
QZ_SetPortAlphaOpaque ()
{
SDL_Surface *surface = current_video->screen;
int bpp;
bpp = surface->format->BitsPerPixel;
if (bpp == 32) {
Uint32 *pixels = (Uint32 *) surface->pixels;
Uint32 rowPixels = surface->pitch / 4;
Uint32 i, j;
for (i = 0; i < surface->h; i++)
for (j = 0; j < surface->w; j++) {
pixels[(i * rowPixels) + j] |= 0xFF000000;
}
}
}
@implementation SDL_QuartzWindow
/* we override these methods to fix the miniaturize animation/dock icon bug */
- (void) miniaturize:(id) sender {
if (SDL_VideoSurface->flags & SDL_INTERNALOPENGL) {
/*
Future: Grab framebuffer and put into NSImage
[ qz_window setMiniwindowImage:image ];
*/
} else {
/* make the alpha channel opaque so anim won't have holes in it */
QZ_SetPortAlphaOpaque ();
}
/* window is hidden now */
SDL_PrivateAppActive (0, SDL_APPACTIVE);
[super miniaturize:sender];
}
-(void) display {
/*
This method fires just before the window deminaturizes from the Dock.
We'll save the current visible surface, let the window manager redraw any
UI elements, and restore the SDL surface. This way, no expose event
is required, and the deminiaturize works perfectly.
*/
SDL_VideoDevice *this = (SDL_VideoDevice *) current_video;
/* make sure pixels are fully opaque */
if (!(SDL_VideoSurface->flags & SDL_INTERNALOPENGL))
QZ_SetPortAlphaOpaque ();
/* save current visible SDL surface */
[self cacheImageInRect:[window_view frame]];
/* let the window manager redraw controls, border, etc */
[super display];
/* restore visible SDL surface */
[self restoreCachedImage];
/* window is visible again */
SDL_PrivateAppActive (1, SDL_APPACTIVE);
}
-(void) setFrame:(NSRect)
frameRect display:(BOOL) flag
{
/*
If the video surface is NULL, this originated from QZ_SetVideoMode,
so don't send the resize event.
*/
SDL_VideoDevice *this = (SDL_VideoDevice *) current_video;
if (this && SDL_VideoSurface == NULL) {
[super setFrame: frameRect display:flag];
} else if (this && qz_window) {
NSRect newViewFrame;
[super setFrame: frameRect display:flag];
newViewFrame =[window_view frame];
SDL_PrivateResize (newViewFrame.size.width, newViewFrame.size.height);
/* If not OpenGL, we have to update the pixels and pitch */
if (!(SDL_VideoSurface->flags & SDL_INTERNALOPENGL)) {
CGrafPtr thePort =[window_view qdPort];
LockPortBits (thePort);
SDL_VideoSurface->pixels =
GetPixBaseAddr (GetPortPixMap (thePort));
SDL_VideoSurface->pitch =
GetPixRowBytes (GetPortPixMap (thePort));
/*
SDL_VideoSurface->pixels now points to the window's pixels
We want it to point to the *view's* pixels
*/
{
int vOffset =[qz_window frame].size.height -
newViewFrame.size.height - newViewFrame.origin.y;
int hOffset = newViewFrame.origin.x;
SDL_VideoSurface->pixels =
(Uint8 *) SDL_VideoSurface->pixels +
(vOffset * SDL_VideoSurface->pitch) +
hOffset * (device_bpp / 8);
}
UnlockPortBits (thePort);
}
}
}
-(void) appDidHide:(NSNotification *) note {
SDL_PrivateAppActive (0, SDL_APPACTIVE);
}
-(void) appWillUnhide:(NSNotification *) note {
SDL_VideoDevice *this = (SDL_VideoDevice *) current_video;
if (this) {
/* make sure pixels are fully opaque */
if (!(SDL_VideoSurface->flags & SDL_INTERNALOPENGL))
QZ_SetPortAlphaOpaque ();
/* save current visible SDL surface */
[self cacheImageInRect:[window_view frame]];
}
}
-(void) appDidUnhide:(NSNotification *) note {
/* restore cached image, since it may not be current, post expose event too */
[self restoreCachedImage];
/*SDL_PrivateExpose (); */
SDL_PrivateAppActive (1, SDL_APPACTIVE);
}
-(id) initWithContentRect:(NSRect)
contentRect styleMask:(unsigned int)
styleMask backing:(NSBackingStoreType)
backingType defer:(BOOL) flag
{
/* Make our window subclass receive these application notifications */
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector (appDidHide: )name: NSApplicationDidHideNotification object:NSApp];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector (appDidUnhide: )name: NSApplicationDidUnhideNotification object:NSApp];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector (appWillUnhide: )name: NSApplicationWillUnhideNotification object:NSApp];
return[super initWithContentRect: contentRect styleMask: styleMask backing: backingType defer:flag];
}
@end @ implementation SDL_QuartzWindowDelegate - (BOOL) windowShouldClose:(id) sender
{
SDL_PrivateQuit ();
return NO;
}
-(void) windowDidBecomeKey:(NSNotification *) aNotification {
QZ_DoActivate (current_video);
}
-(void) windowDidResignKey:(NSNotification *) aNotification {
QZ_DoDeactivate (current_video);
}
@end
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2003 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
#include "SDL_QuartzVideo.h"
#include "SDL_QuartzWindow.h"
#include "../SDL_yuvfuncs.h"
#define yuv_idh (this->hidden->yuv_idh)
#define yuv_matrix (this->hidden->yuv_matrix)
#define yuv_codec (this->hidden->yuv_codec)
#define yuv_seq (this->hidden->yuv_seq)
#define yuv_pixmap (this->hidden->yuv_pixmap)
#define yuv_data (this->hidden->yuv_data)
#define yuv_width (this->hidden->yuv_width)
#define yuv_height (this->hidden->yuv_height)
#define yuv_port (this->hidden->yuv_port)
static int
QZ_LockYUV (_THIS, SDL_Overlay * overlay)
{
return 0;
}
static void
QZ_UnlockYUV (_THIS, SDL_Overlay * overlay)
{
;
}
static int
QZ_DisplayYUV (_THIS, SDL_Overlay * overlay, SDL_Rect * src, SDL_Rect * dst)
{
OSErr err;
CodecFlags flags;
if (dst->x != 0 || dst->y != 0) {
SDL_SetError ("Need a dst at (0,0)");
return -1;
}
if (dst->w != yuv_width || dst->h != yuv_height) {
Fixed scale_x, scale_y;
scale_x = FixDiv (Long2Fix (dst->w), Long2Fix (overlay->w));
scale_y = FixDiv (Long2Fix (dst->h), Long2Fix (overlay->h));
SetIdentityMatrix (yuv_matrix);
ScaleMatrix (yuv_matrix, scale_x, scale_y, Long2Fix (0),
Long2Fix (0));
SetDSequenceMatrix (yuv_seq, yuv_matrix);
yuv_width = dst->w;
yuv_height = dst->h;
}
if ((err = DecompressSequenceFrameS (yuv_seq,
(void *) yuv_pixmap,
sizeof (PlanarPixmapInfoYUV420),
codecFlagUseImageBuffer, &flags,
nil) != noErr)) {
SDL_SetError ("DecompressSequenceFrameS failed");
}
return err != noErr;
}
static void
QZ_FreeHWYUV (_THIS, SDL_Overlay * overlay)
{
CDSequenceEnd (yuv_seq);
ExitMovies ();
SDL_free (overlay->hwfuncs);
SDL_free (overlay->pitches);
SDL_free (overlay->pixels);
if (SDL_VideoSurface->flags & SDL_FULLSCREEN) {
[qz_window close];
qz_window = nil;
}
SDL_free (yuv_matrix);
DisposeHandle ((Handle) yuv_idh);
}
/* check for 16 byte alignment, bail otherwise */
#define CHECK_ALIGN(x) do { if ((Uint32)x & 15) { SDL_SetError("Alignment error"); return NULL; } } while(0)
/* align a byte offset, return how much to add to make it a multiple of 16 */
#define ALIGN(x) ((16 - (x & 15)) & 15)
SDL_Overlay *
QZ_CreateYUVOverlay (_THIS, int width, int height,
Uint32 format, SDL_Surface * display)
{
Uint32 codec;
OSStatus err;
CGrafPtr port;
SDL_Overlay *overlay;
if (format == SDL_YV12_OVERLAY || format == SDL_IYUV_OVERLAY) {
codec = kYUV420CodecType;
} else {
SDL_SetError ("Hardware: unsupported video format");
return NULL;
}
yuv_idh =
(ImageDescriptionHandle) NewHandleClear (sizeof (ImageDescription));
if (yuv_idh == NULL) {
SDL_OutOfMemory ();
return NULL;
}
yuv_matrix = (MatrixRecordPtr) SDL_malloc (sizeof (MatrixRecord));
if (yuv_matrix == NULL) {
SDL_OutOfMemory ();
return NULL;
}
if (EnterMovies () != noErr) {
SDL_SetError ("Could not init QuickTime for YUV playback");
return NULL;
}
err = FindCodec (codec, bestSpeedCodec, nil, &yuv_codec);
if (err != noErr) {
SDL_SetError ("Could not find QuickTime codec for format");
return NULL;
}
if (SDL_VideoSurface->flags & SDL_FULLSCREEN) {
/*
Acceleration requires a window to be present.
A CGrafPtr that points to the screen isn't good enough
*/
NSRect content =
NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
qz_window =[[SDL_QuartzWindow alloc] initWithContentRect: content styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer:NO];
if (qz_window == nil) {
SDL_SetError ("Could not create the Cocoa window");
return NULL;
}
[qz_window setContentView:[[NSQuickDrawView alloc] init]];
[qz_window setReleasedWhenClosed:YES];
[qz_window center];
[qz_window setAcceptsMouseMovedEvents:YES];
[qz_window setLevel:CGShieldingWindowLevel ()];
[qz_window makeKeyAndOrderFront:nil];
port =[[qz_window contentView] qdPort];
SetPort (port);
/*
BUG: would like to remove white flash when window kicks in
{
Rect r;
SetRect (&r, 0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h);
PaintRect (&r);
QDFlushPortBuffer (port, nil);
}
*/
} else {
port =[window_view qdPort];
SetPort (port);
}
SetIdentityMatrix (yuv_matrix);
HLock ((Handle) yuv_idh);
(**yuv_idh).idSize = sizeof (ImageDescription);
(**yuv_idh).cType = codec;
(**yuv_idh).version = 1;
(**yuv_idh).revisionLevel = 0;
(**yuv_idh).width = width;
(**yuv_idh).height = height;
(**yuv_idh).hRes = Long2Fix (72);
(**yuv_idh).vRes = Long2Fix (72);
(**yuv_idh).spatialQuality = codecLosslessQuality;
(**yuv_idh).frameCount = 1;
(**yuv_idh).clutID = -1;
(**yuv_idh).dataSize = 0;
(**yuv_idh).depth = 24;
HUnlock ((Handle) yuv_idh);
err = DecompressSequenceBeginS (&yuv_seq,
yuv_idh,
NULL,
0,
port,
NULL,
NULL,
yuv_matrix,
0,
NULL,
codecFlagUseImageBuffer,
codecLosslessQuality, yuv_codec);
if (err != noErr) {
SDL_SetError ("Error trying to start YUV codec.");
return NULL;
}
overlay = (SDL_Overlay *) SDL_malloc (sizeof (*overlay));
if (overlay == NULL) {
SDL_OutOfMemory ();
return NULL;
}
overlay->format = format;
overlay->w = width;
overlay->h = height;
overlay->planes = 3;
overlay->hw_overlay = 1;
{
int offset;
Uint8 **pixels;
Uint16 *pitches;
int plane2, plane3;
if (format == SDL_IYUV_OVERLAY) {
plane2 = 1; /* Native codec format */
plane3 = 2;
} else if (format == SDL_YV12_OVERLAY) {
/* switch the U and V planes */
plane2 = 2; /* U plane maps to plane 3 */
plane3 = 1; /* V plane maps to plane 2 */
} else {
SDL_SetError ("Unsupported YUV format");
return NULL;
}
pixels = (Uint8 **) SDL_malloc (sizeof (*pixels) * 3);
pitches = (Uint16 *) SDL_malloc (sizeof (*pitches) * 3);
if (pixels == NULL || pitches == NULL) {
SDL_OutOfMemory ();
return NULL;
}
yuv_pixmap = (PlanarPixmapInfoYUV420 *)
SDL_malloc (sizeof (PlanarPixmapInfoYUV420) +
(width * height * 2));
if (yuv_pixmap == NULL) {
SDL_OutOfMemory ();
return NULL;
}
/* CHECK_ALIGN(yuv_pixmap); */
offset = sizeof (PlanarPixmapInfoYUV420);
/* offset += ALIGN(offset); */
/* CHECK_ALIGN(offset); */
pixels[0] = (Uint8 *) yuv_pixmap + offset;
/* CHECK_ALIGN(pixels[0]); */
pitches[0] = width;
yuv_pixmap->componentInfoY.offset = offset;
yuv_pixmap->componentInfoY.rowBytes = width;
offset += width * height;
pixels[plane2] = (Uint8 *) yuv_pixmap + offset;
pitches[plane2] = width / 2;
yuv_pixmap->componentInfoCb.offset = offset;
yuv_pixmap->componentInfoCb.rowBytes = width / 2;
offset += (width * height / 4);
pixels[plane3] = (Uint8 *) yuv_pixmap + offset;
pitches[plane3] = width / 2;
yuv_pixmap->componentInfoCr.offset = offset;
yuv_pixmap->componentInfoCr.rowBytes = width / 2;
overlay->pixels = pixels;
overlay->pitches = pitches;
}
overlay->hwfuncs = SDL_malloc (sizeof (*overlay->hwfuncs));
if (overlay->hwfuncs == NULL) {
SDL_OutOfMemory ();
return NULL;
}
overlay->hwfuncs->Lock = QZ_LockYUV;
overlay->hwfuncs->Unlock = QZ_UnlockYUV;
overlay->hwfuncs->Display = QZ_DisplayYUV;
overlay->hwfuncs->FreeHW = QZ_FreeHWYUV;
yuv_width = overlay->w;
yuv_height = overlay->h;
return overlay;
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <math.h>
#include "SDL.h" #include "SDL.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment