src/video/quartz/SDL_QuartzVideo.h
author Ryan C. Gordon
Fri, 27 Dec 2002 20:52:41 +0000
changeset 563 04dcaf3da918
parent 561 4bcf7dd06c47
child 588 2c6510c0a304
permissions -rw-r--r--
Massive Quartz input enhancements from Darrell Walisser. His email:

Enclosed is a patch that addresses the following:

--Various minor cleanups.
Removed dead/obsolete code, made some style cleanups

--Mouse Events
Now keep track of what button(s) were pressed so we know when to send
the mouse up event. This fixes the case where the mouse is dragged
outside of the game window and released (in which case we want to send
the mouse up event even though the mouse is outside the game window).

--Input Grabbing
Here is my take on the grabbing situation, which is the basis for the
new implementation.

There are 3 grab states, ungrabbed (UG), visible (VG), and invisible
(IG). Both VG and IG keep the mouse constrained to the window and
produce relative motion events. In VG the cursor is visible (duh), in
IG it is not. In VG, absolute motion events also work.

There are 6 actions that can affect grabbing:

1. Set Fullscreen/Window (F/W). In fullscreen, a visible grab should do
nothing. However, a fullscreen visible grab can be treated just like a
windowed visible grab, which is what I have done to help simplify
things.

2. Cursor hide/show (H/S). If the cursor is hidden when grabbing, the
grab is an invisible grab. If the cursor is visible, the grab should
just constrain the mouse to the window.

3. Input grab/ungrab(G/U). If grabbed, the cursor should be confined to
the window as should the keyboard input. On Mac OS X, the keyboard
input is implicitly grabbed by confining the cursor, except for
command-tab which can switch away from the application. Should the
window come to the foreground if the application is deactivated and
grab input is called? This isn't necessary in this implementation
because the grab state will be asserted upon activation.

Using my notation, these are all the cases that need to be handled
(state + action = new state).

UG+U = UG
UG+G = VG or IG, if cursor is visible or not
UG+H = UG
UG+S = UG

VG+U = UG
VG+G = VG
VG+H = IG
VG+S = VG

IG+U = UG
IG+G = IG
IG+H = IG
IG+S = VG

The cases that result in the same state can be ignored in the code,
which cuts it down to just 5 cases.

