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