src/video/cocoa/SDL_cocoawindow.m
author Edward Rudd <urkle@outoforder.cc>
Sun, 23 Nov 2014 15:48:52 -0500
changeset 9236 a845edf98a80
parent 9086 c5e33f9a0d03
child 9237 2cc90bb31777
permissions -rw-r--r--
Cocoa: add in handling of "lost" touches on OS X. [bug #2635]

This scenario can occur, for example, when the 4-finger touch sequence is used to switch spaces. the SDL window does not receive the touch up events and ends up thinking there are far more fingers on the pad than there are.

So the solution here is everytime a new "touch" appears we can through and check if there are any existing known touches by the OS and if there are none, abut SDL things there are, we simply go through and cancel the SDL touches.

Side affects.
- the "touch up" won't occur until the users sends a new touch (could be well after the actual release really did occur)
slouken@1933
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@8149
     3
  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
slouken@1933
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1933
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1933
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1933
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@1933
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_COCOA
slouken@6044
    24
slouken@8083
    25
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
slouken@8083
    26
# error SDL for Mac OS X must be built with a 10.7 SDK or above.
slouken@8083
    27
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1070 */
slouken@8083
    28
slouken@1933
    29
#include "SDL_syswm.h"
slouken@5398
    30
#include "SDL_timer.h"  /* For SDL_GetTicks() */
slouken@7915
    31
#include "SDL_hints.h"
slouken@1933
    32
#include "../SDL_sysvideo.h"
slouken@1933
    33
#include "../../events/SDL_keyboard_c.h"
slouken@1933
    34
#include "../../events/SDL_mouse_c.h"
slouken@4673
    35
#include "../../events/SDL_touch_c.h"
slouken@1933
    36
#include "../../events/SDL_windowevents_c.h"
slouken@1933
    37
#include "SDL_cocoavideo.h"
eligottlieb@4811
    38
#include "SDL_cocoashape.h"
gzjjgod@5057
    39
#include "SDL_cocoamouse.h"
jorgen@7594
    40
#include "SDL_cocoaopengl.h"
icculus@8295
    41
#include "SDL_assert.h"
slouken@1933
    42
jorgen@8261
    43
/* #define DEBUG_COCOAWINDOW */
jorgen@8261
    44
jorgen@8261
    45
#ifdef DEBUG_COCOAWINDOW
jorgen@8261
    46
#define DLog(fmt, ...) printf("%s: " fmt "\n", __func__, ##__VA_ARGS__)
jorgen@8261
    47
#else
jorgen@8261
    48
#define DLog(...) do { } while (0)
jorgen@8261
    49
#endif
jorgen@8261
    50
jorgen@8261
    51
slouken@8801
    52
#define FULLSCREEN_MASK (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN)
slouken@8801
    53
slouken@8801
    54
jorgen@8260
    55
@interface SDLWindow : NSWindow
jorgen@8260
    56
/* These are needed for borderless/fullscreen windows */
jorgen@8260
    57
- (BOOL)canBecomeKeyWindow;
jorgen@8260
    58
- (BOOL)canBecomeMainWindow;
jorgen@8260
    59
- (void)sendEvent:(NSEvent *)event;
slouken@8809
    60
- (void)doCommandBySelector:(SEL)aSelector;
jorgen@8260
    61
@end
jorgen@8260
    62
jorgen@8260
    63
@implementation SDLWindow
jorgen@8260
    64
- (BOOL)canBecomeKeyWindow
jorgen@8260
    65
{
jorgen@8260
    66
    return YES;
jorgen@8260
    67
}
jorgen@8260
    68
jorgen@8260
    69
- (BOOL)canBecomeMainWindow
jorgen@8260
    70
{
jorgen@8260
    71
    return YES;
jorgen@8260
    72
}
jorgen@8260
    73
jorgen@8260
    74
- (void)sendEvent:(NSEvent *)event
jorgen@8260
    75
{
jorgen@8260
    76
  [super sendEvent:event];
jorgen@8260
    77
jorgen@8260
    78
  if ([event type] != NSLeftMouseUp) {
jorgen@8260
    79
      return;
jorgen@8260
    80
  }
jorgen@8260
    81
jorgen@8260
    82
  id delegate = [self delegate];
jorgen@8260
    83
  if (![delegate isKindOfClass:[Cocoa_WindowListener class]]) {
jorgen@8260
    84
      return;
jorgen@8260
    85
  }
jorgen@8260
    86
jorgen@8260
    87
  if ([delegate isMoving]) {
jorgen@8260
    88
      [delegate windowDidFinishMoving];
jorgen@8260
    89
  }
jorgen@8260
    90
}
slouken@8809
    91
slouken@8809
    92
/* We'll respond to selectors by doing nothing so we don't beep.
slouken@8809
    93
 * The escape key gets converted to a "cancel" selector, etc.
slouken@8809
    94
 */
slouken@8809
    95
- (void)doCommandBySelector:(SEL)aSelector
slouken@8809
    96
{
slouken@8809
    97
    /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
slouken@8809
    98
}
jorgen@8260
    99
@end
jorgen@8260
   100
jorgen@8260
   101
slouken@5398
   102
static Uint32 s_moveHack;
slouken@5398
   103
slouken@8801
   104
static void ConvertNSRect(NSScreen *screen, BOOL fullscreen, NSRect *r)
slouken@1933
   105
{
slouken@9086
   106
    r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
slouken@1933
   107
}
slouken@1933
   108
slouken@7952
   109
static void
slouken@7952
   110
ScheduleContextUpdates(SDL_WindowData *data)
jorgen@7595
   111
{
jorgen@8258
   112
    NSOpenGLContext *currentContext = [NSOpenGLContext currentContext];
jorgen@7595
   113
    NSMutableArray *contexts = data->nscontexts;
jorgen@7595
   114
    @synchronized (contexts) {
jorgen@7595
   115
        for (SDLOpenGLContext *context in contexts) {
jorgen@8258
   116
            if (context == currentContext) {
jorgen@8258
   117
                [context update];
jorgen@8258
   118
            } else {
jorgen@8258
   119
                [context scheduleUpdate];
jorgen@8258
   120
            }
jorgen@7595
   121
        }
jorgen@7595
   122
    }
jorgen@7595
   123
}
jorgen@7595
   124
slouken@7952
   125
static int
slouken@7952
   126
GetHintCtrlClickEmulateRightClick()
slouken@7915
   127
{
slouken@7915
   128
	const char *hint = SDL_GetHint( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK );
slouken@7915
   129
	return hint != NULL && *hint != '0';
slouken@7915
   130
}
slouken@7915
   131
slouken@7952
   132
static unsigned int
slouken@7952
   133
GetWindowStyle(SDL_Window * window)
slouken@7952
   134
{
slouken@7952
   135
    unsigned int style;
slouken@7952
   136
icculus@8295
   137
    if (window->flags & SDL_WINDOW_FULLSCREEN) {
slouken@7952
   138
        style = NSBorderlessWindowMask;
slouken@7952
   139
    } else {
slouken@7952
   140
        if (window->flags & SDL_WINDOW_BORDERLESS) {
slouken@7952
   141
            style = NSBorderlessWindowMask;
slouken@7952
   142
        } else {
slouken@7952
   143
            style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
slouken@7952
   144
        }
slouken@7952
   145
        if (window->flags & SDL_WINDOW_RESIZABLE) {
slouken@7952
   146
            style |= NSResizableWindowMask;
slouken@7952
   147
        }
slouken@7952
   148
    }
slouken@7952
   149
    return style;
slouken@7952
   150
}
slouken@7952
   151
slouken@7990
   152
static SDL_bool
slouken@7990
   153
SetWindowStyle(SDL_Window * window, unsigned int style)
slouken@7990
   154
{
slouken@7990
   155
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@7990
   156
    NSWindow *nswindow = data->nswindow;
slouken@7990
   157
slouken@7990
   158
    if (![nswindow respondsToSelector: @selector(setStyleMask:)]) {
slouken@7990
   159
        return SDL_FALSE;
slouken@7990
   160
    }
slouken@7990
   161
slouken@7990
   162
    /* The view responder chain gets messed with during setStyleMask */
slouken@7990
   163
    if ([[nswindow contentView] nextResponder] == data->listener) {
slouken@7990
   164
        [[nswindow contentView] setNextResponder:nil];
slouken@7990
   165
    }
slouken@7990
   166
slouken@7990
   167
    [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)style];
slouken@7990
   168
slouken@7990
   169
    /* The view responder chain gets messed with during setStyleMask */
slouken@7990
   170
    if ([[nswindow contentView] nextResponder] != data->listener) {
slouken@7990
   171
        [[nswindow contentView] setNextResponder:data->listener];
slouken@7990
   172
    }
slouken@7990
   173
slouken@7990
   174
    return SDL_TRUE;
slouken@7990
   175
}
slouken@7990
   176
slouken@7952
   177
slouken@1933
   178
@implementation Cocoa_WindowListener
slouken@1933
   179
slouken@1933
   180
