From f7d7e14f7e45b72551db92e1f9f7bdca9a424361 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 21 Aug 2001 07:19:59 +0000 Subject: [PATCH] Date: Tue, 21 Aug 2001 03:50:01 +0200 From: Max Horn Subject: New patch for OS X Attached a .patch file for SDL/OSX with some nice bug fixes / enhancments. * fixes the activation issues, which also caused the window to be always drawn like an inactive. The close/minimize widgets now are animated properly, too. * the menu items are automatically adjusted to use the app name instead of just "SDL App". I did this so that we really can use one central SDLMain.nib file, w/o requiring developers to make a copy of it and adjust it. * libSDLMain now contains the proper cocoa code, not as before the carbon code. This means apps no longer have to carry a copy of SDLMain.m/SDLMain.h * revamped configure.in to properly build a Cocoa/Quartz SDL lib, not a Carbon based SDL lib --- configure.in | 48 ++++++++++++---- src/main/Makefile.am | 4 ++ src/main/macosx/SDLMain.h | 7 +++ src/main/macosx/SDLMain.m | 85 +++++++++++++++++++++++++++-- src/video/quartz/SDL_QuartzEvents.m | 38 +++++++------ src/video/quartz/SDL_QuartzVideo.h | 6 +- src/video/quartz/SDL_QuartzVideo.m | 28 +++++----- src/video/quartz/SDL_QuartzWM.m | 16 +++--- 8 files changed, 170 insertions(+), 62 deletions(-) diff --git a/configure.in b/configure.in index 0ded54451..b892dce2c 100644 --- a/configure.in +++ b/configure.in @@ -63,10 +63,6 @@ case "$target" in *-*-linux*) AC_PROG_CXX ;; - *-*-darwin*) - OBJC="???" - AC_SUBST(OBJC) - ;; esac AC_PROG_INSTALL AC_FUNC_ALLOCA @@ -1192,6 +1188,21 @@ CheckCARBON() VIDEO_DRIVERS="$VIDEO_DRIVERS macrom/libvideo_macrom.la" } +dnl Set up the Mac toolbox video driver for Mac OS X +CheckQUARTZ() +{ + # "MACOSX" is not an official definition, but it's commonly + # accepted as a way to differentiate between what runs on X + # and what runs on older Macs - while in theory "Carbon" defns + # are consistent between the two, in practice Carbon is still + # changing. -sts Aug 2000 + CFLAGS="$CFLAGS -I/System/Library/Frameworks/Carbon.framework/Headers \ + -I/System/Library/Frameworks/Cocoa.framework/Headers -fpascal-strings \ + -DENABLE_QUARTZ -DMACOSX -DTARGET_API_MAC_CARBON=1 -I\$(top_srcdir)/src/video/quartz" + VIDEO_SUBDIRS="$VIDEO_SUBDIRS quartz" + VIDEO_DRIVERS="$VIDEO_DRIVERS quartz/libvideo_quartz.la" +} + dnl Set up the kernel statistics library for Solaris CheckKSTAT() { @@ -1994,17 +2005,17 @@ case "$target" in ;; *-*-darwin* ) # Strictly speaking, we want "Mac OS X", not "Darwin", which is - # just the OS X kernel sans upper layers like Carbon. But - # config.guess comes back with "darwin", so go with the flow. - ARCH=macos + # just the OS X kernel sans upper layers like Carbon and Cocoa. + # But config.guess comes back with "darwin", so go with the flow. + ARCH=macosx CheckDummyVideo CheckDiskAudio - CheckCARBON + CheckQUARTZ CheckMacGL CheckPTHREAD # Set up files for the main() stub - # COPY_ARCH_SRC(src/main, macos, SDL_main.c) - COPY_ARCH_SRC(src/main, linux, SDL_main.c) + COPY_ARCH_SRC(src/main, macosx, SDLmain.m) + COPY_ARCH_SRC(src/main, macosx, SDLmain.h) # Set up files for the audio library if test x$enable_audio = xyes; then AUDIO_SUBDIRS="$AUDIO_SUBDIRS macrom" @@ -2040,8 +2051,8 @@ case "$target" in COPY_ARCH_SRC(src/timer, linux, SDL_systimer.c) fi # The MacOS X platform requires special setup - SDL_CFLAGS="$SDL_CFLAGS -F/System/Library/Frameworks/Carbon.framework" - SDL_LIBS="-lSDLmain $SDL_LIBS -framework Carbon" + SDL_CFLAGS="$SDL_CFLAGS -F/System/Library/Frameworks/Carbon.framework -F/System/Library/Frameworks/Cocoa.framework" + SDL_LIBS="-lSDLmain $SDL_LIBS -framework Carbon -framework Cocoa" ;; *) AC_MSG_ERROR(Unsupported target: Please add to configure.in) @@ -2061,6 +2072,7 @@ AM_CONDITIONAL(TARGET_AIX, test $ARCH = aix) AM_CONDITIONAL(TARGET_WIN32, test $ARCH = win32) AM_CONDITIONAL(TARGET_BEOS, test $ARCH = beos) AM_CONDITIONAL(TARGET_MACOS, test $ARCH = macos) +AM_CONDITIONAL(TARGET_MACOSX, test $ARCH = macosx) # Set conditional variables for shared and static library selection. # These are not used in any Makefile.am but in sdl-config.in. @@ -2122,6 +2134,18 @@ CFLAGS="$CFLAGS -I\$(top_srcdir)/src/endian" CFLAGS="$CFLAGS -I\$(top_srcdir)/src/file" CXXFLAGS="$CFLAGS" + +# Check for darwin at the very end and set up the Objective C compiler +# We do this here so that we get the full CFLAGS into OBJCFLAGS +case "$target" in + *-*-darwin*) + OBJC="cc" + OBJCFLAGS="$CFLAGS" + AC_SUBST(OBJC) + AC_SUBST(OBJCFLAGS) + ;; +esac + # Finally create all the generated files dnl Important: Any directory that you want to be in the distcheck should dnl have a file listed here, so that configure generates the diff --git a/src/main/Makefile.am b/src/main/Makefile.am index 06d64a751..a74c430b3 100644 --- a/src/main/Makefile.am +++ b/src/main/Makefile.am @@ -10,7 +10,11 @@ ARCH_SUBDIRS = $(srcdir)/beos $(srcdir)/linux \ # Build a separate library containing the main() entry point. lib_LIBRARIES = libSDLmain.a +if TARGET_MACOSX +MAINLIB_ARCH_SRCS = SDLmain.m SDLmain.h +else MAINLIB_ARCH_SRCS = SDL_main.c +endif libSDLmain_a_SOURCES = $(MAINLIB_ARCH_SRCS) diff --git a/src/main/macosx/SDLMain.h b/src/main/macosx/SDLMain.h index 18da5ca82..1ed070e05 100644 --- a/src/main/macosx/SDLMain.h +++ b/src/main/macosx/SDLMain.h @@ -1,7 +1,14 @@ +/* SDLMain.h - main entry point for our Cocoa-ized SDL app + Darrell Walisser - dwaliss1@purdue.edu + + Feel free to customize this file to suit your needs +*/ + #import @interface SDLMain : NSObject { } - (IBAction)quit:(id)sender; +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification; @end diff --git a/src/main/macosx/SDLMain.m b/src/main/macosx/SDLMain.m index 779e84243..ac11e75b5 100644 --- a/src/main/macosx/SDLMain.m +++ b/src/main/macosx/SDLMain.m @@ -11,6 +11,12 @@ static int gArgc; static char **gArgv; +static NSString *gAppName = 0; + +@interface NSString (ReplaceSubString) +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; +@end + /* The main class of the application, the application's delegate */ @implementation SDLMain @@ -18,9 +24,9 @@ @implementation SDLMain /* Invoked from the Quit menu item */ - (void) quit:(id)sender { - SDL_Event event; - event.type = SDL_QUIT; - SDL_PushEvent(&event); + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); } /* Set the working directory to the .app's parent directory */ @@ -29,7 +35,7 @@ - (void) setupWorkingDirectory char parentdir[MAXPATHLEN]; char *c; - strncpy ( parentdir, gArgv[0], MAXPATHLEN ); + strncpy ( parentdir, gArgv[0], sizeof(parentdir) ); c = (char*) parentdir; while (*c != '\0') /* go to end */ @@ -38,10 +44,35 @@ - (void) setupWorkingDirectory while (*c != '/') /* back up to parent */ c--; - *c = '\0'; /* cut off last part (binary name) */ + *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 */ + + gAppName = [ NSString stringWithCString: c ]; +} + +/* Fix menu to contain the real app name instead of "SDL App" */ +- (void) fixMenu:(NSMenu *)aMenu +{ + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; + + aRange = [[aMenu title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:gAppName]]; + + enumerator = [[aMenu itemArray] objectEnumerator]; + while ((menuItem = [enumerator nextObject])) + { + aRange = [[menuItem title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:gAppName]]; + if ([menuItem hasSubmenu]) + [self fixMenu: [menuItem submenu]]; + } + [ aMenu sizeToFit ]; } /* Called when the internal event loop has just started running */ @@ -52,6 +83,9 @@ - (void) applicationDidFinishLaunching: (NSNotification *) note /* Set the working directory to the .app's parent directory */ [ self setupWorkingDirectory ]; + /* Set the main menu to contain the real app name instead of "SDL App" */ + [ self fixMenu: [ NSApp mainMenu ] ]; + /* Hand off to main application code */ status = SDL_main (gArgc, gArgv); @@ -60,6 +94,47 @@ - (void) applicationDidFinishLaunching: (NSNotification *) note } @end + +@implementation NSString (ReplaceSubString) + +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString +{ + unsigned int bufferSize; + unsigned int selfLen = [self length]; + unsigned int aStringLen = [aString length]; + unichar *buffer; + NSRange localRange; + NSString *result; + + bufferSize = selfLen + aStringLen - aRange.length; + buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + // Get first part into buffer + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; + + // Get middle part into buffer + localRange.location = 0; + localRange.length = aStringLen; + [aString getCharacters:(buffer+aRange.location) range:localRange]; + + // Get last part into buffer + localRange.location = aRange.location + aRange.length; + localRange.length = selfLen - localRange.location; + [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; + + // Build output string + result = [NSString stringWithCharacters:buffer length:bufferSize]; + + NSDeallocateMemoryPages(buffer, bufferSize); + + return result; +} + +@end + + #ifdef main # undef main #endif diff --git a/src/video/quartz/SDL_QuartzEvents.m b/src/video/quartz/SDL_QuartzEvents.m index 4a2f17d14..002a1d2db 100644 --- a/src/video/quartz/SDL_QuartzEvents.m +++ b/src/video/quartz/SDL_QuartzEvents.m @@ -223,7 +223,7 @@ static void QZ_DoDeactivate (_THIS) { } static void QZ_PumpEvents (_THIS) -{ +{ NSDate *distantPast; NSEvent *event; NSRect winRect; @@ -247,27 +247,29 @@ static void QZ_PumpEvents (_THIS) if (event != nil) { unsigned int type; + BOOL isForGameWin; - #define DO_MOUSE_DOWN(button, sendToWindow) \ + #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 if (sendToWindow) \ - [ window sendEvent:event ]; \ } \ else { \ QZ_DoActivate (this); \ - } - - #define DO_MOUSE_UP(button, sendToWindow) \ + } \ + [ 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); \ - if (sendToWindow) \ - [ window sendEvent:event ] - + [ NSApp sendEvent:event ]; \ + } while(0) + type = [ event type ]; + isForGameWin = (qz_window == [ event window ]); switch (type) { case NSLeftMouseDown: @@ -351,8 +353,8 @@ static void QZ_PumpEvents (_THIS) case NSFlagsChanged: QZ_DoModifiers( [ event modifierFlags ] ); break; - case NSMouseEntered: break; - case NSMouseExited: break; +// case NSMouseEntered: break; +// case NSMouseExited: break; case NSAppKitDefined: switch ( [ event subtype ] ) { case NSApplicationActivatedEventType: @@ -361,14 +363,14 @@ static void QZ_PumpEvents (_THIS) case NSApplicationDeactivatedEventType: QZ_DoDeactivate (this); break; - case NSWindowMovedEventType: - [ window sendEvent:event ]; - break; } + [ NSApp sendEvent:event ]; break; - case NSApplicationDefined: break; - case NSPeriodic: break; - case NSCursorUpdate: break; +// case NSApplicationDefined: break; +// case NSPeriodic: break; +// case NSCursorUpdate: break; + default: + [ NSApp sendEvent:event ]; } } } while (event != nil); diff --git a/src/video/quartz/SDL_QuartzVideo.h b/src/video/quartz/SDL_QuartzVideo.h index daf73aef2..10a0aa3b3 100644 --- a/src/video/quartz/SDL_QuartzVideo.h +++ b/src/video/quartz/SDL_QuartzVideo.h @@ -44,10 +44,6 @@ - Launch times are slow, maybe prebinding will help - Direct framebuffer access has some artifacts, maybe a driver issue - Cursor in 8 bit modes is screwy - - Modifier + mouse-down maps alternate mouse button, but if modifier is released - before mouse button, corresponding mouse-up event is not generated. - - Clicking in content activates app, but doesn't generate the activate event, - and subsequent switches generate no activate/deactivate events! (OS Bug I hope) */ #include @@ -107,7 +103,7 @@ typedef struct SDL_PrivateVideoData { #define device_bpp (this->hidden->bpp) #define mode_flags (this->hidden->flags) #define video_set (this->hidden->video_is_set) -#define window (this->hidden->window) +#define qz_window (this->hidden->window) #define windowView (this->hidden->view) /* Interface for hardware fill not (yet) in the public API */ diff --git a/src/video/quartz/SDL_QuartzVideo.m b/src/video/quartz/SDL_QuartzVideo.m index c596b9d07..91ce8e31c 100644 --- a/src/video/quartz/SDL_QuartzVideo.m +++ b/src/video/quartz/SDL_QuartzVideo.m @@ -267,9 +267,9 @@ static void QZ_UnsetVideoMode (_THIS) { UnlockPortBits ( [ windowView qdPort ] ); [ windowView release ]; } - [ window setContentView:nil ]; - [ window setDelegate:nil ]; - [ window close ]; + [ qz_window setContentView:nil ]; + [ qz_window setDelegate:nil ]; + [ qz_window close ]; } /* Set pixels to null (so other code doesn't try to free it) */ @@ -408,9 +408,9 @@ static void QZ_UnsetVideoMode (_THIS) { } /* Manually create a window, avoids having a nib file resource */ - window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect + qz_window = [ [ SDL_QuartzWindow alloc ] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO ]; - if (window == nil) { + if (qz_window == nil) { SDL_SetError ("Could not create the Cocoa window"); return NULL; } @@ -419,12 +419,12 @@ static void QZ_UnsetVideoMode (_THIS) { current->w = width; current->h = height; - [ window setReleasedWhenClosed:YES ]; + [ qz_window setReleasedWhenClosed:YES ]; QZ_SetCaption(this, this->wm_title, this->wm_icon); - [ window setAcceptsMouseMovedEvents:YES ]; - [ window setViewsNeedDisplay:NO ]; - [ window center ]; - [ window setDelegate: + [ qz_window setAcceptsMouseMovedEvents:YES ]; + [ qz_window setViewsNeedDisplay:NO ]; + [ qz_window center ]; + [ qz_window setDelegate: [ [ [ SDL_QuartzWindowDelegate alloc ] init ] autorelease ] ]; /* For OpenGL, we set the content view to a NSOpenGLView */ @@ -434,17 +434,17 @@ static void QZ_UnsetVideoMode (_THIS) { return NULL; } - [ gl_context setView: [ window contentView ] ]; + [ gl_context setView: [ qz_window contentView ] ]; [ gl_context makeCurrentContext]; - [ window orderFront:nil ]; + [ qz_window makeKeyAndOrderFront:nil ]; current->flags |= SDL_OPENGL; } /* For 2D, we set the content view to a NSQuickDrawView */ else { windowView = [ [ NSQuickDrawView alloc ] init ]; - [ window setContentView:windowView ]; - [ window orderFront:nil ]; + [ qz_window setContentView:windowView ]; + [ qz_window makeKeyAndOrderFront:nil ]; LockPortBits ( [ windowView qdPort ] ); current->pixels = GetPixBaseAddr ( GetPortPixMap ( [ windowView qdPort ] ) ); diff --git a/src/video/quartz/SDL_QuartzWM.m b/src/video/quartz/SDL_QuartzWM.m index d23848e3f..2bc6d2ef6 100644 --- a/src/video/quartz/SDL_QuartzWM.m +++ b/src/video/quartz/SDL_QuartzWM.m @@ -96,7 +96,7 @@ static void QZ_PrivateWarpCursor (_THIS, int fullscreen, int h, int x, int y) { /* Convert to absolute screen coordinates */ NSPoint base, screen; base = NSMakePoint (p.x, p.y); - screen = [ window convertBaseToScreen:base ]; + screen = [ qz_window convertBaseToScreen:base ]; p.x = screen.x; p.y = device_height - screen.y; CGDisplayMoveCursorToPoint (display_id, p); @@ -122,16 +122,16 @@ static void QZ_CheckMouseMode (_THIS) { } static void QZ_SetCaption (_THIS, const char *title, const char *icon) { - if ( window != nil ) { + if ( qz_window != nil ) { NSString *string; if ( title != NULL ) { string = [ [ NSString alloc ] initWithCString:title ]; - [ window setTitle:string ]; + [ qz_window setTitle:string ]; [ string release ]; } if ( icon != NULL ) { string = [ [ NSString alloc ] initWithCString:icon ]; - [ window setMiniwindowTitle:string ]; + [ qz_window setMiniwindowTitle:string ]; [ string release ]; } } @@ -144,19 +144,19 @@ static void QZ_SetIcon (_THIS, SDL_Surface *icon, Uint8 *mask) { static int QZ_IconifyWindow (_THIS) { /* Bug! minimize erases the framebuffer */ - if ( ! [ window isMiniaturized ] ) { - [ window miniaturize:nil ]; + if ( ! [ qz_window isMiniaturized ] ) { + [ qz_window miniaturize:nil ]; return 1; } else { - SDL_SetError ("window already iconified"); + SDL_SetError ("qz_window already iconified"); return 0; } } /* static int QZ_GetWMInfo (_THIS, SDL_SysWMinfo *info) { - info->nsWindowPtr = window; + info->nsWindowPtr = qz_window; return 0; }*/