src/video/quartz/SDL_QuartzVideo.h
author Sam Lantinga <slouken@libsdl.org>
Sun, 20 Apr 2003 05:41:16 +0000
changeset 615 7ec821f3cbd0
parent 588 2c6510c0a304
child 656 864e2d2a9a55
permissions -rw-r--r--
Date: Thu, 17 Apr 2003 23:27:34 -0400
From: Darrell Walisser
Subject: Yet another OS X cursor bug

The synopsis:

1. Call SDL_ShowCursor(0);
2. Call SDL_SetVideoMode();
3. Call SDL_GetEvent();
3. Call SDL_ShowCursor(1);

The result: Sometimes the cursor doesn't come back! Ack! Oddly enough,
it does come back when mousing over the dock or clicking in the menu
bar. But that's besides the point.

The reason why this is happening is a flaw in the handling of
activation/deactivation events. The short explanation is that the
HideCursor() and ShowCursor() calls must be balanced, but if the cursor
was initially hidden, HideCursor() was called again on the activate
event - so now the next ShowCursor() fails (as does the next, and the
next, for some reason).

So, here's the patch. All it does is keep track of the
HideCursor()/ShowCursor() calls so that they will always be balanced.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 
    23 /*    
    24     @file   SDL_QuartzVideo.h
    25     @author Darrell Walisser, Max Horn, et al.
    26     
    27     @abstract SDL video driver for Mac OS X.
    28     
    29     @discussion
    30     
    31     TODO
    32         - Hardware Cursor support with NSCursor instead of Carbon
    33         - Keyboard repeat/mouse speed adjust (if needed)
    34         - Multiple monitor support (currently only main display)
    35         - Accelerated blitting support
    36         - Fix white OpenGL window on minimize (fixed) (update: broken again on 10.2)
    37         - Find out what events should be sent/ignored if window is minimized
    38         - Find a way to deal with external resolution/depth switch while app is running
    39         - Resizeable windows (done)
    40         - Check accuracy of QZ_SetGamma()
    41     Problems:
    42         - OGL not working in full screen with software renderer
    43         - SetColors sets palette correctly but clears framebuffer
    44         - Crash in CG after several mode switches (I think this has been fixed)
    45         - Retained windows don't draw their title bar quite right (OS Bug) (not using retained windows)
    46         - Cursor in 8 bit modes is screwy (might just be Radeon PCI bug) (update: not just Radeon)
    47         - Warping cursor delays mouse events for a fraction of a second,
    48           there is a hack around this that helps a bit
    49 */
    50 
    51 #include <Cocoa/Cocoa.h>
    52 #include <OpenGL/OpenGL.h>
    53 #include <Carbon/Carbon.h>
    54 #include <QuickTime/QuickTime.h>
    55 #include <IOKit/IOKitLib.h>	/* For powersave handling */
    56 #include <pthread.h>
    57 
    58 #include "SDL_thread.h"
    59 #include "SDL_video.h"
    60 #include "SDL_error.h"
    61 #include "SDL_timer.h"
    62 #include "SDL_syswm.h"
    63 #include "SDL_sysvideo.h"
    64 #include "SDL_pixels_c.h"
    65 #include "SDL_events_c.h"
    66 
    67 /* 
    68     Add methods to get at private members of NSScreen. 
    69     Since there is a bug in Apple's screen switching code
    70     that does not update this variable when switching
    71     to fullscreen, we'll set it manually (but only for the
    72     main screen).
    73 */
    74 @interface NSScreen (NSScreenAccess)
    75 - (void) setFrame:(NSRect)frame;
    76 @end
    77 
    78 @implementation NSScreen (NSScreenAccess)
    79 - (void) setFrame:(NSRect)frame;
    80 {
    81     _frame = frame;
    82 }
    83 @end
    84 
    85 /* 
    86     This is a workaround to directly access NSOpenGLContext's CGL context
    87     We need this to check for errors NSOpenGLContext doesn't support
    88 */
    89 @interface NSOpenGLContext (CGLContextAccess)
    90 - (CGLContextObj) cglContext;
    91 @end
    92 
    93 @implementation NSOpenGLContext (CGLContextAccess)
    94 - (CGLContextObj) cglContext;
    95 {
    96     return _contextAuxiliary;
    97 }
    98 @end
    99 
   100 /* 
   101     Structure for rez switch gamma fades
   102     We can hide the monitor flicker by setting the gamma tables to 0
   103 */
   104 #define QZ_GAMMA_TABLE_SIZE 256
   105 
   106 typedef struct {
   107 
   108     CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
   109     CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
   110     CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
   111 
   112 } SDL_QuartzGammaTable;
   113 
   114 /* Main driver structure to store required state information */
   115 typedef struct SDL_PrivateVideoData {
   116 
   117     CGDirectDisplayID  display;            /* 0 == main display (only support single display) */
   118     CFDictionaryRef    mode;               /* current mode of the display */
   119     CFDictionaryRef    save_mode;          /* original mode of the display */
   120     CFArrayRef         mode_list;          /* list of available fullscreen modes */
   121     CGDirectPaletteRef palette;            /* palette of an 8-bit display */
   122     NSOpenGLContext    *gl_context;        /* OpenGL rendering context */
   123     Uint32             width, height, bpp; /* frequently used data about the display */
   124     Uint32             flags;              /* flags for current mode, for teardown purposes */
   125     Uint32             video_set;          /* boolean; indicates if video was set correctly */
   126     Uint32             warp_flag;          /* boolean; notify to event loop that a warp just occured */
   127     Uint32             warp_ticks;         /* timestamp when the warp occured */
   128     NSWindow           *window;            /* Cocoa window to implement the SDL window */
   129     NSQuickDrawView    *view;              /* the window's view; draw 2D and OpenGL into this view */
   130     SDL_Surface        *resize_icon;       /* icon for the resize badge, we have to draw it by hand */
   131     SDL_GrabMode       current_grab_mode;  /* default value is SDL_GRAB_OFF */
   132     BOOL               in_foreground;      /* boolean; indicate if app is in foreground or not */
   133     SDL_Rect           **client_mode_list; /* resolution list to pass back to client */
   134     SDLKey             keymap[256];        /* Mac OS X to SDL key mapping */
   135     Uint32             current_mods;       /* current keyboard modifiers, to track modifier state */
   136     Uint32             last_virtual_button;/* last virtual mouse button pressed */
   137     io_connect_t       power_connection;   /* used with IOKit to detect wake from sleep */
   138     Uint8              expect_mouse_up;    /* used to determine when to send mouse up events */
   139     Uint8              grab_state;         /* used to manage grab behavior */
   140     NSPoint            cursor_loc;         /* saved cursor coords, for activate/deactivate when grabbed */
   141     BOOL          	   cursor_visible;     /* tells if cursor was instructed to be hidden or not (SDL_ShowCursor) */
   142     BOOL               cursor_hidden;      /* tells if cursor is *actually* hidden or not */
   143     Uint8*             sw_buffers[2];      /* pointers to the two software buffers for double-buffer emulation */
   144     SDL_Thread         *thread;            /* thread for async updates to the screen */
   145     SDL_sem            *sem1, *sem2;       /* synchronization for async screen updates */
   146     Uint8              *current_buffer;    /* the buffer being copied to the screen */
   147     BOOL               quit_thread;        /* used to quit the async blitting thread */
   148     
   149     ImageDescriptionHandle yuv_idh;
   150     MatrixRecordPtr        yuv_matrix;
   151     DecompressorComponent  yuv_codec;
   152     ImageSequence          yuv_seq;
   153     PlanarPixmapInfoYUV420 *yuv_pixmap;
   154     Sint16                  yuv_width, yuv_height;
   155     CGrafPtr                yuv_port;
   156 
   157 } SDL_PrivateVideoData ;
   158 
   159 #define _THIS    SDL_VideoDevice *this
   160 #define display_id (this->hidden->display)
   161 #define mode (this->hidden->mode)
   162 #define save_mode (this->hidden->save_mode)
   163 #define mode_list (this->hidden->mode_list)
   164 #define palette (this->hidden->palette)
   165 #define gl_context (this->hidden->gl_context)
   166 #define device_width (this->hidden->width)
   167 #define device_height (this->hidden->height)
   168 #define device_bpp (this->hidden->bpp)
   169 #define mode_flags (this->hidden->flags)
   170 #define qz_window (this->hidden->window)
   171 #define window_view (this->hidden->view)
   172 #define video_set (this->hidden->video_set)
   173 #define warp_ticks (this->hidden->warp_ticks)
   174 #define warp_flag (this->hidden->warp_flag)
   175 #define resize_icon (this->hidden->resize_icon)
   176 #define current_grab_mode (this->hidden->current_grab_mode)
   177 #define in_foreground (this->hidden->in_foreground)
   178 #define client_mode_list (this->hidden->client_mode_list)
   179 #define keymap (this->hidden->keymap)
   180 #define current_mods (this->hidden->current_mods)
   181 #define last_virtual_button (this->hidden->last_virtual_button)
   182 #define power_connection (this->hidden->power_connection)
   183 #define expect_mouse_up (this->hidden->expect_mouse_up)
   184 #define grab_state (this->hidden->grab_state)
   185 #define cursor_loc (this->hidden->cursor_loc)
   186 #define cursor_visible (this->hidden->cursor_visible)
   187 #define cursor_hidden (this->hidden->cursor_hidden)
   188 #define sw_buffers (this->hidden->sw_buffers)
   189 #define thread (this->hidden->thread)
   190 #define sem1 (this->hidden->sem1)
   191 #define sem2 (this->hidden->sem2)
   192 #define current_buffer (this->hidden->current_buffer)
   193 #define quit_thread (this->hidden->quit_thread)
   194 
   195 #define yuv_idh (this->hidden->yuv_idh)
   196 #define yuv_matrix (this->hidden->yuv_matrix)
   197 #define yuv_codec (this->hidden->yuv_codec)
   198 #define yuv_seq (this->hidden->yuv_seq)
   199 #define yuv_pixmap (this->hidden->yuv_pixmap)
   200 #define yuv_data (this->hidden->yuv_data)
   201 #define yuv_width (this->hidden->yuv_width)
   202 #define yuv_height (this->hidden->yuv_height)
   203 #define yuv_port (this->hidden->yuv_port)
   204 
   205 
   206 /* grab states - the input is in one of these states */
   207 enum {
   208     QZ_UNGRABBED = 0,
   209     QZ_VISIBLE_GRAB,
   210     QZ_INVISIBLE_GRAB
   211 };
   212 
   213 /* grab actions - these can change the grabbed state */
   214 enum {
   215     QZ_ENABLE_GRAB = 0,
   216     QZ_DISABLE_GRAB,
   217     QZ_HIDECURSOR,
   218     QZ_SHOWCURSOR
   219 };
   220 
   221 /* 
   222     Obscuring code: maximum number of windows above ours (inclusive) 
   223     
   224     Note: this doesn't work too well in practice and should be
   225     phased out when we add OpenGL 2D acceleration. It was never
   226     enabled in the first place, so this shouldn't be a problem ;-)
   227 */
   228 #define kMaxWindows 256
   229 
   230 /* Some of the Core Graphics Server API for obscuring code */
   231 #define kCGSWindowLevelTop          2147483632
   232 #define kCGSWindowLevelDockIconDrag 500
   233 #define kCGSWindowLevelDockMenu     101
   234 #define kCGSWindowLevelMenuIgnore    21
   235 #define kCGSWindowLevelMenu          20
   236 #define kCGSWindowLevelDockLabel     12
   237 #define kCGSWindowLevelDockIcon      11
   238 #define kCGSWindowLevelDock          10
   239 #define kCGSWindowLevelUtility        3
   240 #define kCGSWindowLevelNormal         0
   241 
   242 /* 
   243     For completeness; We never use these window levels, they are always below us
   244     #define kCGSWindowLevelMBarShadow -20
   245     #define kCGSWindowLevelDesktopPicture -2147483647
   246     #define kCGSWindowLevelDesktop        -2147483648
   247 */
   248 
   249 typedef CGError       CGSError;
   250 typedef long          CGSWindowCount;
   251 typedef void *        CGSConnectionID;
   252 typedef int           CGSWindowID;
   253 typedef CGSWindowID*  CGSWindowIDList;
   254 typedef CGWindowLevel CGSWindowLevel;
   255 typedef NSRect        CGSRect;
   256 
   257 extern CGSConnectionID _CGSDefaultConnection ();
   258 
   259 extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid,
   260                                           CGSConnectionID owner,
   261                                           CGSWindowCount listCapacity,
   262                                           CGSWindowIDList list,
   263                                           CGSWindowCount *listCount);
   264 
   265 extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid,
   266                                            CGSWindowID wid,
   267                                            CGSRect *rect);
   268 
   269 extern CGWindowLevel CGSGetWindowLevel (CGSConnectionID cid,
   270                                         CGSWindowID wid,
   271                                         CGSWindowLevel *level);
   272 
   273 extern CGSError CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y,
   274                                   unsigned int w, unsigned int h, unsigned int color);
   275 
   276 extern CGSError CGSDisplayCanHWFill (CGDirectDisplayID id);
   277 
   278 extern CGSError CGSGetMouseEnabledFlags (CGSConnectionID cid, CGSWindowID wid, int *flags);
   279 
   280 int CGSDisplayHWSync (CGDirectDisplayID id);
   281 
   282 /* Bootstrap functions */
   283 static int              QZ_Available ();
   284 static SDL_VideoDevice* QZ_CreateDevice (int device_index);
   285 static void             QZ_DeleteDevice (SDL_VideoDevice *device);
   286 
   287 /* Initialization, Query, Setup, and Redrawing functions */
   288 static int          QZ_VideoInit        (_THIS, SDL_PixelFormat *video_format);
   289 
   290 static SDL_Rect**   QZ_ListModes        (_THIS, SDL_PixelFormat *format,
   291                                          Uint32 flags);
   292 static void         QZ_UnsetVideoMode   (_THIS);
   293 
   294 static SDL_Surface* QZ_SetVideoMode     (_THIS, SDL_Surface *current,
   295                                          int width, int height, int bpp,
   296                                          Uint32 flags);
   297 static int          QZ_ToggleFullScreen (_THIS, int on);
   298 static int          QZ_SetColors        (_THIS, int first_color,
   299                                          int num_colors, SDL_Color *colors);
   300 
   301 static int          QZ_LockDoubleBuffer   (_THIS, SDL_Surface *surface);
   302 static void         QZ_UnlockDoubleBuffer (_THIS, SDL_Surface *surface);
   303 static int          QZ_ThreadFlip         (_THIS);
   304 static int          QZ_FlipDoubleBuffer   (_THIS, SDL_Surface *surface);
   305 static void         QZ_DoubleBufferUpdate (_THIS, int num_rects, SDL_Rect *rects);
   306 
   307 static void         QZ_DirectUpdate     (_THIS, int num_rects, SDL_Rect *rects);
   308 static int          QZ_LockWindow       (_THIS, SDL_Surface *surface);
   309 static void         QZ_UnlockWindow     (_THIS, SDL_Surface *surface);
   310 static void         QZ_UpdateRects      (_THIS, int num_rects, SDL_Rect *rects);
   311 static void         QZ_VideoQuit        (_THIS);
   312 
   313 /* Hardware surface functions (for fullscreen mode only) */
   314 static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
   315 static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface);
   316 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface);
   317 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface);
   318 /* static int  QZ_FlipHWSurface (_THIS, SDL_Surface *surface); */
   319 
   320 /* Gamma Functions */
   321 static int QZ_SetGamma     (_THIS, float red, float green, float blue);
   322 static int QZ_GetGamma     (_THIS, float *red, float *green, float *blue);
   323 static int QZ_SetGammaRamp (_THIS, Uint16 *ramp);
   324 static int QZ_GetGammaRamp (_THIS, Uint16 *ramp);
   325 
   326 /* OpenGL functions */
   327 static int    QZ_SetupOpenGL       (_THIS, int bpp, Uint32 flags);
   328 static void   QZ_TearDownOpenGL    (_THIS);
   329 static void*  QZ_GL_GetProcAddress (_THIS, const char *proc);
   330 static int    QZ_GL_GetAttribute   (_THIS, SDL_GLattr attrib, int* value);
   331 static int    QZ_GL_MakeCurrent    (_THIS);
   332 static void   QZ_GL_SwapBuffers    (_THIS);
   333 static int    QZ_GL_LoadLibrary    (_THIS, const char *location);
   334 
   335 /* Private function to warp the cursor (used internally) */
   336 static void  QZ_PrivateWarpCursor (_THIS, int x, int y);
   337 
   338 /* Cursor and Mouse functions */
   339 static void         QZ_FreeWMCursor     (_THIS, WMcursor *cursor);
   340 static WMcursor*    QZ_CreateWMCursor   (_THIS, Uint8 *data, Uint8 *mask,
   341                                          int w, int h, int hot_x, int hot_y);
   342 static int          QZ_ShowWMCursor     (_THIS, WMcursor *cursor);
   343 static void         QZ_WarpWMCursor     (_THIS, Uint16 x, Uint16 y);
   344 static void         QZ_MoveWMCursor     (_THIS, int x, int y);
   345 static void         QZ_CheckMouseMode   (_THIS);
   346 
   347 /* Event functions */
   348 static void         QZ_InitOSKeymap     (_THIS);
   349 static void         QZ_PumpEvents       (_THIS);
   350 
   351 /* Window Manager functions */
   352 static void QZ_SetCaption        (_THIS, const char *title, const char *icon);
   353 static void QZ_SetIcon           (_THIS, SDL_Surface *icon, Uint8 *mask);
   354 static int  QZ_IconifyWindow     (_THIS);
   355 static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode);
   356 /*static int  QZ_GetWMInfo     (_THIS, SDL_SysWMinfo *info);*/
   357 
   358 /* YUV functions */
   359 static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height,
   360                                          Uint32 format, SDL_Surface *display);