- (void)listen:(SDL_WindowData *)data
slouken@1933
   181
{
slouken@1933
   182
    NSNotificationCenter *center;
slouken@5371
   183
    NSWindow *window = data->nswindow;
slouken@5371
   184
    NSView *view = [window contentView];
slouken@1933
   185
slouken@1933
   186
    _data = data;
jorgen@7087
   187
    observingVisible = YES;
slouken@7740
   188
    wasCtrlLeft = NO;
jorgen@7087
   189
    wasVisible = [window isVisible];
slouken@7967
   190
    isFullscreenSpace = NO;
slouken@7952
   191
    inFullscreenTransition = NO;
slouken@7963
   192
    pendingWindowOperation = PENDING_OPERATION_NONE;
jorgen@8260
   193
    isMoving = NO;
icculus@8931
   194
    isDragAreaRunning = NO;
slouken@1933
   195
slouken@1933
   196
    center = [NSNotificationCenter defaultCenter];
slouken@1933
   197
slouken@5374
   198
    if ([window delegate] != nil) {
slouken@5374
   199
        [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
slouken@5374
   200
        [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
slouken@5374
   201
        [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
slouken@5374
   202
        [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
slouken@5374
   203
        [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
slouken@5374
   204
        [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
slouken@5374
   205
        [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
slouken@7952
   206
        [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
slouken@7952
   207
        [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
slouken@7952
   208
        [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
slouken@7952
   209
        [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window];
slouken@5374
   210
    } else {
slouken@5374
   211
        [window setDelegate:self];
slouken@5374
   212
    }
slouken@1933
   213
slouken@7191
   214
    /* Haven't found a delegate / notification that triggers when the window is
slouken@7191
   215
     * ordered out (is not visible any more). You can be ordered out without
slouken@7191
   216
     * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
slouken@7191
   217
     */
jorgen@7084
   218
    [window addObserver:self
jorgen@7084
   219
             forKeyPath:@"visible"
jorgen@7084
   220
                options:NSKeyValueObservingOptionNew
jorgen@7084
   221
                context:NULL];
jorgen@7084
   222
slouken@5371
   223
    [window setNextResponder:self];
slouken@5371
   224
    [window setAcceptsMouseMovedEvents:YES];
slouken@5371
   225
slouken@5371
   226
    [view setNextResponder:self];
icculus@6108
   227
icculus@6108
   228
    if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
icculus@6108
   229
        [view setAcceptsTouchEvents:YES];
icculus@6108
   230
    }
slouken@1933
   231
}
slouken@1933
   232
jorgen@7084
   233
- (void)observeValueForKeyPath:(NSString *)keyPath
jorgen@7084
   234
                      ofObject:(id)object
jorgen@7084
   235
                        change:(NSDictionary *)change
jorgen@7084
   236
                       context:(void *)context
jorgen@7084
   237
{
jorgen@7087
   238
    if (!observingVisible) {
jorgen@7087
   239
        return;
jorgen@7087
   240
    }
jorgen@7087
   241
jorgen@7084
   242
    if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
jorgen@7084
   243
        int newVisibility = [[change objectForKey:@"new"] intValue];
jorgen@7084
   244
        if (newVisibility) {
jorgen@7084
   245
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
jorgen@7084
   246
        } else {
jorgen@7084
   247
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
jorgen@7084
   248
        }
jorgen@7084
   249
    }
jorgen@7084
   250
}
jorgen@7084
   251
jorgen@7087
   252
-(void) pauseVisibleObservation
jorgen@7087
   253
{
jorgen@7087
   254
    observingVisible = NO;
jorgen@7087
   255
    wasVisible = [_data->nswindow isVisible];
jorgen@7087
   256
}
jorgen@7087
   257
jorgen@7087
   258
-(void) resumeVisibleObservation
jorgen@7087
   259
{
jorgen@7087
   260
    BOOL isVisible = [_data->nswindow isVisible];
jorgen@7087
   261
    observingVisible = YES;
jorgen@7087
   262
    if (wasVisible != isVisible) {
jorgen@7087
   263
        if (isVisible) {
jorgen@7087
   264
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
jorgen@7087
   265
        } else {
jorgen@7087
   266
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
jorgen@7087
   267
        }
jorgen@7087
   268
jorgen@7087
   269
        wasVisible = isVisible;
jorgen@7087
   270
    }
jorgen@7087
   271
}
jorgen@7087
   272
icculus@8284
   273
-(BOOL) setFullscreenSpace:(BOOL) state
slouken@7961
   274
{
slouken@7961
   275
    SDL_Window *window = _data->window;
slouken@7961
   276
    NSWindow *nswindow = _data->nswindow;
icculus@8295
   277
    SDL_VideoData *videodata = ((SDL_WindowData *) window->driverdata)->videodata;
slouken@7961
   278
icculus@8295
   279
    if (!videodata->allow_spaces) {
icculus@8295
   280
        return NO;  /* Spaces are forcibly disabled. */
icculus@8295
   281
    } else if (state && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)) {
icculus@8292
   282
        return NO;  /* we only allow you to make a Space on FULLSCREEN_DESKTOP windows. */
slouken@8798
   283
    } else if (!state && ((window->last_fullscreen_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP)) {
slouken@8798
   284
        return NO;  /* we only handle leaving the Space on windows that were previously FULLSCREEN_DESKTOP. */
icculus@8284
   285
    } else if (state == isFullscreenSpace) {
icculus@8284
   286
        return YES;  /* already there. */
slouken@7961
   287
    }
slouken@7961
   288
slouken@7961
   289
    if (inFullscreenTransition) {
slouken@7961
   290
        if (state) {
slouken@7963
   291
            [self addPendingWindowOperation:PENDING_OPERATION_ENTER_FULLSCREEN];
slouken@7961
   292
        } else {
slouken@7963
   293
            [self addPendingWindowOperation:PENDING_OPERATION_LEAVE_FULLSCREEN];
slouken@7961
   294
        }
slouken@7961
   295
        return YES;
slouken@7961
   296
    }
slouken@7968
   297
    inFullscreenTransition = YES;
slouken@7968
   298
icculus@8295
   299
    /* you need to be FullScreenPrimary, or toggleFullScreen doesn't work. Unset it again in windowDidExitFullScreen. */
icculus@8284
   300
    [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
slouken@7965
   301
    [nswindow performSelectorOnMainThread: @selector(toggleFullScreen:) withObject:nswindow waitUntilDone:NO];
slouken@7961
   302
    return YES;
slouken@7952
   303
}
slouken@7952
   304
slouken@7968
   305
-(BOOL) isInFullscreenSpace
slouken@7968
   306
{
slouken@7968
   307
    return isFullscreenSpace;
slouken@7968
   308
}
slouken@7968
   309
slouken@7968
   310
-(BOOL) isInFullscreenSpaceTransition
slouken@7963
   311
{
slouken@7963
   312
    return inFullscreenTransition;
slouken@7963
   313
}
slouken@7963
   314
slouken@7963
   315
-(void) addPendingWindowOperation:(PendingWindowOperation) operation
slouken@7963
   316
{
slouken@7963
   317
    pendingWindowOperation = operation;
slouken@7963
   318
}
slouken@7963
   319
slouken@1933
   320
- (void)close
slouken@1933
   321
{
slouken@1933
   322
    NSNotificationCenter *center;
slouken@5371
   323
    NSWindow *window = _data->nswindow;
slouken@5371
   324
    NSView *view = [window contentView];
icculus@7534
   325
    NSArray *windows = nil;
slouken@1933
   326
slouken@1933
   327
    center = [NSNotificationCenter defaultCenter];
slouken@1933
   328
slouken@5374
   329
    if ([window delegate] != self) {
slouken@5374
   330
        [center removeObserver:self name:NSWindowDidExposeNotification object:window];
slouken@5374
   331
        [center removeObserver:self name:NSWindowDidMoveNotification object:window];
slouken@5374
   332
        [center removeObserver:self name:NSWindowDidResizeNotification object:window];
slouken@5374
   333
        [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
slouken@5374
   334
        [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
slouken@5374
   335
        [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
slouken@5374
   336
        [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
slouken@7952
   337
        [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
slouken@7952
   338
        [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
slouken@7952
   339
        [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
slouken@7952
   340
        [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window];
slouken@5374
   341
    } else {
slouken@5374
   342
        [window setDelegate:nil];
slouken@5374
   343
    }
slouken@5371
   344
slouken@7961
   345
    [window removeObserver:self forKeyPath:@"visible"];
jorgen@7084
   346
slouken@5374
   347
    if ([window nextResponder] == self) {
slouken@5374
   348
        [window setNextResponder:nil];
slouken@5374
   349
    }
slouken@5374
   350
    if ([view nextResponder] == self) {
slouken@5374
   351
        [view setNextResponder:nil];
slouken@5374
   352
    }
icculus@7534
   353
icculus@7534
   354
    /* Make the next window in the z-order Key. If we weren't the foreground
icculus@7535
   355
       when closed, this is a no-op.
icculus@7535
   356
       !!! FIXME: Note that this is a hack, and there are corner cases where
icculus@7535
   357
       !!! FIXME:  this fails (such as the About box). The typical nib+RunLoop
icculus@7535
   358
       !!! FIXME:  handles this for Cocoa apps, but we bypass all that in SDL.
icculus@7535
   359
       !!! FIXME:  We should remove this code when we find a better way to
icculus@7535
   360
       !!! FIXME:  have the system do this for us. See discussion in
icculus@7535
   361
       !!! FIXME:   http://bugzilla.libsdl.org/show_bug.cgi?id=1825
icculus@7535
   362
    */
icculus@7534
   363
    windows = [NSApp orderedWindows];
slouken@8986
   364
    for (NSWindow *win in windows) {
jorgen@8111
   365
        if (win == window) {
jorgen@8111
   366
            continue;
jorgen@8111
   367
        }
jorgen@8111
   368
icculus@7534
   369
        [win makeKeyAndOrderFront:self];
jorgen@8111
   370
        break;
icculus@7534
   371
    }
slouken@1933
   372
}
slouken@1933
   373
jorgen@8260
   374
- (BOOL)isMoving
jorgen@8260
   375
{
jorgen@8260
   376
    return isMoving;
jorgen@8260
   377
}
jorgen@8260
   378
jorgen@8260
   379
-(void) setPendingMoveX:(int)x Y:(int)y
jorgen@8260
   380
{
jorgen@8260
   381
    pendingWindowWarpX = x;
jorgen@8260
   382
    pendingWindowWarpY = y;
jorgen@8260
   383
}
jorgen@8260
   384
jorgen@8260
   385
- (void)windowDidFinishMoving
jorgen@8260
   386
{
slouken@8986
   387
    if ([self isMoving]) {
jorgen@8260
   388
        isMoving = NO;
jorgen@8260
   389
jorgen@8260
   390
        SDL_Mouse *mouse = SDL_GetMouse();
slouken@9086
   391
        if (pendingWindowWarpX != INT_MAX && pendingWindowWarpY != INT_MAX) {
slouken@9086
   392
            mouse->WarpMouseGlobal(pendingWindowWarpX, pendingWindowWarpY);
slouken@9086
   393
            pendingWindowWarpX = pendingWindowWarpY = INT_MAX;
jorgen@8260
   394
        }
slouken@9086
   395
        if (mouse->relative_mode && !mouse->relative_mode_warp && mouse->focus == _data->window) {
jorgen@8260
   396
            mouse->SetRelativeMouseMode(SDL_TRUE);
jorgen@8260
   397
        }
jorgen@8260
   398
    }
jorgen@8260
   399
}
jorgen@8260
   400
slouken@1933
   401
- (BOOL)windowShouldClose:(id)sender
slouken@1933
   402
{
slouken@3685
   403
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
slouken@1933
   404
    return NO;
slouken@1933
   405
}
slouken@1933
   406
slouken@1933
   407
- (void)windowDidExpose:(NSNotification *)aNotification
slouken@1933
   408
{
slouken@3685
   409
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
slouken@1933
   410
}
slouken@1933
   411
jorgen@8260
   412
- (void)windowWillMove:(NSNotification *)aNotification
jorgen@8260
   413
{
jorgen@8260
   414
    if ([_data->nswindow isKindOfClass:[SDLWindow class]]) {
slouken@9086
   415
        pendingWindowWarpX = pendingWindowWarpY = INT_MAX;
jorgen@8260
   416
        isMoving = YES;
jorgen@8260
   417
    }
jorgen@8260
   418
}
jorgen@8260
   419
slouken@1933
   420
- (void)windowDidMove:(NSNotification *)aNotification
slouken@1933
   421
{
slouken@1933
   422
    int x, y;
slouken@5398
   423
    SDL_Window *window = _data->window;
slouken@5398
   424
    NSWindow *nswindow = _data->nswindow;
slouken@8801
   425
    BOOL fullscreen = window->flags & FULLSCREEN_MASK;
slouken@5398
   426
    NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@8801
   427
    ConvertNSRect([nswindow screen], fullscreen, &rect);
slouken@5398
   428
slouken@5398
   429
    if (s_moveHack) {
slouken@5398
   430
        SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
slouken@5398
   431
slouken@5398
   432
        s_moveHack = 0;
slouken@5398
   433
slouken@5398
   434
        if (blockMove) {
slouken@5398
   435
            /* Cocoa is adjusting the window in response to a mode change */
slouken@5398
   436
            rect.origin.x = window->x;
slouken@5398
   437
            rect.origin.y = window->y;
slouken@8801
   438
            ConvertNSRect([nswindow screen], fullscreen, &rect);
slouken@5398
   439
            [nswindow setFrameOrigin:rect.origin];
slouken@5398
   440
            return;
slouken@5398
   441
        }
slouken@5398
   442
    }
slouken@5398
   443
slouken@3507
   444
    x = (int)rect.origin.x;
slouken@3507
   445
    y = (int)rect.origin.y;
icculus@5564
   446
jorgen@7595
   447
    ScheduleContextUpdates(_data);
icculus@5564
   448
slouken@5398
   449
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@1933
   450
}
slouken@1933
   451
slouken@1933
   452
- (void)windowDidResize:(NSNotification *)aNotification
slouken@1933
   453
{
icculus@8284
   454
    if (inFullscreenTransition) {
icculus@8284
   455
        /* We'll take care of this at the end of the transition */
icculus@8284
   456
        return;
icculus@8284
   457
    }
icculus@8284
   458
slouken@7963
   459
    SDL_Window *window = _data->window;
slouken@7963
   460
    NSWindow *nswindow = _data->nswindow;
slouken@6231
   461
    int x, y, w, h;
slouken@7963
   462
    NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@8801
   463
    ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
slouken@6231
   464
    x = (int)rect.origin.x;
slouken@6231
   465
    y = (int)rect.origin.y;
slouken@1933
   466
    w = (int)rect.size.width;
slouken@1933
   467
    h = (int)rect.size.height;
slouken@7952
   468
slouken@7963
   469
    if (SDL_IsShapedWindow(window)) {
slouken@7963
   470
        Cocoa_ResizeWindowShape(window);
slouken@7952
   471
    }
icculus@5564
   472
jorgen@7595
   473
    ScheduleContextUpdates(_data);
icculus@5564
   474
slouken@6231
   475
    /* The window can move during a resize event, such as when maximizing
slouken@6231
   476
       or resizing from a corner */
slouken@7963
   477
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@7963
   478
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
icculus@7566
   479
slouken@7963
   480
    const BOOL zoomed = [nswindow isZoomed];
icculus@7566
   481
    if (!zoomed) {
slouken@7963
   482
        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
icculus@7566
   483
    } else if (zoomed) {
slouken@7963
   484
        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
icculus@7566
   485
    }
slouken@1933
   486
}
slouken@1933
   487
slouken@1933
   488
- (void)windowDidMiniaturize:(NSNotification *)aNotification
slouken@1933
   489
{
slouken@3685
   490
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
slouken@1933
   491
}
slouken@1933
   492
slouken@1933
   493
- (void)windowDidDeminiaturize:(NSNotification *)aNotification
slouken@1933
   494
{
slouken@3685
   495
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@1933
   496
}
slouken@1933
   497
slouken@1933
   498
- (void)windowDidBecomeKey:(NSNotification *)aNotification
slouken@1933
   499
{
slouken@5367
   500
    SDL_Window *window = _data->window;
jorgen@7271
   501
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@9086
   502
    if (mouse->relative_mode && !mouse->relative_mode_warp && ![self isMoving]) {
jorgen@8260
   503
        mouse->SetRelativeMouseMode(SDL_TRUE);
jorgen@8260
   504
    }
slouken@5367
   505
slouken@3688
   506
    /* We're going to get keyboard events, since we're key. */
slouken@5367
   507
    SDL_SetKeyboardFocus(window);
slouken@5367
   508
slouken@5367
   509
    /* If we just gained focus we need the updated mouse position */
jorgen@7271
   510
    if (!mouse->relative_mode) {
slouken@5367
   511
        NSPoint point;
slouken@5396
   512
        int x, y;
slouken@5396
   513
slouken@5396
   514
        point = [_data->nswindow mouseLocationOutsideOfEventStream];
slouken@5396
   515
        x = (int)point.x;
slouken@5396
   516
        y = (int)(window->h - point.y);
slouken@5396
   517
slouken@5396
   518
        if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
slouken@6950
   519
            SDL_SendMouseMotion(window, 0, 0, x, y);
slouken@5396
   520
        }
slouken@5367
   521
    }
slouken@1962
   522
slouken@4503
   523
    /* Check to see if someone updated the clipboard */
slouken@4503
   524
    Cocoa_CheckClipboardUpdate(_data->videodata);
icculus@8288
   525
icculus@8293
   526
    if ((isFullscreenSpace) && ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)) {
icculus@8288
   527
        [NSMenu setMenuBarVisible:NO];
icculus@8288
   528
    }
slouken@1933
   529
}
slouken@1933
   530
slouken@1933
   531
- (void)windowDidResignKey:(NSNotification *)aNotification
slouken@1933
   532
{
jorgen@8260
   533
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@9086
   534
    if (mouse->relative_mode && !mouse->relative_mode_warp) {
jorgen@8260
   535
        mouse->SetRelativeMouseMode(SDL_FALSE);
jorgen@8260
   536
    }
jorgen@8260
   537
slouken@2059
   538
    /* Some other window will get mouse events, since we're not key. */
slouken@4465
   539
    if (SDL_GetMouseFocus() == _data->window) {
slouken@4465
   540
        SDL_SetMouseFocus(NULL);
slouken@2059
   541
    }
slouken@2059
   542
slouken@2059
   543
    /* Some other window will get keyboard events, since we're not key. */
slouken@4465
   544
    if (SDL_GetKeyboardFocus() == _data->window) {
slouken@4465
   545
        SDL_SetKeyboardFocus(NULL);
slouken@4465
   546
    }
icculus@8288
   547
icculus@8288
   548
    if (isFullscreenSpace) {
icculus@8288
   549
        [NSMenu setMenuBarVisible:YES];
icculus@8288
   550
    }
slouken@1933
   551
}
slouken@1933
   552
slouken@7952
   553
- (void)windowWillEnterFullScreen:(NSNotification *)aNotification
slouken@7952
   554
{
slouken@7952
   555
    SDL_Window *window = _data->window;
slouken@7952
   556
slouken@7990
   557
    SetWindowStyle(window, (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask));
slouken@7965
   558
slouken@7967
   559
    isFullscreenSpace = YES;
slouken@7952
   560
    inFullscreenTransition = YES;
slouken@7952
   561
}
slouken@7952
   562
slouken@7952
   563
- (void)windowDidEnterFullScreen:(NSNotification *)aNotification
slouken@7952
   564
{
slouken@7965
   565
    SDL_Window *window = _data->window;
slouken@7965
   566
slouken@7952
   567
    inFullscreenTransition = NO;
slouken@7961
   568
slouken@7963
   569
    if (pendingWindowOperation == PENDING_OPERATION_LEAVE_FULLSCREEN) {
slouken@7963
   570
        pendingWindowOperation = PENDING_OPERATION_NONE;
slouken@7967
   571
        [self setFullscreenSpace:NO];
slouken@7961
   572
    } else {
icculus@8284
   573
        if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
icculus@8284
   574
            [NSMenu setMenuBarVisible:NO];
icculus@8284
   575
        }
icculus@8284
   576
slouken@7963
   577
        pendingWindowOperation = PENDING_OPERATION_NONE;
slouken@7965
   578
        /* Force the size change event in case it was delivered earlier
slouken@7965
   579
           while the window was still animating into place.
slouken@7965
   580
         */
slouken@7965
   581
        window->w = 0;
slouken@7965
   582
        window->h = 0;
slouken@7961
   583
        [self windowDidResize:aNotification];
slouken@7961
   584
    }
slouken@7952
   585
}
slouken@7952
   586
slouken@7952
   587
- (void)windowWillExitFullScreen:(NSNotification *)aNotification
slouken@7952
   588
{
slouken@7964
   589
    SDL_Window *window = _data->window;
slouken@7964
   590
slouken@7990
   591
    SetWindowStyle(window, GetWindowStyle(window));
slouken@7964
   592
slouken@7967
   593
    isFullscreenSpace = NO;
slouken@7952
   594
    inFullscreenTransition = YES;
slouken@7952
   595
}
slouken@7952
   596
slouken@7952
   597
- (void)windowDidExitFullScreen:(NSNotification *)aNotification
slouken@7952
   598
{
slouken@7965
   599
    SDL_Window *window = _data->window;
slouken@7952
   600
    NSWindow *nswindow = _data->nswindow;
slouken@7952
   601
slouken@7952
   602
    inFullscreenTransition = NO;
slouken@7961
   603
slouken@8618
   604
    [nswindow setLevel:kCGNormalWindowLevel];
slouken@8618
   605
slouken@7963
   606
    if (pendingWindowOperation == PENDING_OPERATION_ENTER_FULLSCREEN) {
slouken@7963
   607
        pendingWindowOperation = PENDING_OPERATION_NONE;
slouken@7967
   608
        [self setFullscreenSpace:YES];
slouken@7963
   609
    } else if (pendingWindowOperation == PENDING_OPERATION_MINIMIZE) {
slouken@7963
   610
        pendingWindowOperation = PENDING_OPERATION_NONE;
slouken@7963
   611
        [nswindow miniaturize:nil];
slouken@7961
   612
    } else {
icculus@8291
   613
        /* Adjust the fullscreen toggle button and readd menu now that we're here. */
icculus@8291
   614
        if (window->flags & SDL_WINDOW_RESIZABLE) {
icculus@8291
   615
            /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
icculus@8291
   616
            [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
icculus@8291
   617
        } else {
icculus@8284
   618
            [nswindow setCollectionBehavior:NSWindowCollectionBehaviorManaged];
icculus@8284
   619
        }
icculus@8291
   620
        [NSMenu setMenuBarVisible:YES];
icculus@8284
   621
slouken@7963
   622
        pendingWindowOperation = PENDING_OPERATION_NONE;
slouken@7965
   623
        /* Force the size change event in case it was delivered earlier
slouken@7965
   624
           while the window was still animating into place.
slouken@7965
   625
         */
slouken@7965
   626
        window->w = 0;
slouken@7965
   627
        window->h = 0;
slouken@7961
   628
        [self windowDidResize:aNotification];
icculus@8622
   629
slouken@8623
   630
        /* FIXME: Why does the window get hidden? */
slouken@8623
   631
        if (window->flags & SDL_WINDOW_SHOWN) {
slouken@8623
   632
            Cocoa_ShowWindow(SDL_GetVideoDevice(), window);
slouken@8623
   633
        }
slouken@7961
   634
    }
slouken@7952
   635
}
slouken@7952
   636
icculus@8291
   637
-(NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions
icculus@8291
   638
{
icculus@8291
   639
    if ((_data->window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
icculus@8291
   640
        return NSApplicationPresentationFullScreen | NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
icculus@8291
   641
    } else {
icculus@8291
   642
        return proposedOptions;
icculus@8291
   643
    }
icculus@8291
   644
}
icculus@8291
   645
icculus@8291
   646
slouken@7191
   647
/* We'll respond to key events by doing nothing so we don't beep.
slouken@7191
   648
 * We could handle key messages here, but we lose some in the NSApp dispatch,
slouken@7191
   649
 * where they get converted to action messages, etc.
slouken@7191
   650
 */
slouken@6514
   651
- (void)flagsChanged:(NSEvent *)theEvent
slouken@6514
   652
{
slouken@7191
   653
    /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
slouken@6514
   654
}
slouken@6514
   655
- (void)keyDown:(NSEvent *)theEvent
slouken@6514
   656
{
slouken@7191
   657
    /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
slouken@6514
   658
}
slouken@6514
   659
- (void)keyUp:(NSEvent *)theEvent
slouken@6514
   660
{
slouken@7191
   661
    /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
slouken@6514
   662
}
slouken@6514
   663
slouken@7191
   664
/* We'll respond to selectors by doing nothing so we don't beep.
slouken@7191
   665
 * The escape key gets converted to a "cancel" selector, etc.
slouken@7191
   666
 */
slouken@6514
   667
- (void)doCommandBySelector:(SEL)aSelector
slouken@6514
   668
{
slouken@7191
   669
    /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
slouken@6514
   670
}
slouken@6514
   671
icculus@8935
   672
- (BOOL)processHitTest:(NSEvent *)theEvent
icculus@8931
   673
{
icculus@8935
   674
    SDL_assert(isDragAreaRunning == [_data->nswindow isMovableByWindowBackground]);
icculus@8931
   675
icculus@8935
   676
    if (_data->window->hit_test) {  /* if no hit-test, skip this. */
icculus@8931
   677
        const NSPoint location = [theEvent locationInWindow];
icculus@8931
   678
        const SDL_Point point = { (int) location.x, _data->window->h - (((int) location.y)-1) };
icculus@8935
   679
        const SDL_HitTestResult rc = _data->window->hit_test(_data->window, &point, _data->window->hit_test_data);
icculus@8935
   680
        if (rc == SDL_HITTEST_DRAGGABLE) {
icculus@8935
   681
            if (!isDragAreaRunning) {
icculus@8935
   682
                isDragAreaRunning = YES;
icculus@8935
   683
                [_data->nswindow setMovableByWindowBackground:YES];
icculus@8931
   684
            }
icculus@8935
   685
            return YES;  /* dragging! */
icculus@8931
   686
        }
icculus@8931
   687
    }
icculus@8931
   688
icculus@8931
   689
    if (isDragAreaRunning) {
icculus@8931
   690
        isDragAreaRunning = NO;
icculus@8931
   691
        [_data->nswindow setMovableByWindowBackground:NO];
icculus@8931
   692
        return YES;  /* was dragging, drop event. */
icculus@8931
   693
    }
icculus@8931
   694
icculus@8935
   695
    return NO;  /* not a special area, carry on. */
icculus@8931
   696
}
icculus@8931
   697
slouken@1933
   698
- (void)mouseDown:(NSEvent *)theEvent
slouken@1933
   699
{
slouken@1959
   700
    int button;
slouken@1933
   701
icculus@8935
   702
    if ([self processHitTest:theEvent]) {
icculus@8931
   703
        return;  /* dragging, drop event. */
icculus@8931
   704
    }
icculus@8931
   705
slouken@1959
   706
    switch ([theEvent buttonNumber]) {
slouken@1959
   707
    case 0:
slouken@7915
   708
        if (([theEvent modifierFlags] & NSControlKeyMask) &&
slouken@7915
   709
		    GetHintCtrlClickEmulateRightClick()) {
slouken@7740
   710
            wasCtrlLeft = YES;
slouken@7740
   711
            button = SDL_BUTTON_RIGHT;
slouken@7740
   712
        } else {
slouken@7740
   713
            wasCtrlLeft = NO;
slouken@7740
   714
            button = SDL_BUTTON_LEFT;
slouken@7740
   715
        }
slouken@1959
   716
        break;
slouken@1959
   717
    case 1:
slouken@1959
   718
        button = SDL_BUTTON_RIGHT;
slouken@1959
   719
        break;
slouken@1959
   720
    case 2:
slouken@1959
   721
        button = SDL_BUTTON_MIDDLE;
slouken@1959
   722
        break;
slouken@1959
   723
    default:
slouken@5061
   724
        button = [theEvent buttonNumber] + 1;
slouken@1959
   725
        break;
slouken@1959
   726
    }
slouken@6950
   727
    SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
slouken@1933
   728
}
slouken@1933
   729
slouken@1933
   730
- (void)rightMouseDown:(NSEvent *)theEvent
slouken@1933
   731
{
slouken@1959
   732
    [self mouseDown:theEvent];
slouken@1933
   733
}
slouken@1933
   734
slouken@1933
   735
- (void)otherMouseDown:(NSEvent *)theEvent
slouken@1933
   736
{
slouken@1959
   737
    [self mouseDown:theEvent];
slouken@1933
   738
}
slouken@1933
   739
slouken@1933
   740
- (void)mouseUp:(NSEvent *)theEvent
slouken@1933
   741
{
slouken@1959
   742
    int button;
slouken@1933
   743
icculus@8935
   744
    if ([self processHitTest:theEvent]) {
icculus@8931
   745
        return;  /* stopped dragging, drop event. */
icculus@8931
   746
    }
icculus@8931
   747
slouken@1959
   748
    switch ([theEvent buttonNumber]) {
slouken@1959
   749
    case 0:
slouken@7740
   750
        if (wasCtrlLeft) {
slouken@7740
   751
            button = SDL_BUTTON_RIGHT;
slouken@7740
   752
            wasCtrlLeft = NO;
slouken@7740
   753
        } else {
slouken@7740
   754
            button = SDL_BUTTON_LEFT;
slouken@7740
   755
        }
slouken@1959
   756
        break;
slouken@1959
   757
    case 1:
slouken@1959
   758
        button = SDL_BUTTON_RIGHT;
slouken@1959
   759
        break;
slouken@1959
   760
    case 2:
slouken@1959
   761
        button = SDL_BUTTON_MIDDLE;
slouken@1959
   762
        break;
slouken@1959
   763
    default:
slouken@5061
   764
        button = [theEvent buttonNumber] + 1;
slouken@1959
   765
        break;
slouken@1959
   766
    }
slouken@6950
   767
    SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
slouken@1933
   768
}
slouken@1933
   769
slouken@1933
   770
- (void)rightMouseUp:(NSEvent *)theEvent
slouken@1933
   771
{
slouken@1959
   772
    [self mouseUp:theEvent];
slouken@1933
   773
}
slouken@1933
   774
slouken@1933
   775
- (void)otherMouseUp:(NSEvent *)theEvent
slouken@1933
   776
{
slouken@1959
   777
    [self mouseUp:theEvent];
slouken@1933
   778
}
slouken@1933
   779
slouken@1933
   780
- (void)mouseMoved:(NSEvent *)theEvent
slouken@1933
   781
{
slouken@5406
   782
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@3685
   783
    SDL_Window *window = _data->window;
slouken@5396
   784
    NSPoint point;
slouken@5396
   785
    int x, y;
slouken@1933
   786
icculus@8935
   787
    if ([self processHitTest:theEvent]) {
icculus@8931
   788
        return;  /* dragging, drop event. */
icculus@8931
   789
    }
icculus@8931
   790
slouken@5406
   791
    if (mouse->relative_mode) {
gzjjgod@5059
   792
        return;
slouken@5371
   793
    }
gzjjgod@5059
   794
slouken@5396
   795
    point = [theEvent locationInWindow];
slouken@5396
   796
    x = (int)point.x;
slouken@5396
   797
    y = (int)(window->h - point.y);
slouken@5371
   798
icculus@8929
   799
    if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
icculus@8929
   800
        if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
slouken@6666
   801
            if (x < 0) {
slouken@6666
   802
                x = 0;
slouken@6666
   803
            } else if (x >= window->w) {
slouken@6666
   804
                x = window->w - 1;
slouken@6666
   805
            }
slouken@6666
   806
            if (y < 0) {
slouken@6666
   807
                y = 0;
slouken@6666
   808
            } else if (y >= window->h) {
slouken@6666
   809
                y = window->h - 1;
slouken@6666
   810
            }
slouken@6666
   811
jorgen@7593
   812
#if !SDL_MAC_NO_SANDBOX
jorgen@8260
   813
            CGPoint cgpoint;
jorgen@8260
   814
jorgen@7593
   815
            /* When SDL_MAC_NO_SANDBOX is set, this is handled by
jorgen@7593
   816
             * SDL_cocoamousetap.m.
jorgen@7593
   817
             */
jorgen@7593
   818
slouken@6666
   819
            cgpoint.x = window->x + x;
slouken@6666
   820
            cgpoint.y = window->y + y;
jorgen@7098
   821
jorgen@7113
   822
            /* According to the docs, this was deprecated in 10.6, but it's still
jorgen@7113
   823
             * around. The substitute requires a CGEventSource, but I'm not entirely
jorgen@7113
   824
             * sure how we'd procure the right one for this event.
jorgen@7098
   825
             */
jorgen@7113
   826
            CGSetLocalEventsSuppressionInterval(0.0);
slouken@6666
   827
            CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
jorgen@7113
   828
            CGSetLocalEventsSuppressionInterval(0.25);
jorgen@8261
   829
jorgen@8261
   830
            Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
jorgen@7593
   831
#endif
slouken@5396
   832
        }
slouken@2059
   833
    }
slouken@6950
   834
    SDL_SendMouseMotion(window, 0, 0, x, y);
slouken@1933
   835
}
slouken@1933
   836
slouken@1957
   837
- (void)mouseDragged:(NSEvent *)theEvent
slouken@1957
   838
{
slouken@1957
   839
    [self mouseMoved:theEvent];
slouken@1957
   840
}
slouken@1957
   841
slouken@1958
   842
- (void)rightMouseDragged:(NSEvent *)theEvent
slouken@1958
   843
{
slouken@1958
   844
    [self mouseMoved:theEvent];
slouken@1958
   845
}
slouken@1958
   846
slouken@1958
   847
- (void)otherMouseDragged:(NSEvent *)theEvent
slouken@1958
   848
{
slouken@1958
   849
    [self mouseMoved:theEvent];
slouken@1958
   850
}
slouken@1958
   851
slouken@1933
   852
- (void)scrollWheel:(NSEvent *)theEvent
slouken@1933
   853
{
gzjjgod@5057
   854
    Cocoa_HandleMouseWheel(_data->window, theEvent);
slouken@3688
   855
}
slouken@3688
   856
slouken@4673
   857
- (void)touchesBeganWithEvent:(NSEvent *) theEvent
slouken@4673
   858
{
urkle@9236
   859
    NSSet *touches = [theEvent touchesMatchingPhase:NSTouchPhaseAny inView:nil];
urkle@9236
   860
    int existingTouchCount = 0;
urkle@9236
   861
urkle@9236
   862
    for (NSTouch* touch in touches) {
urkle@9236
   863
        if ([touch phase] != NSTouchPhaseBegan) {
urkle@9236
   864
            existingTouchCount++;
urkle@9236
   865
        }
urkle@9236
   866
    }
urkle@9236
   867
    if (existingTouchCount == 0) {
urkle@9236
   868
        SDL_TouchID touchID = (SDL_TouchID)(intptr_t)[[touches anyObject] device];
urkle@9236
   869
        int numFingers = SDL_GetNumTouchFingers(touchID);
urkle@9236
   870
        DLog("Reset Lost Fingers: %d", numFingers);
urkle@9236
   871
        for (--numFingers; numFingers >= 0; --numFingers) {
urkle@9236
   872
            SDL_Finger* finger = SDL_GetTouchFinger(touchID, numFingers);
urkle@9236
   873
            SDL_SendTouch(touchID, finger->id, SDL_FALSE, 0, 0, 0);
urkle@9236
   874
        }
urkle@9236
   875
    }
urkle@9236
   876
urkle@9236
   877
    DLog("Began Fingers: %lu .. existing: %d", (unsigned long)[touches count], existingTouchCount);
slouken@8986
   878
    [self handleTouches:NSTouchPhaseBegan withEvent:theEvent];
slouken@4673
   879
}
slouken@4673
   880
slouken@4673
   881
- (void)touchesMovedWithEvent:(NSEvent *) theEvent
slouken@4673
   882
{
slouken@8986
   883
    [self handleTouches:NSTouchPhaseMoved withEvent:theEvent];
slouken@4673
   884
}
slouken@4673
   885
slouken@4673
   886
- (void)touchesEndedWithEvent:(NSEvent *) theEvent
slouken@4673
   887
{
slouken@8986
   888
    [self handleTouches:NSTouchPhaseEnded withEvent:theEvent];
slouken@4673
   889
}
slouken@4673
   890
slouken@4673
   891
- (void)touchesCancelledWithEvent:(NSEvent *) theEvent
slouken@4673
   892
{
slouken@8986
   893
    [self handleTouches:NSTouchPhaseCancelled withEvent:theEvent];
slouken@4673
   894
}
slouken@4673
   895
slouken@8986
   896
- (void)handleTouches:(NSTouchPhase) phase withEvent:(NSEvent *) theEvent
slouken@4673
   897
{
slouken@8986
   898
    NSSet *touches = [theEvent touchesMatchingPhase:phase inView:nil];
slouken@4673
   899
slouken@8986
   900
    for (NSTouch *touch in touches) {
slouken@6953
   901
        const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
slouken@4673
   902
        if (!SDL_GetTouch(touchId)) {
slouken@6951
   903
            if (SDL_AddTouch(touchId, "") < 0) {
slouken@4680
   904
                return;
slouken@4673
   905
            }
slouken@7191
   906
        }
slouken@4687
   907
slouken@6953
   908
        const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
slouken@4673
   909
        float x = [touch normalizedPosition].x;
slouken@4673
   910
        float y = [touch normalizedPosition].y;
slouken@5261
   911
        /* Make the origin the upper left instead of the lower left */
slouken@5261
   912
        y = 1.0f - y;
slouken@4687
   913
slouken@8986
   914
        switch (phase) {
slouken@8986
   915
        case NSTouchPhaseBegan:
slouken@6951
   916
            SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
slouken@4673
   917
            break;
slouken@8986
   918
        case NSTouchPhaseEnded:
slouken@8986
   919
        case NSTouchPhaseCancelled:
slouken@6951
   920
            SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
slouken@4673
   921
            break;
slouken@8986
   922
        case NSTouchPhaseMoved:
slouken@6951
   923
            SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
slouken@4673
   924
            break;
slouken@8986
   925
        default:
slouken@8986
   926
            break;
slouken@4673
   927
        }
slouken@4673
   928
    }
slouken@1933
   929
}
slouken@1933
   930
slouken@1933
   931
@end
slouken@1933
   932
slouken@5379
   933
@interface SDLView : NSView
jorgen@7158
   934
slouken@5379
   935
/* The default implementation doesn't pass rightMouseDown to responder chain */
slouken@5379
   936
- (void)rightMouseDown:(NSEvent *)theEvent;
icculus@8931
   937
- (BOOL)mouseDownCanMoveWindow;
gzjjgod@4915
   938
@end
gzjjgod@4915
   939
gzjjgod@4915
   940
@implementation SDLView
gzjjgod@4915
   941
- (void)rightMouseDown:(NSEvent *)theEvent
gzjjgod@4915
   942
{
slouken@5371
   943
    [[self nextResponder] rightMouseDown:theEvent];
gzjjgod@4915
   944
}
jorgen@7158
   945
icculus@8931
   946
- (BOOL)mouseDownCanMoveWindow
icculus@8931
   947
{
icculus@8931
   948
    /* Always say YES, but this doesn't do anything until we call
icculus@8931
   949
       -[NSWindow setMovableByWindowBackground:YES], which we ninja-toggle
icculus@8931
   950
       during mouse events when we're using a drag area. */
icculus@8931
   951
    return YES;
icculus@8931
   952
}
icculus@8931
   953
jorgen@7158
   954
- (void)resetCursorRects
jorgen@7158
   955
{
jorgen@7158
   956
    [super resetCursorRects];
jorgen@7158
   957
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7158
   958
jorgen@7270
   959
    if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
jorgen@7158
   960
        [self addCursorRect:[self bounds]
jorgen@7158
   961
                     cursor:mouse->cur_cursor->driverdata];
jorgen@7158
   962
    } else {
jorgen@7158
   963
        [self addCursorRect:[self bounds]
jorgen@7158
   964
                     cursor:[NSCursor invisibleCursor]];
jorgen@7158
   965
    }
jorgen@7158
   966
}
gzjjgod@4915
   967
@end
gzjjgod@4915
   968
slouken@1933
   969
static int
slouken@1951
   970
SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
slouken@1933
   971
{
slouken@6848
   972
    NSAutoreleasePool *pool;
slouken@1951
   973
    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
slouken@1933
   974
    SDL_WindowData *data;
slouken@1933
   975
slouken@1933
   976
    /* Allocate the window data */
slouken@8926
   977
    window->driverdata = data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
slouken@1933
   978
    if (!data) {
icculus@7037
   979
        return SDL_OutOfMemory();
slouken@1933
   980
    }
slouken@3685
   981
    data->window = window;
slouken@3688
   982
    data->nswindow = nswindow;
slouken@1933
   983
    data->created = created;
slouken@1951
   984
    data->videodata = videodata;
jorgen@7595
   985
    data->nscontexts = [[NSMutableArray alloc] init];
slouken@1933
   986
slouken@6848
   987
    pool = [[NSAutoreleasePool alloc] init];
slouken@1933
   988
slouken@6848
   989
    /* Create an event listener for the window */
slouken@6848
   990
    data->listener = [[Cocoa_WindowListener alloc] init];
slouken@6848
   991
slouken@6848
   992
    /* Fill in the SDL window with the window data */
slouken@6848
   993
    {
slouken@6848
   994
        NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@8801
   995
        ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
slouken@6848
   996
        window->x = (int)rect.origin.x;
slouken@6848
   997
        window->y = (int)rect.origin.y;
slouken@6848
   998
        window->w = (int)rect.size.width;
slouken@6848
   999
        window->h = (int)rect.size.height;
slouken@6848
  1000
    }
slouken@6848
  1001
slouken@6848
  1002
    /* Set up the listener after we create the view */
slouken@6848
  1003
    [data->listener listen:data];
slouken@6848
  1004
slouken@6848
  1005
    if ([nswindow isVisible]) {
slouken@6848
  1006
        window->flags |= SDL_WINDOW_SHOWN;
slouken@6848
  1007
    } else {
slouken@6848
  1008
        window->flags &= ~SDL_WINDOW_SHOWN;
slouken@6848
  1009
    }
jorgen@7084
  1010
slouken@6848
  1011
    {
slouken@6848
  1012
        unsigned int style = [nswindow styleMask];
slouken@6848
  1013
slouken@6848
  1014
        if (style == NSBorderlessWindowMask) {
slouken@6848
  1015
            window->flags |= SDL_WINDOW_BORDERLESS;
slouken@6848
  1016
        } else {
slouken@6848
  1017
            window->flags &= ~SDL_WINDOW_BORDERLESS;
alexey@6832
  1018
        }
slouken@6848
  1019
        if (style & NSResizableWindowMask) {
slouken@6848
  1020
            window->flags |= SDL_WINDOW_RESIZABLE;
slouken@6848
  1021
        } else {
slouken@6848
  1022
            window->flags &= ~SDL_WINDOW_RESIZABLE;
slouken@6848
  1023
        }
slouken@6848
  1024
    }
jorgen@7084
  1025
slouken@6848
  1026
    /* isZoomed always returns true if the window is not resizable */
slouken@6848
  1027
    if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
slouken@6848
  1028
        window->flags |= SDL_WINDOW_MAXIMIZED;
slouken@6848
  1029
    } else {
slouken@6848
  1030
        window->flags &= ~SDL_WINDOW_MAXIMIZED;
slouken@6848
  1031
    }
jorgen@7084
  1032
slouken@6848
  1033
    if ([nswindow isMiniaturized]) {
slouken@6848
  1034
        window->flags |= SDL_WINDOW_MINIMIZED;
slouken@6848
  1035
    } else {
slouken@6848
  1036
        window->flags &= ~SDL_WINDOW_MINIMIZED;
slouken@6848
  1037
    }
jorgen@7084
  1038
slouken@6848
  1039
    if ([nswindow isKeyWindow]) {
slouken@6848
  1040
        window->flags |= SDL_WINDOW_INPUT_FOCUS;
slouken@6848
  1041
        SDL_SetKeyboardFocus(data->window);
slouken@6848
  1042
    }
slouken@1933
  1043
jorgen@7085
  1044
    /* Prevents the window's "window device" from being destroyed when it is
jorgen@7085
  1045
     * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
jorgen@7085
  1046
     */
jorgen@7085
  1047
    [nswindow setOneShot:NO];
jorgen@7085
  1048
slouken@6848
  1049
    /* All done! */
slouken@6848
  1050
    [pool release];
slouken@6848
  1051
    window->driverdata = data;
slouken@6848
  1052
    return 0;
slouken@1933
  1053
}
slouken@1933
  1054
slouken@1933
  1055
int
slouken@1933
  1056
Cocoa_CreateWindow(_THIS, SDL_Window * window)
slouken@1933
  1057
{
icculus@8295
  1058
    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
slouken@6848
  1059
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1060
    NSWindow *nswindow;
slouken@6848
  1061
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@6848
  1062
    NSRect rect;
slouken@6848
  1063
    SDL_Rect bounds;
slouken@6848
  1064
    unsigned int style;
slouken@8986
  1065
    NSArray *screens = [NSScreen screens];
slouken@1933
  1066
slouken@6848
  1067
    Cocoa_GetDisplayBounds(_this, display, &bounds);
slouken@6848
  1068
    rect.origin.x = window->x;
slouken@6848
  1069
    rect.origin.y = window->y;
slouken@6848
  1070
    rect.size.width = window->w;
slouken@6848
  1071
    rect.size.height = window->h;
slouken@8986
  1072
    ConvertNSRect([screens objectAtIndex:0], (window->flags & FULLSCREEN_MASK), &rect);
slouken@1933
  1073
slouken@6848
  1074
    style = GetWindowStyle(window);
slouken@1933
  1075
slouken@6848
  1076
    /* Figure out which screen to place this window */
slouken@6848
  1077
    NSScreen *screen = nil;
slouken@8986
  1078
    for (NSScreen *candidate in screens) {
slouken@6848
  1079
        NSRect screenRect = [candidate frame];
slouken@6848
  1080
        if (rect.origin.x >= screenRect.origin.x &&
slouken@6848
  1081
            rect.origin.x < screenRect.origin.x + screenRect.size.width &&
slouken@6848
  1082
            rect.origin.y >= screenRect.origin.y &&
slouken@6848
  1083
            rect.origin.y < screenRect.origin.y + screenRect.size.height) {
slouken@6848
  1084
            screen = candidate;
slouken@6848
  1085
            rect.origin.x -= screenRect.origin.x;
slouken@6848
  1086
            rect.origin.y -= screenRect.origin.y;
slouken@3506
  1087
        }
slouken@6848
  1088
    }
slouken@7946
  1089
slouken@7946
  1090
    @try {
slouken@7946
  1091
        nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
slouken@7946
  1092
    }
slouken@7946
  1093
    @catch (NSException *e) {
slouken@7946
  1094
        SDL_SetError("%s", [[e reason] UTF8String]);
slouken@7948
  1095
        [pool release];
slouken@7946
  1096
        return -1;
slouken@7946
  1097
    }
icculus@7205
  1098
    [nswindow setBackgroundColor:[NSColor blackColor]];
icculus@8284
  1099
icculus@8295
  1100
    if (videodata->allow_spaces) {
slouken@8986
  1101
        SDL_assert(floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6);
icculus@8295
  1102
        SDL_assert([nswindow respondsToSelector:@selector(toggleFullScreen:)]);
icculus@8284
  1103
        /* we put FULLSCREEN_DESKTOP windows in their own Space, without a toggle button or menubar, later */
icculus@8284
  1104
        if (window->flags & SDL_WINDOW_RESIZABLE) {
icculus@8284
  1105
            /* resizable windows are Spaces-friendly: they get the "go fullscreen" toggle button on their titlebar. */
slouken@7968
  1106
            [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
slouken@7968
  1107
        }
slouken@7955
  1108
    }
alexey@6832
  1109
slouken@7191
  1110
    /* Create a default view for this window */
slouken@6848
  1111
    rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@6848
  1112
    NSView *contentView = [[SDLView alloc] initWithFrame:rect];
urkle@7746
  1113
slouken@7955
  1114
    if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
urkle@7746
  1115
        if ([contentView respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)]) {
urkle@7746
  1116
            [contentView setWantsBestResolutionOpenGLSurface:YES];
urkle@7746
  1117
        }
urkle@7746
  1118
    }
urkle@7746
  1119
slouken@6848
  1120
    [nswindow setContentView: contentView];
slouken@6848
  1121
    [contentView release];
alexey@6832
  1122
slouken@6848
  1123
    [pool release];
slouken@6848
  1124
slouken@6848
  1125
    if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
slouken@6848
  1126
        [nswindow release];
slouken@6848
  1127
        return -1;
slouken@3506
  1128
    }
slouken@6848
  1129
    return 0;
slouken@1933
  1130
}
slouken@1933
  1131
slouken@1933
  1132
int
slouken@1933
  1133
Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
slouken@1933
  1134
{
slouken@6848
  1135
    NSAutoreleasePool *pool;
slouken@1933
  1136
    NSWindow *nswindow = (NSWindow *) data;
slouken@1933
  1137
    NSString *title;
slouken@1933
  1138
slouken@6848
  1139
    pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1140
slouken@6848
  1141
    /* Query the title from the existing window */
slouken@6848
  1142
    title = [nswindow title];
slouken@6848
  1143
    if (title) {
slouken@6848
  1144
        window->title = SDL_strdup([title UTF8String]);
slouken@1933
  1145
    }
slouken@1933
  1146
slouken@6848
  1147
    [pool release];
slouken@6848
  1148
slouken@1951
  1149
    return SetupWindowData(_this, window, nswindow, SDL_FALSE);
slouken@1933
  1150
}
slouken@1933
  1151
slouken@1933
  1152
void
slouken@1933
  1153
Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
slouken@1933
  1154
{
slouken@6848
  1155
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1156
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@6848
  1157
    NSString *string;
slouken@1933
  1158
slouken@6848
  1159
    if(window->title) {
slouken@6848
  1160
        string = [[NSString alloc] initWithUTF8String:window->title];
slouken@6848
  1161
    } else {
slouken@6848
  1162
        string = [[NSString alloc] init];
slouken@1956
  1163
    }
slouken@6848
  1164
    [nswindow setTitle:string];
slouken@6848
  1165
    [string release];
slouken@6848
  1166
slouken@6848
  1167
    [pool release];
slouken@1933
  1168
}
slouken@1933
  1169
slouken@1933
  1170
void
slouken@5375
  1171
Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
slouken@5375
  1172
{
slouken@6848
  1173
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1174
    NSImage *nsimage = Cocoa_CreateImage(icon);
slouken@5375
  1175
slouken@6848
  1176
    if (nsimage) {
slouken@6848
  1177
        [NSApp setApplicationIconImage:nsimage];
slouken@5375
  1178
    }
slouken@6848
  1179
slouken@6848
  1180
    [pool release];
slouken@5375
  1181
}
slouken@5375
  1182
slouken@5375
  1183
void
slouken@1933
  1184
Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
slouken@1933
  1185
{
slouken@6848
  1186
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7594
  1187
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
jorgen@7594
  1188
    NSWindow *nswindow = windata->nswindow;
slouken@6848
  1189
    NSRect rect;
slouken@6848
  1190
    Uint32 moveHack;
slouken@1933
  1191
slouken@6848
  1192
    rect.origin.x = window->x;
slouken@6848
  1193
    rect.origin.y = window->y;
slouken@6848
  1194
    rect.size.width = window->w;
slouken@6848
  1195
    rect.size.height = window->h;
slouken@8801
  1196
    ConvertNSRect([nswindow screen], (window->flags & FULLSCREEN_MASK), &rect);
slouken@5478
  1197
slouken@6848
  1198
    moveHack = s_moveHack;
slouken@6848
  1199
    s_moveHack = 0;
slouken@6848
  1200
    [nswindow setFrameOrigin:rect.origin];
slouken@6848
  1201
    s_moveHack = moveHack;
slouken@5478
  1202
jorgen@7595
  1203
    ScheduleContextUpdates(windata);
slouken@6848
  1204
slouken@6848
  1205
    [pool release];
slouken@1933
  1206
}
slouken@1933
  1207
slouken@1933
  1208
void
slouken@1933
  1209
Cocoa_SetWindowSize(_THIS, SDL_Window * window)
slouken@1933
  1210
{
slouken@6848
  1211
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1212
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
slouken@6848
  1213
    NSWindow *nswindow = windata->nswindow;
slouken@6848
  1214
    NSSize size;
slouken@1933
  1215
slouken@6848
  1216
    size.width = window->w;
slouken@6848
  1217
    size.height = window->h;
slouken@6848
  1218
    [nswindow setContentSize:size];
icculus@5564
  1219
jorgen@7595
  1220
    ScheduleContextUpdates(windata);
slouken@6848
  1221
slouken@6848
  1222
    [pool release];
slouken@1933
  1223
}
slouken@1933
  1224
slouken@1933
  1225
void
stopiccot@6681
  1226
Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
stopiccot@6681
  1227
{
slouken@6848
  1228
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1229
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
slouken@7191
  1230
slouken@6848
  1231
    NSSize minSize;
slouken@6848
  1232
    minSize.width = window->min_w;
slouken@6848
  1233
    minSize.height = window->min_h;
slouken@7191
  1234
slouken@6848
  1235
    [windata->nswindow setContentMinSize:minSize];
slouken@7191
  1236
slouken@6848
  1237
    [pool release];
slouken@6788
  1238
}
slouken@6788
  1239
slouken@6788
  1240
void
slouken@6788
  1241
Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
slouken@6788
  1242
{
slouken@6848
  1243
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1244
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
slouken@7191
  1245
slouken@6848
  1246
    NSSize maxSize;
slouken@6848
  1247
    maxSize.width = window->max_w;
slouken@6848
  1248
    maxSize.height = window->max_h;
slouken@7191
  1249
slouken@6848
  1250
    [windata->nswindow setContentMaxSize:maxSize];
slouken@7191
  1251
slouken@6848
  1252
    [pool release];
stopiccot@6681
  1253
}
stopiccot@6681
  1254
stopiccot@6681
  1255
void
slouken@1933
  1256
Cocoa_ShowWindow(_THIS, SDL_Window * window)
slouken@1933
  1257
{
slouken@6848
  1258
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7087
  1259
    SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
jorgen@7087
  1260
    NSWindow *nswindow = windowData->nswindow;
slouken@1933
  1261
slouken@6848
  1262
    if (![nswindow isMiniaturized]) {
jorgen@7087
  1263
        [windowData->listener pauseVisibleObservation];
slouken@6848
  1264
        [nswindow makeKeyAndOrderFront:nil];
jorgen@7087
  1265
        [windowData->listener resumeVisibleObservation];
slouken@1956
  1266
    }
slouken@6848
  1267
    [pool release];
slouken@1933
  1268
}
slouken@1933
  1269
slouken@1933
  1270
void
slouken@1933
  1271
Cocoa_HideWindow(_THIS, SDL_Window * window)
slouken@1933
  1272
{
slouken@6848
  1273
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1274
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@6848
  1275
slouken@6848
  1276
    [nswindow orderOut:nil];
slouken@6848
  1277
    [pool release];
slouken@1933
  1278
}
slouken@1933
  1279
slouken@1933
  1280
void
slouken@1933
  1281
Cocoa_RaiseWindow(_THIS, SDL_Window * window)
slouken@1933
  1282
{
slouken@6848
  1283
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7087
  1284
    SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
jorgen@7087
  1285
    NSWindow *nswindow = windowData->nswindow;
slouken@6848
  1286
slouken@7771
  1287
    /* makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
slouken@7771
  1288
       a minimized or hidden window, so check for that before showing it.
slouken@7771
  1289
     */
jorgen@7087
  1290
    [windowData->listener pauseVisibleObservation];
jorgen@7469
  1291
    if (![nswindow isMiniaturized] && [nswindow isVisible]) {
alfred@9041
  1292
        [NSApp activateIgnoringOtherApps:YES];
jorgen@7469
  1293
        [nswindow makeKeyAndOrderFront:nil];
jorgen@7469
  1294
    }
jorgen@7087
  1295
    [windowData->listener resumeVisibleObservation];
jorgen@7087
  1296
slouken@6848
  1297
    [pool release];
slouken@1933
  1298
}
slouken@1933
  1299
slouken@1933
  1300
void
slouken@1933
  1301
Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
slouken@1933
  1302
{
slouken@6848
  1303
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7594
  1304
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
jorgen@7594
  1305
    NSWindow *nswindow = windata->nswindow;
slouken@1933
  1306
slouken@6848
  1307
    [nswindow zoom:nil];
slouken@6848
  1308
jorgen@7595
  1309
    ScheduleContextUpdates(windata);
slouken@6848
  1310
slouken@6848
  1311
    [pool release];
slouken@1933
  1312
}
slouken@1933
  1313
slouken@1933
  1314
void
slouken@1933
  1315
Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
slouken@1933
  1316
{
slouken@6848
  1317
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@7963
  1318
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@7963
  1319
    NSWindow *nswindow = data->nswindow;
slouken@6848
  1320
slouken@7968
  1321
    if ([data->listener isInFullscreenSpaceTransition]) {
slouken@7963
  1322
        [data->listener addPendingWindowOperation:PENDING_OPERATION_MINIMIZE];
slouken@7963
  1323
    } else {
slouken@7963
  1324
        [nswindow miniaturize:nil];
slouken@7963
  1325
    }
slouken@6848
  1326
    [pool release];
slouken@1933
  1327
}
slouken@1933
  1328
slouken@1933
  1329
void
slouken@1933
  1330
Cocoa_RestoreWindow(_THIS, SDL_Window * window)
slouken@1933
  1331
{
slouken@6848
  1332
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1333
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@1933
  1334
slouken@6848
  1335
    if ([nswindow isMiniaturized]) {
slouken@6848
  1336
        [nswindow deminiaturize:nil];
slouken@6848
  1337
    } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
slouken@6848
  1338
        [nswindow zoom:nil];
slouken@1956
  1339
    }
slouken@6848
  1340
    [pool release];
slouken@1933
  1341
}
slouken@1933
  1342
slouken@5400
  1343
static NSWindow *
slouken@5400
  1344
Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
slouken@5400
  1345
{
slouken@5400
  1346
    if (!data->created) {
slouken@5400
  1347
        /* Don't mess with other people's windows... */
slouken@5400
  1348
        return nswindow;
slouken@5400
  1349
    }
slouken@5400
  1350
slouken@5400
  1351
    [data->listener close];
jorgen@7085
  1352
    data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
slouken@5400
  1353
    [data->nswindow setContentView:[nswindow contentView]];
jorgen@7085
  1354
    /* See comment in SetupWindowData. */
jorgen@7085
  1355
    [data->nswindow setOneShot:NO];
slouken@5400
  1356
    [data->listener listen:data];
slouken@5400
  1357
slouken@5400
  1358
    [nswindow close];
slouken@5400
  1359
slouken@5400
  1360
    return data->nswindow;
slouken@5400
  1361
}
slouken@5400
  1362
slouken@1933
  1363
void
icculus@6422
  1364
Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
icculus@6422
  1365
{
slouken@6848
  1366
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@7990
  1367
    if (SetWindowStyle(window, GetWindowStyle(window))) {
slouken@6848
  1368
        if (bordered) {
slouken@7191
  1369
            Cocoa_SetWindowTitle(_this, window);  /* this got blanked out. */
icculus@6426
  1370
        }
icculus@6422
  1371
    }
slouken@6848
  1372
    [pool release];
icculus@6422
  1373
}
icculus@6422
  1374
slouken@7952
  1375
slouken@7968
  1376
void
slouken@7968
  1377
Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
slouken@7952
  1378
{
slouken@7968
  1379
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1380
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@6848
  1381
    NSWindow *nswindow = data->nswindow;
slouken@6848
  1382
    NSRect rect;
slouken@5249
  1383
slouken@6848
  1384
    /* The view responder chain gets messed with during setStyleMask */
slouken@6848
  1385
    if ([[nswindow contentView] nextResponder] == data->listener) {
slouken@6848
  1386
        [[nswindow contentView] setNextResponder:nil];
slouken@6848
  1387
    }
slouken@6848
  1388
slouken@6848
  1389
    if (fullscreen) {
slouken@6848
  1390
        SDL_Rect bounds;
slouken@6848
  1391
slouken@6848
  1392
        Cocoa_GetDisplayBounds(_this, display, &bounds);
slouken@6848
  1393
        rect.origin.x = bounds.x;
slouken@6848
  1394
        rect.origin.y = bounds.y;
slouken@6848
  1395
        rect.size.width = bounds.w;
slouken@6848
  1396
        rect.size.height = bounds.h;
slouken@8801
  1397
        ConvertNSRect([nswindow screen], fullscreen, &rect);
slouken@6848
  1398
slouken@6848
  1399
        /* Hack to fix origin on Mac OS X 10.4 */
slouken@6848
  1400
        NSRect screenRect = [[nswindow screen] frame];
slouken@6848
  1401
        if (screenRect.size.height >= 1.0f) {
slouken@6848
  1402
            rect.origin.y += (screenRect.size.height - rect.size.height);
slouken@5401
  1403
        }
slouken@5401
  1404
slouken@6848
  1405
        if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
slouken@6848
  1406
            [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
slouken@6848
  1407
        } else {
slouken@6848
  1408
            nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
slouken@6848
  1409
        }
slouken@6848
  1410
    } else {
slouken@6848
  1411
        rect.origin.x = window->windowed.x;
slouken@6848
  1412
        rect.origin.y = window->windowed.y;
slouken@6848
  1413
        rect.size.width = window->windowed.w;
slouken@6848
  1414
        rect.size.height = window->windowed.h;
slouken@8801
  1415
        ConvertNSRect([nswindow screen], fullscreen, &rect);
alexey@6832
  1416
slouken@6848
  1417
        if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
slouken@6848
  1418
            [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
slouken@5400
  1419
        } else {
slouken@6848
  1420
            nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
slouken@5361
  1421
        }
slouken@5398
  1422
    }
slouken@6848
  1423
slouken@6848
  1424
    /* The view responder chain gets messed with during setStyleMask */
slouken@6848
  1425
    if ([[nswindow contentView] nextResponder] != data->listener) {
slouken@6848
  1426
        [[nswindow contentView] setNextResponder:data->listener];
slouken@6848
  1427
    }
slouken@6848
  1428
slouken@6848
  1429
    s_moveHack = 0;
slouken@7873
  1430
    [nswindow setContentSize:rect.size];
slouken@6848
  1431
    [nswindow setFrameOrigin:rect.origin];
slouken@6848
  1432
    s_moveHack = SDL_GetTicks();
slouken@6848
  1433
slouken@6848
  1434
    /* When the window style changes the title is cleared */
slouken@6848
  1435
    if (!fullscreen) {
slouken@6848
  1436
        Cocoa_SetWindowTitle(_this, window);
slouken@6848
  1437
    }
slouken@6848
  1438
slouken@6848
  1439
    if (SDL_ShouldAllowTopmost() && fullscreen) {
slouken@6848
  1440
        /* OpenGL is rendering to the window, so make it visible! */
slouken@6848
  1441
        [nswindow setLevel:CGShieldingWindowLevel()];
slouken@6848
  1442
    } else {
slouken@6848
  1443
        [nswindow setLevel:kCGNormalWindowLevel];
slouken@6848
  1444
    }
jorgen@7087
  1445
jorgen@7636
  1446
    if ([nswindow isVisible] || fullscreen) {
jorgen@7636
  1447
        [data->listener pauseVisibleObservation];
jorgen@7636
  1448
        [nswindow makeKeyAndOrderFront:nil];
jorgen@7636
  1449
        [data->listener resumeVisibleObservation];
jorgen@7636
  1450
    }
slouken@6848
  1451
jorgen@7595
  1452
    ScheduleContextUpdates(data);
slouken@6848
  1453
slouken@6848
  1454
    [pool release];
slouken@5249
  1455
}
slouken@5249
  1456
slouken@5466
  1457
int
slouken@5466
  1458
Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
slouken@5466
  1459
{
slouken@5466
  1460
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@5466
  1461
    CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
slouken@5466
  1462
    const uint32_t tableSize = 256;
slouken@5466
  1463
    CGGammaValue redTable[tableSize];
slouken@5466
  1464
    CGGammaValue greenTable[tableSize];
slouken@5466
  1465
    CGGammaValue blueTable[tableSize];
slouken@5466
  1466
    uint32_t i;
slouken@5466
  1467
    float inv65535 = 1.0f / 65535.0f;
slouken@5466
  1468
slouken@5466
  1469
    /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
slouken@5466
  1470
    for (i = 0; i < 256; i++) {
slouken@5466
  1471
        redTable[i] = ramp[0*256+i] * inv65535;
slouken@5466
  1472
        greenTable[i] = ramp[1*256+i] * inv65535;
slouken@5466
  1473
        blueTable[i] = ramp[2*256+i] * inv65535;
slouken@5466
  1474
    }
slouken@5466
  1475
slouken@5466
  1476
    if (CGSetDisplayTransferByTable(display_id, tableSize,
slouken@5466
  1477
                                    redTable, greenTable, blueTable) != CGDisplayNoErr) {
icculus@7037
  1478
        return SDL_SetError("CGSetDisplayTransferByTable()");
slouken@5466
  1479
    }
slouken@5466
  1480
    return 0;
slouken@5466
  1481
}
slouken@5466
  1482
slouken@5466
  1483
int
slouken@5466
  1484
Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
slouken@5466
  1485
{
slouken@5466
  1486
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@5466
  1487
    CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
slouken@5466
  1488
    const uint32_t tableSize = 256;
slouken@5466
  1489
    CGGammaValue redTable[tableSize];
slouken@5466
  1490
    CGGammaValue greenTable[tableSize];
slouken@5466
  1491
    CGGammaValue blueTable[tableSize];
slouken@5466
  1492
    uint32_t i, tableCopied;
slouken@5466
  1493
slouken@5466
  1494
    if (CGGetDisplayTransferByTable(display_id, tableSize,
slouken@5466
  1495
                                    redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
icculus@7037
  1496
        return SDL_SetError("CGGetDisplayTransferByTable()");
slouken@5466
  1497
    }
slouken@5466
  1498
slouken@5466
  1499
    for (i = 0; i < tableCopied; i++) {
slouken@5466
  1500
        ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
slouken@5466
  1501
        ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
slouken@5466
  1502
        ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
slouken@5466
  1503
    }
slouken@5466
  1504
    return 0;
slouken@5466
  1505
}
slouken@5466
  1506
slouken@5249
  1507
void
slouken@6662
  1508
Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
slouken@1933
  1509
{
slouken@5371
  1510
    /* Move the cursor to the nearest point in the window */
jorgen@8260
  1511
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
jorgen@8260
  1512
    if (grabbed && data && ![data->listener isMoving]) {
slouken@5371
  1513
        int x, y;
slouken@5371
  1514
        CGPoint cgpoint;
slouken@5371
  1515
slouken@5371
  1516
        SDL_GetMouseState(&x, &y);
slouken@5371
  1517
        cgpoint.x = window->x + x;
slouken@5371
  1518
        cgpoint.y = window->y + y;
jorgen@8261
  1519
jorgen@8261
  1520
        Cocoa_HandleMouseWarp(cgpoint.x, cgpoint.y);
jorgen@8261
  1521
jorgen@8261
  1522
        DLog("Returning cursor to (%g, %g)", cgpoint.x, cgpoint.y);
slouken@5371
  1523
        CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
slouken@5371
  1524
    }
slouken@7191
  1525
icculus@8652
  1526
    if ( data && (window->flags & SDL_WINDOW_FULLSCREEN) ) {
slouken@7191
  1527
        if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
slouken@7191
  1528
            /* OpenGL is rendering to the window, so make it visible! */
slouken@7191
  1529
            [data->nswindow setLevel:CGShieldingWindowLevel()];
slouken@7191
  1530
        } else {
slouken@7191
  1531
            [data->nswindow setLevel:kCGNormalWindowLevel];
slouken@7191
  1532
        }
slouken@7191
  1533
    }
slouken@1933
  1534
}
slouken@1933
  1535
slouken@1933
  1536
void
slouken@1933
  1537
Cocoa_DestroyWindow(_THIS, SDL_Window * window)
slouken@1933
  1538
{
slouken@6848
  1539
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1540
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@1933
  1541
slouken@6848
  1542
    if (data) {
slouken@6848
  1543
        [data->listener close];
slouken@6848
  1544
        [data->listener release];
slouken@6848
  1545
        if (data->created) {
slouken@6848
  1546
            [data->nswindow close];
slouken@1933
  1547
        }
jorgen@7595
  1548
jorgen@7595
  1549
        NSArray *contexts = [[data->nscontexts copy] autorelease];
jorgen@7595
  1550
        for (SDLOpenGLContext *context in contexts) {
jorgen@7595
  1551
            /* Calling setWindow:NULL causes the context to remove itself from the context list. */            
jorgen@7595
  1552
            [context setWindow:NULL];
jorgen@7595
  1553
        }
jorgen@7595
  1554
        [data->nscontexts release];
jorgen@7595
  1555
slouken@6848
  1556
        SDL_free(data);
slouken@1933
  1557
    }
slouken@8978
  1558
    window->driverdata = NULL;
slouken@8978
  1559
slouken@6848
  1560
    [pool release];
slouken@1933
  1561
}
slouken@1933
  1562
slouken@1933
  1563
SDL_bool
slouken@1933
  1564
Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
slouken@1933
  1565
{
slouken@4900
  1566
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@1933
  1567
slouken@1933
  1568
    if (info->version.major <= SDL_MAJOR_VERSION) {
slouken@4900
  1569
        info->subsystem = SDL_SYSWM_COCOA;
slouken@5056
  1570
        info->info.cocoa.window = nswindow;
slouken@1933
  1571
        return SDL_TRUE;
slouken@1933
  1572
    } else {
slouken@1933
  1573
        SDL_SetError("Application not compiled with SDL %d.%d\n",
slouken@1933
  1574
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
slouken@1933
  1575
        return SDL_FALSE;
slouken@1933
  1576
    }
slouken@1933
  1577
}
slouken@1933
  1578
slouken@7968
  1579
SDL_bool
slouken@7969
  1580
Cocoa_IsWindowInFullscreenSpace(SDL_Window * window)
slouken@7969
  1581
{
slouken@7969
  1582
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@7969
  1583
slouken@7969
  1584
    if ([data->listener isInFullscreenSpace]) {
slouken@7969
  1585
        return SDL_TRUE;
slouken@7969
  1586
    } else {
slouken@7969
  1587
        return SDL_FALSE;
slouken@7969
  1588
    }
slouken@7969
  1589
}
slouken@7969
  1590
slouken@7969
  1591
SDL_bool
slouken@7968
  1592
Cocoa_SetWindowFullscreenSpace(SDL_Window * window, SDL_bool state)
slouken@7968
  1593
{
slouken@7968
  1594
    SDL_bool succeeded = SDL_FALSE;
slouken@7968
  1595
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@7968
  1596
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@7968
  1597
slouken@7968
  1598
    if ([data->listener setFullscreenSpace:(state ? YES : NO)]) {
slouken@7968
  1599
        succeeded = SDL_TRUE;
slouken@8810
  1600
slouken@8810
  1601
        /* Wait for the transition to complete, so application changes
slouken@8810
  1602
           take effect properly (e.g. setting the window size, etc.)
slouken@8810
  1603
         */
slouken@8810
  1604
        const int limit = 10000;
slouken@8810
  1605
        int count = 0;
slouken@8810
  1606
        while ([data->listener isInFullscreenSpaceTransition]) {
slouken@8810
  1607
            if ( ++count == limit ) {
slouken@8810
  1608
                /* Uh oh, transition isn't completing. Should we assert? */
slouken@8810
  1609
                break;
slouken@8810
  1610
            }
slouken@8810
  1611
            SDL_Delay(1);
slouken@8810
  1612
            SDL_PumpEvents();
slouken@8810
  1613
        }
slouken@7968
  1614
    }
slouken@7968
  1615
slouken@7968
  1616
    [pool release];
slouken@7968
  1617
slouken@7968
  1618
    return succeeded;
slouken@7968
  1619
}
slouken@7968
  1620
icculus@8931
  1621
int
icculus@8935
  1622
Cocoa_SetWindowHitTest(SDL_Window * window, SDL_bool enabled)
icculus@8931
  1623
{
icculus@8931
  1624
    return 0;  /* just succeed, the real work is done elsewhere. */
icculus@8931
  1625
}
icculus@8931
  1626
slouken@6044
  1627
#endif /* SDL_VIDEO_DRIVER_COCOA */
slouken@6044
  1628
slouken@1933
  1629
/* vi: set ts=4 sw=4 expandtab: */