diff options
Diffstat (limited to 'distrib/sdl-1.2.12/src/video/quartz')
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/CGS.h | 84 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzEvents.m | 984 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzGL.m | 281 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzKeys.h | 146 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.h | 237 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.m | 1691 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.h | 28 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.m | 574 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.h | 43 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.m | 232 | ||||
-rw-r--r-- | distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzYUV.m | 330 |
11 files changed, 4630 insertions, 0 deletions
diff --git a/distrib/sdl-1.2.12/src/video/quartz/CGS.h b/distrib/sdl-1.2.12/src/video/quartz/CGS.h new file mode 100644 index 0000000..234ff77 --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/CGS.h @@ -0,0 +1,84 @@ +/* + 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); + diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzEvents.m b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzEvents.m new file mode 100644 index 0000000..6f7f7cb --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzEvents.m @@ -0,0 +1,984 @@ +/* + 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_QuartzWM.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_F13] = SDLK_F13; + keymap[QZ_F14] = SDLK_F14; + keymap[QZ_F15] = SDLK_F15; +/* + 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 i, numChars, clearChars = 0; + 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. + */ + if (SDL_TranslateUNICODE && state == SDL_PRESSED) { + [field_edit interpretKeyEvents:[NSArray arrayWithObject:event]]; + chars = [ event characters ]; + numChars = [ chars length ]; + clearChars = 1; + } else { + numChars = 0; + } + + if (numChars == 0) { + + key.scancode = [ event keyCode ]; + key.sym = keymap [ key.scancode ]; + key.unicode = 0; + key.mod = KMOD_NONE; + + SDL_PrivateKeyboard (state, &key); + } + else 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); + + for (i = 1; i < numChars; i++) { + + key.scancode = 0; + key.sym = 0; + key.unicode = [ chars characterAtIndex:i]; + key.mod = KMOD_NONE; + + SDL_PrivateKeyboard (state, &key); + } + } + if (clearChars) { + [field_edit setString:@""]; + } + + 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)); + + QZ_UpdateCursor(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); + + QZ_UpdateCursor(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, ¬ifier); + + 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; + 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. */ + if (!allow_screensaver) { + 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); + + /* while grabbed, accumulate all 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 { + + /* + Get the absolute mouse location. This is not the + mouse location after the currently processed event, + but the *current* mouse location, i.e. after all + pending events. This means that if there are + multiple mouse moved events in the queue, we make + multiple identical calls to SDL_PrivateMouseMotion(), + but that's no problem since the latter only + generates SDL events for nonzero movements. In my + experience on PBG4/10.4.8, this rarely happens anyway. + */ + NSPoint p; + QZ_GetMouseLocation (this, &p); + SDL_PrivateMouseMotion (0, 0, p.x, p.y); + } + + /* + 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); + + QZ_UpdateCursor(this); + } + else + if ( isInGameWin && (SDL_GetAppState() & (SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS)) == SDL_APPINPUTFOCUS ) { + + SDL_PrivateAppActive (1, SDL_APPMOUSEFOCUS); + + QZ_UpdateCursor(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: + [ NSApp sendEvent:event ]; + if ([ event subtype ] == NSApplicationActivatedEventType && (mode_flags & SDL_FULLSCREEN)) { + /* the default handling of this event seems to reset any cursor set by [NSCursor set] (used by SDL_SetCursor() in fullscreen mode) to the default system arrow cursor */ + SDL_Cursor *sdlc = SDL_GetCursor(); + if (sdlc != NULL && sdlc->wm_cursor != NULL) { + [ sdlc->wm_cursor->nscursor set ]; + } + } + 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); +} diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzGL.m b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzGL.m new file mode 100644 index 0000000..ef44745 --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzGL.m @@ -0,0 +1,281 @@ +/* + 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 ]; +} diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzKeys.h b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzKeys.h new file mode 100644 index 0000000..8b1c13b --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzKeys.h @@ -0,0 +1,146 @@ +/* + 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_F13 0x69 +#define QZ_F14 0x6B +#define QZ_F15 0x71 +/* +#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 diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.h b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.h new file mode 100644 index 0000000..404803d --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.h @@ -0,0 +1,237 @@ +/* + 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/OpenGL.h> /* For CGL functions and types */ +#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 { + + BOOL allow_screensaver; /* 0 == disable screensaver */ + 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 */ + NSText *field_edit; /* a field editor for keyboard composition processing */ + 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 allow_screensaver (this->hidden->allow_screensaver) +#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 field_edit (this->hidden->field_edit) +#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); +void QZ_SetWindowPos (_THIS, int x, int y); +void QZ_GetWindowPos (_THIS, int *px, int *py); +int QZ_IsWindowVisible (_THIS, int recenter); +int QZ_GetMonitorDPI (_THIS, int *xDpi, int *yDpi); +int QZ_GetMonitorRect (_THIS, SDL_Rect *rect); + +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_PrivateGlobalToLocal (_THIS, NSPoint *p); +void QZ_PrivateCocoaToSDL (_THIS, NSPoint *p); +BOOL QZ_IsMouseInWindow (_THIS); +void QZ_DoActivate (_THIS); +void QZ_DoDeactivate (_THIS); diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.m b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.m new file mode 100644 index 0000000..5edd60b --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzVideo.m @@ -0,0 +1,1691 @@ +/* + 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_QuartzWM.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 + + +/* 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->SetWindowPos = QZ_SetWindowPos; + device->GetWindowPos = QZ_GetWindowPos; + device->IsWindowVisible = QZ_IsWindowVisible; + device->GetMonitorDPI = QZ_GetMonitorDPI; + device->GetMonitorRect = QZ_GetMonitorRect; + 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) { + + NSRect r = NSMakeRect(0.0, 0.0, 0.0, 0.0); + const char *env = NULL; + + /* 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 (); + + env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER"); + allow_screensaver = ( env && SDL_atoi(env) ) ? YES : NO; + + /* 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; + field_edit = [[NSTextView alloc] initWithFrame:r]; + + 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]); + } + + /* If we still have a valid window, close it. */ + if ( qz_window ) { + [ qz_window close ]; + [ qz_window release ]; + qz_window = nil; + window_view = nil; + } + /* + Release the OpenGL context + Do this first to avoid trash on the display before fade + */ + if ( mode_flags & SDL_OPENGL ) { + + QZ_TearDownOpenGL (this); + CGLSetFullScreen (NULL); + } + if (to_desktop) { + ShowMenuBar (); + /* Restore original screen resolution/bpp */ + CGDisplaySwitchToMode (display_id, save_mode); + CGReleaseAllDisplays (); + /* + 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_OPENGL ) + 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; + NSRect contentRect; + BOOL isCustom = NO; + 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; + + /* The code below checks for any valid custom windows and views. If none are + available, then we create new ones. Window/View code was added in FULLSCREEN + so that special events like the changing of the cursor image would be handled + ( only the front-most and active application can change the cursor appearance + and with no valid window/view in FULLSCREEN, SDL wouldn't update its cursor. ) + */ + /* Check for user-specified window and view */ + { + char *windowPtrString = getenv ("SDL_NSWindowPointer"); + char *viewPtrString = getenv ("SDL_NSQuickDrawViewPointer"); + + contentRect = NSMakeRect (0, 0, width, height); + + 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 ]; + } + } + /* Check if we should recreate the window */ + if (qz_window == nil) { + /* Manually create a window, avoids having a nib file resource */ + qz_window = [ [ SDL_QuartzWindow alloc ] + initWithContentRect:contentRect + styleMask:nil + backing:NSBackingStoreBuffered + defer:NO ]; + + if (qz_window != nil) { + [ qz_window setAcceptsMouseMovedEvents:YES ]; + [ qz_window setViewsNeedDisplay:NO ]; + } + } + /* 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 ]; + } + } + + /* Setup OpenGL for a fullscreen context */ + if (flags & SDL_OPENGL) { + + CGLError err; + CGLContextObj ctx; + + if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { + goto ERR_NO_GL; + } + + /* Initialize the NSView and add it to our window. The presence of a valid window and + view allow the cursor to be changed whilst in fullscreen.*/ + window_view = [ [ NSView alloc ] initWithFrame:contentRect ]; + [ [ qz_window contentView ] addSubview:window_view ]; + [ window_view release ]; + + 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_OPENGL; + } + + /* 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_OPENGL) || + (flags & SDL_OPENGL) ) { + 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; + } + } + /* 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 ( QZ_WindowPosition(this, &origin_x, &origin_y) ) { + [ qz_window setFrameTopLeftPoint:NSMakePoint(origin_x,this->info.current_h - origin_y) ]; + } else { + [ qz_window center ]; + } + [ qz_window setDelegate: + [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; + [ qz_window setContentView: [ [ [ SDL_QuartzView 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_OPENGL ) { + + 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_OPENGL; + } + /* For 2D, we set the subview to an NSQuickDrawView */ + else { + short qdbpp = 0; + CGrafPtr qdport; + + /* 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 ]; + } + + qdport = [ window_view qdPort ]; + + LockPortBits ( qdport ); + current->pixels = GetPixBaseAddr ( GetPortPixMap ( qdport ) ); + current->pitch = GetPixRowBytes ( GetPortPixMap ( qdport ) ); + qdbpp = GetPixDepth ( GetPortPixMap ( qdport ) ); + UnlockPortBits ( 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 + */ + { + NSRect winFrame = [ qz_window frame ]; + NSRect viewFrame = [ window_view frame ]; + + int vOffset = winFrame.size.height - viewFrame.size.height - viewFrame.origin.y; + int hOffset = viewFrame.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, ¶m); + policy = SCHED_RR; + param.sched_priority = sched_get_priority_max (policy); + pthread_setschedparam (current_thread, policy, ¶m); + } + + 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) { +#if 1 + return LockPortBits( [ window_view qdPort ] ); +#else + CGrafPtr qdport = [ window_view qdPort ]; + int result = LockPortBits ( qdport ); + + if ( !result ) { + Uint8* pixels = GetPixBaseAddr ( GetPortPixMap ( qdport ) ); + NSRect viewFrame = [ window_view frame ]; + NSRect winFrame = [ qz_window frame ]; + int vOffset = winFrame.size.height - viewFrame.size.height - viewFrame.origin.y; + int hOffset = viewFrame.origin.x; + + pixels = pixels + (vOffset * surface->pitch) + hOffset *4; + + if ( surface->pixels != pixels ) { + fprintf(stderr,"XXX: surface->pixels is %p, should be %p\n", surface->pixels, pixels); + } + } else { + fprintf(stderr, "XXX: could not lock port %p for surface %p\n", qdport, surface); + } + return result; +#endif +} + +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 (SDL_VideoSurface->flags & SDL_OPENGLBLIT) { + QZ_GL_SwapBuffers (this); + } + else 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 (field_edit) { + [field_edit release]; + field_edit = NULL; + } +} + +#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; +} + diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.h b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.h new file mode 100644 index 0000000..755607b --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.h @@ -0,0 +1,28 @@ +/* + 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 +*/ + +struct WMcursor { + NSCursor *nscursor; +}; + +void QZ_UpdateCursor(_THIS); +int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info); diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.m b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.m new file mode 100644 index 0000000..334234a --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWM.m @@ -0,0 +1,574 @@ +/* + 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_QuartzWM.h" + +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_UpdateCursor (_THIS) { + BOOL state; + + if (cursor_should_be_visible || !(SDL_GetAppState() & SDL_APPMOUSEFOCUS)) { + state = YES; + } else { + state = NO; + } + if (state != cursor_visible) { + if (state) { + [ NSCursor unhide ]; + } else { + [ NSCursor hide ]; + } + cursor_visible = state; + } +} + +BOOL QZ_IsMouseInWindow (_THIS) { + if (qz_window == nil || (mode_flags & SDL_FULLSCREEN)) 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 ) { + cursor_should_be_visible = NO; + QZ_ChangeGrabState (this, QZ_HIDECURSOR); + } + QZ_UpdateCursor(this); + } + else { + if (qz_window ==nil || (mode_flags & SDL_FULLSCREEN)) { + [ cursor->nscursor set ]; + } + else { + [ qz_window invalidateCursorRectsForView: [ qz_window contentView ] ]; + } + if ( ! cursor_should_be_visible ) { + cursor_should_be_visible = YES; + QZ_ChangeGrabState (this, QZ_SHOWCURSOR); + } + QZ_UpdateCursor(this); + } + + 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_SetWindowPos (_THIS, int x, int y) +{ + if ( qz_window == nil ) { + //printf( "%s(%d,%d): called for NULL window\n", __FUNCTION__, x, y ); + return; + } + + [ qz_window setFrameTopLeftPoint:NSMakePoint( x, this->hidden->height - y ) ]; + //printf( "%s(%d,%d): done\n", __FUNCTION__, x, y ); +} + +void QZ_GetWindowPos(_THIS, int *px, int *py) +{ + NSPoint pt; + + *px = *py = 0; + + if ( qz_window == NULL ) { + //printf( "%s: called on NULL window\n", __FUNCTION__ ); + } + + if ( qz_window != nil ) { + NSRect rect = [ qz_window frame ]; + *px = rect.origin.x; + *py = this->hidden->height - rect.origin.y - rect.size.height; + //printf( "%s: returning (%d,%d)\n", __FUNCTION__, *px, *py ); + } +} + +/* determine if the window is fully visible on the current screen configuration */ +int QZ_IsWindowVisible(_THIS, int recenter) +{ + int result = 0; + + //printf( "... enter %s\n", __FUNCTION__ ); + + if ( qz_window != NULL ) { + NSRect frame = [ qz_window frame ]; + NSArray* screens = [ NSScreen screens ]; + unsigned int count = [ screens count ]; + unsigned int n; + //printf( "window frame (%d,%d) (%d,%d)\n", frame.origin.x, frame.origin.y, + // frame.size.width, frame.size.height ); + for (n = 0; n < count; n++) { + NSScreen* screen = [ screens objectAtIndex: n ]; + NSRect vis = [ screen visibleFrame ]; + + //printf( "screen %d/%d frame (%d,%d) (%d,%d)\n", n+1, count, + // vis.origin.x, vis.origin.y, vis.size.width, vis.size.height ); + + if (frame.origin.x >= vis.origin.x && + frame.origin.x + frame.size.width <= vis.origin.x + vis.size.width && + frame.origin.y >= vis.origin.y && + frame.origin.y + frame.size.height <= vis.origin.y + vis.size.height ) + { + result = 1; + break; + } + } + } + //printf ( "... exit %s, result = %d\n", __FUNCTION__, result ); + if ( !result && recenter ) { + [ qz_window center ] ; + } + return result; +} + +int QZ_GetMonitorDPI(_THIS, int *xDpi, int *yDpi) +{ + /* FIXME: how to get this information from Cocoa ? */ + return -1; +} + +int QZ_GetMonitorRect (_THIS, SDL_Rect *rect) +{ + NSWindow* window = qz_window; + NSRect frame = [ window frame ]; + int fx1 = frame.origin.x; + int fy1 = frame.origin.y; + int fx2 = frame.size.width + fx1; + int fy2 = frame.size.height + fy1; + NSArray* screens = [ NSScreen screens ]; + unsigned int count = [ screens count ]; + int bestScreen = -1; + int bestArea = 0; + + unsigned int n; + + /* we need to compute which screen has the most window pixels */ + for (n = 0; n < count; n++) { + NSScreen* screen = [ screens objectAtIndex: n ]; + NSRect vis = [ screen visibleFrame ]; + int vx1 = vis.origin.x; + int vy1 = vis.origin.y; + int vx2 = vis.size.width + vx1; + int vy2 = vis.size.height + vy1; + int cx1, cx2, cy1, cy2, cArea; + + if (fx1 >= vx2 || vx1 >= fx2 || fy1 >= vy2 || vy1 >= fy2) + continue; + + cx1 = (fx1 < vx1) ? vx1 : fx1; + cx2 = (fx2 > vx2) ? vx2 : fx2; + cy1 = (fy1 < vy1) ? vy1 : fy1; + cy2 = (fy2 > vy2) ? vy2 : fy2; + + if (cx1 >= cx2 || cy1 >= cy2) + continue; + + cArea = (cx2-cx1)*(cy2-cy1); + + if (bestScreen < 0 || cArea > bestArea) { + bestScreen = n; + bestArea = cArea; + } + } + if (bestScreen < 0) + bestScreen = 0; + + { + NSScreen* screen = [ screens objectAtIndex: bestScreen ]; + NSRect vis = [ screen visibleFrame ]; + + rect->x = vis.origin.x; + rect->y = vis.origin.y; + rect->w = vis.size.width; + rect->h = vis.size.height; + } + return 0; +} + +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; +} diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.h b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.h new file mode 100644 index 0000000..cdfdec4 --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.h @@ -0,0 +1,43 @@ +/* + 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" + +/* Subclass of NSWindow to fix genie effect and support resize events */ +@interface SDL_QuartzWindow : NSWindow +- (void)miniaturize:(id)sender; +- (void)display; +- (void)setFrame:(NSRect)frameRect display:(BOOL)flag; +- (void)appDidHide:(NSNotification*)note; +- (void)appWillUnhide:(NSNotification*)note; +- (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 + +/* Subclass of NSView to set cursor rectangle */ +@interface SDL_QuartzView : NSView +- (void)resetCursorRects; +@end diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.m b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.m new file mode 100644 index 0000000..b56f9a7 --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzWindow.m @@ -0,0 +1,232 @@ +/* + 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_QuartzWM.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_OPENGL) { + + /* + 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_OPENGL ) ) + 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_OPENGL ) ) { + + 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_OPENGL ) ) + 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 + +@implementation SDL_QuartzView + +- (void)resetCursorRects +{ + SDL_Cursor *sdlc = SDL_GetCursor(); + if (sdlc != NULL && sdlc->wm_cursor != NULL) { + [self addCursorRect: [self visibleRect] cursor: sdlc->wm_cursor->nscursor]; + } +} + +@end diff --git a/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzYUV.m b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzYUV.m new file mode 100644 index 0000000..acb3d94 --- /dev/null +++ b/distrib/sdl-1.2.12/src/video/quartz/SDL_QuartzYUV.m @@ -0,0 +1,330 @@ +/* + 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; + } + + /* Fix: jc.bertin@free.fr + PlanarPixmapInfoYUV420 is a big-endian struct */ + 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 = EndianS32_NtoB(offset); + yuv_pixmap->componentInfoY.rowBytes = EndianU32_NtoB(width); + + offset += width * height; + pixels[plane2] = (Uint8*)yuv_pixmap + offset; + pitches[plane2] = width / 2; + yuv_pixmap->componentInfoCb.offset = EndianS32_NtoB(offset); + yuv_pixmap->componentInfoCb.rowBytes = EndianU32_NtoB(width / 2); + + offset += (width * height / 4); + pixels[plane3] = (Uint8*)yuv_pixmap + offset; + pitches[plane3] = width / 2; + yuv_pixmap->componentInfoCr.offset = EndianS32_NtoB(offset); + yuv_pixmap->componentInfoCr.rowBytes = EndianU32_NtoB(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; +} |