Home | History | Annotate | Download | only in quartz
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012  Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 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     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public
     16     License along with this library; if not, write to the Free
     17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #include "SDL_QuartzVideo.h"
     25 #include "SDL_QuartzWM.h"
     26 #include "SDL_QuartzWindow.h"
     27 
     28 /*
     29     This function makes the *SDL region* of the window 100% opaque.
     30     The genie effect uses the alpha component. Otherwise,
     31     it doesn't seem to matter what value it has.
     32 */
     33 static void QZ_SetPortAlphaOpaque () {
     34 
     35     SDL_Surface *surface = current_video->screen;
     36     int bpp = surface->format->BitsPerPixel;
     37     Uint32 amask = surface->format->Amask;
     38 
     39     if (bpp == 32 && amask != 0) {
     40 
     41         Uint32    *pixels = (Uint32*) surface->pixels;
     42         Uint32    rowPixels = surface->pitch / 4;
     43         Uint32    i, j;
     44 
     45         for (i = 0; i < surface->h; i++)
     46             for (j = 0; j < surface->w; j++) {
     47 
     48                 pixels[ (i * rowPixels) + j ] |= amask;
     49             }
     50     }
     51 }
     52 
     53 @implementation SDL_QuartzWindow
     54 
     55 /* we override these methods to fix the miniaturize animation/dock icon bug */
     56 - (void)miniaturize:(id)sender
     57 {
     58     if (SDL_VideoSurface->flags & SDL_OPENGL) {
     59 
     60         /*
     61             Future: Grab framebuffer and put into NSImage
     62             [ qz_window setMiniwindowImage:image ];
     63         */
     64     }
     65     else {
     66 
     67         /* make the alpha channel opaque so anim won't have holes in it */
     68         QZ_SetPortAlphaOpaque ();
     69     }
     70 
     71     /* window is hidden now */
     72     SDL_PrivateAppActive (0, SDL_APPACTIVE);
     73 
     74     [ super miniaturize:sender ];
     75 }
     76 
     77 - (void)display
     78 {
     79     /*
     80         This method fires just before the window deminaturizes from the Dock.
     81 
     82         We'll save the current visible surface, let the window manager redraw any
     83         UI elements, and restore the SDL surface. This way, no expose event
     84         is required, and the deminiaturize works perfectly.
     85     */
     86      SDL_VideoDevice *this = (SDL_VideoDevice*)current_video;
     87 
     88     /* make sure pixels are fully opaque */
     89     if (! ( SDL_VideoSurface->flags & SDL_OPENGL ) )
     90         QZ_SetPortAlphaOpaque ();
     91 
     92     /* save current visible SDL surface */
     93     [ self cacheImageInRect:[ window_view frame ] ];
     94 
     95     /* let the window manager redraw controls, border, etc */
     96     [ super display ];
     97 
     98     /* restore visible SDL surface */
     99     [ self restoreCachedImage ];
    100 
    101     /* window is visible again */
    102     SDL_PrivateAppActive (1, SDL_APPACTIVE);
    103 }
    104 
    105 - (void)setFrame:(NSRect)frameRect display:(BOOL)flag
    106 {
    107 
    108     /*
    109         If the video surface is NULL, this originated from QZ_SetVideoMode,
    110         so don't send the resize event.
    111     */
    112     SDL_VideoDevice *this = (SDL_VideoDevice*)current_video;
    113 
    114     if (this && SDL_VideoSurface == NULL) {
    115 
    116         [ super setFrame:frameRect display:flag ];
    117     }
    118     else if (this && qz_window) {
    119 
    120         NSRect newViewFrame;
    121 
    122         [ super setFrame:frameRect display:flag ];
    123 
    124         newViewFrame = [ window_view frame ];
    125 
    126         SDL_PrivateResize (newViewFrame.size.width, newViewFrame.size.height);
    127     }
    128 }
    129 
    130 /* QZ_DoActivate() calls a low-level CoreGraphics routine to adjust
    131    the cursor position, if input is being grabbed. If app activation is
    132    triggered by a mouse click in the title bar, then the window manager
    133    gets confused and thinks we're dragging the window. The solution
    134    below postpones the activate event to avoid this scenario. */
    135 - (void)becomeKeyWindow
    136 {
    137 	NSEvent *event = [self currentEvent];
    138 	if ([event type] == NSLeftMouseDown && [event window] == self)
    139 		watchForMouseUp = YES;
    140 	else
    141 		[super becomeKeyWindow];
    142 }
    143 
    144 - (void)sendEvent:(NSEvent *)event
    145 {
    146 	[super sendEvent:event];
    147 	if (watchForMouseUp && [event type] == NSLeftMouseUp)
    148 	{
    149 		watchForMouseUp = NO;
    150 		[super becomeKeyWindow];
    151 	}
    152 }
    153 
    154 - (void)appDidHide:(NSNotification*)note
    155 {
    156     SDL_PrivateAppActive (0, SDL_APPACTIVE);
    157 }
    158 
    159 - (void)appWillUnhide:(NSNotification*)note
    160 {
    161     SDL_VideoDevice *this = (SDL_VideoDevice*)current_video;
    162 
    163     if ( this ) {
    164 
    165         /* make sure pixels are fully opaque */
    166         if (! ( SDL_VideoSurface->flags & SDL_OPENGL ) )
    167             QZ_SetPortAlphaOpaque ();
    168 
    169         /* save current visible SDL surface */
    170         [ self cacheImageInRect:[ window_view frame ] ];
    171     }
    172 }
    173 
    174 - (void)appDidUnhide:(NSNotification*)note
    175 {
    176     /* restore cached image, since it may not be current, post expose event too */
    177     [ self restoreCachedImage ];
    178 
    179     /*SDL_PrivateExpose ();*/
    180 
    181     SDL_PrivateAppActive (1, SDL_APPACTIVE);
    182 }
    183 
    184 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
    185 {
    186     /* Make our window subclass receive these application notifications */
    187     [ [ NSNotificationCenter defaultCenter ] addObserver:self
    188         selector:@selector(appDidHide:) name:NSApplicationDidHideNotification object:NSApp ];
    189 
    190     [ [ NSNotificationCenter defaultCenter ] addObserver:self
    191         selector:@selector(appDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp ];
    192 
    193     [ [ NSNotificationCenter defaultCenter ] addObserver:self
    194         selector:@selector(appWillUnhide:) name:NSApplicationWillUnhideNotification object:NSApp ];
    195 
    196     return [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ];
    197 }
    198 
    199 @end
    200 
    201 @implementation SDL_QuartzWindowDelegate
    202 - (BOOL)windowShouldClose:(id)sender
    203 {
    204     SDL_PrivateQuit();
    205     return NO;
    206 }
    207 
    208 - (void)windowDidBecomeKey:(NSNotification *)aNotification
    209 {
    210     QZ_DoActivate (current_video);
    211 }
    212 
    213 - (void)windowDidResignKey:(NSNotification *)aNotification
    214 {
    215     QZ_DoDeactivate (current_video);
    216 }
    217 
    218 @end
    219 
    220 @implementation SDL_QuartzView
    221 
    222 - (void)resetCursorRects
    223 {
    224     SDL_Cursor *sdlc = SDL_GetCursor();
    225     if (sdlc != NULL && sdlc->wm_cursor != NULL) {
    226         [self addCursorRect: [self visibleRect] cursor: sdlc->wm_cursor->nscursor];
    227     }
    228 }
    229 
    230 @end
    231