src/video/cocoa/SDL_cocoawindow.m
author Sam Lantinga <slouken@libsdl.org>
Sun, 30 Jul 2006 05:18:33 +0000
changeset 1959 25d6537feea4
parent 1958 5fc6fb0fb605
child 1962 c92e5f3e68d9
permissions -rw-r--r--
Implemented Cocoa key event handling.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     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.
     9 
    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.
    14 
    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
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    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"
    29 
    30 #include "SDL_cocoavideo.h"
    31 
    32 static __inline__ void ConvertNSRect(NSRect *r)
    33 {
    34     /* FIXME: Cache the display used for this window */
    35     r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
    36 }
    37 
    38 @implementation Cocoa_WindowListener
    39 
    40 - (void)listen:(SDL_WindowData *)data
    41 {
    42     NSNotificationCenter *center;
    43 
    44     _data = data;
    45 
    46     center = [NSNotificationCenter defaultCenter];
    47 
    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];
    57     } else {
    58         [_data->window setDelegate:self];
    59     }
    60     [center addObserver:self selector:@selector(windowDidHide:) name:NSApplicationDidHideNotification object:NSApp];
    61     [center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
    62 
    63     [_data->window setAcceptsMouseMovedEvents:YES];
    64 }
    65 
    66 - (void)close
    67 {
    68     NSNotificationCenter *center;
    69 
    70     center = [NSNotificationCenter defaultCenter];
    71 
    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];
    81     } else {
    82         [_data->window setDelegate:nil];
    83     }
    84     [center removeObserver:self name:NSApplicationDidHideNotification object:NSApp];
    85     [center removeObserver:self name:NSApplicationDidUnhideNotification object:NSApp];
    86 }
    87 
    88 - (BOOL)windowShouldClose:(id)sender
    89 {
    90     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_CLOSE, 0, 0);
    91     return NO;
    92 }
    93 
    94 - (void)windowDidExpose:(NSNotification *)aNotification
    95 {
    96     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_EXPOSED, 0, 0);
    97 }
    98 
    99 - (void)windowDidMove:(NSNotification *)aNotification
   100 {
   101     int x, y;
   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);
   107 }
   108 
   109 - (void)windowDidResize:(NSNotification *)aNotification
   110 {
   111     int w, h;
   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);
   116 }
   117 
   118 - (void)windowDidMiniaturize:(NSNotification *)aNotification
   119 {
   120     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
   121 }
   122 
   123 - (void)windowDidDeminiaturize:(NSNotification *)aNotification
   124 {
   125     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_RESTORED, 0, 0);
   126 }
   127 
   128 - (void)windowDidBecomeKey:(NSNotification *)aNotification
   129 {
   130     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
   131 }
   132 
   133 - (void)windowDidResignKey:(NSNotification *)aNotification
   134 {
   135     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
   136 }
   137 
   138 - (void)windowDidHide:(NSNotification *)aNotification
   139 {
   140     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_HIDDEN, 0, 0);
   141 }
   142 
   143 - (void)windowDidUnhide:(NSNotification *)aNotification
   144 {
   145     SDL_SendWindowEvent(_data->windowID, SDL_WINDOWEVENT_SHOWN, 0, 0);
   146 }
   147 
   148 - (void)mouseDown:(NSEvent *)theEvent
   149 {
   150     int index;
   151     int button;
   152 
   153     index = _data->videodata->mouse;
   154     switch ([theEvent buttonNumber]) {
   155     case 0:
   156         button = SDL_BUTTON_LEFT;
   157         break;
   158     case 1:
   159         button = SDL_BUTTON_RIGHT;
   160         break;
   161     case 2:
   162         button = SDL_BUTTON_MIDDLE;
   163         break;
   164     default:
   165         button = [theEvent buttonNumber];
   166         break;
   167     }
   168     SDL_SendMouseButton(index, SDL_PRESSED, button);
   169 }
   170 
   171 - (void)rightMouseDown:(NSEvent *)theEvent
   172 {
   173     [self mouseDown:theEvent];
   174 }
   175 
   176 - (void)otherMouseDown:(NSEvent *)theEvent
   177 {
   178     [self mouseDown:theEvent];
   179 }
   180 
   181 - (void)mouseUp:(NSEvent *)theEvent
   182 {
   183     int index;
   184     int button;
   185 
   186     index = _data->videodata->mouse;
   187     switch ([theEvent buttonNumber]) {
   188     case 0:
   189         button = SDL_BUTTON_LEFT;
   190         break;
   191     case 1:
   192         button = SDL_BUTTON_RIGHT;
   193         break;
   194     case 2:
   195         button = SDL_BUTTON_MIDDLE;
   196         break;
   197     default:
   198         button = [theEvent buttonNumber];
   199         break;
   200     }
   201     SDL_SendMouseButton(index, SDL_RELEASED, button);
   202 }
   203 
   204 - (void)rightMouseUp:(NSEvent *)theEvent
   205 {
   206     [self mouseUp:theEvent];
   207 }
   208 
   209 - (void)otherMouseUp:(NSEvent *)theEvent
   210 {
   211     [self mouseUp:theEvent];
   212 }
   213 
   214 - (void)mouseMoved:(NSEvent *)theEvent
   215 {
   216     SDL_Window *window = SDL_GetWindowFromID(_data->windowID);
   217     int index;
   218     SDL_Mouse *mouse;
   219     NSPoint point;
   220     NSRect rect = [_data->window contentRectForFrameRect:[_data->window frame]];
   221 
   222     index = _data->videodata->mouse;
   223     mouse = SDL_GetMouse(index);
   224     if (mouse->focus != _data->windowID) {
   225         SDL_SetMouseFocus(index, _data->windowID);
   226     }
   227 
   228     point = [NSEvent mouseLocation];
   229     point.x = point.x - rect.origin.x;
   230     point.y = rect.size.height - (point.y - rect.origin.y);
   231     SDL_SendMouseMotion(index, 0, (int)point.x, (int)point.y);
   232 }
   233 
   234 - (void)mouseDragged:(NSEvent *)theEvent
   235 {
   236     [self mouseMoved:theEvent];
   237 }
   238 
   239 - (void)rightMouseDragged:(NSEvent *)theEvent
   240 {
   241     [self mouseMoved:theEvent];
   242 }
   243 
   244 - (void)otherMouseDragged:(NSEvent *)theEvent
   245 {
   246     [self mouseMoved:theEvent];
   247 }
   248 
   249 - (void)scrollWheel:(NSEvent *)theEvent
   250 {
   251     int index;
   252 
   253     index = _data->videodata->mouse;
   254     SDL_SendMouseWheel(index, (int)([theEvent deltaY]+0.9f));
   255 }
   256 
   257 - (void)keyDown:(NSEvent *)theEvent
   258 {
   259     int index;
   260 
   261     index = _data->videodata->keyboard;
   262 fprintf(stderr, "keyDown\n");
   263     const char *text = [[theEvent characters] UTF8String];
   264     if(text && *text) {
   265         SDL_SendKeyboardText(index, text);
   266     }
   267 }
   268 
   269 - (void)keyUp:(NSEvent *)theEvent
   270 {
   271     int index;
   272 
   273     index = _data->videodata->keyboard;
   274 fprintf(stderr, "keyUp\n");
   275 }
   276 
   277 @end
   278 
   279 static int
   280 SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
   281 {
   282     NSAutoreleasePool *pool;
   283     SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
   284     SDL_WindowData *data;
   285 
   286     /* Allocate the window data */
   287     data = (SDL_WindowData *) SDL_malloc(sizeof(*data));
   288     if (!data) {
   289         SDL_OutOfMemory();
   290         return -1;
   291     }
   292     data->windowID = window->id;
   293     data->window = nswindow;
   294     data->created = created;
   295     data->videodata = videodata;
   296 
   297     pool = [[NSAutoreleasePool alloc] init];
   298 
   299     /* Create an event listener for the window */
   300     data->listener = [[Cocoa_WindowListener alloc] init];
   301     [data->listener listen:data];
   302 
   303     /* Fill in the SDL window with the window data */
   304     {
   305         NSRect rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   306         ConvertNSRect(&rect);
   307         window->x = (int)rect.origin.x;
   308         window->y = (int)rect.origin.y;
   309         window->w = (int)rect.size.width;
   310         window->h = (int)rect.size.height;
   311     }
   312     if ([nswindow isVisible]) {
   313         window->flags |= SDL_WINDOW_SHOWN;
   314     } else {
   315         window->flags &= ~SDL_WINDOW_SHOWN;
   316     }
   317     {
   318         unsigned int style = [nswindow styleMask];
   319 
   320         if ((style & ~NSResizableWindowMask) == NSBorderlessWindowMask) {
   321             window->flags |= SDL_WINDOW_BORDERLESS;
   322         } else {
   323             window->flags &= ~SDL_WINDOW_BORDERLESS;
   324         }
   325         if (style & NSResizableWindowMask) {
   326             window->flags |= SDL_WINDOW_RESIZABLE;
   327         } else {
   328             window->flags &= ~SDL_WINDOW_RESIZABLE;
   329         }
   330     }
   331     if ([nswindow isZoomed]) {
   332         window->flags |= SDL_WINDOW_MAXIMIZED;
   333     } else {
   334         window->flags &= ~SDL_WINDOW_MAXIMIZED;
   335     }
   336     if ([nswindow isMiniaturized]) {
   337         window->flags |= SDL_WINDOW_MINIMIZED;
   338     } else {
   339         window->flags &= ~SDL_WINDOW_MINIMIZED;
   340     }
   341     if ([nswindow isKeyWindow]) {
   342         int index = data->videodata->keyboard;
   343         window->flags |= SDL_WINDOW_INPUT_FOCUS;
   344         SDL_SetKeyboardFocus(index, data->windowID);
   345 
   346         if (window->flags & SDL_WINDOW_INPUT_GRABBED) {
   347             /* FIXME */
   348         }
   349     }
   350 
   351     /* All done! */
   352     [pool release];
   353     window->driverdata = data;
   354     return 0;
   355 }
   356 
   357 int
   358 Cocoa_CreateWindow(_THIS, SDL_Window * window)
   359 {
   360     NSAutoreleasePool *pool;
   361     NSWindow *nswindow;
   362     NSRect rect;
   363     unsigned int style;
   364     NSString *title;
   365     int status;
   366 
   367     pool = [[NSAutoreleasePool alloc] init];
   368 
   369     if (window->x == SDL_WINDOWPOS_CENTERED) {
   370         rect.origin.x = (CGDisplayPixelsWide(kCGDirectMainDisplay) - window->w) / 2;
   371     } else if (window->x == SDL_WINDOWPOS_UNDEFINED) {
   372         rect.origin.x = 0;
   373     } else {
   374         rect.origin.x = window->x;
   375     }
   376     if (window->y == SDL_WINDOWPOS_CENTERED) {
   377         rect.origin.y = (CGDisplayPixelsHigh(kCGDirectMainDisplay) - window->h) / 2;
   378     } else if (window->y == SDL_WINDOWPOS_UNDEFINED) {
   379         rect.origin.y = 0;
   380     } else {
   381         rect.origin.y = window->y;
   382     }
   383     rect.size.width = window->w;
   384     rect.size.height = window->h;
   385     ConvertNSRect(&rect);
   386 
   387     if (window->flags & SDL_WINDOW_BORDERLESS) {
   388         style = NSBorderlessWindowMask;
   389     } else {
   390         style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
   391     }
   392     if (window->flags & SDL_WINDOW_RESIZABLE) {
   393         style |= NSResizableWindowMask;
   394     }
   395 
   396     nswindow = [[NSWindow alloc] initWithContentRect:rect styleMask:style backing:NSBackingStoreBuffered defer:FALSE];
   397 
   398     [pool release];
   399 
   400     if (SetupWindowData(_this, window, nswindow, SDL_TRUE) < 0) {
   401         [nswindow release];
   402         return -1;
   403     }
   404 #ifdef SDL_VIDEO_OPENGL_CGL
   405     if (window->flags & SDL_WINDOW_OPENGL) {
   406         if (Cocoa_GL_SetupWindow(_this, window) < 0) {
   407             Cocoa_DestroyWindow(_this, window);
   408             return -1;
   409         }
   410     }
   411 #endif
   412     return 0;
   413 }
   414 
   415 int
   416 Cocoa_CreateWindowFrom(_THIS, SDL_Window * window, const void *data)
   417 {
   418     NSAutoreleasePool *pool;
   419     NSWindow *nswindow = (NSWindow *) data;
   420     NSString *title;
   421     int status;
   422 
   423     pool = [[NSAutoreleasePool alloc] init];
   424 
   425     /* Query the title from the existing window */
   426     title = [nswindow title];
   427     if (title) {
   428         window->title = SDL_strdup([title UTF8String]);
   429     }
   430 
   431     [pool release];
   432 
   433     return SetupWindowData(_this, window, nswindow, SDL_FALSE);
   434 }
   435 
   436 void
   437 Cocoa_SetWindowTitle(_THIS, SDL_Window * window)
   438 {
   439     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   440     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   441     NSString *string;
   442 
   443     if(window->title) {
   444         string = [[NSString alloc] initWithUTF8String:window->title];
   445     } else {
   446         string = [[NSString alloc] init];
   447     }
   448     [nswindow setTitle:string];
   449     [string release];
   450 
   451     [pool release];
   452 }
   453 
   454 void
   455 Cocoa_SetWindowPosition(_THIS, SDL_Window * window)
   456 {
   457     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   458     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   459     NSRect rect;
   460 
   461     rect.origin.x = window->x;
   462     rect.origin.y = window->y;
   463     rect.size.width = window->w;
   464     rect.size.height = window->h;
   465     ConvertNSRect(&rect);
   466     rect = [nswindow frameRectForContentRect:rect];
   467     [nswindow setFrameOrigin:rect.origin];
   468     [pool release];
   469 }
   470 
   471 void
   472 Cocoa_SetWindowSize(_THIS, SDL_Window * window)
   473 {
   474     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   475     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   476     NSSize size;
   477 
   478     size.width = window->w;
   479     size.height = window->h;
   480     [nswindow setContentSize:size];
   481     [pool release];
   482 }
   483 
   484 void
   485 Cocoa_ShowWindow(_THIS, SDL_Window * window)
   486 {
   487     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   488     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   489 
   490     if (![nswindow isMiniaturized]) {
   491         [nswindow makeKeyAndOrderFront:nil];
   492     }
   493     [pool release];
   494 }
   495 
   496 void
   497 Cocoa_HideWindow(_THIS, SDL_Window * window)
   498 {
   499     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   500     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   501 
   502     [nswindow orderOut:nil];
   503     [pool release];
   504 }
   505 
   506 void
   507 Cocoa_RaiseWindow(_THIS, SDL_Window * window)
   508 {
   509     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   510     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   511 
   512     [nswindow makeKeyAndOrderFront:nil];
   513     [pool release];
   514 }
   515 
   516 void
   517 Cocoa_MaximizeWindow(_THIS, SDL_Window * window)
   518 {
   519     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   520     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   521 
   522     [nswindow zoom:nil];
   523     [pool release];
   524 }
   525 
   526 void
   527 Cocoa_MinimizeWindow(_THIS, SDL_Window * window)
   528 {
   529     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   530     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   531 
   532     [nswindow miniaturize:nil];
   533     [pool release];
   534 }
   535 
   536 void
   537 Cocoa_RestoreWindow(_THIS, SDL_Window * window)
   538 {
   539     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   540     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   541 
   542     if ([nswindow isMiniaturized]) {
   543         [nswindow deminiaturize:nil];
   544     } else if ([nswindow isZoomed]) {
   545         [nswindow zoom:nil];
   546     }
   547     [pool release];
   548 }
   549 
   550 void
   551 Cocoa_SetWindowGrab(_THIS, SDL_Window * window)
   552 {
   553     if ((window->flags & SDL_WINDOW_INPUT_GRABBED) &&
   554         (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
   555         /* FIXME: Grab mouse */
   556     } else {
   557         /* FIXME: Release mouse */
   558     }
   559 }
   560 
   561 void
   562 Cocoa_DestroyWindow(_THIS, SDL_Window * window)
   563 {
   564     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   565     SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   566 
   567     if (data) {
   568 #ifdef SDL_VIDEO_OPENGL_CGL
   569         if (window->flags & SDL_WINDOW_OPENGL) {
   570             Cocoa_GL_CleanupWindow(_this, window);
   571         }
   572 #endif
   573         [data->listener close];
   574         [data->listener release];
   575         if (data->created) {
   576             [data->window close];
   577         }
   578         SDL_free(data);
   579     }
   580     [pool release];
   581 }
   582 
   583 SDL_bool
   584 Cocoa_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   585 {
   586     NSWindow *nswindow = ((SDL_WindowData *) window->driverdata)->window;
   587 
   588     if (info->version.major <= SDL_MAJOR_VERSION) {
   589         //info->window = nswindow;
   590         return SDL_TRUE;
   591     } else {
   592         SDL_SetError("Application not compiled with SDL %d.%d\n",
   593                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   594         return SDL_FALSE;
   595     }
   596 }
   597 
   598 /* vi: set ts=4 sw=4 expandtab: */