00001 00002 // 00003 // SFML - Simple and Fast Multimedia Library 00004 // Copyright (C) 2007-2009 Lucas Soltic (ceylow@gmail.com) and Laurent Gomila (laurent.gom@gmail.com) 00005 // 00006 // This software is provided 'as-is', without any express or implied warranty. 00007 // In no event will the authors be held liable for any damages arising from the use of this software. 00008 // 00009 // Permission is granted to anyone to use this software for any purpose, 00010 // including commercial applications, and to alter it and redistribute it freely, 00011 // subject to the following restrictions: 00012 // 00013 // 1. The origin of this software must not be misrepresented; 00014 // you must not claim that you wrote the original software. 00015 // If you use this software in a product, an acknowledgment 00016 // in the product documentation would be appreciated but is not required. 00017 // 00018 // 2. Altered source versions must be plainly marked as such, 00019 // and must not be misrepresented as being the original software. 00020 // 00021 // 3. This notice may not be removed or altered from any source distribution. 00022 // 00024 00026 // Headers 00028 #import <SFML/Window/Cocoa/GLKit.h> 00029 #import <SFML/Window/Cocoa/AppController.h> 00030 #import <SFML/Window/VideoMode.hpp> 00031 #import <SFML/Window/WindowStyle.hpp> 00032 #import <SFML/System/Sleep.hpp> 00033 #import <OpenGL/gl.h> 00034 #import <iostream> 00035 00036 00040 @implementation GLContext 00041 00042 static GLContext *sharedCtx = nil; 00043 00047 + (id)sharedContext 00048 { 00049 if (sharedCtx == nil) 00050 { 00051 // Make a new context with the default parameters 00052 sf::WindowSettings params(0, 0, 0); 00053 sharedCtx = [[GLContext alloc] initWithAttributes:params sharedContext:nil]; 00054 } 00055 00056 return sharedCtx; 00057 } 00058 00059 - (void)dealloc 00060 { 00061 [mySharedContext release]; 00062 [super dealloc]; 00063 } 00064 00069 - (id)initWithAttributes:(sf::WindowSettings&)attribs sharedContext:(GLContext *)context 00070 { 00071 // Note about antialiasing and other context attributes : 00072 // OpenGL context sharing does not allow the shared contexts to use different attributes. 00073 // The point is that the default shared global OpenGL context uses default parameters. 00074 // That means that all the other context *should* use the same paramaters. 00075 // Fortunately some values parameters for some parameters are compatible, but some are not 00076 // among which : the antialising level. 00077 // 00078 // I've no way to fix this for now. 00079 00080 if (attribs.AntialiasingLevel) 00081 std::cerr << "Warning: antialiasing settings are inhibited under Mac OS X for technical reasons" << std::endl; 00082 00083 NSOpenGLPixelFormat *myPixelFormat = nil; 00084 unsigned idx = 0; 00085 00086 // Attributes list 00087 NSOpenGLPixelFormatAttribute ctxtAttribs[15] = {(NSOpenGLPixelFormatAttribute) 0}; 00088 00089 // Accelerated, double buffered 00090 ctxtAttribs[idx++] = NSOpenGLPFAClosestPolicy; 00091 ctxtAttribs[idx++] = NSOpenGLPFADoubleBuffer; 00092 ctxtAttribs[idx++] = NSOpenGLPFAAccelerated; 00093 00094 // windowed context (even fullscreen mode uses a window) 00095 ctxtAttribs[idx++] = NSOpenGLPFAWindow; 00096 00097 // Color size ; usually 32 bits per pixel 00098 ctxtAttribs[idx++] = NSOpenGLPFAColorSize; 00099 ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) sf::VideoMode::GetDesktopMode().BitsPerPixel; 00100 00101 // Z-buffer size 00102 ctxtAttribs[idx++] = NSOpenGLPFADepthSize; 00103 ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) attribs.DepthBits; 00104 00105 // Stencil bits (I don't really know what's that...) 00106 ctxtAttribs[idx++] = NSOpenGLPFAStencilSize; 00107 ctxtAttribs[idx++] = (NSOpenGLPixelFormatAttribute) attribs.StencilBits; 00108 00109 myPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:ctxtAttribs]; 00110 00111 if (myPixelFormat) { 00112 self = [super initWithFormat:myPixelFormat 00113 shareContext:context]; 00114 00115 mySharedContext = [context retain]; 00116 00117 // Get the effective properties from our OpenGL context 00118 GLint tmpDepthSize = 0, tmpStencilBits = 0, tmpAntialiasingLevel = 0; 00119 00120 if (self) { 00121 [myPixelFormat getValues:&tmpDepthSize 00122 forAttribute:NSOpenGLPFADepthSize 00123 forVirtualScreen:[self currentVirtualScreen]]; 00124 00125 [myPixelFormat getValues:&tmpStencilBits 00126 forAttribute:NSOpenGLPFAStencilSize 00127 forVirtualScreen:[self currentVirtualScreen]]; 00128 00129 [myPixelFormat getValues:&tmpAntialiasingLevel 00130 forAttribute:NSOpenGLPFASamples 00131 forVirtualScreen:[self currentVirtualScreen]]; 00132 } 00133 00134 00135 attribs.DepthBits = (unsigned) tmpDepthSize; 00136 attribs.StencilBits = (unsigned) tmpStencilBits; 00137 attribs.AntialiasingLevel = (unsigned) tmpAntialiasingLevel; 00138 00139 [myPixelFormat release]; 00140 } 00141 00142 return self; 00143 } 00144 00145 @end 00146 00147 00151 @implementation GLView 00152 00159 - (id)initWithFrame:(NSRect)frame 00160 mode:(const sf::VideoMode&)mode 00161 settings:(sf::WindowSettings&)settings 00162 delegate:(sf::priv::WindowImplCocoa *)delegate 00163 { 00164 assert(delegate != NULL); 00165 00166 // make the view 00167 self = [super initWithFrame:frame pixelFormat:nil]; 00168 00169 if (self) 00170 { 00171 // enabled auto-resizing 00172 [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 00173 00174 // make the OpenGL context 00175 myGLContext = [[GLContext alloc] initWithAttributes:settings sharedContext:sharedCtx]; 00176 00177 // We need to update the OpenGL view when it's resized 00178 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 00179 [nc addObserver:self 00180 selector:@selector(viewFrameDidChange:) 00181 name:NSViewFrameDidChangeNotification 00182 object:self]; 00183 00184 // Save the delegate 00185 myDelegate = delegate; 00186 } 00187 00188 return self; 00189 } 00190 00191 00195 - (void)dealloc 00196 { 00197 // Remove the observer and release the OpenGL context 00198 [[NSNotificationCenter defaultCenter] removeObserver:self]; 00199 [myGLContext release]; 00200 00201 [super dealloc]; 00202 } 00203 00204 00208 - (void)finishInitialization 00209 { 00210 assert([self superview] != nil); 00211 assert(myGLContext != nil); 00212 00213 // Attach the OpenGL context to our view 00214 [self clearGLContext]; 00215 [self setOpenGLContext:myGLContext]; 00216 [myGLContext setView:self]; 00217 00218 // Make our view the first responder 00219 [[self window] makeFirstResponder:self]; 00220 } 00221 00222 00226 - (void)enableVerticalSync:(bool)flag 00227 { 00228 GLint enable = (flag) ? 1 : 0; 00229 [[self openGLContext] setValues:&enable forParameter:NSOpenGLCPSwapInterval]; 00230 } 00231 00232 00236 - (void)setActive:(bool)flag 00237 { 00238 if (flag) { 00239 if ([NSOpenGLContext currentContext] != [self openGLContext]) 00240 [[self openGLContext] makeCurrentContext]; 00241 } else { 00242 if ([NSOpenGLContext currentContext] == [self openGLContext]) 00243 [NSOpenGLContext clearCurrentContext]; 00244 } 00245 } 00246 00247 00251 - (void)flushBuffer 00252 { 00253 [[self openGLContext] flushBuffer]; 00254 } 00255 00256 00260 - (void)pushEvent:(sf::Event)sfEvent 00261 { 00262 assert(myDelegate != NULL); 00263 myDelegate->HandleNotifiedEvent(sfEvent); 00264 } 00265 00266 00270 - (void)viewFrameDidChange:(NSNotification *)notification 00271 { 00272 [self update]; 00273 00274 sf::Event ev; 00275 ev.Type = sf::Event::Resized; 00276 ev.Size.Width = (unsigned) [self frame].size.width; 00277 ev.Size.Height = (unsigned) [self frame].size.height; 00278 00279 [self pushEvent:ev]; 00280 } 00281 00282 00286 - (void)keyDown:(NSEvent *)theEvent 00287 { 00288 assert(myDelegate != NULL); 00289 00290 NSText *field = [[self window] fieldEditor:YES forObject:nil]; 00291 [field interpretKeyEvents:[NSArray arrayWithObject:theEvent]]; 00292 [field setString:@""]; 00293 00294 myDelegate->HandleKeyDown(theEvent); 00295 } 00296 00297 00301 - (void)keyUp:(NSEvent *)theEvent 00302 { 00303 assert(myDelegate != NULL); 00304 myDelegate->HandleKeyUp(theEvent); 00305 } 00306 00307 00311 - (void)flagsChanged:(NSEvent *)theEvent 00312 { 00313 assert(myDelegate != NULL); 00314 myDelegate->HandleModifierKey(theEvent); 00315 } 00316 00317 00321 - (void)scrollWheel:(NSEvent *)theEvent 00322 { 00323 assert(myDelegate != NULL); 00324 myDelegate->HandleMouseWheel(theEvent); 00325 } 00326 00327 00331 - (void)mouseDown:(NSEvent *)theEvent 00332 { 00333 assert(myDelegate != NULL); 00334 myDelegate->HandleMouseDown(theEvent); 00335 } 00336 00337 00341 - (void)rightMouseDown:(NSEvent *)theEvent 00342 { 00343 assert(myDelegate != NULL); 00344 myDelegate->HandleMouseDown(theEvent); 00345 } 00346 00347 00351 - (void)mouseUp:(NSEvent *)theEvent 00352 { 00353 assert(myDelegate != NULL); 00354 myDelegate->HandleMouseUp(theEvent); 00355 } 00356 00357 00361 - (void)rightMouseUp:(NSEvent *)theEvent 00362 { 00363 assert(myDelegate != NULL); 00364 myDelegate->HandleMouseUp(theEvent); 00365 } 00366 00367 00371 - (void)mouseMoved:(NSEvent *)theEvent 00372 { 00373 assert(myDelegate != NULL); 00374 myDelegate->HandleMouseMove(theEvent); 00375 } 00376 00380 - (void)mouseDragged:(NSEvent *)theEvent 00381 { 00382 assert(myDelegate != NULL); 00383 myDelegate->HandleMouseMove(theEvent); 00384 } 00385 00389 - (void)rightMouseDragged:(NSEvent *)theEvent 00390 { 00391 assert(myDelegate != NULL); 00392 myDelegate->HandleMouseMove(theEvent); 00393 } 00394 00395 00399 - (BOOL)acceptsFirstResponder 00400 { 00401 return YES; 00402 } 00403 00404 00408 - (BOOL)canBecomeKeyView 00409 { 00410 return YES; 00411 } 00412 00413 @end 00414 00415 00420 @implementation GLWindow 00421 00422 - (BOOL)canBecomeKeyWindow 00423 { 00424 return YES; 00425 } 00426 00427 - (BOOL)canBecomeMainWindow 00428 { 00429 return YES; 00430 } 00431 00432 @end 00433 00434 00438 @implementation WindowWrapper 00439 00445 - (id)initWithSettings:(sf::WindowSettings&)params 00446 videoMode:(sf::VideoMode&)mode 00447 style:(unsigned long)style 00448 title:(NSString *)title 00449 delegate:(sf::priv::WindowImplCocoa *)delegate 00450 { 00451 return [self initWithWindow:nil 00452 settings:params 00453 videoMode:mode 00454 style:style 00455 title:title 00456 delegate:delegate]; 00457 } 00458 00459 00466 - (id)initWithWindow:(NSWindow *)window 00467 settings:(sf::WindowSettings&)params 00468 delegate:(sf::priv::WindowImplCocoa *)delegate 00469 { 00470 sf::VideoMode mode([[myWindow contentView] frame].size.width, [[myWindow contentView] frame].size.height); 00471 return [self initWithWindow:window 00472 settings:params 00473 videoMode:mode 00474 style:0 00475 title:nil 00476 delegate:delegate]; 00477 } 00478 00479 00487 - (id)initWithWindow:(NSWindow *)window 00488 settings:(sf::WindowSettings&)params 00489 videoMode:(sf::VideoMode&)mode 00490 style:(unsigned long)style 00491 title:(NSString *)title 00492 delegate:(sf::priv::WindowImplCocoa *)delegate 00493 { 00494 assert(delegate != NULL); 00495 00496 self = [super init]; 00497 00498 if (self) 00499 { 00500 if (window) { 00501 myWindow = (GLWindow *)[window retain]; 00502 } else { 00503 assert(title != nil); 00504 00505 NSRect frame = NSMakeRect (0.0f, 0.0f, (float) mode.Width, (float) mode.Height); 00506 unsigned int mask = 0; 00507 00508 if (style & sf::Style::Fullscreen) { 00509 myIsFullscreen = true; 00510 00511 // Check display mode and put new values in 'mode' if needed 00512 boolean_t exact = true; 00513 00514 CFDictionaryRef properties = CGDisplayBestModeForParameters(kCGDirectMainDisplay, mode.BitsPerPixel, 00515 mode.Width, mode.Height, &exact); 00516 00517 if (!properties) { 00518 std::cerr << "Unable to get a display mode with the given parameters" << std::endl; 00519 [self autorelease]; 00520 return nil; 00521 } 00522 00523 if (exact == false) { 00524 CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayWidth), 00525 kCFNumberIntType, &mode.Width); 00526 00527 CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayHeight), 00528 kCFNumberIntType, &mode.Height); 00529 00530 CFNumberGetValue((CFNumberRef) CFDictionaryGetValue(properties, kCGDisplayBitsPerPixel), 00531 kCFNumberIntType, &mode.BitsPerPixel); 00532 00533 } 00534 } 00535 00536 // We grab options from WindowStyle and add them to our window mask 00537 if (style & sf::Style::None || style & sf::Style::Fullscreen) { 00538 mask |= NSBorderlessWindowMask; 00539 00540 00541 00542 } else { 00543 if (style & sf::Style::Titlebar) { 00544 mask |= NSTitledWindowMask; 00545 mask |= NSMiniaturizableWindowMask; 00546 } 00547 00548 if (style & sf::Style::Resize) { 00549 mask |= NSTitledWindowMask; 00550 mask |= NSMiniaturizableWindowMask; 00551 mask |= NSResizableWindowMask; 00552 } 00553 00554 if (style & sf::Style::Close) { 00555 mask |= NSTitledWindowMask; 00556 mask |= NSClosableWindowMask; 00557 mask |= NSMiniaturizableWindowMask; 00558 } 00559 } 00560 00561 // Now we make the window with the values we got 00562 // Note: defer flag set to NO to be able to use OpenGL in our window 00563 myWindow = [[GLWindow alloc] initWithContentRect:frame 00564 styleMask:mask 00565 backing:NSBackingStoreBuffered 00566 defer:NO]; 00567 00568 if (myWindow) { 00569 // We set title and window position 00570 [myWindow setTitle:title]; 00571 [myWindow center]; 00572 } else { 00573 std::cerr << "Unable to create the Cocoa window" << std::endl; 00574 [self autorelease]; 00575 return nil; 00576 } 00577 } 00578 00579 // Make the OpenGL view 00580 myView = [[GLView alloc] initWithFrame:[[myWindow contentView] frame] 00581 mode:mode 00582 settings:params 00583 delegate:delegate]; 00584 00585 if (myView) { 00586 // Finish setting up the view and window 00587 // Add the view to our window and tell it to the view 00588 [[myWindow contentView] addSubview:myView]; 00589 [myView finishInitialization]; 00590 00591 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; 00592 00593 // We want to know when our window got the focus 00594 [nc addObserver:self 00595 selector:@selector(windowDidBecomeMain:) 00596 name:NSWindowDidBecomeMainNotification 00597 object:myWindow]; 00598 00599 // We want to know when our window lost the focus 00600 [nc addObserver:self 00601 selector:@selector(windowDidResignMain:) 00602 name:NSWindowDidResignMainNotification 00603 object:myWindow]; 00604 00605 // We want to know when the user closes the window 00606 [nc addObserver:self 00607 selector:@selector(windowWillClose:) 00608 name:NSWindowWillCloseNotification 00609 object:myWindow]; 00610 00611 // I want to re-center the window if it's a full screen one and moved by Spaces 00612 [nc addObserver:self 00613 selector:@selector(windowDidMove:) 00614 name:NSWindowDidMoveNotification 00615 object:myWindow]; 00616 00617 // Needed not to make application crash when releasing the window in our destructor 00618 // (I prefer to take control of everything :P) 00619 [myWindow setReleasedWhenClosed:NO]; 00620 [myWindow setAcceptsMouseMovedEvents:YES]; 00621 00622 } else { 00623 std::cerr << "Unable to create the OpenGL view" << std::endl; 00624 [self autorelease]; 00625 return nil; 00626 } 00627 00628 if (myIsFullscreen) { 00629 myFullscreenMode = mode; 00630 00631 // Using this because full screen window was not always 00632 // in front of the other application windows when unhiding app 00633 [myWindow setLevel:NSFloatingWindowLevel]; 00634 } 00635 } 00636 00637 return self; 00638 } 00639 00640 00644 - (void)dealloc 00645 { 00646 00647 // Remove the notification observer 00648 [[NSNotificationCenter defaultCenter] removeObserver:self]; 00649 00650 // Close the window 00651 [self show:false]; 00652 00653 // Release the window and view 00654 [myView release]; 00655 [myWindow release]; 00656 00657 [super dealloc]; 00658 } 00659 00660 00664 - (NSWindow *)window 00665 { 00666 return myWindow; 00667 } 00668 00669 00673 - (GLView *)glView 00674 { 00675 return myView; 00676 } 00677 00678 00682 - (void)setPosition:(NSPoint)pos 00683 { 00684 assert(myWindow != nil); 00685 00686 if (!myIsFullscreen) { 00687 // Flip Y and set window position 00688 pos.y = [[myWindow screen] frame].size.height - pos.y; 00689 [myWindow setFrameTopLeftPoint:pos]; 00690 } 00691 } 00692 00693 00697 - (void)setSize:(NSSize)size 00698 { 00699 assert(myWindow != nil); 00700 00701 if (!myIsFullscreen) { 00702 [myWindow setFrame:NSMakeRect([myWindow frame].origin.x, 00703 [myWindow frame].origin.y, 00704 size.width, size.height) 00705 display:YES]; 00706 } 00707 } 00708 00709 00713 - (NSPoint)mouseLocation 00714 { 00715 assert(myWindow != nil); 00716 00717 NSPoint relativeLocation = [myWindow convertScreenToBase:[NSEvent mouseLocation]]; 00718 relativeLocation.y = [[self glView] frame].size.height - relativeLocation.y; 00719 return relativeLocation; 00720 } 00721 00722 00726 - (BOOL)mouseInside 00727 { 00728 assert(myWindow != nil); 00729 assert(myView != nil); 00730 00731 BOOL flag = NO; 00732 00733 if ([myWindow isVisible]) { 00734 NSPoint relativeToWindow = [myWindow mouseLocationOutsideOfEventStream]; 00735 NSPoint relativeToView = [myView convertPoint:relativeToWindow fromView:nil]; 00736 00737 if (NSPointInRect (relativeToView, [myView bounds])) 00738 { 00739 flag = YES; 00740 } 00741 } 00742 00743 return flag; 00744 } 00745 00746 00750 - (void)show:(bool)flag 00751 { 00752 assert(myWindow != nil); 00753 00754 if (flag && ![myWindow isVisible]) { 00755 // Wanna open the closed window 00756 00757 if (myIsFullscreen) { 00758 [SharedAppController setFullscreenWindow:self mode:&myFullscreenMode]; 00759 } else { 00760 // Show the window 00761 [myWindow makeKeyAndOrderFront:nil]; 00762 } 00763 } else if (!flag && [myWindow isVisible]) { 00764 // Wanna close the opened window 00765 00766 if (myIsFullscreen) { 00767 [SharedAppController setFullscreenWindow:nil mode:NULL]; 00768 } else { 00769 // Close the window 00770 [myWindow close]; 00771 } 00772 } 00773 } 00774 00775 00779 - (void)enableVerticalSync:(bool)flag 00780 { 00781 assert(myView != nil); 00782 [myView enableVerticalSync:flag]; 00783 } 00784 00785 00789 - (void)setActive:(bool)flag 00790 { 00791 assert(myView != nil); 00792 [myView setActive:flag]; 00793 } 00794 00795 00799 - (void)flushBuffer 00800 { 00801 assert(myView != nil); 00802 [myView flushBuffer]; 00803 } 00804 00805 00809 - (void)windowDidBecomeMain:(NSNotification *)notification 00810 { 00811 sf::Event ev; 00812 ev.Type = sf::Event::GainedFocus; 00813 00814 [myView pushEvent:ev]; 00815 } 00816 00817 00821 - (void)windowDidResignMain:(NSNotification *)notification 00822 { 00823 sf::Event ev; 00824 ev.Type = sf::Event::LostFocus; 00825 00826 [myView pushEvent:ev]; 00827 } 00828 00829 00833 - (void)windowWillClose:(NSNotification *)notification 00834 { 00835 sf::Event ev; 00836 ev.Type = sf::Event::Closed; 00837 00838 [myView pushEvent:ev]; 00839 } 00840 00841 00845 - (void)windowDidMove:(NSNotification *)notification 00846 { 00847 NSWindow *sender = [notification object]; 00848 00849 if (!([sender styleMask] & NSTitledWindowMask)) 00850 [sender center]; 00851 } 00852 00853 @end 00854
:: Copyright © 2007-2008 Laurent Gomila, all rights reserved :: Documentation generated by doxygen 1.5.2 ::