2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2006 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "SDL_config.h"
24 #include "SDL_syswm.h"
25 #include "../SDL_sysvideo.h"
26 #include "../../events/SDL_keyboard_c.h"
27 #include "../../events/SDL_mouse_c.h"
28 #include "../../events/SDL_windowevents_c.h"
30 #include "SDL_cocoavideo.h"
32 static __inline__ void ConvertNSRect(NSRect *r)
34 /* FIXME: Cache the display used for this window */
35 r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
38 @implementation Cocoa_WindowListener
40 - (void)listen:(SDL_WindowData *)data
42 NSNotificationCenter *center;
46 center = [NSNotificationCenter defaultCenter];
48 [_data->window setNextResponder:self];
49 if ([_data->window delegate] != nil) {
50 [center addObserver:self selector:@selector(windowDisExpose:) name:NSWindowDidExposeNotification object:_data->window];
51 [center addObserver:self selector:@selector(windowDidMove:) name:NSWindowDidMoveNotification object:_data->window];
52 [center addObserver:self selector:@selector(windowDidResize:) name:NSWindowDidResizeNotification object:_data->window];
53 [center addObserver:self selector:@selector(windowDidMiniaturize:) name:NSWindowDidMiniaturizeNotification object:_data->window];
54 [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:_data->window];
55 [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:_data->window];
56 [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:_data->window];
58 [_data->window setDelegate:self];
60 [center addObserver:self selector:@selector(windowDidHide:) name:NSApplicationDidHideNotification object:NSApp];
61 [center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
63 [_data->window setAcceptsMouseMovedEvents:YES];
68 NSNotificationCenter *center;
70 center = [NSNotificationCenter defaultCenter];
72 [_data->window setNextResponder:nil];
73 if ([_data->window delegate] != self) {
74 [center removeObserver:self name:NSWindowDidExposeNotification object:_data->window];
75 [center removeObserver:self name:NSWindowDidMoveNotification object:_data->window];
76 [center removeObserver:self name:NSWindowDidResizeNotification object:_data->window];
77 [center removeObserver:self name:NSWindowDidMiniaturizeNotification object:_data->window];
78 [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:_data->window];
79 [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:_data->window];
80 [center removeObserver:self name:NSWindowDidResignKeyNotification object:_data->window];
82 [_data->window setDelegate:nil];
84 [center removeObserver:self name:NSApplicationDidHideNotification object:NSApp];
85 [center removeObserver:self name:NSApplicationDidUnhideNotification object:NSApp];
88 - (BOOL)windowShouldClose:(id)sender
90 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_CLOSE, 0, 0);
94 - (void)windowDidExpose:(NSNotification *)aNotification
96 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_EXPOSED, 0, 0);
99 - (void)windowDidMove:(NSNotification *)aNotification
102 NSRect rect = [_data->window contentRectForFrameRect:[_data->window frame]];
103 ConvertNSRect(&rect);
104 x = (int)rect.origin.x;
105 y = (int)rect.origin.y;
106 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_MOVED, x, y);
109 - (void)windowDidResize:(NSNotification *)aNotification
112 NSRect rect = [_data->window contentRectForFrameRect:[_data->window frame]];
113 w = (int)rect.size.width;
114 h = (int)rect.size.height;
115 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_RESIZED, w, h);
118 - (void)windowDidMiniaturize:(NSNotification *)aNotification
120 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
123 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
125 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_RESTORED, 0, 0);
128 - (void)windowDidBecomeKey:(NSNotification *)aNotification
132 index = _data->videodata->keyboard;
133 SDL_SetKeyboardFocus(index, _data->windowID);
136 - (void)windowDidResignKey:(NSNotification *)aNotification
140 index = _data->videodata->keyboard;
141 SDL_SetKeyboardFocus(index, 0);
144 - (void)windowDidHide:(NSNotification *)aNotification
146 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
149 - (void)windowDidUnhide:(NSNotification *)aNotification
151 SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
154 - (void)mouseDown:(NSEvent *)theEvent
159 index = _data->videodata->mouse;
160 switch ([theEvent buttonNumber]) {
162 button = SDL_BUTTON_LEFT;
165 button = SDL_BUTTON_RIGHT;
168 button = SDL_BUTTON_MIDDLE;
171 button = [theEvent buttonNumber];
174 SDL_SendMouseButton(index, SDL_PRESSED, button);
177 - (void)rightMouseDown:(NSEvent *)theEvent
179 [self mouseDown:theEvent];
182 - (void)otherMouseDown:(NSEvent *)theEvent
184 [self mouseDown:theEvent];
187 - (void)mouseUp:(NSEvent *)theEvent
192 index = _data->videodata->mouse;
193 switch ([theEvent buttonNumber]) {
195 button = SDL_BUTTON_LEFT;
198 button = SDL_BUTTON_RIGHT;
201 button = SDL_BUTTON_MIDDLE;
204 button = [theEvent buttonNumber];
207 SDL_SendMouseButton(index, SDL_RELEASED, button);
210 - (void)rightMouseUp:(NSEvent *)theEvent
212 [self mouseUp:theEvent];
215 - (void)otherMouseUp:(NSEvent *)theEvent
217 [self mouseUp:theEvent];
220 - (void)mouseMoved:(NSEvent *)theEvent
222 SDL_Window *window = SDL_GetWindowFromID(_data->windowID);
226 NSRect rect = [_data->window contentRectForFrameRect:[_data->window frame]];
228 index = _data->videodata->mouse;
229 mouse = SDL_GetMouse(index);
230 if (mouse->focus != _data->windowID) {
231 SDL_SetMouseFocus(index, _data->windowID);
234 point = [NSEvent mouseLocation];
235 point.x = point.x - rect.origin.x;
236 point.y = rect.size.height - (point.y - rect.origin.y);
237 SDL_SendMouseMotion(index, 0, (int)point.x, (int)point.y);
240 - (void)mouseDragged:(NSEvent *)theEvent
242 [self mouseMoved:theEvent];
245 - (void)rightMouseDragged:(NSEvent *)theEvent
247 [self mouseMoved:theEvent];
250 - (void)otherMouseDragged:(NSEvent *)theEvent
252 [self mouseMoved:theEvent];
255 - (void)scrollWheel:(NSEvent *)theEvent
259 index = _data->videodata->mouse;
260 SDL_SendMouseWheel(index, (int)([theEvent deltaY]+0.9f));
266 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
268 NSAutoreleasePool *pool;
269 SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
270 SDL_WindowData *data;
272 /* Allocate the window data */
273 data = (SDL_WindowData *) SDL_malloc(sizeof(*data));
278 data->windowID = window->id;
279 data->window = nswindow;
280 data->created = created;
281 data->videodata = videodata;
283 pool = [[NSAutoreleasePool alloc] init];
285 /* Create an event listener for the window */
286 data->listener = [[Cocoa_WindowListener alloc] init];
287 [data->listener listen:data];
289 /* Fill in the SDL window with the window data */
291 NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
292 ConvertNSRect(&rect);
293 window->x = (int)rect.origin.x;
294 window->y = (int)rect.origin.y;
295 window->w = (int)rect.size.width;
296 window->h = (int)rect.size.height;
298 if ([nswindow isVisible]) {
299 window->flags |= SDL_WINDOW_SHOWN;
301 window->flags &= ~SDL_WINDOW_SHOWN;
304 unsigned int style = [nswindow styleMask];
306 if ((style & ~NSResizableWindowMask) == NSBorderlessWindowMask) {
307 window->flags |= SDL_WINDOW_BORDERLESS;
309 window->flags &= ~SDL_WINDOW_BORDERLESS;
311 if (style & NSResizableWindowMask) {
312 window->flags |= SDL_WINDOW_RESIZABLE;
314 window->flags &= ~SDL_WINDOW_RESIZABLE;
317 if ([nswindow isZoomed]) {
318 window->flags |= SDL_WINDOW_MAXIMIZED;
320 window->flags &= ~SDL_WINDOW_MAXIMIZED;
322 if ([nswindow isMiniaturized]) {
323 window->flags |= SDL_WINDOW_MINIMIZED;
325 window->flags &= ~SDL_WINDOW_MINIMIZED;
327 if ([nswindow isKeyWindow]) {
328 int index = data->videodata->keyboard;
329 window->flags |= SDL_WINDOW_INPUT_FOCUS;
330 SDL_SetKeyboardFocus(index, data->windowID);
332 if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
339 window->driverdata = data;
344 Cocoa_CreateWindow(_THIS, SDL_Window * window)
346 NSAutoreleasePool *pool;
353 pool = [[NSAutoreleasePool alloc] init];
355 if (window->x == SDL_WINDOWPOS_CENTERED) {
356 rect.origin.x = (CGDisplayPixelsWide(kCGDirectMainDisplay) - window->w) / 2;
357 } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
360 rect.origin.x = window->x;
362 if (window->y == SDL_WINDOWPOS_CENTERED) {
363 rect.origin.y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - window->h) / 2;
364 } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
367 rect.origin.y = window->y;
369 rect.size.width = window->w;
370 rect.size.height = window->h;
371 ConvertNSRect(&rect);
373 if (window->flags & SDL_WINDOW_BORDERLESS) {
374 style = NSBorderlessWindowMask;
376 style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
378 if (window->flags & SDL_WINDOW_RESIZABLE) {
379 style |= NSResizableWindowMask;
382 nswindow = [[NSWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:FALSE];
386 if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
390 #ifdef SDL_VIDEO_OPENGL_CGL
391 if (window->flags & SDL_WINDOW_OPENGL) {
392 if (Cocoa_GL_SetupWindow(_this, window) < 0) {
393 Cocoa_DestroyWindow(_this, window);
402 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
404 NSAutoreleasePool *pool;
405 NSWindow *nswindow = (NSWindow *) data;
409 pool = [[NSAutoreleasePool alloc] init];
411 /* Query the title from the existing window */
412 title = [nswindow title];
414 window->title = SDL_strdup([title UTF8String]);
419 return SetupWindowData(_this, window, nswindow, SDL_FALSE);
423 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
425 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
426 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
430 string = [[NSString alloc] initWithUTF8String:window->title];
432 string = [[NSString alloc] init];
434 [nswindow setTitle:string];
441 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
443 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
444 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
447 rect.origin.x = window->x;
448 rect.origin.y = window->y;
449 rect.size.width = window->w;
450 rect.size.height = window->h;
451 ConvertNSRect(&rect);
452 rect = [nswindow frameRectForContentRect:rect];
453 [nswindow setFrameOrigin:rect.origin];
458 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
460 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
461 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
464 size.width = window->w;
465 size.height = window->h;
466 [nswindow setContentSize:size];
471 Cocoa_ShowWindow(_THIS, SDL_Window * window)
473 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
474 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
476 if (![nswindow isMiniaturized]) {
477 [nswindow makeKeyAndOrderFront:nil];
483 Cocoa_HideWindow(_THIS, SDL_Window * window)
485 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
486 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
488 [nswindow orderOut:nil];
493 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
495 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
496 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
498 [nswindow makeKeyAndOrderFront:nil];
503 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
505 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
506 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
513 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
515 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
516 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
518 [nswindow miniaturize:nil];
523 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
525 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
526 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
528 if ([nswindow isMiniaturized]) {
529 [nswindow deminiaturize:nil];
530 } else if ([nswindow isZoomed]) {
537 Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
539 if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
540 (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
541 /* FIXME: Grab mouse */
543 /* FIXME: Release mouse */
548 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
550 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
551 SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
554 #ifdef SDL_VIDEO_OPENGL_CGL
555 if (window->flags & SDL_WINDOW_OPENGL) {
556 Cocoa_GL_CleanupWindow(_this, window);
559 [data->listener close];
560 [data->listener release];
562 [data->window close];
570 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
572 NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
574 if (info->version.major <= SDL_MAJOR_VERSION) {
575 //info->window = nswindow;
578 SDL_SetError("Application not compiled with SDL %d.%d\n",
579 SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
584 /* vi: set ts=4 sw=4 expandtab: */