Another issue is what happens when the app loses/gains input focus from
deactivate/activate or iconify/deiconify. I think that if input focus
is ever lost (outside of SDL's control), the grab state should be
suspended and the cursor should become visible and active again. When
regained, the cursor should reappear in its original location and/or
grab state. This way, when reactivating the cursor is still in the same
position as before so apps shouldn't get confused when the next motion
event comes in. This is what I've done in this patch.
     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 
    57 #include "SDL_video.h"
    58 #include "SDL_error.h"
    59 #include "SDL_timer.h"
    60 #include "SDL_syswm.h"
    61 #include "SDL_sysvideo.h"
    62 #include "SDL_pixels_c.h"
    63 #include "SDL_events_c.h"
    64 
    65 /* 
    66     Add methods to get at private members of NSScreen. 
    67     Since there is a bug in Apple's screen switching code
    68     that does not update this variable when switching
    69     to fullscreen, we'll set it manually (but only for the
    70     main screen).
    71 */
    72 @interface NSScreen (NSScreenAccess)
    73 - (void) setFrame:(NSRect)frame;
    74 @end
    75 
    76 @implementation NSScreen (NSScreenAccess)
    77 - (void) setFrame:(NSRect)frame;
    78 {
    79     _frame = frame;
    80 }
    81 @end
    82 
    83 /* 
    84     This is a workaround to directly access NSOpenGLContext's CGL context
    85     We need this to check for errors NSOpenGLContext doesn't support
    86 */
    87 @interface NSOpenGLContext (CGLContextAccess)
    88 - (CGLContextObj) cglContext;
    89 @end
    90 
    91 @implementation NSOpenGLContext (CGLContextAccess)
    92 - (CGLContextObj) cglContext;
    93 {
    94     return _contextAuxiliary;
    95 }
    96 @end
    97 
    98 /* 
    99     Structure for rez switch gamma fades
   100     We can hide the monitor flicker by setting the gamma tables to 0
   101 */
   102 #define QZ_GAMMA_TABLE_SIZE 256
   103 
   104 typedef struct {
   105 
   106     CGGammaValue red[QZ_GAMMA_TABLE_SIZE];
   107     CGGammaValue green[QZ_GAMMA_TABLE_SIZE];
   108     CGGammaValue blue[QZ_GAMMA_TABLE_SIZE];
   109 
   110 } SDL_QuartzGammaTable;
   111 
   112 /* Main driver structure to store required state information */
   113 typedef struct SDL_PrivateVideoData {
   114 
   115     CGDirectDisplayID  display;            /* 0 == main display (only support single display) */
   116     CFDictionaryRef    mode;               /* current mode of the display */
   117     CFDictionaryRef    save_mode;          /* original mode of the display */
   118     CFArrayRef         mode_list;          /* list of available fullscreen modes */
   119     CGDirectPaletteRef palette;            /* palette of an 8-bit display */
   120     NSOpenGLContext    *gl_context;        /* OpenGL rendering context */
   121     Uint32             width, height, bpp; /* frequently used data about the display */
   122     Uint32             flags;              /* flags for current mode, for teardown purposes */
   123     Uint32             video_set;          /* boolean; indicates if video was set correctly */
   124     Uint32             warp_flag;          /* boolean; notify to event loop that a warp just occured */
   125     Uint32             warp_ticks;         /* timestamp when the warp occured */
   126     NSWindow           *window;            /* Cocoa window to implement the SDL window */
   127     NSQuickDrawView    *view;              /* the window's view; draw 2D and OpenGL into this view */
   128     SDL_Surface        *resize_icon;       /* icon for the resize badge, we have to draw it by hand */
   129     SDL_GrabMode       current_grab_mode;  /* default value is SDL_GRAB_OFF */
   130     BOOL               in_foreground;      /* boolean; indicate if app is in foreground or not */
   131     SDL_Rect           **client_mode_list; /* resolution list to pass back to client */
   132     SDLKey             keymap[256];        /* Mac OS X to SDL key mapping */
   133     Uint32             current_mods;       /* current keyboard modifiers, to track modifier state */
   134     Uint32             last_virtual_button;/* last virtual mouse button pressed */
   135     io_connect_t       power_connection;   /* used with IOKit to detect wake from sleep */
   136     Uint8              expect_mouse_up;    /* used to determine when to send mouse up events */
   137     Uint8              grab_state;         /* used to manage grab behavior */
   138     NSPoint            cursor_loc;         /* saved cursor coords, for activate/deactivate when grabbed */
   139     BOOL          	   cursor_visible;     /* tells if cursor was hidden or not */
   140     
   141     ImageDescriptionHandle yuv_idh;
   142     MatrixRecordPtr        yuv_matrix;
   143     DecompressorComponent  yuv_codec;
   144     ImageSequence          yuv_seq;
   145     PlanarPixmapInfoYUV420 *yuv_pixmap;
   146     Sint16                  yuv_width, yuv_height;
   147     CGrafPtr                yuv_port;
   148 
   149 } SDL_PrivateVideoData ;
   150 
   151 #define _THIS    SDL_VideoDevice *this
   152 #define display_id (this->hidden->display)
   153 #define mode (this->hidden->mode)
   154 #define save_mode (this->hidden->save_mode)
   155 #define mode_list (this->hidden->mode_list)
   156 #define palette (this->hidden->palette)
   157 #define gl_context (this->hidden->gl_context)
   158 #define device_width (this->hidden->width)
   159 #define device_height (this->hidden->height)
   160 #define device_bpp (this->hidden->bpp)
   161 #define mode_flags (this->hidden->flags)
   162 #define qz_window (this->hidden->window)
   163 #define window_view (this->hidden->view)
   164 #define video_set (this->hidden->video_set)
   165 #define warp_ticks (this->hidden->warp_ticks)
   166 #define warp_flag (this->hidden->warp_flag)
   167 #define resize_icon (this->hidden->resize_icon)
   168 #define current_grab_mode (this->hidden->current_grab_mode)
   169 #define in_foreground (this->hidden->in_foreground)
   170 #define client_mode_list (this->hidden->client_mode_list)
   171 #define keymap (this->hidden->keymap)
   172 #define current_mods (this->hidden->current_mods)
   173 #define last_virtual_button (this->hidden->last_virtual_button)
   174 #define power_connection (this->hidden->power_connection)
   175 #define expect_mouse_up (this->hidden->expect_mouse_up)
   176 #define grab_state (this->hidden->grab_state)
   177 #define cursor_loc (this->hidden->cursor_loc)
   178 #define cursor_visible (this->hidden->cursor_visible)
   179 
   180 #define yuv_idh (this->hidden->yuv_idh)
   181 #define yuv_matrix (this->hidden->yuv_matrix)
   182 #define yuv_codec (this->hidden->yuv_codec)
   183 #define yuv_seq (this->hidden->yuv_seq)
   184 #define yuv_pixmap (this->hidden->yuv_pixmap)
   185 #define yuv_data (this->hidden->yuv_data)
   186 #define yuv_width (this->hidden->yuv_width)
   187 #define yuv_height (this->hidden->yuv_height)
   188 #define yuv_port (this->hidden->yuv_port)
   189 
   190 
   191 /* grab states - the input is in one of these states */
   192 enum {
   193     QZ_UNGRABBED = 0,
   194     QZ_VISIBLE_GRAB,
   195     QZ_INVISIBLE_GRAB
   196 };
   197 
   198 /* grab actions - these can change the grabbed state */
   199 enum {
   200     QZ_ENABLE_GRAB = 0,
   201     QZ_DISABLE_GRAB,
   202     QZ_HIDECURSOR,
   203     QZ_SHOWCURSOR
   204 };
   205 
   206 /* 
   207     Obscuring code: maximum number of windows above ours (inclusive) 
   208     
   209     Note: this doesn't work too well in practice and should be
   210     phased out when we add OpenGL 2D acceleration. It was never
   211     enabled in the first place, so this shouldn't be a problem ;-)
   212 */
   213 #define kMaxWindows 256
   214 
   215 /* Some of the Core Graphics Server API for obscuring code */
   216 #define kCGSWindowLevelTop          2147483632
   217 #define kCGSWindowLevelDockIconDrag 500
   218 #define kCGSWindowLevelDockMenu     101
   219 #define kCGSWindowLevelMenuIgnore    21
   220 #define kCGSWindowLevelMenu          20
   221 #define kCGSWindowLevelDockLabel     12
   222 #define kCGSWindowLevelDockIcon      11
   223 #define kCGSWindowLevelDock          10
   224 #define kCGSWindowLevelUtility        3
   225 #define kCGSWindowLevelNormal         0
   226 
   227 /* 
   228     For completeness; We never use these window levels, they are always below us
   229     #define kCGSWindowLevelMBarShadow -20
   230     #define kCGSWindowLevelDesktopPicture -2147483647
   231     #define kCGSWindowLevelDesktop        -2147483648
   232 */
   233 
   234 typedef CGError       CGSError;
   235 typedef long          CGSWindowCount;
   236 typedef void *        CGSConnectionID;
   237 typedef int           CGSWindowID;
   238 typedef CGSWindowID*  CGSWindowIDList;
   239 typedef CGWindowLevel CGSWindowLevel;
   240 typedef NSRect        CGSRect;
   241 
   242 extern CGSConnectionID _CGSDefaultConnection ();
   243 
   244 extern CGSError CGSGetOnScreenWindowList (CGSConnectionID cid,
   245                                           CGSConnectionID owner,
   246                                           CGSWindowCount listCapacity,
   247                                           CGSWindowIDList list,
   248                                           CGSWindowCount *listCount);
   249 
   250 extern CGSError CGSGetScreenRectForWindow (CGSConnectionID cid,
   251                                            CGSWindowID wid,
   252                                            CGSRect *rect);
   253 
   254 extern CGWindowLevel CGSGetWindowLevel (CGSConnectionID cid,
   255                                         CGSWindowID wid,
   256                                         CGSWindowLevel *level);
   257 
   258 extern CGSError CGSDisplayHWFill (CGDirectDisplayID id, unsigned int x, unsigned int y,
   259                                   unsigned int w, unsigned int h, unsigned int color);
   260 
   261 extern CGSError CGSDisplayCanHWFill (CGDirectDisplayID id);
   262 
   263 extern CGSError CGSGetMouseEnabledFlags (CGSConnectionID cid, CGSWindowID wid, int *flags);
   264 
   265 /* Bootstrap functions */
   266 static int              QZ_Available ();
   267 static SDL_VideoDevice* QZ_CreateDevice (int device_index);
   268 static void             QZ_DeleteDevice (SDL_VideoDevice *device);
   269 
   270 /* Initialization, Query, Setup, and Redrawing functions */
   271 static int          QZ_VideoInit        (_THIS, SDL_PixelFormat *video_format);
   272 
   273 static SDL_Rect**   QZ_ListModes        (_THIS, SDL_PixelFormat *format,
   274                                          Uint32 flags);
   275 static void         QZ_UnsetVideoMode   (_THIS);
   276 
   277 static SDL_Surface* QZ_SetVideoMode     (_THIS, SDL_Surface *current,
   278                                          int width, int height, int bpp,
   279                                          Uint32 flags);
   280 static int          QZ_ToggleFullScreen (_THIS, int on);
   281 static int          QZ_SetColors        (_THIS, int first_color,
   282                                          int num_colors, SDL_Color *colors);
   283 static void         QZ_DirectUpdate     (_THIS, int num_rects, SDL_Rect *rects);
   284 static int          QZ_LockWindow       (_THIS, SDL_Surface *surface);
   285 static void         QZ_UnlockWindow     (_THIS, SDL_Surface *surface);
   286 static void         QZ_UpdateRects      (_THIS, int num_rects, SDL_Rect *rects);
   287 static void         QZ_VideoQuit        (_THIS);
   288 
   289 /* Hardware surface functions (for fullscreen mode only) */
   290 static int  QZ_FillHWRect (_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);
   291 static int  QZ_LockHWSurface(_THIS, SDL_Surface *surface);
   292 static void QZ_UnlockHWSurface(_THIS, SDL_Surface *surface);
   293 static void QZ_FreeHWSurface (_THIS, SDL_Surface *surface);
   294 /* static int  QZ_FlipHWSurface (_THIS, SDL_Surface *surface); */
   295 
   296 /* Gamma Functions */
   297 static int QZ_SetGamma     (_THIS, float red, float green, float blue);
   298 static int QZ_GetGamma     (_THIS, float *red, float *green, float *blue);
   299 static int QZ_SetGammaRamp (_THIS, Uint16 *ramp);
   300 static int QZ_GetGammaRamp (_THIS, Uint16 *ramp);
   301 
   302 /* OpenGL functions */
   303 static int    QZ_SetupOpenGL       (_THIS, int bpp, Uint32 flags);
   304 static void   QZ_TearDownOpenGL    (_THIS);
   305 static void*  QZ_GL_GetProcAddress (_THIS, const char *proc);
   306 static int    QZ_GL_GetAttribute   (_THIS, SDL_GLattr attrib, int* value);
   307 static int    QZ_GL_MakeCurrent    (_THIS);
   308 static void   QZ_GL_SwapBuffers    (_THIS);
   309 static int    QZ_GL_LoadLibrary    (_THIS, const char *location);
   310 
   311 /* Private function to warp the cursor (used internally) */
   312 static void  QZ_PrivateWarpCursor (_THIS, int x, int y);
   313 
   314 /* Cursor and Mouse functions */
   315 static void         QZ_FreeWMCursor     (_THIS, WMcursor *cursor);
   316 static WMcursor*    QZ_CreateWMCursor   (_THIS, Uint8 *data, Uint8 *mask,
   317                                          int w, int h, int hot_x, int hot_y);
   318 static int          QZ_ShowWMCursor     (_THIS, WMcursor *cursor);
   319 static void         QZ_WarpWMCursor     (_THIS, Uint16 x, Uint16 y);
   320 static void         QZ_MoveWMCursor     (_THIS, int x, int y);
   321 static void         QZ_CheckMouseMode   (_THIS);
   322 
   323 /* Event functions */
   324 static void         QZ_InitOSKeymap     (_THIS);
   325 static void         QZ_PumpEvents       (_THIS);
   326 
   327 /* Window Manager functions */
   328 static void QZ_SetCaption        (_THIS, const char *title, const char *icon);
   329 static void QZ_SetIcon           (_THIS, SDL_Surface *icon, Uint8 *mask);
   330 static int  QZ_IconifyWindow     (_THIS);
   331 static SDL_GrabMode QZ_GrabInput (_THIS, SDL_GrabMode grab_mode);
   332 /*static int  QZ_GetWMInfo     (_THIS, SDL_SysWMinfo *info);*/
   333 
   334 /* YUV functions */
   335 static SDL_Overlay* QZ_CreateYUVOverlay (_THIS, int width, int height,
   336                                          Uint32 format, SDL_Surface *display);