src/video/cocoa/SDL_cocoawindow.m
author Jørgen P. Tjernø <jorgen@valvesoftware.com>
Wed, 07 Aug 2013 16:29:21 -0700
changeset 7594 6abcf951af68
parent 7593 20298a0d8631
child 7595 ede2237fcebf
permissions -rw-r--r--
Mac: Don't -[NSOpenGLContext update] on (potentially) the wrong thread.

If the user is using their context from a non-main thread, we could be
calling -[NSOpenGLContext update] on our thread, while they were
accessing it on their thread.

With this change, we schedule updates when the event comes in on the
main thread, and act on them when the user calls SDL_GL_MakeCurrent or
SDL_GL_SwapWindow.
slouken@1933
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 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
*/
slouken@1933
    21
#include "SDL_config.h"
slouken@1933
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_COCOA
slouken@6044
    24
slouken@1933
    25
#include "SDL_syswm.h"
slouken@5398
    26
#include "SDL_timer.h"  /* For SDL_GetTicks() */
slouken@1933
    27
#include "../SDL_sysvideo.h"
slouken@1933
    28
#include "../../events/SDL_keyboard_c.h"
slouken@1933
    29
#include "../../events/SDL_mouse_c.h"
slouken@4673
    30
#include "../../events/SDL_touch_c.h"
slouken@1933
    31
#include "../../events/SDL_windowevents_c.h"
slouken@1933
    32
#include "SDL_cocoavideo.h"
eligottlieb@4811
    33
#include "SDL_cocoashape.h"
gzjjgod@5057
    34
#include "SDL_cocoamouse.h"
jorgen@7594
    35
#include "SDL_cocoaopengl.h"
slouken@1933
    36
slouken@5398
    37
slouken@5398
    38
static Uint32 s_moveHack;
slouken@5398
    39
slouken@1933
    40
static __inline__ void ConvertNSRect(NSRect *r)
slouken@1933
    41
{
slouken@1933
    42
    r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
slouken@1933
    43
}
slouken@1933
    44
slouken@1933
    45
@implementation Cocoa_WindowListener
slouken@1933
    46
slouken@1933
    47
