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