Added support for new style fullscreen transitions on Mac OS X
authorSam Lantinga <slouken@libsdl.org>
Mon, 11 Nov 2013 02:53:00 -0800
changeset 79525ac1a895b313
parent 7951 4427e43f4e1b
child 7953 255ca6c77e58
Added support for new style fullscreen transitions on Mac OS X
src/video/cocoa/SDL_cocoaevents.m
src/video/cocoa/SDL_cocoawindow.h
src/video/cocoa/SDL_cocoawindow.m
     1.1 --- a/src/video/cocoa/SDL_cocoaevents.m	Mon Nov 11 02:00:58 2013 -0800
     1.2 +++ b/src/video/cocoa/SDL_cocoaevents.m	Mon Nov 11 02:53:00 2013 -0800
     1.3 @@ -147,6 +147,7 @@
     1.4      NSMenu *appleMenu;
     1.5      NSMenu *serviceMenu;
     1.6      NSMenu *windowMenu;
     1.7 +    NSMenu *viewMenu;
     1.8      NSMenuItem *menuItem;
     1.9  
    1.10      if (NSApp == nil) {
    1.11 @@ -220,6 +221,25 @@
    1.12      /* Tell the application object that this is now the window menu */
    1.13      [NSApp setWindowsMenu:windowMenu];
    1.14      [windowMenu release];
    1.15 +
    1.16 +
    1.17 +    /* Add the fullscreen view toggle menu option, if supported */
    1.18 +    if ([NSApp respondsToSelector:@selector(setPresentationOptions:)]) {
    1.19 +        /* Create the view menu */
    1.20 +        viewMenu = [[NSMenu alloc] initWithTitle:@"View"];
    1.21 +
    1.22 +        /* Add menu items */
    1.23 +        menuItem = [viewMenu addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
    1.24 +        [menuItem setKeyEquivalentModifierMask:NSControlKeyMask | NSCommandKeyMask];
    1.25 +
    1.26 +        /* Put menu into the menubar */
    1.27 +        menuItem = [[NSMenuItem alloc] initWithTitle:@"View" action:nil keyEquivalent:@""];
    1.28 +        [menuItem setSubmenu:viewMenu];
    1.29 +        [[NSApp mainMenu] addItem:menuItem];
    1.30 +        [menuItem release];
    1.31 +
    1.32 +        [viewMenu release];
    1.33 +    }
    1.34  }
    1.35  
    1.36  void
     2.1 --- a/src/video/cocoa/SDL_cocoawindow.h	Mon Nov 11 02:00:58 2013 -0800
     2.2 +++ b/src/video/cocoa/SDL_cocoawindow.h	Mon Nov 11 02:53:00 2013 -0800
     2.3 @@ -32,11 +32,14 @@
     2.4      BOOL observingVisible;
     2.5      BOOL wasCtrlLeft;
     2.6      BOOL wasVisible;
     2.7 +    BOOL isFullscreen;
     2.8 +    BOOL inFullscreenTransition;
     2.9  }
    2.10  
    2.11  -(void) listen:(SDL_WindowData *) data;
    2.12  -(void) pauseVisibleObservation;
    2.13  -(void) resumeVisibleObservation;
    2.14 +-(BOOL) isToggledFullscreen;
    2.15  -(void) close;
    2.16  
    2.17  /* Window delegate functionality */
    2.18 @@ -48,6 +51,10 @@
    2.19  -(void) windowDidDeminiaturize:(NSNotification *) aNotification;
    2.20  -(void) windowDidBecomeKey:(NSNotification *) aNotification;
    2.21  -(void) windowDidResignKey:(NSNotification *) aNotification;
    2.22 +-(void) windowWillEnterFullScreen:(NSNotification *) aNotification;
    2.23 +-(void) windowDidEnterFullScreen:(NSNotification *) aNotification;
    2.24 +-(void) windowWillExitFullScreen:(NSNotification *) aNotification;
    2.25 +-(void) windowDidExitFullScreen:(NSNotification *) aNotification;
    2.26  
    2.27  /* Window event handling */
    2.28  -(void) mouseDown:(NSEvent *) theEvent;
     3.1 --- a/src/video/cocoa/SDL_cocoawindow.m	Mon Nov 11 02:00:58 2013 -0800
     3.2 +++ b/src/video/cocoa/SDL_cocoawindow.m	Mon Nov 11 02:53:00 2013 -0800
     3.3 @@ -50,7 +50,8 @@
     3.4      r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - r->origin.y - r->size.height;
     3.5  }
     3.6  
     3.7 -static void ScheduleContextUpdates(SDL_WindowData *data)
     3.8 +static void
     3.9 +ScheduleContextUpdates(SDL_WindowData *data)
    3.10  {
    3.11      NSMutableArray *contexts = data->nscontexts;
    3.12      @synchronized (contexts) {
    3.13 @@ -60,12 +61,34 @@
    3.14      }
    3.15  }
    3.16  
    3.17 -static int GetHintCtrlClickEmulateRightClick()
    3.18 +static int
    3.19 +GetHintCtrlClickEmulateRightClick()
    3.20  {
    3.21  	const char *hint = SDL_GetHint( SDL_HINT_MAC_CTRL_CLICK_EMULATE_RIGHT_CLICK );
    3.22  	return hint != NULL && *hint != '0';
    3.23  }
    3.24  
    3.25 +static unsigned int
    3.26 +GetWindowStyle(SDL_Window * window)
    3.27 +{
    3.28 +    unsigned int style;
    3.29 +
    3.30 +    if (window->flags & SDL_WINDOW_FULLSCREEN) {
    3.31 +        style = NSBorderlessWindowMask;
    3.32 +    } else {
    3.33 +        if (window->flags & SDL_WINDOW_BORDERLESS) {
    3.34 +            style = NSBorderlessWindowMask;
    3.35 +        } else {
    3.36 +            style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
    3.37 +        }
    3.38 +        if (window->flags & SDL_WINDOW_RESIZABLE) {
    3.39 +            style |= NSResizableWindowMask;
    3.40 +        }
    3.41 +    }
    3.42 +    return style;
    3.43 +}
    3.44 +
    3.45 +
    3.46  @implementation Cocoa_WindowListener
    3.47  
    3.48  - (void)listen:(SDL_WindowData *)data
    3.49 @@ -78,6 +101,8 @@
    3.50      observingVisible = YES;
    3.51      wasCtrlLeft = NO;
    3.52      wasVisible = [window isVisible];
    3.53 +    isFullscreen = NO;
    3.54 +    inFullscreenTransition = NO;
    3.55  
    3.56      center = [NSNotificationCenter defaultCenter];
    3.57  
    3.58 @@ -89,6 +114,10 @@
    3.59          [center addObserver:self selector:@selector(windowDidDeminiaturize:) name:NSWindowDidDeminiaturizeNotification object:window];
    3.60          [center addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:window];
    3.61          [center addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:window];
    3.62 +        [center addObserver:self selector:@selector(windowWillEnterFullScreen:) name:NSWindowWillEnterFullScreenNotification object:window];
    3.63 +        [center addObserver:self selector:@selector(windowDidEnterFullScreen:) name:NSWindowDidEnterFullScreenNotification object:window];
    3.64 +        [center addObserver:self selector:@selector(windowWillExitFullScreen:) name:NSWindowWillExitFullScreenNotification object:window];
    3.65 +        [center addObserver:self selector:@selector(windowDidExitFullScreen:) name:NSWindowDidExitFullScreenNotification object:window];
    3.66      } else {
    3.67          [window setDelegate:self];
    3.68      }
    3.69 @@ -152,6 +181,11 @@
    3.70      }
    3.71  }
    3.72  
    3.73 +- (BOOL) isToggledFullscreen
    3.74 +{
    3.75 +    return isFullscreen;
    3.76 +}
    3.77 +
    3.78  - (void)close
    3.79  {
    3.80      NSNotificationCenter *center;
    3.81 @@ -169,6 +203,10 @@
    3.82          [center removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
    3.83          [center removeObserver:self name:NSWindowDidBecomeKeyNotification object:window];
    3.84          [center removeObserver:self name:NSWindowDidResignKeyNotification object:window];
    3.85 +        [center removeObserver:self name:NSWindowWillEnterFullScreenNotification object:window];
    3.86 +        [center removeObserver:self name:NSWindowDidEnterFullScreenNotification object:window];
    3.87 +        [center removeObserver:self name:NSWindowWillExitFullScreenNotification object:window];
    3.88 +        [center removeObserver:self name:NSWindowDidExitFullScreenNotification object:window];
    3.89      } else {
    3.90          [window setDelegate:nil];
    3.91      }
    3.92 @@ -250,8 +288,15 @@
    3.93      y = (int)rect.origin.y;
    3.94      w = (int)rect.size.width;
    3.95      h = (int)rect.size.height;
    3.96 -    if (SDL_IsShapedWindow(_data->window))
    3.97 +
    3.98 +    if (inFullscreenTransition) {
    3.99 +        /* We'll take care of this at the end of the transition */
   3.100 +        return;
   3.101 +    }
   3.102 +
   3.103 +    if (SDL_IsShapedWindow(_data->window)) {
   3.104          Cocoa_ResizeWindowShape(_data->window);
   3.105 +    }
   3.106  
   3.107      ScheduleContextUpdates(_data);
   3.108  
   3.109 @@ -317,6 +362,46 @@
   3.110      }
   3.111  }
   3.112  
   3.113 +- (void)windowWillEnterFullScreen:(NSNotification *)aNotification
   3.114 +{
   3.115 +    SDL_Window *window = _data->window;
   3.116 +    NSWindow *nswindow = _data->nswindow;
   3.117 +
   3.118 +    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   3.119 +        if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   3.120 +            [nswindow setStyleMask:(NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask)];
   3.121 +        } else {
   3.122 +            [nswindow setStyleMask:NSBorderlessWindowMask];
   3.123 +        }
   3.124 +    }
   3.125 +    isFullscreen = YES;
   3.126 +    inFullscreenTransition = YES;
   3.127 +}
   3.128 +
   3.129 +- (void)windowDidEnterFullScreen:(NSNotification *)aNotification
   3.130 +{
   3.131 +    inFullscreenTransition = NO;
   3.132 +    [self windowDidResize:aNotification];
   3.133 +}
   3.134 +
   3.135 +- (void)windowWillExitFullScreen:(NSNotification *)aNotification
   3.136 +{
   3.137 +    inFullscreenTransition = YES;
   3.138 +}
   3.139 +
   3.140 +- (void)windowDidExitFullScreen:(NSNotification *)aNotification
   3.141 +{
   3.142 +    SDL_Window *window = _data->window;
   3.143 +    NSWindow *nswindow = _data->nswindow;
   3.144 +
   3.145 +    if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
   3.146 +        [nswindow setStyleMask:GetWindowStyle(window)];
   3.147 +    }
   3.148 +    isFullscreen = NO;
   3.149 +    inFullscreenTransition = NO;
   3.150 +    [self windowDidResize:aNotification];
   3.151 +}
   3.152 +
   3.153  /* We'll respond to key events by doing nothing so we don't beep.
   3.154   * We could handle key messages here, but we lose some in the NSApp dispatch,
   3.155   * where they get converted to action messages, etc.
   3.156 @@ -606,26 +691,6 @@
   3.157  }
   3.158  @end
   3.159  
   3.160 -static unsigned int
   3.161 -GetWindowStyle(SDL_Window * window)
   3.162 -{
   3.163 -    unsigned int style;
   3.164 -
   3.165 -    if (window->flags & SDL_WINDOW_FULLSCREEN) {
   3.166 -        style = NSBorderlessWindowMask;
   3.167 -    } else {
   3.168 -        if (window->flags & SDL_WINDOW_BORDERLESS) {
   3.169 -            style = NSBorderlessWindowMask;
   3.170 -        } else {
   3.171 -            style = (NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask);
   3.172 -        }
   3.173 -        if (window->flags & SDL_WINDOW_RESIZABLE) {
   3.174 -            style |= NSResizableWindowMask;
   3.175 -        }
   3.176 -    }
   3.177 -    return style;
   3.178 -}
   3.179 -
   3.180  static int
   3.181  SetupWindowData(_THIS, SDL_Window * window, NSWindow *nswindow, SDL_bool created)
   3.182  {
   3.183 @@ -758,6 +823,7 @@
   3.184          return -1;
   3.185      }
   3.186      [nswindow setBackgroundColor:[NSColor blackColor]];
   3.187 +    [nswindow setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
   3.188  
   3.189      /* Create a default view for this window */
   3.190      rect = [nswindow contentRectForFrameRect:[nswindow frame]];
   3.191 @@ -1020,10 +1086,45 @@
   3.192      [pool release];
   3.193  }
   3.194  
   3.195 -void
   3.196 -Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   3.197 +static SDL_bool
   3.198 +Cocoa_CanToggleFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   3.199  {
   3.200 -    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   3.201 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   3.202 +    NSWindow *nswindow = data->nswindow;
   3.203 +
   3.204 +    if (![nswindow respondsToSelector: @selector(toggleFullScreen:)]) {
   3.205 +        return SDL_FALSE;
   3.206 +    }
   3.207 +
   3.208 +    /* We can enter new style fullscreen mode for "fullscreen desktop" */
   3.209 +    if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
   3.210 +        return SDL_TRUE;
   3.211 +    }
   3.212 +
   3.213 +    /* We can always leave new style fullscreen mode */
   3.214 +    if (!fullscreen && [data->listener isToggledFullscreen]) {
   3.215 +        return SDL_TRUE;
   3.216 +    }
   3.217 +
   3.218 +    /* Requesting a mode switched fullscreen mode */
   3.219 +    return SDL_FALSE;
   3.220 +}
   3.221 +
   3.222 +static void
   3.223 +Cocoa_SetWindowFullscreen_NewStyle(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   3.224 +{
   3.225 +    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   3.226 +    NSWindow *nswindow = data->nswindow;
   3.227 + 
   3.228 +    if (fullscreen != [data->listener isToggledFullscreen]) {
   3.229 +        [nswindow toggleFullScreen:nil];
   3.230 +    }
   3.231 +    ScheduleContextUpdates(data);
   3.232 +}
   3.233 +
   3.234 +static void
   3.235 +Cocoa_SetWindowFullscreen_OldStyle(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   3.236 +{
   3.237      SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
   3.238      NSWindow *nswindow = data->nswindow;
   3.239      NSRect rect;
   3.240 @@ -1097,6 +1198,18 @@
   3.241      }
   3.242  
   3.243      ScheduleContextUpdates(data);
   3.244 +}
   3.245 +
   3.246 +void
   3.247 +Cocoa_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   3.248 +{
   3.249 +    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   3.250 +
   3.251 +    if (Cocoa_CanToggleFullscreen(_this, window, display, fullscreen)) {
   3.252 +        Cocoa_SetWindowFullscreen_NewStyle(_this, window, display, fullscreen);
   3.253 +    } else {
   3.254 +        Cocoa_SetWindowFullscreen_OldStyle(_this, window, display, fullscreen);
   3.255 +    }
   3.256  
   3.257      [pool release];
   3.258  }