- (void)listen:(SDL_WindowData *)data
slouken@1933
    48
{
slouken@1933
    49
    NSNotificationCenter *center;
slouken@5371
    50
    NSWindow *window = data->nswindow;
slouken@5371
    51
    NSView *view = [window contentView];
slouken@1933
    52
slouken@1933
    53
    _data = data;
jorgen@7087
    54
    observingVisible = YES;
jorgen@7087
    55
    wasVisible = [window isVisible];
slouken@1933
    56
slouken@1933
    57
    center = [NSNotificationCenter defaultCenter];
slouken@1933
    58
slouken@5374
    59
    if ([window delegate] != nil) {
slouken@5374
    60
        [center addObserver:self selector:@selector(windowDidExpose:) name:NSWindowDidExposeNotification object:window];
slouken@5374
    61
        [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:window];
slouken@5374
    62
        [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:window];
slouken@5374
    63
        [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:window];
slouken@5374
    64
        [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
slouken@5374
    65
        [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
slouken@5374
    66
        [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
slouken@5374
    67
    } else {
slouken@5374
    68
        [window setDelegate:self];
slouken@5374
    69
    }
slouken@1933
    70
slouken@7191
    71
    /* Haven't found a delegate / notification that triggers when the window is
slouken@7191
    72
     * ordered out (is not visible any more). You can be ordered out without
slouken@7191
    73
     * minimizing, so DidMiniaturize doesn't work. (e.g. -[NSWindow orderOut:])
slouken@7191
    74
     */
jorgen@7084
    75
    [window addObserver:self
jorgen@7084
    76
             forKeyPath:@"visible"
jorgen@7084
    77
                options:NSKeyValueObservingOptionNew
jorgen@7084
    78
                context:NULL];
jorgen@7084
    79
slouken@5371
    80
    [window setNextResponder:self];
slouken@5371
    81
    [window setAcceptsMouseMovedEvents:YES];
slouken@5371
    82
slouken@5371
    83
    [view setNextResponder:self];
icculus@6108
    84
icculus@6108
    85
    if ([view respondsToSelector:@selector(setAcceptsTouchEvents:)]) {
icculus@6108
    86
        [view setAcceptsTouchEvents:YES];
icculus@6108
    87
    }
slouken@1933
    88
}
slouken@1933
    89
jorgen@7084
    90
- (void)observeValueForKeyPath:(NSString *)keyPath
jorgen@7084
    91
                      ofObject:(id)object
jorgen@7084
    92
                        change:(NSDictionary *)change
jorgen@7084
    93
                       context:(void *)context
jorgen@7084
    94
{
jorgen@7087
    95
    if (!observingVisible) {
jorgen@7087
    96
        return;
jorgen@7087
    97
    }
jorgen@7087
    98
jorgen@7084
    99
    if (object == _data->nswindow && [keyPath isEqualToString:@"visible"]) {
jorgen@7084
   100
        int newVisibility = [[change objectForKey:@"new"] intValue];
jorgen@7084
   101
        if (newVisibility) {
jorgen@7084
   102
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
jorgen@7084
   103
        } else {
jorgen@7084
   104
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
jorgen@7084
   105
        }
jorgen@7084
   106
    }
jorgen@7084
   107
}
jorgen@7084
   108
jorgen@7087
   109
-(void) pauseVisibleObservation
jorgen@7087
   110
{
jorgen@7087
   111
    observingVisible = NO;
jorgen@7087
   112
    wasVisible = [_data->nswindow isVisible];
jorgen@7087
   113
}
jorgen@7087
   114
jorgen@7087
   115
-(void) resumeVisibleObservation
jorgen@7087
   116
{
jorgen@7087
   117
    BOOL isVisible = [_data->nswindow isVisible];
jorgen@7087
   118
    observingVisible = YES;
jorgen@7087
   119
    if (wasVisible != isVisible) {
jorgen@7087
   120
        if (isVisible) {
jorgen@7087
   121
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_SHOWN, 0, 0);
jorgen@7087
   122
        } else {
jorgen@7087
   123
            SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_HIDDEN, 0, 0);
jorgen@7087
   124
        }
jorgen@7087
   125
jorgen@7087
   126
        wasVisible = isVisible;
jorgen@7087
   127
    }
jorgen@7087
   128
}
jorgen@7087
   129
slouken@1933
   130
- (void)close
slouken@1933
   131
{
slouken@1933
   132
    NSNotificationCenter *center;
slouken@5371
   133
    NSWindow *window = _data->nswindow;
slouken@5371
   134
    NSView *view = [window contentView];
icculus@7534
   135
    NSArray *windows = nil;
slouken@1933
   136
slouken@1933
   137
    center = [NSNotificationCenter defaultCenter];
slouken@1933
   138
slouken@5374
   139
    if ([window delegate] != self) {
slouken@5374
   140
        [center removeObserver:self name:NSWindowDidExposeNotification object:window];
slouken@5374
   141
        [center removeObserver:self name:NSWindowDidMoveNotification object:window];
slouken@5374
   142
        [center removeObserver:self name:NSWindowDidResizeNotification object:window];
slouken@5374
   143
        [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:window];
slouken@5374
   144
        [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
slouken@5374
   145
        [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
slouken@5374
   146
        [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
slouken@5374
   147
    } else {
slouken@5374
   148
        [window setDelegate:nil];
slouken@5374
   149
    }
slouken@5371
   150
jorgen@7084
   151
    [window removeObserver:self
jorgen@7084
   152
                forKeyPath:@"visible"];
jorgen@7084
   153
slouken@5374
   154
    if ([window nextResponder] == self) {
slouken@5374
   155
        [window setNextResponder:nil];
slouken@5374
   156
    }
slouken@5374
   157
    if ([view nextResponder] == self) {
slouken@5374
   158
        [view setNextResponder:nil];
slouken@5374
   159
    }
icculus@7534
   160
icculus@7534
   161
    /* Make the next window in the z-order Key. If we weren't the foreground
icculus@7535
   162
       when closed, this is a no-op.
icculus@7535
   163
       !!! FIXME: Note that this is a hack, and there are corner cases where
icculus@7535
   164
       !!! FIXME:  this fails (such as the About box). The typical nib+RunLoop
icculus@7535
   165
       !!! FIXME:  handles this for Cocoa apps, but we bypass all that in SDL.
icculus@7535
   166
       !!! FIXME:  We should remove this code when we find a better way to
icculus@7535
   167
       !!! FIXME:  have the system do this for us. See discussion in
icculus@7535
   168
       !!! FIXME:   http://bugzilla.libsdl.org/show_bug.cgi?id=1825
icculus@7535
   169
    */
icculus@7534
   170
    windows = [NSApp orderedWindows];
icculus@7534
   171
    if ([windows count] > 0) {
icculus@7534
   172
        NSWindow *win = (NSWindow *) [windows objectAtIndex:0];
icculus@7534
   173
        [win makeKeyAndOrderFront:self];
icculus@7534
   174
    }
slouken@1933
   175
}
slouken@1933
   176
slouken@1933
   177
- (BOOL)windowShouldClose:(id)sender
slouken@1933
   178
{
slouken@3685
   179
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
slouken@1933
   180
    return NO;
slouken@1933
   181
}
slouken@1933
   182
slouken@1933
   183
- (void)windowDidExpose:(NSNotification *)aNotification
slouken@1933
   184
{
slouken@3685
   185
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_EXPOSED, 0, 0);
slouken@1933
   186
}
slouken@1933
   187
slouken@1933
   188
- (void)windowDidMove:(NSNotification *)aNotification
slouken@1933
   189
{
slouken@1933
   190
    int x, y;
slouken@5398
   191
    SDL_Window *window = _data->window;
slouken@5398
   192
    NSWindow *nswindow = _data->nswindow;
slouken@5398
   193
    NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@1933
   194
    ConvertNSRect(&rect);
slouken@5398
   195
slouken@5398
   196
    if (s_moveHack) {
slouken@5398
   197
        SDL_bool blockMove = ((SDL_GetTicks() - s_moveHack) < 500);
slouken@5398
   198
slouken@5398
   199
        s_moveHack = 0;
slouken@5398
   200
slouken@5398
   201
        if (blockMove) {
slouken@5398
   202
            /* Cocoa is adjusting the window in response to a mode change */
slouken@5398
   203
            rect.origin.x = window->x;
slouken@5398
   204
            rect.origin.y = window->y;
slouken@5398
   205
            ConvertNSRect(&rect);
slouken@5398
   206
            [nswindow setFrameOrigin:rect.origin];
slouken@5398
   207
            return;
slouken@5398
   208
        }
slouken@5398
   209
    }
slouken@5398
   210
slouken@3507
   211
    x = (int)rect.origin.x;
slouken@3507
   212
    y = (int)rect.origin.y;
icculus@5564
   213
jorgen@7594
   214
    [_data->nscontext scheduleUpdate];
icculus@5564
   215
slouken@5398
   216
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@1933
   217
}
slouken@1933
   218
slouken@1933
   219
- (void)windowDidResize:(NSNotification *)aNotification
slouken@1933
   220
{
slouken@6231
   221
    int x, y, w, h;
slouken@3688
   222
    NSRect rect = [_data->nswindow contentRectForFrameRect:[_data->nswindow frame]];
slouken@6231
   223
    ConvertNSRect(&rect);
slouken@6231
   224
    x = (int)rect.origin.x;
slouken@6231
   225
    y = (int)rect.origin.y;
slouken@1933
   226
    w = (int)rect.size.width;
slouken@1933
   227
    h = (int)rect.size.height;
slouken@4937
   228
    if (SDL_IsShapedWindow(_data->window))
slouken@4937
   229
        Cocoa_ResizeWindowShape(_data->window);
icculus@5564
   230
jorgen@7594
   231
    [_data->nscontext scheduleUpdate];
icculus@5564
   232
slouken@6231
   233
    /* The window can move during a resize event, such as when maximizing
slouken@6231
   234
       or resizing from a corner */
slouken@6231
   235
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MOVED, x, y);
slouken@3685
   236
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESIZED, w, h);
icculus@7566
   237
icculus@7566
   238
    const BOOL zoomed = [_data->nswindow isZoomed];
icculus@7566
   239
    if (!zoomed) {
icculus@7566
   240
        SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
icculus@7566
   241
    } else if (zoomed) {
icculus@7566
   242
        SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
icculus@7566
   243
    }
slouken@1933
   244
}
slouken@1933
   245
slouken@1933
   246
- (void)windowDidMiniaturize:(NSNotification *)aNotification
slouken@1933
   247
{
slouken@3685
   248
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
slouken@1933
   249
}
slouken@1933
   250
slouken@1933
   251
- (void)windowDidDeminiaturize:(NSNotification *)aNotification
slouken@1933
   252
{
slouken@3685
   253
    SDL_SendWindowEvent(_data->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
slouken@1933
   254
}
slouken@1933
   255
slouken@1933
   256
- (void)windowDidBecomeKey:(NSNotification *)aNotification
slouken@1933
   257
{
slouken@5367
   258
    SDL_Window *window = _data->window;
jorgen@7271
   259
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@5367
   260
slouken@3688
   261
    /* We're going to get keyboard events, since we're key. */
slouken@5367
   262
    SDL_SetKeyboardFocus(window);
slouken@5367
   263
slouken@5367
   264
    /* If we just gained focus we need the updated mouse position */
jorgen@7271
   265
    if (!mouse->relative_mode) {
slouken@5367
   266
        NSPoint point;
slouken@5396
   267
        int x, y;
slouken@5396
   268
slouken@5396
   269
        point = [_data->nswindow mouseLocationOutsideOfEventStream];
slouken@5396
   270
        x = (int)point.x;
slouken@5396
   271
        y = (int)(window->h - point.y);
slouken@5396
   272
slouken@5396
   273
        if (x >= 0 && x < window->w && y >= 0 && y < window->h) {
slouken@6950
   274
            SDL_SendMouseMotion(window, 0, 0, x, y);
slouken@5396
   275
        }
slouken@5367
   276
    }
slouken@1962
   277
slouken@4503
   278
    /* Check to see if someone updated the clipboard */
slouken@4503
   279
    Cocoa_CheckClipboardUpdate(_data->videodata);
slouken@1933
   280
}
slouken@1933
   281
slouken@1933
   282
- (void)windowDidResignKey:(NSNotification *)aNotification
slouken@1933
   283
{
slouken@2059
   284
    /* Some other window will get mouse events, since we're not key. */
slouken@4465
   285
    if (SDL_GetMouseFocus() == _data->window) {
slouken@4465
   286
        SDL_SetMouseFocus(NULL);
slouken@2059
   287
    }
slouken@2059
   288
slouken@2059
   289
    /* Some other window will get keyboard events, since we're not key. */
slouken@4465
   290
    if (SDL_GetKeyboardFocus() == _data->window) {
slouken@4465
   291
        SDL_SetKeyboardFocus(NULL);
slouken@4465
   292
    }
slouken@1933
   293
}
slouken@1933
   294
slouken@7191
   295
/* We'll respond to key events by doing nothing so we don't beep.
slouken@7191
   296
 * We could handle key messages here, but we lose some in the NSApp dispatch,
slouken@7191
   297
 * where they get converted to action messages, etc.
slouken@7191
   298
 */
slouken@6514
   299
- (void)flagsChanged:(NSEvent *)theEvent
slouken@6514
   300
{
slouken@7191
   301
    /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
slouken@6514
   302
}
slouken@6514
   303
- (void)keyDown:(NSEvent *)theEvent
slouken@6514
   304
{
slouken@7191
   305
    /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
slouken@6514
   306
}
slouken@6514
   307
- (void)keyUp:(NSEvent *)theEvent
slouken@6514
   308
{
slouken@7191
   309
    /*Cocoa_HandleKeyEvent(SDL_GetVideoDevice(), theEvent);*/
slouken@6514
   310
}
slouken@6514
   311
slouken@7191
   312
/* We'll respond to selectors by doing nothing so we don't beep.
slouken@7191
   313
 * The escape key gets converted to a "cancel" selector, etc.
slouken@7191
   314
 */
slouken@6514
   315
- (void)doCommandBySelector:(SEL)aSelector
slouken@6514
   316
{
slouken@7191
   317
    /*NSLog(@"doCommandBySelector: %@\n", NSStringFromSelector(aSelector));*/
slouken@6514
   318
}
slouken@6514
   319
slouken@1933
   320
- (void)mouseDown:(NSEvent *)theEvent
slouken@1933
   321
{
slouken@1959
   322
    int button;
slouken@1933
   323
slouken@1959
   324
    switch ([theEvent buttonNumber]) {
slouken@1959
   325
    case 0:
slouken@1959
   326
        button = SDL_BUTTON_LEFT;
slouken@1959
   327
        break;
slouken@1959
   328
    case 1:
slouken@1959
   329
        button = SDL_BUTTON_RIGHT;
slouken@1959
   330
        break;
slouken@1959
   331
    case 2:
slouken@1959
   332
        button = SDL_BUTTON_MIDDLE;
slouken@1959
   333
        break;
slouken@1959
   334
    default:
slouken@5061
   335
        button = [theEvent buttonNumber] + 1;
slouken@1959
   336
        break;
slouken@1959
   337
    }
slouken@6950
   338
    SDL_SendMouseButton(_data->window, 0, SDL_PRESSED, button);
slouken@1933
   339
}
slouken@1933
   340
slouken@1933
   341
- (void)rightMouseDown:(NSEvent *)theEvent
slouken@1933
   342
{
slouken@1959
   343
    [self mouseDown:theEvent];
slouken@1933
   344
}
slouken@1933
   345
slouken@1933
   346
- (void)otherMouseDown:(NSEvent *)theEvent
slouken@1933
   347
{
slouken@1959
   348
    [self mouseDown:theEvent];
slouken@1933
   349
}
slouken@1933
   350
slouken@1933
   351
- (void)mouseUp:(NSEvent *)theEvent
slouken@1933
   352
{
slouken@1959
   353
    int button;
slouken@1933
   354
slouken@1959
   355
    switch ([theEvent buttonNumber]) {
slouken@1959
   356
    case 0:
slouken@1959
   357
        button = SDL_BUTTON_LEFT;
slouken@1959
   358
        break;
slouken@1959
   359
    case 1:
slouken@1959
   360
        button = SDL_BUTTON_RIGHT;
slouken@1959
   361
        break;
slouken@1959
   362
    case 2:
slouken@1959
   363
        button = SDL_BUTTON_MIDDLE;
slouken@1959
   364
        break;
slouken@1959
   365
    default:
slouken@5061
   366
        button = [theEvent buttonNumber] + 1;
slouken@1959
   367
        break;
slouken@1959
   368
    }
slouken@6950
   369
    SDL_SendMouseButton(_data->window, 0, SDL_RELEASED, button);
slouken@1933
   370
}
slouken@1933
   371
slouken@1933
   372
- (void)rightMouseUp:(NSEvent *)theEvent
slouken@1933
   373
{
slouken@1959
   374
    [self mouseUp:theEvent];
slouken@1933
   375
}
slouken@1933
   376
slouken@1933
   377
- (void)otherMouseUp:(NSEvent *)theEvent
slouken@1933
   378
{
slouken@1959
   379
    [self mouseUp:theEvent];
slouken@1933
   380
}
slouken@1933
   381
slouken@1933
   382
- (void)mouseMoved:(NSEvent *)theEvent
slouken@1933
   383
{
slouken@5406
   384
    SDL_Mouse *mouse = SDL_GetMouse();
slouken@3685
   385
    SDL_Window *window = _data->window;
slouken@5396
   386
    NSPoint point;
slouken@5396
   387
    int x, y;
slouken@1933
   388
slouken@5406
   389
    if (mouse->relative_mode) {
gzjjgod@5059
   390
        return;
slouken@5371
   391
    }
gzjjgod@5059
   392
slouken@5396
   393
    point = [theEvent locationInWindow];
slouken@5396
   394
    x = (int)point.x;
slouken@5396
   395
    y = (int)(window->h - point.y);
slouken@5371
   396
slouken@5396
   397
    if (x < 0 || x >= window->w || y < 0 || y >= window->h) {
slouken@6666
   398
        if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
slouken@6666
   399
            CGPoint cgpoint;
slouken@6666
   400
slouken@6666
   401
            if (x < 0) {
slouken@6666
   402
                x = 0;
slouken@6666
   403
            } else if (x >= window->w) {
slouken@6666
   404
                x = window->w - 1;
slouken@6666
   405
            }
slouken@6666
   406
            if (y < 0) {
slouken@6666
   407
                y = 0;
slouken@6666
   408
            } else if (y >= window->h) {
slouken@6666
   409
                y = window->h - 1;
slouken@6666
   410
            }
slouken@6666
   411
jorgen@7593
   412
#if !SDL_MAC_NO_SANDBOX
jorgen@7593
   413
            /* When SDL_MAC_NO_SANDBOX is set, this is handled by
jorgen@7593
   414
             * SDL_cocoamousetap.m.
jorgen@7593
   415
             */
jorgen@7593
   416
slouken@6666
   417
            cgpoint.x = window->x + x;
slouken@6666
   418
            cgpoint.y = window->y + y;
jorgen@7098
   419
jorgen@7113
   420
            /* According to the docs, this was deprecated in 10.6, but it's still
jorgen@7113
   421
             * around. The substitute requires a CGEventSource, but I'm not entirely
jorgen@7113
   422
             * sure how we'd procure the right one for this event.
jorgen@7098
   423
             */
jorgen@7113
   424
            CGSetLocalEventsSuppressionInterval(0.0);
slouken@6666
   425
            CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
jorgen@7113
   426
            CGSetLocalEventsSuppressionInterval(0.25);
jorgen@7593
   427
#endif
slouken@5396
   428
        }
slouken@2059
   429
    }
slouken@6950
   430
    SDL_SendMouseMotion(window, 0, 0, x, y);
slouken@1933
   431
}
slouken@1933
   432
slouken@1957
   433
- (void)mouseDragged:(NSEvent *)theEvent
slouken@1957
   434
{
slouken@1957
   435
    [self mouseMoved:theEvent];
slouken@1957
   436
}
slouken@1957
   437
slouken@1958
   438
- (void)rightMouseDragged:(NSEvent *)theEvent
slouken@1958
   439
{
slouken@1958
   440
    [self mouseMoved:theEvent];
slouken@1958
   441
}
slouken@1958
   442
slouken@1958
   443
- (void)otherMouseDragged:(NSEvent *)theEvent
slouken@1958
   444
{
slouken@1958
   445
    [self mouseMoved:theEvent];
slouken@1958
   446
}
slouken@1958
   447
slouken@1933
   448
- (void)scrollWheel:(NSEvent *)theEvent
slouken@1933
   449
{
gzjjgod@5057
   450
    Cocoa_HandleMouseWheel(_data->window, theEvent);
slouken@3688
   451
}
slouken@3688
   452
slouken@4673
   453
- (void)touchesBeganWithEvent:(NSEvent *) theEvent
slouken@4673
   454
{
slouken@4673
   455
    [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
slouken@4673
   456
}
slouken@4673
   457
slouken@4673
   458
- (void)touchesMovedWithEvent:(NSEvent *) theEvent
slouken@4673
   459
{
slouken@4673
   460
    [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
slouken@4673
   461
}
slouken@4673
   462
slouken@4673
   463
- (void)touchesEndedWithEvent:(NSEvent *) theEvent
slouken@4673
   464
{
slouken@4673
   465
    [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
slouken@4673
   466
}
slouken@4673
   467
slouken@4673
   468
- (void)touchesCancelledWithEvent:(NSEvent *) theEvent
slouken@4673
   469
{
slouken@4673
   470
    [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
slouken@4673
   471
}
slouken@4673
   472
slouken@4673
   473
- (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
slouken@4673
   474
{
slouken@4680
   475
    NSSet *touches = 0;
slouken@4680
   476
    NSEnumerator *enumerator;
slouken@4680
   477
    NSTouch *touch;
slouken@4673
   478
slouken@4680
   479
    switch (type) {
slouken@4680
   480
        case COCOA_TOUCH_DOWN:
slouken@4680
   481
            touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
slouken@4680
   482
            break;
slouken@4680
   483
        case COCOA_TOUCH_UP:
slouken@4680
   484
        case COCOA_TOUCH_CANCELLED:
slouken@4680
   485
            touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
slouken@4680
   486
            break;
slouken@4680
   487
        case COCOA_TOUCH_MOVE:
slouken@4680
   488
            touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
slouken@4680
   489
            break;
slouken@4680
   490
    }
slouken@4680
   491
slouken@4680
   492
    enumerator = [touches objectEnumerator];
slouken@4680
   493
    touch = (NSTouch*)[enumerator nextObject];
slouken@4673
   494
    while (touch) {
slouken@6953
   495
        const SDL_TouchID touchId = (SDL_TouchID)(intptr_t)[touch device];
slouken@4673
   496
        if (!SDL_GetTouch(touchId)) {
slouken@6951
   497
            if (SDL_AddTouch(touchId, "") < 0) {
slouken@4680
   498
                return;
slouken@4673
   499
            }
slouken@7191
   500
        }
slouken@4687
   501
slouken@6953
   502
        const SDL_FingerID fingerId = (SDL_FingerID)(intptr_t)[touch identity];
slouken@4673
   503
        float x = [touch normalizedPosition].x;
slouken@4673
   504
        float y = [touch normalizedPosition].y;
slouken@5261
   505
        /* Make the origin the upper left instead of the lower left */
slouken@5261
   506
        y = 1.0f - y;
slouken@4687
   507
slouken@4673
   508
        switch (type) {
slouken@4673
   509
        case COCOA_TOUCH_DOWN:
slouken@6951
   510
            SDL_SendTouch(touchId, fingerId, SDL_TRUE, x, y, 1.0f);
slouken@4673
   511
            break;
slouken@4673
   512
        case COCOA_TOUCH_UP:
slouken@4673
   513
        case COCOA_TOUCH_CANCELLED:
slouken@6951
   514
            SDL_SendTouch(touchId, fingerId, SDL_FALSE, x, y, 1.0f);
slouken@4673
   515
            break;
slouken@4673
   516
        case COCOA_TOUCH_MOVE:
slouken@6951
   517
            SDL_SendTouchMotion(touchId, fingerId, x, y, 1.0f);
slouken@4673
   518
            break;
slouken@4673
   519
        }
slouken@6951
   520
slouken@4673
   521
        touch = (NSTouch*)[enumerator nextObject];
slouken@4673
   522
    }
slouken@1933
   523
}
slouken@1933
   524
slouken@1933
   525
@end
slouken@1933
   526
slouken@1973
   527
@interface SDLWindow : NSWindow
slouken@1973
   528
/* These are needed for borderless/fullscreen windows */
slouken@1973
   529
- (BOOL)canBecomeKeyWindow;
slouken@1973
   530
- (BOOL)canBecomeMainWindow;
slouken@1973
   531
@end
slouken@1973
   532
slouken@1973
   533
@implementation SDLWindow
slouken@1973
   534
- (BOOL)canBecomeKeyWindow
slouken@1973
   535
{
slouken@1973
   536
    return YES;
slouken@1973
   537
}
slouken@1973
   538
slouken@1973
   539
- (BOOL)canBecomeMainWindow
slouken@1973
   540
{
slouken@1973
   541
    return YES;
slouken@1973
   542
}
slouken@1973
   543
@end
slouken@1973
   544
slouken@5379
   545
@interface SDLView : NSView
jorgen@7158
   546
slouken@5379
   547
/* The default implementation doesn't pass rightMouseDown to responder chain */
slouken@5379
   548
- (void)rightMouseDown:(NSEvent *)theEvent;
gzjjgod@4915
   549
@end
gzjjgod@4915
   550
gzjjgod@4915
   551
@implementation SDLView
gzjjgod@4915
   552
- (void)rightMouseDown:(NSEvent *)theEvent
gzjjgod@4915
   553
{
slouken@5371
   554
    [[self nextResponder] rightMouseDown:theEvent];
gzjjgod@4915
   555
}
jorgen@7158
   556
jorgen@7158
   557
- (void)resetCursorRects
jorgen@7158
   558
{
jorgen@7158
   559
    [super resetCursorRects];
jorgen@7158
   560
    SDL_Mouse *mouse = SDL_GetMouse();
jorgen@7158
   561
jorgen@7270
   562
    if (mouse->cursor_shown && mouse->cur_cursor && !mouse->relative_mode) {
jorgen@7158
   563
        [self addCursorRect:[self bounds]
jorgen@7158
   564
                     cursor:mouse->cur_cursor->driverdata];
jorgen@7158
   565
    } else {
jorgen@7158
   566
        [self addCursorRect:[self bounds]
jorgen@7158
   567
                     cursor:[NSCursor invisibleCursor]];
jorgen@7158
   568
    }
jorgen@7158
   569
}
gzjjgod@4915
   570
@end
gzjjgod@4915
   571
slouken@5249
   572
static unsigned int
slouken@5305
   573
GetWindowStyle(SDL_Window * window)
slouken@5249
   574
{
slouken@5249
   575
    unsigned int style;
slouken@5249
   576
slouken@7191
   577
    if (window->flags & SDL_WINDOW_FULLSCREEN) {
slouken@5249
   578
        style = NSBorderlessWindowMask;
slouken@7191
   579
    } else {
slouken@7191
   580
        if (window->flags & SDL_WINDOW_BORDERLESS) {
slouken@7191
   581
            style = NSBorderlessWindowMask;
slouken@7191
   582
        } else {
slouken@7191
   583
            style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
slouken@7191
   584
        }
slouken@7191
   585
        if (window->flags & SDL_WINDOW_RESIZABLE) {
slouken@7191
   586
            style |= NSResizableWindowMask;
slouken@7191
   587
        }
slouken@7191
   588
    }
slouken@5249
   589
    return style;
slouken@5249
   590
}
slouken@5249
   591
slouken@1933
   592
static int
slouken@1951
   593
SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
slouken@1933
   594
{
slouken@6848
   595
    NSAutoreleasePool *pool;
slouken@1951
   596
    SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
slouken@1933
   597
    SDL_WindowData *data;
slouken@1933
   598
slouken@1933
   599
    /* Allocate the window data */
slouken@5249
   600
    data = (SDL_WindowData *) SDL_calloc(1, sizeof(*data));
slouken@1933
   601
    if (!data) {
icculus@7037
   602
        return SDL_OutOfMemory();
slouken@1933
   603
    }
slouken@3685
   604
    data->window = window;
slouken@3688
   605
    data->nswindow = nswindow;
slouken@1933
   606
    data->created = created;
slouken@1951
   607
    data->videodata = videodata;
slouken@1933
   608
slouken@6848
   609
    pool = [[NSAutoreleasePool alloc] init];
slouken@1933
   610
slouken@6848
   611
    /* Create an event listener for the window */
slouken@6848
   612
    data->listener = [[Cocoa_WindowListener alloc] init];
slouken@6848
   613
slouken@6848
   614
    /* Fill in the SDL window with the window data */
slouken@6848
   615
    {
slouken@6848
   616
        NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@6848
   617
        ConvertNSRect(&rect);
slouken@6848
   618
        window->x = (int)rect.origin.x;
slouken@6848
   619
        window->y = (int)rect.origin.y;
slouken@6848
   620
        window->w = (int)rect.size.width;
slouken@6848
   621
        window->h = (int)rect.size.height;
slouken@6848
   622
    }
slouken@6848
   623
slouken@6848
   624
    /* Set up the listener after we create the view */
slouken@6848
   625
    [data->listener listen:data];
slouken@6848
   626
slouken@6848
   627
    if ([nswindow isVisible]) {
slouken@6848
   628
        window->flags |= SDL_WINDOW_SHOWN;
slouken@6848
   629
    } else {
slouken@6848
   630
        window->flags &= ~SDL_WINDOW_SHOWN;
slouken@6848
   631
    }
jorgen@7084
   632
slouken@6848
   633
    {
slouken@6848
   634
        unsigned int style = [nswindow styleMask];
slouken@6848
   635
slouken@6848
   636
        if (style == NSBorderlessWindowMask) {
slouken@6848
   637
            window->flags |= SDL_WINDOW_BORDERLESS;
slouken@6848
   638
        } else {
slouken@6848
   639
            window->flags &= ~SDL_WINDOW_BORDERLESS;
alexey@6832
   640
        }
slouken@6848
   641
        if (style & NSResizableWindowMask) {
slouken@6848
   642
            window->flags |= SDL_WINDOW_RESIZABLE;
slouken@6848
   643
        } else {
slouken@6848
   644
            window->flags &= ~SDL_WINDOW_RESIZABLE;
slouken@6848
   645
        }
slouken@6848
   646
    }
jorgen@7084
   647
slouken@6848
   648
    /* isZoomed always returns true if the window is not resizable */
slouken@6848
   649
    if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
slouken@6848
   650
        window->flags |= SDL_WINDOW_MAXIMIZED;
slouken@6848
   651
    } else {
slouken@6848
   652
        window->flags &= ~SDL_WINDOW_MAXIMIZED;
slouken@6848
   653
    }
jorgen@7084
   654
slouken@6848
   655
    if ([nswindow isMiniaturized]) {
slouken@6848
   656
        window->flags |= SDL_WINDOW_MINIMIZED;
slouken@6848
   657
    } else {
slouken@6848
   658
        window->flags &= ~SDL_WINDOW_MINIMIZED;
slouken@6848
   659
    }
jorgen@7084
   660
slouken@6848
   661
    if ([nswindow isKeyWindow]) {
slouken@6848
   662
        window->flags |= SDL_WINDOW_INPUT_FOCUS;
slouken@6848
   663
        SDL_SetKeyboardFocus(data->window);
slouken@6848
   664
    }
slouken@1933
   665
jorgen@7085
   666
    /* Prevents the window's "window device" from being destroyed when it is
jorgen@7085
   667
     * hidden. See http://www.mikeash.com/pyblog/nsopenglcontext-and-one-shot.html
jorgen@7085
   668
     */
jorgen@7085
   669
    [nswindow setOneShot:NO];
jorgen@7085
   670
slouken@6848
   671
    /* All done! */
slouken@6848
   672
    [pool release];
slouken@6848
   673
    window->driverdata = data;
slouken@6848
   674
    return 0;
slouken@1933
   675
}
slouken@1933
   676
slouken@1933
   677
int
slouken@1933
   678
Cocoa_CreateWindow(_THIS, SDL_Window * window)
slouken@1933
   679
{
slouken@6848
   680
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   681
    NSWindow *nswindow;
slouken@6848
   682
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@6848
   683
    NSRect rect;
slouken@6848
   684
    SDL_Rect bounds;
slouken@6848
   685
    unsigned int style;
slouken@1933
   686
slouken@6848
   687
    Cocoa_GetDisplayBounds(_this, display, &bounds);
slouken@6848
   688
    rect.origin.x = window->x;
slouken@6848
   689
    rect.origin.y = window->y;
slouken@6848
   690
    rect.size.width = window->w;
slouken@6848
   691
    rect.size.height = window->h;
slouken@6848
   692
    ConvertNSRect(&rect);
slouken@1933
   693
slouken@6848
   694
    style = GetWindowStyle(window);
slouken@1933
   695
slouken@6848
   696
    /* Figure out which screen to place this window */
slouken@6848
   697
    NSArray *screens = [NSScreen screens];
slouken@6848
   698
    NSScreen *screen = nil;
slouken@6848
   699
    NSScreen *candidate;
slouken@6848
   700
    int i, count = [screens count];
slouken@6848
   701
    for (i = 0; i < count; ++i) {
slouken@6848
   702
        candidate = [screens objectAtIndex:i];
slouken@6848
   703
        NSRect screenRect = [candidate frame];
slouken@6848
   704
        if (rect.origin.x >= screenRect.origin.x &&
slouken@6848
   705
            rect.origin.x < screenRect.origin.x + screenRect.size.width &&
slouken@6848
   706
            rect.origin.y >= screenRect.origin.y &&
slouken@6848
   707
            rect.origin.y < screenRect.origin.y + screenRect.size.height) {
slouken@6848
   708
            screen = candidate;
slouken@6848
   709
            rect.origin.x -= screenRect.origin.x;
slouken@6848
   710
            rect.origin.y -= screenRect.origin.y;
slouken@3506
   711
        }
slouken@6848
   712
    }
jorgen@7085
   713
    nswindow = [[SDLWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:NO screen:screen];
icculus@7205
   714
    [nswindow setBackgroundColor:[NSColor blackColor]];
alexey@6832
   715
slouken@7191
   716
    /* Create a default view for this window */
slouken@6848
   717
    rect = [nswindow contentRectForFrameRect:[nswindow frame]];
slouken@6848
   718
    NSView *contentView = [[SDLView alloc] initWithFrame:rect];
slouken@6848
   719
    [nswindow setContentView: contentView];
slouken@6848
   720
    [contentView release];
alexey@6832
   721
slouken@6848
   722
    [pool release];
slouken@6848
   723
slouken@6848
   724
    if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
slouken@6848
   725
        [nswindow release];
slouken@6848
   726
        return -1;
slouken@3506
   727
    }
slouken@6848
   728
    return 0;
slouken@1933
   729
}
slouken@1933
   730
slouken@1933
   731
int
slouken@1933
   732
Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
slouken@1933
   733
{
slouken@6848
   734
    NSAutoreleasePool *pool;
slouken@1933
   735
    NSWindow *nswindow = (NSWindow *) data;
slouken@1933
   736
    NSString *title;
slouken@1933
   737
slouken@6848
   738
    pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   739
slouken@6848
   740
    /* Query the title from the existing window */
slouken@6848
   741
    title = [nswindow title];
slouken@6848
   742
    if (title) {
slouken@6848
   743
        window->title = SDL_strdup([title UTF8String]);
slouken@1933
   744
    }
slouken@1933
   745
slouken@6848
   746
    [pool release];
slouken@6848
   747
slouken@1951
   748
    return SetupWindowData(_this, window, nswindow, SDL_FALSE);
slouken@1933
   749
}
slouken@1933
   750
slouken@1933
   751
void
slouken@1933
   752
Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
slouken@1933
   753
{
slouken@6848
   754
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   755
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@6848
   756
    NSString *string;
slouken@1933
   757
slouken@6848
   758
    if(window->title) {
slouken@6848
   759
        string = [[NSString alloc] initWithUTF8String:window->title];
slouken@6848
   760
    } else {
slouken@6848
   761
        string = [[NSString alloc] init];
slouken@1956
   762
    }
slouken@6848
   763
    [nswindow setTitle:string];
slouken@6848
   764
    [string release];
slouken@6848
   765
slouken@6848
   766
    [pool release];
slouken@1933
   767
}
slouken@1933
   768
slouken@1933
   769
void
slouken@5375
   770
Cocoa_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
slouken@5375
   771
{
slouken@6848
   772
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   773
    NSImage *nsimage = Cocoa_CreateImage(icon);
slouken@5375
   774
slouken@6848
   775
    if (nsimage) {
slouken@6848
   776
        [NSApp setApplicationIconImage:nsimage];
slouken@5375
   777
    }
slouken@6848
   778
slouken@6848
   779
    [pool release];
slouken@5375
   780
}
slouken@5375
   781
slouken@5375
   782
void
slouken@1933
   783
Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
slouken@1933
   784
{
slouken@6848
   785
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7594
   786
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
jorgen@7594
   787
    NSWindow *nswindow = windata->nswindow;
slouken@6848
   788
    NSRect rect;
slouken@6848
   789
    Uint32 moveHack;
slouken@1933
   790
slouken@6848
   791
    rect.origin.x = window->x;
slouken@6848
   792
    rect.origin.y = window->y;
slouken@6848
   793
    rect.size.width = window->w;
slouken@6848
   794
    rect.size.height = window->h;
slouken@6848
   795
    ConvertNSRect(&rect);
slouken@5478
   796
slouken@6848
   797
    moveHack = s_moveHack;
slouken@6848
   798
    s_moveHack = 0;
slouken@6848
   799
    [nswindow setFrameOrigin:rect.origin];
slouken@6848
   800
    s_moveHack = moveHack;
slouken@5478
   801
jorgen@7594
   802
    [windata->nscontext scheduleUpdate];
slouken@6848
   803
slouken@6848
   804
    [pool release];
slouken@1933
   805
}
slouken@1933
   806
slouken@1933
   807
void
slouken@1933
   808
Cocoa_SetWindowSize(_THIS, SDL_Window * window)
slouken@1933
   809
{
slouken@6848
   810
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   811
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
slouken@6848
   812
    NSWindow *nswindow = windata->nswindow;
slouken@6848
   813
    NSSize size;
slouken@1933
   814
slouken@6848
   815
    size.width = window->w;
slouken@6848
   816
    size.height = window->h;
slouken@6848
   817
    [nswindow setContentSize:size];
icculus@5564
   818
jorgen@7594
   819
    [windata->nscontext scheduleUpdate];
slouken@6848
   820
slouken@6848
   821
    [pool release];
slouken@1933
   822
}
slouken@1933
   823
slouken@1933
   824
void
stopiccot@6681
   825
Cocoa_SetWindowMinimumSize(_THIS, SDL_Window * window)
stopiccot@6681
   826
{
slouken@6848
   827
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   828
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
slouken@7191
   829
slouken@6848
   830
    NSSize minSize;
slouken@6848
   831
    minSize.width = window->min_w;
slouken@6848
   832
    minSize.height = window->min_h;
slouken@7191
   833
slouken@6848
   834
    [windata->nswindow setContentMinSize:minSize];
slouken@7191
   835
slouken@6848
   836
    [pool release];
slouken@6788
   837
}
slouken@6788
   838
slouken@6788
   839
void
slouken@6788
   840
Cocoa_SetWindowMaximumSize(_THIS, SDL_Window * window)
slouken@6788
   841
{
slouken@6848
   842
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   843
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
slouken@7191
   844
slouken@6848
   845
    NSSize maxSize;
slouken@6848
   846
    maxSize.width = window->max_w;
slouken@6848
   847
    maxSize.height = window->max_h;
slouken@7191
   848
slouken@6848
   849
    [windata->nswindow setContentMaxSize:maxSize];
slouken@7191
   850
slouken@6848
   851
    [pool release];
stopiccot@6681
   852
}
stopiccot@6681
   853
stopiccot@6681
   854
void
slouken@1933
   855
Cocoa_ShowWindow(_THIS, SDL_Window * window)
slouken@1933
   856
{
slouken@6848
   857
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7087
   858
    SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
jorgen@7087
   859
    NSWindow *nswindow = windowData->nswindow;
slouken@1933
   860
slouken@6848
   861
    if (![nswindow isMiniaturized]) {
jorgen@7087
   862
        [windowData->listener pauseVisibleObservation];
slouken@6848
   863
        [nswindow makeKeyAndOrderFront:nil];
jorgen@7087
   864
        [windowData->listener resumeVisibleObservation];
slouken@1956
   865
    }
slouken@6848
   866
    [pool release];
slouken@1933
   867
}
slouken@1933
   868
slouken@1933
   869
void
slouken@1933
   870
Cocoa_HideWindow(_THIS, SDL_Window * window)
slouken@1933
   871
{
slouken@6848
   872
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   873
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@6848
   874
slouken@6848
   875
    [nswindow orderOut:nil];
slouken@6848
   876
    [pool release];
slouken@1933
   877
}
slouken@1933
   878
slouken@1933
   879
void
slouken@1933
   880
Cocoa_RaiseWindow(_THIS, SDL_Window * window)
slouken@1933
   881
{
slouken@6848
   882
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7087
   883
    SDL_WindowData *windowData = ((SDL_WindowData *) window->driverdata);
jorgen@7087
   884
    NSWindow *nswindow = windowData->nswindow;
slouken@6848
   885
jorgen@7469
   886
    // makeKeyAndOrderFront: has the side-effect of deminiaturizing and showing
jorgen@7469
   887
    // a minimized or hidden window, so check for that before showing it.
jorgen@7087
   888
    [windowData->listener pauseVisibleObservation];
jorgen@7469
   889
    if (![nswindow isMiniaturized] && [nswindow isVisible]) {
jorgen@7469
   890
        [nswindow makeKeyAndOrderFront:nil];
jorgen@7469
   891
    }
jorgen@7087
   892
    [windowData->listener resumeVisibleObservation];
jorgen@7087
   893
slouken@6848
   894
    [pool release];
slouken@1933
   895
}
slouken@1933
   896
slouken@1933
   897
void
slouken@1933
   898
Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
slouken@1933
   899
{
slouken@6848
   900
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
jorgen@7594
   901
    SDL_WindowData *windata = (SDL_WindowData *) window->driverdata;
jorgen@7594
   902
    NSWindow *nswindow = windata->nswindow;
slouken@1933
   903
slouken@6848
   904
    [nswindow zoom:nil];
slouken@6848
   905
jorgen@7594
   906
    [windata->nscontext scheduleUpdate];
slouken@6848
   907
slouken@6848
   908
    [pool release];
slouken@1933
   909
}
slouken@1933
   910
slouken@1933
   911
void
slouken@1933
   912
Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
slouken@1933
   913
{
slouken@6848
   914
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   915
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@6848
   916
slouken@6848
   917
    [nswindow miniaturize:nil];
slouken@6848
   918
    [pool release];
slouken@1933
   919
}
slouken@1933
   920
slouken@1933
   921
void
slouken@1933
   922
Cocoa_RestoreWindow(_THIS, SDL_Window * window)
slouken@1933
   923
{
slouken@6848
   924
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   925
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@1933
   926
slouken@6848
   927
    if ([nswindow isMiniaturized]) {
slouken@6848
   928
        [nswindow deminiaturize:nil];
slouken@6848
   929
    } else if ((window->flags & SDL_WINDOW_RESIZABLE) && [nswindow isZoomed]) {
slouken@6848
   930
        [nswindow zoom:nil];
slouken@1956
   931
    }
slouken@6848
   932
    [pool release];
slouken@1933
   933
}
slouken@1933
   934
slouken@5400
   935
static NSWindow *
slouken@5400
   936
Cocoa_RebuildWindow(SDL_WindowData * data, NSWindow * nswindow, unsigned style)
slouken@5400
   937
{
slouken@5400
   938
    if (!data->created) {
slouken@5400
   939
        /* Don't mess with other people's windows... */
slouken@5400
   940
        return nswindow;
slouken@5400
   941
    }
slouken@5400
   942
slouken@5400
   943
    [data->listener close];
jorgen@7085
   944
    data->nswindow = [[SDLWindow alloc] initWithContentRect:[[nswindow contentView] frame] styleMask:style backing:NSBackingStoreBuffered defer:NO screen:[nswindow screen]];
slouken@5400
   945
    [data->nswindow setContentView:[nswindow contentView]];
jorgen@7085
   946
    /* See comment in SetupWindowData. */
jorgen@7085
   947
    [data->nswindow setOneShot:NO];
slouken@5400
   948
    [data->listener listen:data];
slouken@5400
   949
slouken@5400
   950
    [nswindow close];
slouken@5400
   951
slouken@5400
   952
    return data->nswindow;
slouken@5400
   953
}
slouken@5400
   954
slouken@1933
   955
void
icculus@6422
   956
Cocoa_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
icculus@6422
   957
{
slouken@6848
   958
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   959
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@6848
   960
    if ([nswindow respondsToSelector:@selector(setStyleMask:)]) {
slouken@6848
   961
        [nswindow setStyleMask:GetWindowStyle(window)];
slouken@6848
   962
        if (bordered) {
slouken@7191
   963
            Cocoa_SetWindowTitle(_this, window);  /* this got blanked out. */
icculus@6426
   964
        }
icculus@6422
   965
    }
slouken@6848
   966
    [pool release];
icculus@6422
   967
}
icculus@6422
   968
icculus@6422
   969
void
slouken@5305
   970
Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
slouken@5249
   971
{
slouken@6848
   972
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
   973
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@6848
   974
    NSWindow *nswindow = data->nswindow;
slouken@6848
   975
    NSRect rect;
slouken@5249
   976
slouken@6848
   977
    /* The view responder chain gets messed with during setStyleMask */
slouken@6848
   978
    if ([[nswindow contentView] nextResponder] == data->listener) {
slouken@6848
   979
        [[nswindow contentView] setNextResponder:nil];
slouken@6848
   980
    }
slouken@6848
   981
slouken@6848
   982
    if (fullscreen) {
slouken@6848
   983
        SDL_Rect bounds;
slouken@6848
   984
slouken@6848
   985
        Cocoa_GetDisplayBounds(_this, display, &bounds);
slouken@6848
   986
        rect.origin.x = bounds.x;
slouken@6848
   987
        rect.origin.y = bounds.y;
slouken@6848
   988
        rect.size.width = bounds.w;
slouken@6848
   989
        rect.size.height = bounds.h;
slouken@6848
   990
        ConvertNSRect(&rect);
slouken@6848
   991
slouken@6848
   992
        /* Hack to fix origin on Mac OS X 10.4 */
slouken@6848
   993
        NSRect screenRect = [[nswindow screen] frame];
slouken@6848
   994
        if (screenRect.size.height >= 1.0f) {
slouken@6848
   995
            rect.origin.y += (screenRect.size.height - rect.size.height);
slouken@5401
   996
        }
slouken@5401
   997
slouken@6848
   998
        if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
slouken@6848
   999
            [nswindow performSelector: @selector(setStyleMask:) withObject: (id)NSBorderlessWindowMask];
slouken@6848
  1000
        } else {
slouken@6848
  1001
            nswindow = Cocoa_RebuildWindow(data, nswindow, NSBorderlessWindowMask);
slouken@6848
  1002
        }
slouken@6848
  1003
    } else {
slouken@6848
  1004
        rect.origin.x = window->windowed.x;
slouken@6848
  1005
        rect.origin.y = window->windowed.y;
slouken@6848
  1006
        rect.size.width = window->windowed.w;
slouken@6848
  1007
        rect.size.height = window->windowed.h;
slouken@6848
  1008
        ConvertNSRect(&rect);
alexey@6832
  1009
slouken@6848
  1010
        if ([nswindow respondsToSelector: @selector(setStyleMask:)]) {
slouken@6848
  1011
            [nswindow performSelector: @selector(setStyleMask:) withObject: (id)(uintptr_t)GetWindowStyle(window)];
slouken@5400
  1012
        } else {
slouken@6848
  1013
            nswindow = Cocoa_RebuildWindow(data, nswindow, GetWindowStyle(window));
slouken@5361
  1014
        }
slouken@5398
  1015
    }
slouken@6848
  1016
slouken@6848
  1017
    /* The view responder chain gets messed with during setStyleMask */
slouken@6848
  1018
    if ([[nswindow contentView] nextResponder] != data->listener) {
slouken@6848
  1019
        [[nswindow contentView] setNextResponder:data->listener];
slouken@6848
  1020
    }
slouken@6848
  1021
slouken@6848
  1022
    s_moveHack = 0;
slouken@6848
  1023
    [nswindow setFrameOrigin:rect.origin];
slouken@6848
  1024
    [nswindow setContentSize:rect.size];
slouken@6848
  1025
    s_moveHack = SDL_GetTicks();
slouken@6848
  1026
slouken@6848
  1027
    /* When the window style changes the title is cleared */
slouken@6848
  1028
    if (!fullscreen) {
slouken@6848
  1029
        Cocoa_SetWindowTitle(_this, window);
slouken@6848
  1030
    }
slouken@6848
  1031
slouken@6848
  1032
    if (SDL_ShouldAllowTopmost() && fullscreen) {
slouken@6848
  1033
        /* OpenGL is rendering to the window, so make it visible! */
slouken@6848
  1034
        [nswindow setLevel:CGShieldingWindowLevel()];
slouken@6848
  1035
    } else {
slouken@6848
  1036
        [nswindow setLevel:kCGNormalWindowLevel];
slouken@6848
  1037
    }
jorgen@7087
  1038
jorgen@7087
  1039
    [data->listener pauseVisibleObservation];
slouken@6848
  1040
    [nswindow makeKeyAndOrderFront:nil];
jorgen@7087
  1041
    [data->listener resumeVisibleObservation];
slouken@6848
  1042
jorgen@7594
  1043
    [data->nscontext scheduleUpdate];
slouken@6848
  1044
slouken@6848
  1045
    [pool release];
slouken@5249
  1046
}
slouken@5249
  1047
slouken@5466
  1048
int
slouken@5466
  1049
Cocoa_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
slouken@5466
  1050
{
slouken@5466
  1051
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@5466
  1052
    CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
slouken@5466
  1053
    const uint32_t tableSize = 256;
slouken@5466
  1054
    CGGammaValue redTable[tableSize];
slouken@5466
  1055
    CGGammaValue greenTable[tableSize];
slouken@5466
  1056
    CGGammaValue blueTable[tableSize];
slouken@5466
  1057
    uint32_t i;
slouken@5466
  1058
    float inv65535 = 1.0f / 65535.0f;
slouken@5466
  1059
slouken@5466
  1060
    /* Extract gamma values into separate tables, convert to floats between 0.0 and 1.0 */
slouken@5466
  1061
    for (i = 0; i < 256; i++) {
slouken@5466
  1062
        redTable[i] = ramp[0*256+i] * inv65535;
slouken@5466
  1063
        greenTable[i] = ramp[1*256+i] * inv65535;
slouken@5466
  1064
        blueTable[i] = ramp[2*256+i] * inv65535;
slouken@5466
  1065
    }
slouken@5466
  1066
slouken@5466
  1067
    if (CGSetDisplayTransferByTable(display_id, tableSize,
slouken@5466
  1068
                                    redTable, greenTable, blueTable) != CGDisplayNoErr) {
icculus@7037
  1069
        return SDL_SetError("CGSetDisplayTransferByTable()");
slouken@5466
  1070
    }
slouken@5466
  1071
    return 0;
slouken@5466
  1072
}
slouken@5466
  1073
slouken@5466
  1074
int
slouken@5466
  1075
Cocoa_GetWindowGammaRamp(_THIS, SDL_Window * window, Uint16 * ramp)
slouken@5466
  1076
{
slouken@5466
  1077
    SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
slouken@5466
  1078
    CGDirectDisplayID display_id = ((SDL_DisplayData *)display->driverdata)->display;
slouken@5466
  1079
    const uint32_t tableSize = 256;
slouken@5466
  1080
    CGGammaValue redTable[tableSize];
slouken@5466
  1081
    CGGammaValue greenTable[tableSize];
slouken@5466
  1082
    CGGammaValue blueTable[tableSize];
slouken@5466
  1083
    uint32_t i, tableCopied;
slouken@5466
  1084
slouken@5466
  1085
    if (CGGetDisplayTransferByTable(display_id, tableSize,
slouken@5466
  1086
                                    redTable, greenTable, blueTable, &tableCopied) != CGDisplayNoErr) {
icculus@7037
  1087
        return SDL_SetError("CGGetDisplayTransferByTable()");
slouken@5466
  1088
    }
slouken@5466
  1089
slouken@5466
  1090
    for (i = 0; i < tableCopied; i++) {
slouken@5466
  1091
        ramp[0*256+i] = (Uint16)(redTable[i] * 65535.0f);
slouken@5466
  1092
        ramp[1*256+i] = (Uint16)(greenTable[i] * 65535.0f);
slouken@5466
  1093
        ramp[2*256+i] = (Uint16)(blueTable[i] * 65535.0f);
slouken@5466
  1094
    }
slouken@5466
  1095
    return 0;
slouken@5466
  1096
}
slouken@5466
  1097
slouken@5249
  1098
void
slouken@6662
  1099
Cocoa_SetWindowGrab(_THIS, SDL_Window * window, SDL_bool grabbed)
slouken@1933
  1100
{
slouken@5371
  1101
    /* Move the cursor to the nearest point in the window */
slouken@6662
  1102
    if (grabbed) {
slouken@5371
  1103
        int x, y;
slouken@5371
  1104
        CGPoint cgpoint;
slouken@5371
  1105
slouken@5371
  1106
        SDL_GetMouseState(&x, &y);
slouken@5371
  1107
        cgpoint.x = window->x + x;
slouken@5371
  1108
        cgpoint.y = window->y + y;
slouken@5371
  1109
        CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, cgpoint);
slouken@5371
  1110
    }
slouken@7191
  1111
slouken@6784
  1112
    if ( window->flags & SDL_WINDOW_FULLSCREEN ) {
slouken@7191
  1113
        SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@6755
  1114
slouken@7191
  1115
        if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
slouken@7191
  1116
            /* OpenGL is rendering to the window, so make it visible! */
slouken@7191
  1117
            [data->nswindow setLevel:CGShieldingWindowLevel()];
slouken@7191
  1118
        } else {
slouken@7191
  1119
            [data->nswindow setLevel:kCGNormalWindowLevel];
slouken@7191
  1120
        }
slouken@7191
  1121
    }
slouken@1933
  1122
}
slouken@1933
  1123
slouken@1933
  1124
void
slouken@1933
  1125
Cocoa_DestroyWindow(_THIS, SDL_Window * window)
slouken@1933
  1126
{
slouken@6848
  1127
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
slouken@6848
  1128
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
slouken@1933
  1129
slouken@6848
  1130
    if (data) {
slouken@6848
  1131
        [data->listener close];
slouken@6848
  1132
        [data->listener release];
slouken@6848
  1133
        if (data->created) {
slouken@6848
  1134
            [data->nswindow close];
slouken@1933
  1135
        }
slouken@6848
  1136
        SDL_free(data);
slouken@1933
  1137
    }
slouken@6848
  1138
    [pool release];
slouken@1933
  1139
}
slouken@1933
  1140
slouken@1933
  1141
SDL_bool
slouken@1933
  1142
Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
slouken@1933
  1143
{
slouken@4900
  1144
    NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->nswindow;
slouken@1933
  1145
slouken@1933
  1146
    if (info->version.major <= SDL_MAJOR_VERSION) {
slouken@4900
  1147
        info->subsystem = SDL_SYSWM_COCOA;
slouken@5056
  1148
        info->info.cocoa.window = nswindow;
slouken@1933
  1149
        return SDL_TRUE;
slouken@1933
  1150
    } else {
slouken@1933
  1151
        SDL_SetError("Application not compiled with SDL %d.%d\n",
slouken@1933
  1152
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
slouken@1933
  1153
        return SDL_FALSE;
slouken@1933
  1154
    }
slouken@1933
  1155
}
slouken@1933
  1156
slouken@6044
  1157
#endif /* SDL_VIDEO_DRIVER_COCOA */
slouken@6044
  1158
slouken@1933
  1159
/* vi: set ts=4 sw=4 expandtab: */