From ee1f975a07ebfa8c2d81aaff1990353f21820d85 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 1 Jun 2002 23:05:05 +0000 Subject: [PATCH] Date: Sat, 1 Jun 2002 17:56:45 -0500 From: Darrell Walisser Subject: mac patch In this patch: - yuv code - links to QuickTime - tabs -> 4 spaces - mouse events fix - SDLMain path parsing fix - BUGS updates - some miscellaneous docs/comments/code cleanup --- BUGS | 8 +- src/main/macosx/SDLMain.m | 31 +- src/video/quartz/SDL_QuartzEvents.m | 922 +++++++++++++------------- src/video/quartz/SDL_QuartzKeys.h | 34 +- src/video/quartz/SDL_QuartzVideo.h | 66 +- src/video/quartz/SDL_QuartzVideo.m | 987 ++++++++++++++++++---------- src/video/quartz/SDL_QuartzWM.m | 79 ++- 7 files changed, 1215 insertions(+), 912 deletions(-) diff --git a/BUGS b/BUGS index 0f5893527..f9518cad8 100644 --- a/BUGS +++ b/BUGS @@ -72,26 +72,20 @@ MacOS X: Joystick code is not extensively tested yet. - Window may not close when unsetting video mode and resetting. - Resizeable windows aren't implemented yet. Depth switching for windowed mode isn't implemented yet. Palette handling isn't implemented in windowed mode yet. - Command-line arguments Dialog is not implemented yet. + Command-line arguments dialog is not implemented yet. Fullscreen drawing has some artifacts. - Fullscreen window covers *all* other windows - even force quit. - Fullscreen OpenGL for the software renderer is broken. Some OpenGL parameters are not accounted for, for example color bits customization. - Getting OpenGL context parameters is not implemented. - Continuous mouse motion perhaps is not as smooth as it should be. SDL_WM_GrabInput() is implemented, but it "freezes" the hardware diff --git a/src/main/macosx/SDLMain.m b/src/main/macosx/SDLMain.m index 19694b5ff..0c757d1ac 100644 --- a/src/main/macosx/SDLMain.m +++ b/src/main/macosx/SDLMain.m @@ -51,24 +51,25 @@ @implementation SDLMain /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { - char parentdir[MAXPATHLEN]; - char *c; - - strncpy ( parentdir, gArgv[0], sizeof(parentdir) ); - c = (char*) parentdir; - while (*c != '\0') /* go to end */ - c++; - - while (*c != '/') /* back up to parent */ - c--; - - *c++ = '\0'; /* cut off last part (binary name) */ - if (shouldChdir) { - assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ - assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */ + char parentdir[MAXPATHLEN]; + char *c; + + strncpy ( parentdir, gArgv[0], sizeof(parentdir) ); + c = (char*) parentdir; + + while (*c != '\0') /* go to end */ + c++; + + while (*c != '/') /* back up to parent */ + c--; + + *c++ = '\0'; /* cut off last part (binary name) */ + + assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ + assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */ } } diff --git a/src/video/quartz/SDL_QuartzEvents.m b/src/video/quartz/SDL_QuartzEvents.m index d4d17abdf..87ac064b6 100644 --- a/src/video/quartz/SDL_QuartzEvents.m +++ b/src/video/quartz/SDL_QuartzEvents.m @@ -1,23 +1,23 @@ /* - SDL - Simple DirectMedia Layer - Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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 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. + 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 + 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 + Sam Lantinga + slouken@libsdl.org */ #include @@ -27,479 +27,473 @@ static unsigned int currentMods = 0; /* Current keyboard modifiers, to track modifier state */ static int last_virtual_button = 0; /* Last virtual mouse button pressed */ -static void QZ_InitOSKeymap (_THIS) { - const void *KCHRPtr; - UInt32 state; - UInt32 value; - int i; - int world = SDLK_WORLD_0; - - for ( i=0; ikeysym 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 - * bascially 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_InitOSKeymap (_THIS) { + const void *KCHRPtr; + UInt32 state; + UInt32 value; + int i; + int world = SDLK_WORLD_0; + + for ( i=0; ikeysym 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 + * bascially 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 (int state, NSEvent *event) { - NSString *chars; - int i; - SDL_keysym key; - - /* An event can contain multiple characters */ - /* I'll ignore this fact for now, since there is only one virtual key code per event */ - chars = [ event characters ]; - for (i =0; i < 1 /*[ chars length ] */; i++) { - - key.scancode = [ event keyCode ]; - key.sym = keymap [ key.scancode ]; - key.unicode = [ chars characterAtIndex:i]; - key.mod = KMOD_NONE; - - SDL_PrivateKeyboard (state, &key); - } + NSString *chars; + int i; + SDL_keysym key; + + /* An event can contain multiple characters */ + /* I'll ignore this fact for now, since there is only one virtual key code per event */ + chars = [ event characters ]; + for (i =0; i < 1 /*[ chars length ] */; i++) { + + key.scancode = [ event keyCode ]; + key.sym = keymap [ key.scancode ]; + key.unicode = [ chars characterAtIndex:i]; + key.mod = KMOD_NONE; + + SDL_PrivateKeyboard (state, &key); + } } static void QZ_DoModifiers (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 = currentMods & 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); - } - } - - currentMods = 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 = currentMods & 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); + } + } + + currentMods = newMods; } static void QZ_DoActivate (_THIS) { - inForeground = YES; - - /* Regrab the mouse */ - if (currentGrabMode == SDL_GRAB_ON) { - QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2); - CGAssociateMouseAndMouseCursorPosition (0); - } - - /* Hide the mouse cursor if inside the app window */ - if (!QZ_cursor_visible) { - HideCursor (); - } - - SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS); + inForeground = YES; + + /* Regrab the mouse */ + if (currentGrabMode == SDL_GRAB_ON) { + QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2); + CGAssociateMouseAndMouseCursorPosition (0); + } + + /* Hide the mouse cursor if inside the app window */ + if (!QZ_cursor_visible) { + HideCursor (); + } + + SDL_PrivateAppActive (1, SDL_APPINPUTFOCUS); } static void QZ_DoDeactivate (_THIS) { - - inForeground = NO; - - /* Ungrab mouse if it is grabbed */ - if (currentGrabMode == SDL_GRAB_ON) { - CGAssociateMouseAndMouseCursorPosition (1); - } - - /* Show the mouse cursor */ - if (!QZ_cursor_visible) { - ShowCursor (); - } - - SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS); + + inForeground = NO; + + /* Ungrab mouse if it is grabbed */ + if (currentGrabMode == SDL_GRAB_ON) { + CGAssociateMouseAndMouseCursorPosition (1); + } + + /* Show the mouse cursor */ + if (!QZ_cursor_visible) { + ShowCursor (); + } + + SDL_PrivateAppActive (0, SDL_APPINPUTFOCUS); } static void QZ_PumpEvents (_THIS) { - - static NSPoint lastMouse; - NSPoint mouse, saveMouse; - Point qdMouse; - CGMouseDelta dx, dy; - - NSDate *distantPast; - NSEvent *event; - NSRect winRect; - NSRect titleBarRect; - NSAutoreleasePool *pool; - - pool = [ [ NSAutoreleasePool alloc ] init ]; - distantPast = [ NSDate distantPast ]; - - winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); - titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w, - SDL_VideoSurface->h + 22 ); - - if (currentGrabMode != SDL_GRAB_ON) { /* if grabbed, the cursor can't move! (see fallback below) */ - - /* 1/2 second after a warp, the mouse cannot move (don't ask me why) */ - /* So, approximate motion with CGGetLastMouseDelta, which still works, somehow */ - if (! warp_flag) { + static NSPoint lastMouse; + NSPoint mouse, saveMouse; + Point qdMouse; + CGMouseDelta dx, dy; + + NSDate *distantPast; + NSEvent *event; + NSRect winRect; + NSRect titleBarRect; + NSAutoreleasePool *pool; + + pool = [ [ NSAutoreleasePool alloc ] init ]; + distantPast = [ NSDate distantPast ]; + + winRect = NSMakeRect (0, 0, SDL_VideoSurface->w, SDL_VideoSurface->h); + titleBarRect = NSMakeRect ( 0, SDL_VideoSurface->h, SDL_VideoSurface->w, + SDL_VideoSurface->h + 22 ); + + if (currentGrabMode != SDL_GRAB_ON) { /* if grabbed, the cursor can't move! (see fallback below) */ + + /* 1/2 second after a warp, the mouse cannot move (don't ask me why) */ + /* So, approximate motion with CGGetLastMouseDelta, which still works, somehow */ + if (! warp_flag) { + + GetGlobalMouse (&qdMouse); /* use Carbon since [ NSEvent mouseLocation ] is broken */ + mouse = NSMakePoint (qdMouse.h, qdMouse.v); + saveMouse = mouse; + + if (mouse.x != lastMouse.x || mouse.y != lastMouse.y) { + + QZ_PrivateCGToSDL (this, &mouse); + /* -note- we now generate mouse motion events if the mouse isn't over the window */ + if (inForeground /* && NSPointInRect (mouse, winRect)*/) { + //printf ("Mouse Loc: (%f, %f)\n", mouse.x, mouse.y); + SDL_PrivateMouseMotion (0, 0, mouse.x, mouse.y); + } + } + lastMouse = saveMouse; + } + } + + /* accumulate any mouse 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) { + + unsigned int type; + BOOL isForGameWin; + + #define DO_MOUSE_DOWN(button, sendToWindow) do { \ + if ( inForeground ) { \ + if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) || \ + NSPointInRect([event locationInWindow], winRect) ) \ + SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0); \ + } \ + else { \ + QZ_DoActivate (this); \ + } \ + [ NSApp sendEvent:event ]; \ + } while(0) + + #define DO_MOUSE_UP(button, sendToWindow) do { \ + if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) || \ + !NSPointInRect([event locationInWindow], titleBarRect) ) \ + SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); \ + [ NSApp sendEvent:event ]; \ + } while(0) - GetGlobalMouse (&qdMouse); /* use Carbon since [ NSEvent mouseLocation ] is broken */ - mouse = NSMakePoint (qdMouse.h, qdMouse.v); - saveMouse = mouse; + type = [ event type ]; + isForGameWin = (qz_window == [ event window ]); + switch (type) { + + case NSLeftMouseDown: + if ( NSCommandKeyMask & currentMods ) { + last_virtual_button = 3; + DO_MOUSE_DOWN (3, 0); + } + else if ( NSAlternateKeyMask & currentMods ) { + last_virtual_button = 2; + DO_MOUSE_DOWN (2, 0); + } + else { + DO_MOUSE_DOWN (1, 1); + } + break; + case NSOtherMouseDown: DO_MOUSE_DOWN (2, 0); break; + case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break; + case NSLeftMouseUp: + if ( last_virtual_button != 0 ) { + DO_MOUSE_UP (last_virtual_button, 0); + last_virtual_button = 0; + } + else { + DO_MOUSE_UP (1, 1); + } + break; + case NSOtherMouseUp: DO_MOUSE_UP (2, 0); break; + case NSRightMouseUp: DO_MOUSE_UP (3, 0); break; + case NSSystemDefined: + //if ([event subtype] == 7) { + // unsigned int buttons; // up to 32 mouse button states! + // buttons = [ event data2 ]; + //} + break; + case NSLeftMouseDragged: + case NSRightMouseDragged: + case 27: + case NSMouseMoved: + if (currentGrabMode == SDL_GRAB_ON) { + + /** + * If input is grabbed, we'll wing it and try to send some mouse + * moved events with CGGetLastMouseDelta(). Not optimal, but better + * than nothing. + **/ + CGMouseDelta dx1, dy1; + CGGetLastMouseDelta (&dx1, &dy1); + dx += dx1; + dy += dy1; + } + else if (warp_flag) { + + Uint32 ticks; + + ticks = SDL_GetTicks(); + if (ticks - warp_ticks < 150) { - if (mouse.x != lastMouse.x || mouse.y != lastMouse.y) { + CGMouseDelta dx1, dy1; + CGGetLastMouseDelta (&dx1, &dy1); + dx += dx1; + dy += dy1; + } + else { - QZ_PrivateCGToSDL (this, &mouse); - if (inForeground && NSPointInRect (mouse, winRect)) { - //printf ("Mouse Loc: (%f, %f)\n", mouse.x, mouse.y); - SDL_PrivateMouseMotion (0, 0, mouse.x, mouse.y); + warp_flag = 0; + } } - } - lastMouse = saveMouse; + break; + case NSScrollWheel: + if (NSPointInRect([ event locationInWindow ], winRect)) { + float dy; + dy = [ event deltaY ]; + if ( dy > 0.0 ) /* Scroll up */ + SDL_PrivateMouseButton (SDL_PRESSED, 4, 0, 0); + else /* Scroll down */ + SDL_PrivateMouseButton (SDL_PRESSED, 5, 0, 0); + } + break; + case NSKeyUp: + QZ_DoKey (SDL_RELEASED, event); + break; + case NSKeyDown: + QZ_DoKey (SDL_PRESSED, event); + break; + case NSFlagsChanged: + QZ_DoModifiers( [ event modifierFlags ] ); + break; + case NSAppKitDefined: + switch ( [ event subtype ] ) { + case NSApplicationActivatedEventType: + QZ_DoActivate (this); + break; + case NSApplicationDeactivatedEventType: + QZ_DoDeactivate (this); + break; + } + [ NSApp sendEvent:event ]; + break; + /* case NSApplicationDefined: break; */ + /* case NSPeriodic: break; */ + /* case NSCursorUpdate: break; */ + default: + [ NSApp sendEvent:event ]; } } - - /* accumulate any mouse 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) { - unsigned int type; - BOOL isForGameWin; - - #define DO_MOUSE_DOWN(button, sendToWindow) do { \ - if ( inForeground ) { \ - if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) || \ - NSPointInRect([event locationInWindow], winRect) ) \ - SDL_PrivateMouseButton (SDL_PRESSED, button, 0, 0); \ - } \ - else { \ - QZ_DoActivate (this); \ - } \ - [ NSApp sendEvent:event ]; \ - } while(0) - - #define DO_MOUSE_UP(button, sendToWindow) do { \ - if ( (SDL_VideoSurface->flags & SDL_FULLSCREEN) || \ - !NSPointInRect([event locationInWindow], titleBarRect) ) \ - SDL_PrivateMouseButton (SDL_RELEASED, button, 0, 0); \ - [ NSApp sendEvent:event ]; \ - } while(0) - - type = [ event type ]; - isForGameWin = (qz_window == [ event window ]); - switch (type) { - - case NSLeftMouseDown: - if ( NSCommandKeyMask & currentMods ) { - last_virtual_button = 3; - DO_MOUSE_DOWN (3, 0); - } - else if ( NSAlternateKeyMask & currentMods ) { - last_virtual_button = 2; - DO_MOUSE_DOWN (2, 0); - } - else { - DO_MOUSE_DOWN (1, 1); - } - break; - case NSOtherMouseDown: DO_MOUSE_DOWN (2, 0); break; - case NSRightMouseDown: DO_MOUSE_DOWN (3, 0); break; - case NSLeftMouseUp: - - if ( last_virtual_button != 0 ) { - DO_MOUSE_UP (last_virtual_button, 0); - last_virtual_button = 0; - } - else { - DO_MOUSE_UP (1, 1); - } - break; - case NSOtherMouseUp: DO_MOUSE_UP (2, 0); break; - case NSRightMouseUp: DO_MOUSE_UP (3, 0); break; - case NSSystemDefined: - //if ([event subtype] == 7) { - // unsigned int buttons; // up to 32 mouse button states! - // buttons = [ event data2 ]; - //} - break; - case NSLeftMouseDragged: - case NSRightMouseDragged: - case 27: - case NSMouseMoved: - - if (currentGrabMode == SDL_GRAB_ON) { - - /** - * If input is grabbed, we'll wing it and try to send some mouse - * moved events with CGGetLastMouseDelta(). Not optimal, but better - * than nothing. - **/ - CGMouseDelta dx1, dy1; - CGGetLastMouseDelta (&dx1, &dy1); - dx += dx1; - dy += dy1; - } - else if (warp_flag) { - - Uint32 ticks; - - ticks = SDL_GetTicks(); - if (ticks - warp_ticks < 150) { - - CGMouseDelta dx1, dy1; - CGGetLastMouseDelta (&dx1, &dy1); - dx += dx1; - dy += dy1; - } - else { - - warp_flag = 0; - } - } - - break; - case NSScrollWheel: - { - if (NSPointInRect([ event locationInWindow ], winRect)) { - float dy; - dy = [ event deltaY ]; - if ( dy > 0.0 ) /* Scroll up */ - SDL_PrivateMouseButton (SDL_PRESSED, 4, 0, 0); - else /* Scroll down */ - SDL_PrivateMouseButton (SDL_PRESSED, 5, 0, 0); - } - } - break; - case NSKeyUp: - QZ_DoKey (SDL_RELEASED, event); - break; - case NSKeyDown: - QZ_DoKey (SDL_PRESSED, event); - break; - case NSFlagsChanged: - QZ_DoModifiers( [ event modifierFlags ] ); - break; - case NSAppKitDefined: - switch ( [ event subtype ] ) { - case NSApplicationActivatedEventType: - QZ_DoActivate (this); - break; - case NSApplicationDeactivatedEventType: - QZ_DoDeactivate (this); - break; - } - [ NSApp sendEvent:event ]; - break; - /* case NSApplicationDefined: break; */ - /* case NSPeriodic: break; */ - /* case NSCursorUpdate: break; */ - - default: - [ NSApp sendEvent:event ]; - } - } - } while (event != nil); - - /* check for accumulated mouse events */ - if (dx != 0 || dy != 0) - SDL_PrivateMouseMotion (0, 1, dx, dy); - - [ pool release ]; + } while (event != nil); + + /* check for accumulated mouse events */ + if (dx != 0 || dy != 0) + SDL_PrivateMouseMotion (0, 1, dx, dy); + + [ pool release ]; } diff --git a/src/video/quartz/SDL_QuartzKeys.h b/src/video/quartz/SDL_QuartzKeys.h index 88f88ec8c..3d12b522f 100644 --- a/src/video/quartz/SDL_QuartzKeys.h +++ b/src/video/quartz/SDL_QuartzKeys.h @@ -1,24 +1,24 @@ /* SDL - Simple DirectMedia Layer Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 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 -*/ + */ /* These are the Macintosh key scancode constants -- from Inside Macintosh */ @@ -36,10 +36,10 @@ #define QZ_F11 0x67 #define QZ_F12 0x6F #define QZ_PRINT 0x69 -#define QZ_SCROLLOCK 0x6B +#define QZ_SCROLLOCK 0x6B #define QZ_PAUSE 0x71 #define QZ_POWER 0x7F -#define QZ_BACKQUOTE 0x32 +#define QZ_BACKQUOTE 0x32 #define QZ_1 0x12 #define QZ_2 0x13 #define QZ_3 0x14 @@ -52,14 +52,14 @@ #define QZ_0 0x1D #define QZ_MINUS 0x1B #define QZ_EQUALS 0x18 -#define QZ_BACKSPACE 0x33 +#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_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 @@ -71,9 +71,9 @@ #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_LEFTBRACKET 0x21 +#define QZ_RIGHTBRACKET 0x1E +#define QZ_BACKSLASH 0x2A #define QZ_DELETE 0x75 #define QZ_END 0x77 #define QZ_PAGEDOWN 0x79 @@ -91,7 +91,7 @@ #define QZ_j 0x26 #define QZ_k 0x28 #define QZ_l 0x25 -#define QZ_SEMICOLON 0x29 +#define QZ_SEMICOLON 0x29 #define QZ_QUOTE 0x27 #define QZ_RETURN 0x24 #define QZ_KP4 0x56 @@ -130,11 +130,11 @@ #define QZ_DOWN 0x7D #define QZ_RIGHT 0x7C #define QZ_KP0 0x52 -#define QZ_KP_PERIOD 0x41 +#define QZ_KP_PERIOD 0x41 /* Wierd, these keys are on my iBook under MacOS 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 +#define QZ_IBOOK_UP 0x3E diff --git a/src/video/quartz/SDL_QuartzVideo.h b/src/video/quartz/SDL_QuartzVideo.h index 80e06623a..391bbf086 100644 --- a/src/video/quartz/SDL_QuartzVideo.h +++ b/src/video/quartz/SDL_QuartzVideo.h @@ -20,7 +20,7 @@ slouken@libsdl.org */ -/* +/* @file SDL_QuartzVideo.h @author Darrell Walisser @@ -33,16 +33,15 @@ - Keyboard repeat/mouse speed adjust (if needed) - Multiple monitor support (currently only main display) - Accelerated blitting support - - Set the window icon (dock icon when API is available) - - Fix white OpenGL window on minimize + - Fix white OpenGL window on minimize (fixed) - Find out what events should be sent/ignored if window is mimimized - - Find a better way to deal with resolution/depth switch while app is running + - Find a way to deal with external resolution/depth switch while app is running - Resizeable windows - 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 + - 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) - Warping cursor delays mouse events for a fraction of a second, @@ -52,6 +51,7 @@ #include #include #include +#include #include "SDL_video.h" #include "SDL_error.h" @@ -102,10 +102,17 @@ typedef struct SDL_PrivateVideoData { 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 into this view */ - + ImageDescriptionHandle yuv_idh; + MatrixRecordPtr yuv_matrix; + DecompressorComponent yuv_codec; + ImageSequence yuv_seq; + PlanarPixmapInfoYUV420 *yuv_pixmap; + Sint16 yuv_width, yuv_height; + CGrafPtr yuv_port; + } SDL_PrivateVideoData ; -#define _THIS SDL_VideoDevice *this +#define _THIS SDL_VideoDevice *this #define display_id (this->hidden->display) #define mode (this->hidden->mode) #define save_mode (this->hidden->save_mode) @@ -121,6 +128,15 @@ typedef struct SDL_PrivateVideoData { #define video_set (this->hidden->video_set) #define warp_ticks (this->hidden->warp_ticks) #define warp_flag (this->hidden->warp_flag) +#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) /* Obscuring code: maximum number of windows above ours (inclusive) */ #define kMaxWindows 256 @@ -144,16 +160,16 @@ typedef struct SDL_PrivateVideoData { */ typedef CGError CGSError; -typedef long CGSWindowCount; -typedef void * CGSConnectionID; -typedef int CGSWindowID; +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, +extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid, CGSConnectionID owner, CGSWindowCount listCapacity, CGSWindowIDList list, @@ -166,9 +182,9 @@ extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid, 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 CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y, + unsigned int w, unsigned int h, unsigned int color); extern CGSError CGSDisplayCanHWFill (CGDirectDisplayID id); @@ -182,16 +198,16 @@ 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 SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, + Uint32 flags); static void QZ_UnsetVideoMode (_THIS); -static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, - int width, int height, int bpp, - Uint32 flags); +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_SetColors (_THIS, int first_color, + int num_colors, SDL_Color *colors); static void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects); static void QZ_UpdateRects (_THIS, int num_rects, SDL_Rect *rects); static void QZ_VideoQuit (_THIS); @@ -223,8 +239,8 @@ static void QZ_PrivateWarpCursor (_THIS, int x, int y); /* Cursor and Mouse functions */ static void QZ_FreeWMCursor (_THIS, WMcursor *cursor); -static WMcursor* QZ_CreateWMCursor (_THIS, Uint8 *data, Uint8 *mask, - int w, int h, int hot_x, int hot_y); +static WMcursor* QZ_CreateWMCursor (_THIS, Uint8 *data, Uint8 *mask, + int w, int h, int hot_x, int hot_y); static int QZ_ShowWMCursor (_THIS, WMcursor *cursor); static void QZ_WarpWMCursor (_THIS, Uint16 x, Uint16 y); static void QZ_MoveWMCursor (_THIS, int x, int y); @@ -241,3 +257,7 @@ static int QZ_IconifyWindow (_THIS); static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode); /*static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info);*/ +/* YUV functions */ +static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height, + Uint32 format, SDL_Surface *display); + diff --git a/src/video/quartz/SDL_QuartzVideo.m b/src/video/quartz/SDL_QuartzVideo.m index bdd0b3a6f..f802d6893 100644 --- a/src/video/quartz/SDL_QuartzVideo.m +++ b/src/video/quartz/SDL_QuartzVideo.m @@ -32,7 +32,6 @@ #include "SDL_QuartzEvents.m" #include "SDL_QuartzWindow.m" - /* Bootstrap binding, enables entry point into the driver */ VideoBootStrap QZ_bootstrap = { "Quartz", "Mac OS X CoreGraphics", QZ_Available, QZ_CreateDevice @@ -100,7 +99,9 @@ static int QZ_Available () { /*device->GetWMInfo = QZ_GetWMInfo;*/ device->GrabInput = QZ_GrabInput; - device->free = QZ_DeleteDevice; + device->CreateYUVOverlay = QZ_CreateYUVOverlay; + + device->free = QZ_DeleteDevice; return device; } @@ -135,106 +136,106 @@ static int QZ_VideoInit (_THIS, SDL_PixelFormat *video_format) { } static SDL_Rect** QZ_ListModes (_THIS, SDL_PixelFormat *format, Uint32 flags) { - + CFIndex num_modes; CFIndex i; static SDL_Rect **list = NULL; 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 ( list != NULL ) { - int i; + int i; - for (i = 0; list[i] != NULL; i++) - free (list[i]); + for (i = 0; list[i] != NULL; i++) + free (list[i]); - free (list); - list = NULL; + free (list); + 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 (list[i]->w == width && list[i]->h == height) { - hasMode = SDL_TRUE; - break; + 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 (list[i]->w == width && 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 (list == NULL) - list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) ); - else - list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1)); - - rect = (SDL_Rect*) malloc (sizeof(**list)); - - if (list == NULL || rect == NULL) { - SDL_OutOfMemory (); - return NULL; + + /* Grow the list and add mode to the list */ + if ( ! hasMode ) { + + SDL_Rect *rect; + + list_size++; + + if (list == NULL) + list = (SDL_Rect**) malloc (sizeof(*list) * (list_size+1) ); + else + list = (SDL_Rect**) realloc (list, sizeof(*list) * (list_size+1)); + + rect = (SDL_Rect*) malloc (sizeof(**list)); + + if (list == NULL || rect == NULL) { + SDL_OutOfMemory (); + return NULL; + } + + rect->w = width; + rect->h = height; + + list[list_size-1] = rect; + list[list_size] = NULL; } - - rect->w = width; - rect->h = height; - - list[list_size-1] = rect; - 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 = list[j]->w * list[j]->h; area2 = list[j+1]->w * list[j+1]->h; - + if (area1 < area2) { SDL_Rect *tmp = list[j]; list[j] = list[j+1]; @@ -299,8 +300,8 @@ static UInt32 QZ_FadeGammaOut (_THIS, SDL_QuartzGammaTable *table) { static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) { CGGammaValue redTable[QZ_GAMMA_TABLE_SIZE], - greenTable[QZ_GAMMA_TABLE_SIZE], - blueTable[QZ_GAMMA_TABLE_SIZE]; + greenTable[QZ_GAMMA_TABLE_SIZE], + blueTable[QZ_GAMMA_TABLE_SIZE]; float percent; int j; @@ -308,7 +309,7 @@ static UInt32 QZ_FadeGammaIn (_THIS, SDL_QuartzGammaTable *table) { memset (redTable, 0, sizeof(redTable)); memset (greenTable, 0, sizeof(greenTable)); memset (blueTable, 0, sizeof(greenTable)); - + for (percent = 0.0; percent <= 1.0; percent += 0.01) { for (j = 0; j < QZ_GAMMA_TABLE_SIZE; j++) { @@ -338,7 +339,7 @@ static void QZ_UnsetVideoMode (_THIS) { this->info.blit_fill = 0; this->FillHWRect = NULL; this->UpdateRects = NULL; - + /* Release fullscreen resources */ if ( mode_flags & SDL_FULLSCREEN ) { @@ -351,7 +352,7 @@ static void QZ_UnsetVideoMode (_THIS) { /* Do this first to avoid trash on the display before fade */ if ( mode_flags & SDL_OPENGL ) QZ_TearDownOpenGL (this); - + if (mode_flags & SDL_OPENGL) CGLSetFullScreen(NULL); @@ -359,12 +360,12 @@ static void QZ_UnsetVideoMode (_THIS) { CGDisplaySwitchToMode (display_id, save_mode); CGDisplayRelease (display_id); ShowMenuBar (); - + if (! gamma_error) QZ_FadeGammaIn (this, &gamma_table); } /* Release window mode resources */ - else { + else { if ( (mode_flags & SDL_OPENGL) == 0 ) { UnlockPortBits ( [ window_view qdPort ] ); [ window_view release ]; @@ -373,7 +374,7 @@ static void QZ_UnsetVideoMode (_THIS) { [ qz_window setDelegate:nil ]; [ qz_window close ]; [ qz_window release ]; - qz_window = nil; + qz_window = nil; /* Release the OpenGL context */ if ( mode_flags & SDL_OPENGL ) @@ -382,15 +383,15 @@ static void QZ_UnsetVideoMode (_THIS) { /* Restore gamma settings */ CGDisplayRestoreColorSyncSettings (); - + /* Set pixels to null (so other code doesn't try to free it) */ if (this->screen != NULL) this->screen->pixels = NULL; - + /* Ensure the cursor will be visible and working when we quit */ CGDisplayShowCursor (display_id); CGAssociateMouseAndMouseCursorPosition (1); - + /* Signal successful teardown */ video_set = SDL_FALSE; } @@ -400,11 +401,11 @@ static void QZ_UnsetVideoMode (_THIS) { int exact_match; int gamma_error; SDL_QuartzGammaTable gamma_table; - + /* See if requested mode exists */ - mode = CGDisplayBestModeForParameters (display_id, bpp, width, - height, &exact_match); - + mode = CGDisplayBestModeForParameters (display_id, bpp, width, + height, &exact_match); + /* Require an exact match to the requested mode */ if ( ! exact_match ) { sprintf (QZ_Error, "Failed to find display resolution: %dx%dx%d", width, height, bpp); @@ -421,7 +422,7 @@ static void QZ_UnsetVideoMode (_THIS) { goto ERR_NO_CAPTURE; } - + /* Do the physical switch */ if ( CGDisplayNoErr != CGDisplaySwitchToMode (display_id, mode) ) { SDL_SetError ("Failed switching display resolution"); @@ -434,45 +435,45 @@ static void QZ_UnsetVideoMode (_THIS) { current->flags = 0; current->w = width; current->h = height; - current->flags |= SDL_FULLSCREEN; + current->flags |= SDL_FULLSCREEN; current->flags |= SDL_HWSURFACE; - + this->UpdateRects = QZ_DirectUpdate; - + /* Setup some mode-dependant info */ if ( CGSDisplayCanHWFill (display_id) ) { - this->info.blit_fill = 1; - this->FillHWRect = QZ_FillHWRect; + this->info.blit_fill = 1; + this->FillHWRect = QZ_FillHWRect; } - + if ( CGDisplayCanSetPalette (display_id) ) current->flags |= SDL_HWPALETTE; - + /* Setup OpenGL for a fullscreen context */ if (flags & SDL_OPENGL) { CGLError err; CGLContextObj ctx; - + if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { goto ERR_NO_GL; } - + ctx = [ gl_context cglContext ]; err = CGLSetFullScreen (ctx); - + if (err) { sprintf (QZ_Error, "Error setting OpenGL fullscreen: %s", CGLErrorString(err)); SDL_SetError (QZ_Error); goto ERR_NO_GL; } - + [ gl_context makeCurrentContext]; glClear (GL_COLOR_BUFFER_BIT); [ gl_context flushBuffer ]; - + current->flags |= SDL_OPENGL; } @@ -482,23 +483,23 @@ static void QZ_UnsetVideoMode (_THIS) { /* Fade the display to original gamma */ if (! gamma_error ) QZ_FadeGammaIn (this, &gamma_table); - + /* Save the flags to ensure correct tear-down */ mode_flags = current->flags; - + return current; - /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ - ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode); - ERR_NO_SWITCH: CGDisplayRelease (display_id); - ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); } - ERR_NO_MATCH: return NULL; + /* Since the blanking window covers *all* windows (even force quit) correct recovery is crucial */ +ERR_NO_GL: CGDisplaySwitchToMode (display_id, save_mode); +ERR_NO_SWITCH: CGDisplayRelease (display_id); +ERR_NO_CAPTURE: if (!gamma_error) { QZ_FadeGammaIn (this, &gamma_table); } +ERR_NO_MATCH: return NULL; } static SDL_Surface* QZ_SetVideoWindowed (_THIS, SDL_Surface *current, int width, - int height, int bpp, Uint32 flags) { + int height, int bpp, Uint32 flags) { unsigned int style; - NSRect rect; + NSRect rect; rect = NSMakeRect (0, 0, width, height); #if 1 // FIXME - the resize button doesn't show? Also need resize events... @@ -515,17 +516,17 @@ static void QZ_UnsetVideoMode (_THIS) { } /* Manually create a window, avoids having a nib file resource */ - qz_window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect - styleMask:style backing:NSBackingStoreBuffered defer:NO ]; + qz_window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect + styleMask:style backing:NSBackingStoreBuffered defer:NO ]; if (qz_window == nil) { SDL_SetError ("Could not create the Cocoa window"); return NULL; } - + current->flags = 0; current->w = width; current->h = height; - + [ qz_window setReleasedWhenClosed:YES ]; QZ_SetCaption(this, this->wm_title, this->wm_icon); [ qz_window setAcceptsMouseMovedEvents:YES ]; @@ -533,14 +534,14 @@ static void QZ_UnsetVideoMode (_THIS) { [ qz_window center ]; [ qz_window setDelegate: [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; - + /* For OpenGL, we set the content view to a NSOpenGLView */ if ( flags & SDL_OPENGL ) { - + if ( ! QZ_SetupOpenGL (this, bpp, flags) ) { return NULL; } - + [ gl_context setView: [ qz_window contentView ] ]; [ gl_context makeCurrentContext]; [ qz_window makeKeyAndOrderFront:nil ]; @@ -548,45 +549,45 @@ static void QZ_UnsetVideoMode (_THIS) { } /* For 2D, we set the content view to a NSQuickDrawView */ else { - + window_view = [ [ SDL_QuartzWindowView alloc ] init ]; [ qz_window setContentView:window_view ]; - [ qz_window makeKeyAndOrderFront:nil ]; - + [ qz_window makeKeyAndOrderFront:nil ]; + LockPortBits ( [ window_view qdPort ] ); current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ window_view qdPort ] ) ); current->pitch = GetPixRowBytes ( GetPortPixMap ( [ window_view qdPort ] ) ); - + current->flags |= SDL_SWSURFACE; current->flags |= SDL_PREALLOC; - - if ( flags & SDL_NOFRAME ) - current->flags |= SDL_NOFRAME; - if ( flags & SDL_RESIZABLE ) - current->flags |= SDL_RESIZABLE; + + if ( flags & SDL_NOFRAME ) + current->flags |= SDL_NOFRAME; + if ( flags & SDL_RESIZABLE ) + current->flags |= SDL_RESIZABLE; /* Offset 22 pixels down to fill the full content region */ - if ( ! (current->flags & SDL_NOFRAME) ) { - current->pixels += 22 * current->pitch; - } + if ( ! (current->flags & SDL_NOFRAME) ) { + current->pixels += 22 * current->pitch; + } this->UpdateRects = QZ_UpdateRects; } - + /* Save flags to ensure correct teardown */ mode_flags = current->flags; - + return current; } -static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, - int height, int bpp, Uint32 flags) { +static SDL_Surface* QZ_SetVideoMode (_THIS, SDL_Surface *current, int width, + int height, int bpp, Uint32 flags) { if (video_set == SDL_TRUE) QZ_UnsetVideoMode (this); - + current->flags = 0; - + /* Setup full screen video */ if ( flags & SDL_FULLSCREEN ) { current = QZ_SetVideoFullScreen (this, current, width, height, bpp, flags ); @@ -601,17 +602,17 @@ static void QZ_UnsetVideoMode (_THIS) { if (current == NULL) return NULL; } - + /* Setup the new pixel format */ { - int amask = 0, - rmask = 0, - gmask = 0, - bmask = 0; - + int amask = 0, + rmask = 0, + gmask = 0, + bmask = 0; + switch (bpp) { case 16: /* (1)-5-5-5 RGB */ - amask = 0; + amask = 0; rmask = 0x7C00; gmask = 0x03E0; bmask = 0x001F; @@ -626,212 +627,212 @@ static void QZ_UnsetVideoMode (_THIS) { bmask = 0x000000FF; break; } - + if ( ! SDL_ReallocFormat (current, bpp, rmask, gmask, bmask, amask ) ) { - SDL_SetError ("Couldn't reallocate pixel format"); - return NULL; - } + 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) { +static int QZ_ToggleFullScreen (_THIS, int on) { return -1; } -static int QZ_SetColors (_THIS, int first_color, int num_colors, - SDL_Color *colors) { +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 void QZ_DirectUpdate (_THIS, int num_rects, SDL_Rect *rects) { - #pragma unused(this,num_rects,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. **/ static int QZ_IsWindowObscured (NSWindow *window) { -//#define TEST_OBSCURED 1 + //#define TEST_OBSCURED 1 #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 + 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) - */ + 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) - /* Cache the connection to the window server */ - static CGSConnectionID cgsConnection = (CGSConnectionID) -1; + 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; + + CGSWindowID windows[kMaxWindows]; + CGSWindowCount i, count; + CGSWindowLevel winLevel; + CGSRect winRect; CGSRect contentRect; int windowNumber; //int isMainWindow; - int firstDockIcon; + 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 */ - + + /* 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 (cgsConnection) { + if ( ! [ window styleMask ] & NSBorderlessWindowMask ) windowContentOffset = 22; else windowContentOffset = 0; - + windowNumber = [ window windowNumber ]; //isMainWindow = [ window isMainWindow ]; - + /* 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 */ + + /* 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; + 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; @@ -839,52 +840,52 @@ they are too big (but will work) for background windows */ shadowBottom = 24; } else if (winLevel == kCGSWindowLevelDock) { - + /* Create dock icon cache */ if (numCachedDockIcons != (i-firstDockIcon) || dockIconCacheMiss) { - + numCachedDockIcons = i - firstDockIcon; - memcpy (dockIcons, &(windows[firstDockIcon]), + memcpy (dockIcons, &(windows[firstDockIcon]), numCachedDockIcons * sizeof(*windows)); } - + /* no shadow */ shadowSide = 0; shadowTop = 0; shadowBottom = 0; } else { - + /* kCGSWindowLevelDockLabel, - kCGSWindowLevelDock, - kOther??? */ - + 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 */ - + + } /* window was not our window */ + } /* iterate over windows */ - + } /* get cgsConnection */ - + } /* window is visible */ return obscured; @@ -893,86 +894,86 @@ they are too big (but will work) for background windows */ #endif } -static void QZ_UpdateRects (_THIS, int numRects, SDL_Rect *rects) { +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 ] && + else if ( [ qz_window isMiniaturized ] && ! (SDL_VideoSurface->flags & SDL_OPENGL)) { - - /** + + /** * Set port alpha opaque so deminiaturize looks right - * This isn't so nice, but there is no + * This isn't so nice, but there is no * initial deminatureize notification (before demini starts) **/ QZ_SetPortAlphaOpaque ([ [ qz_window contentView ] qdPort], - [ qz_window styleMask ] & NSBorderlessWindowMask); + [ qz_window styleMask ] & NSBorderlessWindowMask); } 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; + 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].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); + + MacSetRectRgn (temp, rects[i].x, rects[i].y, + rects[i].x + rects[i].w, rects[i].y + rects[i].h); MacUnionRgn (dirty, temp, dirty); } - + /* Flush the dirty region */ QDFlushPortBuffer ( [ window_view qdPort ], dirty ); DisposeRgn (dirty); @@ -993,7 +994,7 @@ static int QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color return 0; } -static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { +static int QZ_LockHWSurface(_THIS, SDL_Surface *surface) { return 1; } @@ -1006,10 +1007,10 @@ static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface) { } /* -int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) { - return 0; -} -*/ + int QZ_FlipHWSurface (_THIS, SDL_Surface *surface) { + return 0; + } + */ /* Gamma functions */ static int QZ_SetGamma (_THIS, float red, float green, float blue) { @@ -1030,14 +1031,14 @@ static int QZ_SetGamma (_THIS, float red, float green, float blue) { blue = FLT_MAX; else blue = 1.0 / blue; - - if ( CGDisplayNoErr == CGSetDisplayTransferByFormula - (display_id, min, max, red, min, max, green, min, max, blue) ) { - + + if ( CGDisplayNoErr == CGSetDisplayTransferByFormula + (display_id, min, max, red, min, max, green, min, max, blue) ) { + return 0; } else { - + return -1; } } @@ -1046,66 +1047,66 @@ static 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) ) - + (display_id, &dummy, &dummy, red, + &dummy, &dummy, green, &dummy, &dummy, blue) ) + return 0; else return -1; } static 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) ) + + 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; } static 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) - + + 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; + + return 0; } /* OpenGL helper functions (used internally) */ @@ -1118,53 +1119,53 @@ static int QZ_SetupOpenGL (_THIS, int bpp, Uint32 flags) { int colorBits = bpp; if ( flags & SDL_FULLSCREEN ) { - + attr[i++] = NSOpenGLPFAFullScreen; } /* In windowed mode, the OpenGL pixel depth must match device pixel depth */ - else if ( colorBits != device_bpp ) { + 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.stencil_size != 0 ) { attr[i++] = NSOpenGLPFAStencilSize; attr[i++] = this->gl_config.stencil_size; } - + 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]; - + + gl_context = [ [ NSOpenGLContext alloc ] initWithFormat:fmt + shareContext:nil]; + if (gl_context == nil) { SDL_SetError ("Failed creating OpenGL context"); return 0; - } - + } + /* Convince SDL that the GL "driver" is loaded */ this->gl_config.driver_loaded = 1; - + [ fmt release ]; - + return 1; } @@ -1187,23 +1188,23 @@ static int QZ_GL_LoadLibrary (_THIS, const char *location) { /* We may want to cache the bundleRef at some point */ CFBundleRef bundle; - CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, - CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true); - - CFStringRef functionName = CFStringCreateWithCString + CFURLRef bundleURL = CFURLCreateWithFileSystemPath (kCFAllocatorDefault, + CFSTR("/System/Library/Frameworks/OpenGL.framework"), kCFURLPOSIXPathStyle, true); + + CFStringRef functionName = CFStringCreateWithCString (kCFAllocatorDefault, proc, kCFStringEncodingASCII); - + void *function; - + bundle = CFBundleCreate (kCFAllocatorDefault, bundleURL); assert (bundle != NULL); - + function = CFBundleGetFunctionPointerForName (bundle, functionName); CFRelease ( bundleURL ); CFRelease ( functionName ); CFRelease ( bundle ); - + return function; } @@ -1214,18 +1215,18 @@ static int QZ_GL_GetAttribute (_THIS, SDL_GLattr attrib, int* value) { 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_BUFFER_SIZE: + 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_BUFFER_SIZE: { GLint bits = 0; GLint component; @@ -1254,4 +1255,298 @@ static void QZ_GL_SwapBuffers (_THIS) { [ gl_context flushBuffer ]; } +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 *dstrect) { + + OSErr err; + CodecFlags flags; + + if (dstrect->x != 0 || dstrect->y != 0) { + + SDL_SetError ("Need a dstrect at (0,0)"); + return -1; + } + + if (dstrect->w != yuv_width || dstrect->h != yuv_height) { + + Fixed scale_x, scale_y; + + scale_x = FixDiv ( Long2Fix (dstrect->w), Long2Fix (overlay->w) ); + scale_y = FixDiv ( Long2Fix (dstrect->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 = dstrect->w; + yuv_height = dstrect->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(); + + free (overlay->hwfuncs); + free (overlay->pitches); + free (overlay->pixels); + + if (SDL_VideoSurface->flags & SDL_FULLSCREEN) { + [ qz_window close ]; + qz_window = nil; + } + + free (yuv_matrix); + DisposeHandle ((Handle)yuv_idh); +} + +#include "SDL_yuvfuncs.h" + +/** + * 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) + +static 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) 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) { + + /** + * Good 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:[ [ SDL_QuartzWindowView 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 = [ [ qz_window contentView ] 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 = 12; + + 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*) 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**) malloc (sizeof(*pixels) * 3); + pitches = (Uint16*) malloc (sizeof(*pitches) * 3); + if (pixels == NULL || pitches == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + yuv_pixmap = (PlanarPixmapInfoYUV420*) + malloc (sizeof(PlanarPixmapInfoYUV420) + + (width * height * 2)); + if (yuv_pixmap == NULL) { + SDL_OutOfMemory (); + return NULL; + } + + //CHECK_ALIGN(yuv_pixmap); + offset = sizeof(PlanarPixmapInfoYUV420); + //offset += ALIGN(offset); + //CHECK_ALIGN(offset); + + pixels[0] = (Uint8*)yuv_pixmap + offset; + //CHECK_ALIGN(pixels[0]); + + pitches[0] = width; + yuv_pixmap->componentInfoY.offset = offset; + yuv_pixmap->componentInfoY.rowBytes = width; + + offset += width * height; + pixels[plane2] = (Uint8*)yuv_pixmap + offset; + pitches[plane2] = width / 2; + yuv_pixmap->componentInfoCb.offset = offset; + yuv_pixmap->componentInfoCb.rowBytes = width / 2; + + offset += (width * height / 4); + pixels[plane3] = (Uint8*)yuv_pixmap + offset; + pitches[plane3] = width / 2; + yuv_pixmap->componentInfoCr.offset = offset; + yuv_pixmap->componentInfoCr.rowBytes = width / 2; + + overlay->pixels = pixels; + overlay->pitches = pitches; + } + + overlay->hwfuncs = 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; +} diff --git a/src/video/quartz/SDL_QuartzWM.m b/src/video/quartz/SDL_QuartzWM.m index a4dbf8313..6f7ef4ac8 100644 --- a/src/video/quartz/SDL_QuartzWM.m +++ b/src/video/quartz/SDL_QuartzWM.m @@ -32,17 +32,17 @@ static void QZ_FreeWMCursor (_THIS, WMcursor *cursor) { /* Use the Carbon cursor routines for now */ static WMcursor* QZ_CreateWMCursor (_THIS, Uint8 *data, Uint8 *mask, - int w, int h, int hot_x, int hot_y) { - WMcursor *cursor; - int row, bytes; - - /* Allocate the cursor memory */ - cursor = (WMcursor *)malloc(sizeof(WMcursor)); - if ( cursor == NULL ) { - SDL_OutOfMemory(); - return(NULL); - } - memset(cursor, 0, sizeof(*cursor)); + int w, int h, int hot_x, int hot_y) { + WMcursor *cursor; + int row, bytes; + + /* Allocate the cursor memory */ + cursor = (WMcursor *)malloc(sizeof(WMcursor)); + if ( cursor == NULL ) { + SDL_OutOfMemory(); + return(NULL); + } + memset(cursor, 0, sizeof(*cursor)); if (w > 16) w = 16; @@ -50,19 +50,19 @@ static void QZ_FreeWMCursor (_THIS, WMcursor *cursor) { if (h > 16) h = 16; - bytes = (w+7)/8; - - for ( row=0; rowcurs.data[row], data, bytes); - data += bytes; - } - for ( row=0; rowcurs.mask[row], mask, bytes); - mask += bytes; - } - cursor->curs.hotSpot.h = hot_x; - cursor->curs.hotSpot.v = hot_y; - + bytes = (w+7)/8; + + for ( row=0; rowcurs.data[row], data, bytes); + data += bytes; + } + for ( row=0; rowcurs.mask[row], mask, bytes); + mask += bytes; + } + cursor->curs.hotSpot.h = hot_x; + cursor->curs.hotSpot.v = hot_y; + return(cursor); } @@ -246,18 +246,18 @@ static void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask) #define ALPHASHIFT 3 for (i=0;i>3]&(1<<(7-j)))?0xFF:0x00; + surfPtr[ALPHASHIFT+((i+j)<<2)]=(mask[i>>3]&(1<<(7-j)))?0xFF:0x00; } - imgrep = [[NSBitmapImageRep alloc] -initWithBitmapDataPlanes:(unsigned char **)&mergedSurface->pixels -pixelsWide:icon->w pixelsHigh:icon->h bitsPerSample:8 samplesPerPixel:4 -hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace -bytesPerRow:icon->w<<2 bitsPerPixel:32]; - img = [[NSImage alloc] initWithSize:imgSize]; - [img addRepresentation: imgrep]; - [NSApp setApplicationIconImage:img]; - [img release]; - [imgrep release]; + imgrep = [ [ NSBitmapImageRep alloc] + initWithBitmapDataPlanes:(unsigned char **)&mergedSurface->pixels + pixelsWide:icon->w pixelsHigh:icon->h bitsPerSample:8 samplesPerPixel:4 + hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:icon->w<<2 bitsPerPixel:32 ]; + img = [ [ NSImage alloc ] initWithSize:imgSize ]; + [ img addRepresentation: imgrep ]; + [ NSApp setApplicationIconImage:img ]; + [ img release ]; + [ imgrep release ]; SDL_FreeSurface(mergedSurface); freePool: [pool release]; @@ -285,19 +285,18 @@ static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) { static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode) { switch (grab_mode) { - case SDL_GRAB_QUERY: + case SDL_GRAB_QUERY: break; - case SDL_GRAB_OFF: + case SDL_GRAB_OFF: CGAssociateMouseAndMouseCursorPosition (1); currentGrabMode = SDL_GRAB_OFF; break; - case SDL_GRAB_ON: + case SDL_GRAB_ON: QZ_WarpWMCursor (this, SDL_VideoSurface->w / 2, SDL_VideoSurface->h / 2); CGAssociateMouseAndMouseCursorPosition (0); currentGrabMode = SDL_GRAB_ON; break; - case SDL_GRAB_FULLSCREEN: - + case SDL_GRAB_FULLSCREEN: break; }