Fixed the responder chain for event handling, the listener fully handles mouse events - even in fullscreen mode.
authorSam Lantinga <slouken@libsdl.org>
Mon, 21 Feb 2011 10:50:53 -0800
changeset 5371fc3d3d580777
parent 5370 cb219a294ebf
child 5372 a244ea780baa
Fixed the responder chain for event handling, the listener fully handles mouse events - even in fullscreen mode.
The only reason we need a custom view is to handle right mouse down.

Implemented mouse grabbing, although it's kind of clunky right now. I'll be adding a relative mode that will be smoother soon.
src/events/SDL_mouse.c
src/events/SDL_mouse_c.h
src/video/cocoa/SDL_cocoamouse.m
src/video/cocoa/SDL_cocoawindow.h
src/video/cocoa/SDL_cocoawindow.m
     1.1 --- a/src/events/SDL_mouse.c	Sun Feb 20 23:51:59 2011 -0800
     1.2 +++ b/src/events/SDL_mouse.c	Mon Feb 21 10:50:53 2011 -0800
     1.3 @@ -29,43 +29,7 @@
     1.4  #include "../video/SDL_sysvideo.h"
     1.5  
     1.6  
     1.7 -/* Global mouse information */
     1.8 -
     1.9 -typedef struct SDL_Mouse SDL_Mouse;
    1.10 -
    1.11 -struct SDL_Mouse
    1.12 -{
    1.13 -    /* Create a cursor from a surface */
    1.14 -    SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
    1.15 -
    1.16 -    /* Show the specified cursor, or hide if cursor is NULL */
    1.17 -    int (*ShowCursor) (SDL_Cursor * cursor);
    1.18 -
    1.19 -    /* This is called when a mouse motion event occurs */
    1.20 -    void (*MoveCursor) (SDL_Cursor * cursor);
    1.21 -
    1.22 -    /* Free a window manager cursor */
    1.23 -    void (*FreeCursor) (SDL_Cursor * cursor);
    1.24 -
    1.25 -    /* Warp the mouse to (x,y) */
    1.26 -    void (*WarpMouse) (SDL_Mouse * mouse, SDL_Window * window, int x, int y);
    1.27 -
    1.28 -    /* Data common to all mice */
    1.29 -    SDL_Window *focus;
    1.30 -    int x;
    1.31 -    int y;
    1.32 -    int xdelta;
    1.33 -    int ydelta;
    1.34 -    int last_x, last_y;         /* the last reported x and y coordinates */
    1.35 -    Uint8 buttonstate;
    1.36 -    SDL_bool relative_mode;
    1.37 -
    1.38 -    SDL_Cursor *cursors;
    1.39 -    SDL_Cursor *def_cursor;
    1.40 -    SDL_Cursor *cur_cursor;
    1.41 -    SDL_bool cursor_shown;
    1.42 -};
    1.43 -
    1.44 +/* The mouse state */
    1.45  static SDL_Mouse SDL_mouse;
    1.46  
    1.47  
    1.48 @@ -76,6 +40,12 @@
    1.49      return (0);
    1.50  }
    1.51  
    1.52 +SDL_Mouse *
    1.53 +SDL_GetMouse(void)
    1.54 +{
    1.55 +    return &SDL_mouse;
    1.56 +}
    1.57 +
    1.58  void
    1.59  SDL_ResetMouse(void)
    1.60  {
    1.61 @@ -85,7 +55,7 @@
    1.62  SDL_Window *
    1.63  SDL_GetMouseFocus(void)
    1.64  {
    1.65 -    SDL_Mouse *mouse = &SDL_mouse;
    1.66 +    SDL_Mouse *mouse = SDL_GetMouse();
    1.67  
    1.68      return mouse->focus;
    1.69  }
    1.70 @@ -93,7 +63,7 @@
    1.71  void
    1.72  SDL_SetMouseFocus(SDL_Window * window)
    1.73  {
    1.74 -    SDL_Mouse *mouse = &SDL_mouse;
    1.75 +    SDL_Mouse *mouse = SDL_GetMouse();
    1.76  
    1.77      if (mouse->focus == window) {
    1.78          return;
    1.79 @@ -114,7 +84,7 @@
    1.80  int
    1.81  SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
    1.82  {
    1.83 -    SDL_Mouse *mouse = &SDL_mouse;
    1.84 +    SDL_Mouse *mouse = SDL_GetMouse();
    1.85      int posted;
    1.86      int xrel;
    1.87      int yrel;
    1.88 @@ -204,7 +174,7 @@
    1.89  int
    1.90  SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
    1.91  {
    1.92 -    SDL_Mouse *mouse = &SDL_mouse;
    1.93 +    SDL_Mouse *mouse = SDL_GetMouse();
    1.94      int posted;
    1.95      Uint32 type;
    1.96  
    1.97 @@ -253,7 +223,7 @@
    1.98  int
    1.99  SDL_SendMouseWheel(SDL_Window * window, int x, int y)
   1.100  {
   1.101 -    SDL_Mouse *mouse = &SDL_mouse;
   1.102 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.103      int posted;
   1.104  
   1.105      if (window) {
   1.106 @@ -285,7 +255,7 @@
   1.107  Uint8
   1.108  SDL_GetMouseState(int *x, int *y)
   1.109  {
   1.110 -    SDL_Mouse *mouse = &SDL_mouse;
   1.111 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.112  
   1.113      if (x) {
   1.114          *x = mouse->x;
   1.115 @@ -299,7 +269,7 @@
   1.116  Uint8
   1.117  SDL_GetRelativeMouseState(int *x, int *y)
   1.118  {
   1.119 -    SDL_Mouse *mouse = &SDL_mouse;
   1.120 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.121  
   1.122      if (x) {
   1.123          *x = mouse->xdelta;
   1.124 @@ -315,10 +285,10 @@
   1.125  void
   1.126  SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
   1.127  {
   1.128 -    SDL_Mouse *mouse = &SDL_mouse;
   1.129 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.130  
   1.131      if (mouse->WarpMouse) {
   1.132 -        mouse->WarpMouse(mouse, window, x, y);
   1.133 +        mouse->WarpMouse(window, x, y);
   1.134      } else {
   1.135          SDL_SendMouseMotion(window, 0, x, y);
   1.136      }
   1.137 @@ -327,7 +297,7 @@
   1.138  int
   1.139  SDL_SetRelativeMouseMode(SDL_bool enabled)
   1.140  {
   1.141 -    SDL_Mouse *mouse = &SDL_mouse;
   1.142 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.143  
   1.144      /* Flush pending mouse motion */
   1.145      SDL_FlushEvent(SDL_MOUSEMOTION);
   1.146 @@ -349,7 +319,7 @@
   1.147  SDL_bool
   1.148  SDL_GetRelativeMouseMode()
   1.149  {
   1.150 -    SDL_Mouse *mouse = &SDL_mouse;
   1.151 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.152  
   1.153      return mouse->relative_mode;
   1.154  }
   1.155 @@ -358,7 +328,7 @@
   1.156  SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
   1.157                   int w, int h, int hot_x, int hot_y)
   1.158  {
   1.159 -    SDL_Mouse *mouse = &SDL_mouse;
   1.160 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.161      SDL_Surface *surface;
   1.162      SDL_Cursor *cursor;
   1.163      int x, y;
   1.164 @@ -424,7 +394,7 @@
   1.165  void
   1.166  SDL_SetCursor(SDL_Cursor * cursor)
   1.167  {
   1.168 -    SDL_Mouse *mouse = &SDL_mouse;
   1.169 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.170  
   1.171      /* Set the new cursor */
   1.172      if (cursor) {
   1.173 @@ -458,7 +428,7 @@
   1.174  SDL_Cursor *
   1.175  SDL_GetCursor(void)
   1.176  {
   1.177 -    SDL_Mouse *mouse = &SDL_mouse;
   1.178 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.179  
   1.180      if (!mouse) {
   1.181          return NULL;
   1.182 @@ -469,7 +439,7 @@
   1.183  void
   1.184  SDL_FreeCursor(SDL_Cursor * cursor)
   1.185  {
   1.186 -    SDL_Mouse *mouse = &SDL_mouse;
   1.187 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.188      SDL_Cursor *curr, *prev;
   1.189  
   1.190      if (!cursor) {
   1.191 @@ -503,7 +473,7 @@
   1.192  int
   1.193  SDL_ShowCursor(int toggle)
   1.194  {
   1.195 -    SDL_Mouse *mouse = &SDL_mouse;
   1.196 +    SDL_Mouse *mouse = SDL_GetMouse();
   1.197      SDL_bool shown;
   1.198  
   1.199      if (!mouse) {
     2.1 --- a/src/events/SDL_mouse_c.h	Sun Feb 20 23:51:59 2011 -0800
     2.2 +++ b/src/events/SDL_mouse_c.h	Mon Feb 21 10:50:53 2011 -0800
     2.3 @@ -24,15 +24,54 @@
     2.4  #ifndef _SDL_mouse_c_h
     2.5  #define _SDL_mouse_c_h
     2.6  
     2.7 +#include "SDL_mouse.h"
     2.8 +
     2.9  struct SDL_Cursor
    2.10  {
    2.11      struct SDL_Cursor *next;
    2.12      void *driverdata;
    2.13  };
    2.14  
    2.15 +typedef struct
    2.16 +{
    2.17 +    /* Create a cursor from a surface */
    2.18 +    SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
    2.19 +
    2.20 +    /* Show the specified cursor, or hide if cursor is NULL */
    2.21 +    int (*ShowCursor) (SDL_Cursor * cursor);
    2.22 +
    2.23 +    /* This is called when a mouse motion event occurs */
    2.24 +    void (*MoveCursor) (SDL_Cursor * cursor);
    2.25 +
    2.26 +    /* Free a window manager cursor */
    2.27 +    void (*FreeCursor) (SDL_Cursor * cursor);
    2.28 +
    2.29 +    /* Warp the mouse to (x,y) */
    2.30 +    void (*WarpMouse) (SDL_Window * window, int x, int y);
    2.31 +
    2.32 +    /* Data common to all mice */
    2.33 +    SDL_Window *focus;
    2.34 +    int x;
    2.35 +    int y;
    2.36 +    int xdelta;
    2.37 +    int ydelta;
    2.38 +    int last_x, last_y;         /* the last reported x and y coordinates */
    2.39 +    Uint8 buttonstate;
    2.40 +    SDL_bool relative_mode;
    2.41 +
    2.42 +    SDL_Cursor *cursors;
    2.43 +    SDL_Cursor *def_cursor;
    2.44 +    SDL_Cursor *cur_cursor;
    2.45 +    SDL_bool cursor_shown;
    2.46 +} SDL_Mouse;
    2.47 +
    2.48 +
    2.49  /* Initialize the mouse subsystem */
    2.50  extern int SDL_MouseInit(void);
    2.51  
    2.52 +/* Get the mouse state structure */
    2.53 +SDL_Mouse *SDL_GetMouse(void);
    2.54 +
    2.55  /* Clear the mouse state */
    2.56  extern void SDL_ResetMouse(void);
    2.57  
     3.1 --- a/src/video/cocoa/SDL_cocoamouse.m	Sun Feb 20 23:51:59 2011 -0800
     3.2 +++ b/src/video/cocoa/SDL_cocoamouse.m	Mon Feb 21 10:50:53 2011 -0800
     3.3 @@ -49,62 +49,7 @@
     3.4  void
     3.5  Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
     3.6  {
     3.7 -    int i;
     3.8 -    NSPoint point = { 0, 0 };
     3.9 -    SDL_Window *window;
    3.10 -    SDL_Window *focus = SDL_GetMouseFocus();
    3.11 -
    3.12 -    /* See if there are any fullscreen windows that might handle this event */
    3.13 -    window = NULL;
    3.14 -    for (i = 0; i < _this->num_displays; ++i) {
    3.15 -        SDL_VideoDisplay *display = &_this->displays[i];
    3.16 -        SDL_Window *candidate = display->fullscreen_window;
    3.17 -
    3.18 -        if (candidate) {
    3.19 -            SDL_Rect bounds;
    3.20 -
    3.21 -            Cocoa_GetDisplayBounds(_this, display, &bounds);
    3.22 -            point = [NSEvent mouseLocation];
    3.23 -            point.x = point.x - bounds.x;
    3.24 -            point.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - point.y - bounds.y;
    3.25 -            if ((point.x >= 0 && point.x < candidate->w) &&
    3.26 -                (point.y >= 0 && point.y < candidate->h)) {
    3.27 -                /* This is it! */
    3.28 -                window = candidate;
    3.29 -                break;
    3.30 -            } else if (candidate == focus) {
    3.31 -                SDL_SetMouseFocus(NULL);
    3.32 -            }
    3.33 -        }
    3.34 -    }
    3.35 -
    3.36 -    if (!window) {
    3.37 -        return;
    3.38 -    }
    3.39 -
    3.40 -    switch ([event type]) {
    3.41 -    case NSLeftMouseDown:
    3.42 -    case NSOtherMouseDown:
    3.43 -    case NSRightMouseDown:
    3.44 -        SDL_SendMouseButton(window, SDL_PRESSED, ConvertMouseButtonToSDL([event buttonNumber]));
    3.45 -        break;
    3.46 -    case NSLeftMouseUp:
    3.47 -    case NSOtherMouseUp:
    3.48 -    case NSRightMouseUp:
    3.49 -        SDL_SendMouseButton(window, SDL_RELEASED, ConvertMouseButtonToSDL([event buttonNumber]));
    3.50 -        break;
    3.51 -    case NSScrollWheel:
    3.52 -        Cocoa_HandleMouseWheel(window, event);
    3.53 -        break;
    3.54 -    case NSLeftMouseDragged:
    3.55 -    case NSRightMouseDragged:
    3.56 -    case NSOtherMouseDragged: /* usually middle mouse dragged */
    3.57 -    case NSMouseMoved:
    3.58 -        SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
    3.59 -        break;
    3.60 -    default: /* just to avoid compiler warnings */
    3.61 -        break;
    3.62 -    }
    3.63 +    /* We're correctly using views even in fullscreen mode now */
    3.64  }
    3.65  
    3.66  void
     4.1 --- a/src/video/cocoa/SDL_cocoawindow.h	Sun Feb 20 23:51:59 2011 -0800
     4.2 +++ b/src/video/cocoa/SDL_cocoawindow.h	Mon Feb 21 10:50:53 2011 -0800
     4.3 @@ -29,11 +29,7 @@
     4.4  typedef struct SDL_WindowData SDL_WindowData;
     4.5  
     4.6  /* *INDENT-OFF* */
     4.7 -#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
     4.8 -@interface Cocoa_WindowListener : NSResponder <NSWindowDelegate> {
     4.9 -#else
    4.10  @interface Cocoa_WindowListener : NSResponder {
    4.11 -#endif		
    4.12      SDL_WindowData *_data;
    4.13  }
    4.14  
    4.15 @@ -59,6 +55,8 @@
    4.16  -(void) mouseUp:(NSEvent *) theEvent;
    4.17  -(void) rightMouseUp:(NSEvent *) theEvent;
    4.18  -(void) otherMouseUp:(NSEvent *) theEvent;
    4.19 +-(void) mouseEntered:(NSEvent *)theEvent;
    4.20 +-(void) mouseExited:(NSEvent *)theEvent;
    4.21  -(void) mouseMoved:(NSEvent *) theEvent;
    4.22  -(void) mouseDragged:(NSEvent *) theEvent;
    4.23  -(void) rightMouseDragged:(NSEvent *) theEvent;
     5.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Sun Feb 20 23:51:59 2011 -0800
     5.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Mon Feb 21 10:50:53 2011 -0800
     5.3 @@ -41,54 +41,53 @@
     5.4  - (void)listen:(SDL_WindowData *)data
     5.5  {
     5.6      NSNotificationCenter *center;
     5.7 +    NSWindow *window = data->nswindow;
     5.8 +    NSView *view = [window contentView];
     5.9  
    5.10      _data = data;
    5.11  
    5.12      center = [NSNotificationCenter defaultCenter];
    5.13  
    5.14 -    [_data->nswindow setNextResponder:self];
    5.15 -    if ([_data->nswindow delegate] != nil) {
    5.16 -        [center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:_data->nswindow];
    5.17 -        [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:_data->nswindow];
    5.18 -        [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:_data->nswindow];
    5.19 -        [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:_data->nswindow];
    5.20 -        [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:_data->nswindow];
    5.21 -        [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:_data->nswindow];
    5.22 -        [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:_data->nswindow];
    5.23 -    } else {
    5.24 -        [_data->nswindow setDelegate:self];
    5.25 -    }
    5.26 -// FIXME: Why doesn't this work?
    5.27 -//    [center addObserver:self selector:@selector(rightMouseDown:) name:[NSString stringWithCString:"rightMouseDown" encoding:NSUTF8StringEncoding] object:[_data->nswindow contentView]];
    5.28 +    [center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:window];
    5.29 +    [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
    5.30 +    [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
    5.31 +    [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
    5.32 +    [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
    5.33 +    [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
    5.34 +    [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
    5.35      [center addObserver:self selector:@selector(windowDidHide:) name:NSApplicationDidHideNotification object:NSApp];
    5.36      [center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
    5.37  
    5.38 -    [_data->nswindow setAcceptsMouseMovedEvents:YES];
    5.39 +    [window setNextResponder:self];
    5.40 +    [window setAcceptsMouseMovedEvents:YES];
    5.41 +
    5.42 +    [view setNextResponder:self];
    5.43 +    [view addTrackingRect:[view visibleRect] owner:self userData:nil assumeInside:NO];
    5.44  #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
    5.45 -    [[_data->nswindow contentView] setAcceptsTouchEvents:YES];
    5.46 +    [view setAcceptsTouchEvents:YES];
    5.47  #endif
    5.48  }
    5.49  
    5.50  - (void)close
    5.51  {
    5.52      NSNotificationCenter *center;
    5.53 +    NSWindow *window = _data->nswindow;
    5.54 +    NSView *view = [window contentView];
    5.55  
    5.56      center = [NSNotificationCenter defaultCenter];
    5.57  
    5.58 -    [_data->nswindow setNextResponder:nil];
    5.59 -    if ([_data->nswindow delegate] != self) {
    5.60 -        [center removeObserver:self name:NSWindowDidExposeNotification object:_data->nswindow];
    5.61 -        [center removeObserver:self name:NSWindowDidMoveNotification object:_data->nswindow];
    5.62 -        [center removeObserver:self name:NSWindowDidResizeNotification object:_data->nswindow];
    5.63 -        [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:_data->nswindow];
    5.64 -        [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:_data->nswindow];
    5.65 -        [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:_data->nswindow];
    5.66 -        [center removeObserver:self name:NSWindowDidResignKeyNotification object:_data->nswindow];
    5.67 -    } else {
    5.68 -        [_data->nswindow setDelegate:nil];
    5.69 -    }
    5.70 +    [center removeObserver:self name:NSWindowDidExposeNotification object:window];
    5.71 +    [center removeObserver:self name:NSWindowDidMoveNotification object:window];
    5.72 +    [center removeObserver:self name:NSWindowDidResizeNotification object:window];
    5.73 +    [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
    5.74 +    [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
    5.75 +    [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
    5.76 +    [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
    5.77      [center removeObserver:self name:NSApplicationDidHideNotification object:NSApp];
    5.78      [center removeObserver:self name:NSApplicationDidUnhideNotification object:NSApp];
    5.79 +
    5.80 +    [window setNextResponder:nil];
    5.81 +    [view setNextResponder:nil];
    5.82  }
    5.83  
    5.84  - (BOOL)windowShouldClose:(id)sender
    5.85 @@ -141,11 +140,10 @@
    5.86      SDL_SetKeyboardFocus(window);
    5.87  
    5.88      /* If we just gained focus we need the updated mouse position */
    5.89 -    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
    5.90 +    if (SDL_GetMouseFocus() == window) {
    5.91          NSPoint point;
    5.92          point = [NSEvent mouseLocation];
    5.93          point = [_data->nswindow convertScreenToBase:point];
    5.94 -        point = [[_data->nswindow contentView] convertPoint:point fromView:nil];
    5.95          point.y = window->h - point.y;
    5.96          SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
    5.97      }
    5.98 @@ -239,22 +237,51 @@
    5.99      [self mouseUp:theEvent];
   5.100  }
   5.101  
   5.102 +- (void)mouseEntered:(NSEvent *)theEvent
   5.103 +{
   5.104 +    SDL_SetMouseFocus(_data->window);
   5.105 +}
   5.106 +
   5.107 +- (void)mouseExited:(NSEvent *)theEvent
   5.108 +{
   5.109 +    SDL_Window *window = _data->window;
   5.110 +
   5.111 +    if (SDL_GetMouseFocus() == window) {
   5.112 +        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   5.113 +            int x, y;
   5.114 +            NSPoint point;
   5.115 +            CGPoint cgpoint;
   5.116 +
   5.117 +            point = [theEvent locationInWindow];
   5.118 +            point.y = window->h - point.y;
   5.119 +
   5.120 +            SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   5.121 +            SDL_GetMouseState(&x, &y);
   5.122 +            cgpoint.x = window->x + x;
   5.123 +            cgpoint.y = window->y + y;
   5.124 +            CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   5.125 +        } else {
   5.126 +            SDL_SetMouseFocus(NULL);
   5.127 +        }
   5.128 +    }
   5.129 +}
   5.130 +
   5.131  - (void)mouseMoved:(NSEvent *)theEvent
   5.132  {
   5.133      SDL_Window *window = _data->window;
   5.134 -    NSPoint point;
   5.135  
   5.136 -    if (window->flags & SDL_WINDOW_FULLSCREEN)
   5.137 +#ifdef RELATIVE_MOTION
   5.138 +    if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   5.139          return;
   5.140 +    }
   5.141 +#endif
   5.142  
   5.143 -    point = [theEvent locationInWindow];
   5.144 -    point.y = window->h - point.y;
   5.145 -    if ( point.x < 0 || point.x >= window->w ||
   5.146 -         point.y < 0 || point.y >= window->h ) {
   5.147 -        if (SDL_GetMouseFocus() == window) {
   5.148 -            SDL_SetMouseFocus(NULL);
   5.149 -        }
   5.150 -    } else {
   5.151 +    if (SDL_GetMouseFocus() == window) {
   5.152 +        NSPoint point;
   5.153 +
   5.154 +        point = [theEvent locationInWindow];
   5.155 +        point.y = window->h - point.y;
   5.156 +
   5.157          SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
   5.158      }
   5.159  }
   5.160 @@ -386,28 +413,14 @@
   5.161  }
   5.162  @end
   5.163  
   5.164 -@interface SDLView : NSView {
   5.165 -    Cocoa_WindowListener *listener;
   5.166 -}
   5.167 +@interface SDLView : NSView { }
   5.168  @end
   5.169  
   5.170  @implementation SDLView
   5.171 -
   5.172 -- (id) initWithFrame: (NSRect) rect
   5.173 -            listener: (Cocoa_WindowListener *) theListener
   5.174 -{
   5.175 -    if (self = [super initWithFrame:rect]) {
   5.176 -        listener = theListener;
   5.177 -    }
   5.178 -
   5.179 -    return self;
   5.180 -}
   5.181 -
   5.182  - (void)rightMouseDown:(NSEvent *)theEvent
   5.183  {
   5.184 -    [listener mouseDown:theEvent];
   5.185 +    [[self nextResponder] rightMouseDown:theEvent];
   5.186  }
   5.187 -
   5.188  @end
   5.189  
   5.190  static unsigned int
   5.191 @@ -452,16 +465,11 @@
   5.192  
   5.193      /* Create an event listener for the window */
   5.194      data->listener = [[Cocoa_WindowListener alloc] init];
   5.195 -    [data->listener listen:data];
   5.196  
   5.197      /* Fill in the SDL window with the window data */
   5.198      {
   5.199          NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   5.200 -        NSView *contentView = [[SDLView alloc] initWithFrame: rect
   5.201 -                                                    listener: data->listener];
   5.202 -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
   5.203 -        [contentView setAcceptsTouchEvents:YES];
   5.204 -#endif
   5.205 +        NSView *contentView = [[SDLView alloc] initWithFrame:rect];
   5.206          [nswindow setContentView: contentView];
   5.207          [contentView release];
   5.208  
   5.209 @@ -471,6 +479,10 @@
   5.210          window->w = (int)rect.size.width;
   5.211          window->h = (int)rect.size.height;
   5.212      }
   5.213 +
   5.214 +    /* Set up the listener after we create the view */
   5.215 +    [data->listener listen:data];
   5.216 +
   5.217      if ([nswindow isVisible]) {
   5.218          window->flags |= SDL_WINDOW_SHOWN;
   5.219      } else {
   5.220 @@ -764,15 +776,35 @@
   5.221      [pool release];
   5.222  }
   5.223  
   5.224 +NSPoint origin;
   5.225  void
   5.226  Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
   5.227  {
   5.228 +#ifdef RELATIVE_MOTION
   5.229 +    /* FIXME: work in progress
   5.230 +        You set relative mode by using the following code in conjunction with
   5.231 +        CGDisplayHideCursor(kCGDirectMainDisplay) and
   5.232 +        CGDisplayShowCursor(kCGDirectMainDisplay)
   5.233 +    */
   5.234      if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   5.235          (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   5.236 -        /* FIXME: Grab mouse */
   5.237 +        CGAssociateMouseAndMouseCursorPosition(NO);
   5.238      } else {
   5.239 -        /* FIXME: Release mouse */
   5.240 +        CGAssociateMouseAndMouseCursorPosition(YES);
   5.241      }
   5.242 +#else
   5.243 +    /* Move the cursor to the nearest point in the window */
   5.244 +    if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   5.245 +        (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   5.246 +        int x, y;
   5.247 +        CGPoint cgpoint;
   5.248 +
   5.249 +        SDL_GetMouseState(&x, &y);
   5.250 +        cgpoint.x = window->x + x;
   5.251 +        cgpoint.y = window->y + y;
   5.252 +        CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
   5.253 +    }
   5.254 +#endif
   5.255  }
   5.256  
   5.257  void