Commit 65899724 authored by Sam Lantinga's avatar Sam Lantinga

Fixed the responder chain for event handling, the listener fully handles mouse...

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.
parent c379a10f
......@@ -29,43 +29,7 @@
#include "../video/SDL_sysvideo.h"
/* Global mouse information */
typedef struct SDL_Mouse SDL_Mouse;
struct SDL_Mouse
{
/* Create a cursor from a surface */
SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
/* Show the specified cursor, or hide if cursor is NULL */
int (*ShowCursor) (SDL_Cursor * cursor);
/* This is called when a mouse motion event occurs */
void (*MoveCursor) (SDL_Cursor * cursor);
/* Free a window manager cursor */
void (*FreeCursor) (SDL_Cursor * cursor);
/* Warp the mouse to (x,y) */
void (*WarpMouse) (SDL_Mouse * mouse, SDL_Window * window, int x, int y);
/* Data common to all mice */
SDL_Window *focus;
int x;
int y;
int xdelta;
int ydelta;
int last_x, last_y; /* the last reported x and y coordinates */
Uint8 buttonstate;
SDL_bool relative_mode;
SDL_Cursor *cursors;
SDL_Cursor *def_cursor;
SDL_Cursor *cur_cursor;
SDL_bool cursor_shown;
};
/* The mouse state */
static SDL_Mouse SDL_mouse;
......@@ -76,6 +40,12 @@ SDL_MouseInit(void)
return (0);
}
SDL_Mouse *
SDL_GetMouse(void)
{
return &SDL_mouse;
}
void
SDL_ResetMouse(void)
{
......@@ -85,7 +55,7 @@ SDL_ResetMouse(void)
SDL_Window *
SDL_GetMouseFocus(void)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
return mouse->focus;
}
......@@ -93,7 +63,7 @@ SDL_GetMouseFocus(void)
void
SDL_SetMouseFocus(SDL_Window * window)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->focus == window) {
return;
......@@ -114,7 +84,7 @@ SDL_SetMouseFocus(SDL_Window * window)
int
SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
int xrel;
int yrel;
......@@ -204,7 +174,7 @@ SDL_SendMouseMotion(SDL_Window * window, int relative, int x, int y)
int
SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
Uint32 type;
......@@ -253,7 +223,7 @@ SDL_SendMouseButton(SDL_Window * window, Uint8 state, Uint8 button)
int
SDL_SendMouseWheel(SDL_Window * window, int x, int y)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
int posted;
if (window) {
......@@ -285,7 +255,7 @@ SDL_MouseQuit(void)
Uint8
SDL_GetMouseState(int *x, int *y)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
if (x) {
*x = mouse->x;
......@@ -299,7 +269,7 @@ SDL_GetMouseState(int *x, int *y)
Uint8
SDL_GetRelativeMouseState(int *x, int *y)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
if (x) {
*x = mouse->xdelta;
......@@ -315,10 +285,10 @@ SDL_GetRelativeMouseState(int *x, int *y)
void
SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
if (mouse->WarpMouse) {
mouse->WarpMouse(mouse, window, x, y);
mouse->WarpMouse(window, x, y);
} else {
SDL_SendMouseMotion(window, 0, x, y);
}
......@@ -327,7 +297,7 @@ SDL_WarpMouseInWindow(SDL_Window * window, int x, int y)
int
SDL_SetRelativeMouseMode(SDL_bool enabled)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
/* Flush pending mouse motion */
SDL_FlushEvent(SDL_MOUSEMOTION);
......@@ -349,7 +319,7 @@ SDL_SetRelativeMouseMode(SDL_bool enabled)
SDL_bool
SDL_GetRelativeMouseMode()
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
return mouse->relative_mode;
}
......@@ -358,7 +328,7 @@ SDL_Cursor *
SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
int w, int h, int hot_x, int hot_y)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Surface *surface;
SDL_Cursor *cursor;
int x, y;
......@@ -424,7 +394,7 @@ SDL_CreateCursor(const Uint8 * data, const Uint8 * mask,
void
SDL_SetCursor(SDL_Cursor * cursor)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
/* Set the new cursor */
if (cursor) {
......@@ -458,7 +428,7 @@ SDL_SetCursor(SDL_Cursor * cursor)
SDL_Cursor *
SDL_GetCursor(void)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
if (!mouse) {
return NULL;
......@@ -469,7 +439,7 @@ SDL_GetCursor(void)
void
SDL_FreeCursor(SDL_Cursor * cursor)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Cursor *curr, *prev;
if (!cursor) {
......@@ -503,7 +473,7 @@ SDL_FreeCursor(SDL_Cursor * cursor)
int
SDL_ShowCursor(int toggle)
{
SDL_Mouse *mouse = &SDL_mouse;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_bool shown;
if (!mouse) {
......
......@@ -24,15 +24,54 @@
#ifndef _SDL_mouse_c_h
#define _SDL_mouse_c_h
#include "SDL_mouse.h"
struct SDL_Cursor
{
struct SDL_Cursor *next;
void *driverdata;
};
typedef struct
{
/* Create a cursor from a surface */
SDL_Cursor *(*CreateCursor) (SDL_Surface * surface, int hot_x, int hot_y);
/* Show the specified cursor, or hide if cursor is NULL */
int (*ShowCursor) (SDL_Cursor * cursor);
/* This is called when a mouse motion event occurs */
void (*MoveCursor) (SDL_Cursor * cursor);
/* Free a window manager cursor */
void (*FreeCursor) (SDL_Cursor * cursor);
/* Warp the mouse to (x,y) */
void (*WarpMouse) (SDL_Window * window, int x, int y);
/* Data common to all mice */
SDL_Window *focus;
int x;
int y;
int xdelta;
int ydelta;
int last_x, last_y; /* the last reported x and y coordinates */
Uint8 buttonstate;
SDL_bool relative_mode;
SDL_Cursor *cursors;
SDL_Cursor *def_cursor;
SDL_Cursor *cur_cursor;
SDL_bool cursor_shown;
} SDL_Mouse;
/* Initialize the mouse subsystem */
extern int SDL_MouseInit(void);
/* Get the mouse state structure */
SDL_Mouse *SDL_GetMouse(void);
/* Clear the mouse state */
extern void SDL_ResetMouse(void);
......
......@@ -49,62 +49,7 @@ ConvertMouseButtonToSDL(int button)
void
Cocoa_HandleMouseEvent(_THIS, NSEvent *event)
{
int i;
NSPoint point = { 0, 0 };
SDL_Window *window;
SDL_Window *focus = SDL_GetMouseFocus();
/* See if there are any fullscreen windows that might handle this event */
window = NULL;
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
SDL_Window *candidate = display->fullscreen_window;
if (candidate) {
SDL_Rect bounds;
Cocoa_GetDisplayBounds(_this, display, &bounds);
point = [NSEvent mouseLocation];
point.x = point.x - bounds.x;
point.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - point.y - bounds.y;
if ((point.x >= 0 && point.x < candidate->w) &&
(point.y >= 0 && point.y < candidate->h)) {
/* This is it! */
window = candidate;
break;
} else if (candidate == focus) {
SDL_SetMouseFocus(NULL);
}
}
}
if (!window) {
return;
}
switch ([event type]) {
case NSLeftMouseDown:
case NSOtherMouseDown:
case NSRightMouseDown:
SDL_SendMouseButton(window, SDL_PRESSED, ConvertMouseButtonToSDL([event buttonNumber]));
break;
case NSLeftMouseUp:
case NSOtherMouseUp:
case NSRightMouseUp:
SDL_SendMouseButton(window, SDL_RELEASED, ConvertMouseButtonToSDL([event buttonNumber]));
break;
case NSScrollWheel:
Cocoa_HandleMouseWheel(window, event);
break;
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged: /* usually middle mouse dragged */
case NSMouseMoved:
SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
break;
default: /* just to avoid compiler warnings */
break;
}
/* We're correctly using views even in fullscreen mode now */
}
void
......
......@@ -29,11 +29,7 @@
typedef struct SDL_WindowData SDL_WindowData;
/* *INDENT-OFF* */
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
@interface Cocoa_WindowListener : NSResponder <NSWindowDelegate> {
#else
@interface Cocoa_WindowListener : NSResponder {
#endif
SDL_WindowData *_data;
}
......@@ -59,6 +55,8 @@ typedef struct SDL_WindowData SDL_WindowData;
-(void) mouseUp:(NSEvent *) theEvent;
-(void) rightMouseUp:(NSEvent *) theEvent;
-(void) otherMouseUp:(NSEvent *) theEvent;
-(void) mouseEntered:(NSEvent *)theEvent;
-(void) mouseExited:(NSEvent *)theEvent;
-(void) mouseMoved:(NSEvent *) theEvent;
-(void) mouseDragged:(NSEvent *) theEvent;
-(void) rightMouseDragged:(NSEvent *) theEvent;
......
......@@ -41,54 +41,53 @@ static __inline__ void ConvertNSRect(NSRect *r)
- (void)listen:(SDL_WindowData *)data
{
NSNotificationCenter *center;
NSWindow *window = data->nswindow;
NSView *view = [window contentView];
_data = data;
center = [NSNotificationCenter defaultCenter];
[_data->nswindow setNextResponder:self];
if ([_data->nswindow delegate] != nil) {
[center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:_data->nswindow];
[center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:_data->nswindow];
[center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:_data->nswindow];
[center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:_data->nswindow];
[center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:_data->nswindow];
[center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:_data->nswindow];
[center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:_data->nswindow];
} else {
[_data->nswindow setDelegate:self];
}
// FIXME: Why doesn't this work?
// [center addObserver:self selector:@selector(rightMouseDown:) name:[NSString stringWithCString:"rightMouseDown" encoding:NSUTF8StringEncoding] object:[_data->nswindow contentView]];
[center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:window];
[center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
[center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
[center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
[center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
[center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
[center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
[center addObserver:self selector:@selector(windowDidHide:) name:NSApplicationDidHideNotification object:NSApp];
[center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
[_data->nswindow setAcceptsMouseMovedEvents:YES];
[window setNextResponder:self];
[window setAcceptsMouseMovedEvents:YES];
[view setNextResponder:self];
[view addTrackingRect:[view visibleRect] owner:self userData:nil assumeInside:NO];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
[[_data->nswindow contentView] setAcceptsTouchEvents:YES];
[view setAcceptsTouchEvents:YES];
#endif
}
- (void)close
{
NSNotificationCenter *center;
NSWindow *window = _data->nswindow;
NSView *view = [window contentView];
center = [NSNotificationCenter defaultCenter];
[_data->nswindow setNextResponder:nil];
if ([_data->nswindow delegate] != self) {
[center removeObserver:self name:NSWindowDidExposeNotification object:_data->nswindow];
[center removeObserver:self name:NSWindowDidMoveNotification object:_data->nswindow];
[center removeObserver:self name:NSWindowDidResizeNotification object:_data->nswindow];
[center removeObserver:self name:NSWindowDidMiniaturizeNotification object:_data->nswindow];
[center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:_data->nswindow];
[center removeObserver:self name:NSWindowDidBecomeKeyNotification object:_data->nswindow];
[center removeObserver:self name:NSWindowDidResignKeyNotification object:_data->nswindow];
} else {
[_data->nswindow setDelegate:nil];
}
[center removeObserver:self name:NSWindowDidExposeNotification object:window];
[center removeObserver:self name:NSWindowDidMoveNotification object:window];
[center removeObserver:self name:NSWindowDidResizeNotification object:window];
[center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
[center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
[center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
[center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
[center removeObserver:self name:NSApplicationDidHideNotification object:NSApp];
[center removeObserver:self name:NSApplicationDidUnhideNotification object:NSApp];
[window setNextResponder:nil];
[view setNextResponder:nil];
}
- (BOOL)windowShouldClose:(id)sender
......@@ -141,11 +140,10 @@ static __inline__ void ConvertNSRect(NSRect *r)
SDL_SetKeyboardFocus(window);
/* If we just gained focus we need the updated mouse position */
if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
if (SDL_GetMouseFocus() == window) {
NSPoint point;
point = [NSEvent mouseLocation];
point = [_data->nswindow convertScreenToBase:point];
point = [[_data->nswindow contentView] convertPoint:point fromView:nil];
point.y = window->h - point.y;
SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
}
......@@ -239,22 +237,51 @@ static __inline__ void ConvertNSRect(NSRect *r)
[self mouseUp:theEvent];
}
- (void)mouseMoved:(NSEvent *)theEvent
- (void)mouseEntered:(NSEvent *)theEvent
{
SDL_SetMouseFocus(_data->window);
}
- (void)mouseExited:(NSEvent *)theEvent
{
SDL_Window *window = _data->window;
NSPoint point;
if (window->flags & SDL_WINDOW_FULLSCREEN)
return;
if (SDL_GetMouseFocus() == window) {
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
int x, y;
NSPoint point;
CGPoint cgpoint;
point = [theEvent locationInWindow];
point.y = window->h - point.y;
if ( point.x < 0 || point.x >= window->w ||
point.y < 0 || point.y >= window->h ) {
if (SDL_GetMouseFocus() == window) {
SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
SDL_GetMouseState(&x, &y);
cgpoint.x = window->x + x;
cgpoint.y = window->y + y;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
} else {
SDL_SetMouseFocus(NULL);
}
} else {
}
}
- (void)mouseMoved:(NSEvent *)theEvent
{
SDL_Window *window = _data->window;
#ifdef RELATIVE_MOTION
if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
return;
}
#endif
if (SDL_GetMouseFocus() == window) {
NSPoint point;
point = [theEvent locationInWindow];
point.y = window->h - point.y;
SDL_SendMouseMotion(window, 0, (int)point.x, (int)point.y);
}
}
......@@ -386,28 +413,14 @@ static __inline__ void ConvertNSRect(NSRect *r)
}
@end
@interface SDLView : NSView {
Cocoa_WindowListener *listener;
}
@interface SDLView : NSView { }
@end
@implementation SDLView
- (id) initWithFrame: (NSRect) rect
listener: (Cocoa_WindowListener *) theListener
{
if (self = [super initWithFrame:rect]) {
listener = theListener;
}
return self;
}
- (void)rightMouseDown:(NSEvent *)theEvent
{
[listener mouseDown:theEvent];
[[self nextResponder] rightMouseDown:theEvent];
}
@end
static unsigned int
......@@ -452,16 +465,11 @@ SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created
/* Create an event listener for the window */
data->listener = [[Cocoa_WindowListener alloc] init];
[data->listener listen:data];
/* Fill in the SDL window with the window data */
{
NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
NSView *contentView = [[SDLView alloc] initWithFrame: rect
listener: data->listener];
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
[contentView setAcceptsTouchEvents:YES];
#endif
NSView *contentView = [[SDLView alloc] initWithFrame:rect];
[nswindow setContentView: contentView];
[contentView release];
......@@ -471,6 +479,10 @@ SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created
window->w = (int)rect.size.width;
window->h = (int)rect.size.height;
}
/* Set up the listener after we create the view */
[data->listener listen:data];
if ([nswindow isVisible]) {
window->flags |= SDL_WINDOW_SHOWN;
} else {
......@@ -764,15 +776,35 @@ Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display
[pool release];
}
NSPoint origin;
void
Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
{
#ifdef RELATIVE_MOTION
/* FIXME: work in progress
You set relative mode by using the following code in conjunction with
CGDisplayHideCursor(kCGDirectMainDisplay) and
CGDisplayShowCursor(kCGDirectMainDisplay)
*/
if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
/* FIXME: Grab mouse */
CGAssociateMouseAndMouseCursorPosition(NO);
} else {
/* FIXME: Release mouse */
CGAssociateMouseAndMouseCursorPosition(YES);
}
#else
/* Move the cursor to the nearest point in the window */
if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
(window->flags & SDL_WINDOW_INPUT_FOCUS)) {
int x, y;
CGPoint cgpoint;
SDL_GetMouseState(&x, &y);
cgpoint.x = window->x + x;
cgpoint.y = window->y + y;
CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
}
#endif
}
void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment