From 120af2580db0a8c79538fa4c746f623a6ed286dd Mon Sep 17 00:00:00 2001 From: rti Date: Fri, 15 Oct 2010 23:33:42 +0200 Subject: [PATCH] Fixed: #1130 Merge cocoa_adapter.mm code into driver_opengl*.cpp (and cocoa_event_emitter.cpp) --- code/nel/include/nel/misc/common.h | 2 + code/nel/src/3d/driver/opengl/CMakeLists.txt | 2 + .../src/3d/driver/opengl/driver_opengl.cpp | 179 +-- code/nel/src/3d/driver/opengl/driver_opengl.h | 20 +- .../3d/driver/opengl/driver_opengl_window.cpp | 565 +++++++- .../src/3d/driver/opengl/mac/cocoa_adapter.h | 101 +- .../src/3d/driver/opengl/mac/cocoa_adapter.mm | 1133 +---------------- .../driver/opengl/mac/cocoa_event_emitter.cpp | 388 +++++- .../driver/opengl/mac/cocoa_event_emitter.h | 4 + .../3d/driver/opengl/mac/cocoa_opengl_view.h | 3 - .../3d/driver/opengl/mac/cocoa_opengl_view.m | 16 +- 11 files changed, 1006 insertions(+), 1407 deletions(-) diff --git a/code/nel/include/nel/misc/common.h b/code/nel/include/nel/misc/common.h index 04553c2ab..d5460b362 100644 --- a/code/nel/include/nel/misc/common.h +++ b/code/nel/include/nel/misc/common.h @@ -48,6 +48,8 @@ typedef HWND nlWindow; #define EmptyWindow NULL #elif defined(NL_OS_MAC) + // TODO This should be NSView*, but then we would need to include Cocoa.h + // and compile with "-x objective-c++" ... everything including this file. typedef void* nlWindow; #define EmptyWindow NULL #elif defined(NL_OS_UNIX) diff --git a/code/nel/src/3d/driver/opengl/CMakeLists.txt b/code/nel/src/3d/driver/opengl/CMakeLists.txt index ea1a0ab31..d4643f465 100644 --- a/code/nel/src/3d/driver/opengl/CMakeLists.txt +++ b/code/nel/src/3d/driver/opengl/CMakeLists.txt @@ -2,6 +2,8 @@ FILE(GLOB SRC *.cpp *.h *.def) IF(APPLE) FILE(GLOB MAC_SRC mac/*.h mac/*.m mac/*.mm mac/*.cpp) SET(SRC ${SRC} ${MAC_SRC}) + SET_SOURCE_FILES_PROPERTIES(${SRC} + PROPERTIES COMPILE_FLAGS "-x objective-c++") ENDIF(APPLE) IF(WIN32) diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.cpp b/code/nel/src/3d/driver/opengl/driver_opengl.cpp index f0d816f50..5ab7c7475 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl.cpp @@ -29,10 +29,6 @@ # include # include #elif defined(NL_OS_MAC) -# define GL_GLEXT_LEGACY -# include -# include "mac/glext.h" -# include "mac/cocoa_adapter.h" #elif defined (NL_OS_UNIX) # include # include @@ -189,8 +185,24 @@ CDriverGL::CDriverGL() #elif defined(NL_OS_MAC) - NL3D::MAC::ctor(); + _ctx = nil; + _glView = nil; + _backBufferHeight = 0; + _backBufferWidth = 0; + + // autorelease pool for memory management + _autoreleasePool = [[NSAutoreleasePool alloc] init]; + + // init the application object + [NSApplication sharedApplication]; + + // create the menu in the top screen bar + setupApplicationMenu(); + + // finish the application launching + [NSApp finishLaunching]; + #elif defined (NL_OS_UNIX) _cursor = None; @@ -329,9 +341,9 @@ CDriverGL::~CDriverGL() { H_AUTO_OGL(CDriverGL_CDriverGLDtor) release(); - + #if defined(NL_OS_MAC) - NL3D::MAC::dtor(); + [_autoreleasePool release]; #endif } @@ -860,7 +872,12 @@ bool CDriverGL::swapBuffers() #elif defined(NL_OS_MAC) - NL3D::MAC::swapBuffers(_win); + // TODO: maybe do this somewhere else? + [_autoreleasePool release]; + _autoreleasePool = [[NSAutoreleasePool alloc] init]; + + [_ctx flushBuffer]; + [containerView() display]; #elif defined (NL_OS_UNIX) @@ -2213,102 +2230,102 @@ void CDriverGL::retrieveATIDriverVersion() H_AUTO_OGL(CDriverGL_retrieveATIDriverVersion) _ATIDriverVersion = 0; // we may need this driver version to fix flaws of previous ati drivers version (fog issue with V.P) - #ifdef NL_OS_WINDOWS - // get from the registry - HKEY parentKey; - // open key about current video card - LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &parentKey); - if (result == ERROR_SUCCESS) +#ifdef NL_OS_WINDOWS + // get from the registry + HKEY parentKey; + // open key about current video card + LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ, &parentKey); + if (result == ERROR_SUCCESS) + { + // find last config + DWORD keyIndex = 0; + uint latestConfigVersion = 0; + char subKeyName[256]; + char latestSubKeyName[256] = ""; + DWORD nameBufferSize = sizeof(subKeyName) / sizeof(subKeyName[0]); + FILETIME lastWriteTime; + bool configFound = false; + for(;;) { - // find last config - DWORD keyIndex = 0; - uint latestConfigVersion = 0; - char subKeyName[256]; - char latestSubKeyName[256] = ""; - DWORD nameBufferSize = sizeof(subKeyName) / sizeof(subKeyName[0]); - FILETIME lastWriteTime; - bool configFound = false; - for(;;) + nameBufferSize = sizeof(subKeyName) / sizeof(subKeyName[0]); + result = RegEnumKeyEx(parentKey, keyIndex, subKeyName, &nameBufferSize, NULL, NULL, NULL, &lastWriteTime); + if (result == ERROR_NO_MORE_ITEMS) break; + if (result == ERROR_SUCCESS) { - nameBufferSize = sizeof(subKeyName) / sizeof(subKeyName[0]); - result = RegEnumKeyEx(parentKey, keyIndex, subKeyName, &nameBufferSize, NULL, NULL, NULL, &lastWriteTime); - if (result == ERROR_NO_MORE_ITEMS) break; - if (result == ERROR_SUCCESS) + // see if the name is numerical. + bool isNumerical = true; + for(uint k = 0; k < nameBufferSize; ++k) { - // see if the name is numerical. - bool isNumerical = true; - for(uint k = 0; k < nameBufferSize; ++k) + if (!isdigit(subKeyName[k])) { - if (!isdigit(subKeyName[k])) - { - isNumerical = false; - break; - } + isNumerical = false; + break; } - if (isNumerical) - { - uint configVersion; - fromString((const char*)subKeyName, configVersion); - if (configVersion >= latestConfigVersion) - { - configFound = true; - latestConfigVersion = configVersion; - strcpy(latestSubKeyName, subKeyName); - } - } - ++ keyIndex; } - else + if (isNumerical) { - RegCloseKey(parentKey); - return; + uint configVersion; + fromString((const char*)subKeyName, configVersion); + if (configVersion >= latestConfigVersion) + { + configFound = true; + latestConfigVersion = configVersion; + strcpy(latestSubKeyName, subKeyName); + } } + ++ keyIndex; } - if (configFound) + else { - HKEY subKey; - result = RegOpenKeyEx(parentKey, latestSubKeyName, 0, KEY_READ, &subKey); - if (result == ERROR_SUCCESS) + RegCloseKey(parentKey); + return; + } + } + if (configFound) + { + HKEY subKey; + result = RegOpenKeyEx(parentKey, latestSubKeyName, 0, KEY_READ, &subKey); + if (result == ERROR_SUCCESS) + { + // see if it is a radeon card + DWORD valueType; + char driverDesc[256]; + DWORD driverDescBufSize = sizeof(driverDesc) / sizeof(driverDesc[0]); + result = RegQueryValueEx(subKey, "DriverDesc", NULL, &valueType, (unsigned char *) driverDesc, &driverDescBufSize); + if (result == ERROR_SUCCESS && valueType == REG_SZ) { - // see if it is a radeon card - DWORD valueType; - char driverDesc[256]; - DWORD driverDescBufSize = sizeof(driverDesc) / sizeof(driverDesc[0]); - result = RegQueryValueEx(subKey, "DriverDesc", NULL, &valueType, (unsigned char *) driverDesc, &driverDescBufSize); - if (result == ERROR_SUCCESS && valueType == REG_SZ) + toLower(driverDesc); + if (strstr(driverDesc, "radeon")) // is it a radeon card ? { - toLower(driverDesc); - if (strstr(driverDesc, "radeon")) // is it a radeon card ? + char driverVersion[256]; + DWORD driverVersionBufSize = sizeof(driverVersion) / sizeof(driverVersion[0]); + result = RegQueryValueEx(subKey, "DriverVersion", NULL, &valueType, (unsigned char *) driverVersion, &driverVersionBufSize); + if (result == ERROR_SUCCESS && valueType == REG_SZ) { - char driverVersion[256]; - DWORD driverVersionBufSize = sizeof(driverVersion) / sizeof(driverVersion[0]); - result = RegQueryValueEx(subKey, "DriverVersion", NULL, &valueType, (unsigned char *) driverVersion, &driverVersionBufSize); - if (result == ERROR_SUCCESS && valueType == REG_SZ) + int subVersionNumber[4]; + if (sscanf(driverVersion, "%d.%d.%d.%d", &subVersionNumber[0], &subVersionNumber[1], &subVersionNumber[2], &subVersionNumber[3]) == 4) { - int subVersionNumber[4]; - if (sscanf(driverVersion, "%d.%d.%d.%d", &subVersionNumber[0], &subVersionNumber[1], &subVersionNumber[2], &subVersionNumber[3]) == 4) + _ATIDriverVersion = (uint) subVersionNumber[3]; + /** see if fog range for V.P is bad in that driver version (is so, do a fix during vertex program conversion to EXT_vertex_shader + * In earlier versions of the driver, fog coordinates had to be output in the [0, 1] range + * From the 6.14.10.6343 driver, fog output must be in world units + */ + if (_ATIDriverVersion < 6343) { - _ATIDriverVersion = (uint) subVersionNumber[3]; - /** see if fog range for V.P is bad in that driver version (is so, do a fix during vertex program conversion to EXT_vertex_shader - * In earlier versions of the driver, fog coordinates had to be output in the [0, 1] range - * From the 6.14.10.6343 driver, fog output must be in world units - */ - if (_ATIDriverVersion < 6343) - { - _ATIFogRangeFixed = false; - } + _ATIFogRangeFixed = false; } } } } } - RegCloseKey(subKey); } - RegCloseKey(parentKey); + RegCloseKey(subKey); } + RegCloseKey(parentKey); + } #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - nlwarning("OpenGL Driver: Missing Mac Implementation"); +# warning "OpenGL Driver: Missing Mac Implementation for ATI version retrieval" + nlwarning("OpenGL Driver: Missing Mac Implementation for ATI version retrieval"); #elif defined (NL_OS_UNIX) // TODO for Linux: implement retrieveATIDriverVersion... assuming versions under linux are probably different diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.h b/code/nel/src/3d/driver/opengl/driver_opengl.h index 6410ca65b..cf4f93a22 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl.h @@ -32,8 +32,11 @@ # include # include #elif defined(NL_OS_MAC) -# define GL_GLEXT_LEGACY +# define GL_GLEXT_LEGACY +# import # include +# include "mac/glext.h" +# import "mac/cocoa_opengl_view.h" #elif defined (NL_OS_UNIX) # define GLX_GLXEXT_PROTOTYPES # include @@ -700,7 +703,15 @@ private: #elif defined(NL_OS_MAC) - NLMISC::CCocoaEventEmitter _EventEmitter; + NLMISC::CCocoaEventEmitter _EventEmitter; + NSOpenGLContext* _ctx; + NSOpenGLView* _glView; + NSAutoreleasePool* _autoreleasePool; + uint16 _backBufferHeight; + uint16 _backBufferWidth; + + NSView* containerView() { return (NSView*)_win; } + void setupApplicationMenu(); #elif defined (NL_OS_UNIX) @@ -1388,11 +1399,6 @@ public: CVertexProgamDrvInfosGL (CDriverGL *drv, ItVtxPrgDrvInfoPtrList it); }; -#ifdef NL_OS_MAC - // Specific mac functions - extern bool getMacModes(std::vector &modes); -#endif - } // NL3D #endif // NL_DRIVER_OPENGL_H diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp index 2aed89013..f82fbe746 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp @@ -25,10 +25,6 @@ #ifdef NL_OS_WINDOWS # include #elif defined(NL_OS_MAC) -# define GL_GLEXT_LEGACY -# include -# include "mac/glext.h" -# include "mac/cocoa_adapter.h" #elif defined (NL_OS_UNIX) # include # include @@ -298,11 +294,7 @@ bool CDriverGL::init (uint windowIcon, emptyProc exitFunc) retrieveATIDriverVersion(); #elif defined(NL_OS_MAC) - if(!NL3D::MAC::init(windowIcon, exitFunc)) - { - nldebug("cannot init"); - return false; - } + // nothing to do #elif defined (NL_OS_UNIX) @@ -393,11 +385,7 @@ bool CDriverGL::unInit() #elif defined(NL_OS_MAC) - if(!NL3D::MAC::unInit()) - { - nldebug("cannot uninit"); - return false; - } + // nothing to do #elif defined (NL_OS_UNIX) @@ -478,7 +466,7 @@ void CDriverGL::setWindowIcon(const std::vector &bitmaps) #elif defined(NL_OS_MAC) - // nothing to do + // nothing to do, on Mac OS X, only windows representing a file have icons #elif defined(NL_OS_UNIX) @@ -901,10 +889,67 @@ bool CDriverGL::setDisplay(nlWindow wnd, const GfxMode &mode, bool show, bool re #elif defined(NL_OS_MAC) - _win = NL3D::MAC::setDisplay(wnd, mode, show, resizeable); + if (wnd == EmptyWindow) + { + if (!createWindow(mode)) + return false; + } + else + { + _win = wnd; + } - if(_win != EmptyWindow) - _DestroyWindow = true; + // setup opengl settings + NSOpenGLPixelFormatAttribute att[] = + { + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFADepthSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFAStencilSize, 8, + NSOpenGLPFANoRecovery, + NSOpenGLPFAAccelerated, + NSOpenGLPFABackingStore, + 0 + }; + + // put the settings into a format object + NSOpenGLPixelFormat* format = + [[NSOpenGLPixelFormat alloc] initWithAttributes:att]; + + if(!format) + nlerror("cannot create NSOpenGLPixelFormat"); + + // create a opengl view with the created format + _glView = [[CocoaOpenGLView alloc] + initWithFrame:NSMakeRect(0, 0, 0, 0) pixelFormat: format]; + + if(!_glView) + nlerror("cannot create view"); + + // make the view automatically fit the super view + [_glView setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; + + // put the open gl view into the dummy view contained in the window + [containerView() addSubview:_glView]; + + // adjust size + [_glView setFrame: [containerView() frame]]; + + // create a opengl context for the view + _ctx = [_glView openGLContext]; + + if(!_ctx) + nlerror("cannot create context"); + + // free the pixel format object + [format release]; + + // let the open gl view handle the input + [[containerView() window] makeFirstResponder:_glView]; + + [_ctx flushBuffer]; + [containerView() display]; #elif defined(NL_OS_UNIX) @@ -1145,7 +1190,8 @@ bool CDriverGL::restoreScreenMode() return res; } -// -------------------------------------------------- +// *************************************************************************** + #ifdef XF86VIDMODE static sint modeInfoToFrequency(XF86VidModeModeInfo *info) { @@ -1153,7 +1199,8 @@ static sint modeInfoToFrequency(XF86VidModeModeInfo *info) } #endif // XF86VIDMODE -// -------------------------------------------------- +// *************************************************************************** + bool CDriverGL::setScreenMode(const GfxMode &mode) { H_AUTO_OGL(CDriverGL_setScreenMode) @@ -1324,11 +1371,45 @@ bool CDriverGL::createWindow(const GfxMode &mode) #elif defined(NL_OS_MAC) - window = NL3D::MAC::createWindow(mode); + // describe how the window should look like and behave + unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSResizableWindowMask; + + // create a cocoa window with the size provided by the mode parameter + NSWindow* cocoa_window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(0, 0, mode.Width, mode.Height) + styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; + + if(!cocoa_window) + { + nlerror("cannot create cocoa window"); + return false; + } + + // set the window to non transparent + [cocoa_window setOpaque:YES]; + + // enable mouse move events, NeL wants them + [cocoa_window setAcceptsMouseMovedEvents:YES]; + + // there are no overlapping subviews, can use the magical optimization :) + [cocoa_window useOptimizedDrawing:YES]; + + // put the window to the front and make it the key window + [cocoa_window makeKeyAndOrderFront:nil]; + + // this is our main window + [cocoa_window makeMainWindow]; + + // create a dummy view which works like the window on other platforms + // the open gl view will be created as subview of this one. + window = [[NSView alloc] init]; + + [cocoa_window setContentView: (NSView*)window]; if(window == EmptyWindow) { - nldebug("cannot create window"); + nldebug("cannot create cocoa view for cocoa window"); return false; } @@ -1368,6 +1449,7 @@ bool CDriverGL::createWindow(const GfxMode &mode) } // *************************************************************************** + bool CDriverGL::destroyWindow() { H_AUTO_OGL(CDriverGL_destroyWindow) @@ -1404,12 +1486,11 @@ bool CDriverGL::destroyWindow() if(_DestroyWindow) { - if(!NL3D::MAC::destroyWindow(_win)) - { - nldebug("cannot destroy window"); - return false; - } + [containerView() release]; + [[containerView() window] release]; } + + _ctx = nil; #elif defined (NL_OS_UNIX) @@ -1436,6 +1517,8 @@ bool CDriverGL::destroyWindow() return true; } +// *************************************************************************** + CDriverGL::EWindowStyle CDriverGL::getWindowStyle() const { H_AUTO_OGL(CDriverGL_getWindowStyle) @@ -1446,6 +1529,8 @@ CDriverGL::EWindowStyle CDriverGL::getWindowStyle() const return EWSWindowed; } +// *************************************************************************** + bool CDriverGL::setWindowStyle(EWindowStyle windowStyle) { H_AUTO_OGL(CDriverGL_setWindowStyle) @@ -1500,10 +1585,57 @@ bool CDriverGL::setWindowStyle(EWindowStyle windowStyle) #elif defined(NL_OS_MAC) - if(!NL3D::MAC::setWindowStyle(_win, windowStyle == EWSFullscreen)) + // leave fullscreen mode, enter windowed mode + if(windowStyle == EWSWindowed && [containerView() isInFullScreenMode]) { - nldebug("cannot set window style"); - return false; + // disable manual setting of back buffer size, cocoa handles this + // automatically as soon as the view gets resized + CGLError error = CGLDisable((CGLContextObj)[_ctx CGLContextObj], + kCGLCESurfaceBackingSize); + + if(error != kCGLNoError) + nlerror("cannot disable kCGLCESurfaceBackingSize (%s)", + CGLErrorString(error)); + + // pull the view back from fullscreen restoring window options + [containerView() exitFullScreenModeWithOptions:nil]; + + // let the gl view receive key events + [[containerView() window] makeFirstResponder:_glView]; + + // bring the window containing the gl view to the front + [[containerView() window] makeKeyAndOrderFront:nil]; + } + + // enter fullscreen, leave windowed mode + else if(windowStyle == EWSFullscreen && ![containerView() isInFullScreenMode]) + { + // enable manual back buffer size for mode setting in fullscreen + CGLError error = CGLEnable((CGLContextObj)[_ctx CGLContextObj], + kCGLCESurfaceBackingSize); + + if(error != kCGLNoError) + nlerror("cannot enable kCGLCESurfaceBackingSize (%s)", + CGLErrorString(error)); + + // put the view in fullscreen mode, hiding the dock but enabling the menubar + // to pop up if the mouse hits the top screen border. + // NOTE: withOptions:nil disables + application switching! +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + [containerView() enterFullScreenMode:[NSScreen mainScreen] withOptions: + [NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithInt: + NSApplicationPresentationHideDock | + NSApplicationPresentationAutoHideMenuBar], + NSFullScreenModeApplicationPresentationOptions, nil]]; +#endif // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + /* + TODO check if simply using NSView enterFullScreenMode is a good idea. + the context can be set to full screen as well, performance differences? + */ + + // let the gl view receive key events + [[containerView() window] makeFirstResponder:_glView]; } #elif defined(NL_OS_UNIX) @@ -1558,6 +1690,8 @@ bool CDriverGL::setWindowStyle(EWindowStyle windowStyle) #endif // NL_OS_WINDOWS + _FullScreen = (windowStyle == EWSFullscreen); + return true; } @@ -1570,19 +1704,54 @@ bool CDriverGL::setMode(const GfxMode& mode) return false; // when changing window style, it's possible system change window size too - setWindowStyle(mode.Windowed ? EWSWindowed:EWSFullscreen); + setWindowStyle(mode.Windowed ? EWSWindowed : EWSFullscreen); if (!mode.Windowed) _Depth = mode.Depth; - _FullScreen = !mode.Windowed; - setWindowSize(mode.Width, mode.Height); setWindowPos(_WindowX, _WindowY); return true; } +#if defined(NL_OS_MAC) && defined(AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER) + +/// helper to extract bits per pixel value from screen mode, only 16 or 32 bits +static int bppFromDisplayMode(CGDisplayModeRef mode) +{ + CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode); + + if(CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), + kCFCompareCaseInsensitive) == kCFCompareEqualTo) + return 32; + + else if(CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), + kCFCompareCaseInsensitive) == kCFCompareEqualTo) + return 16; + + return 0; +} + +#elif defined(NL_OS_MAC) && !defined(AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER) + +long GetDictionaryLong(CFDictionaryRef theDict, const void* key) +{ + long value = 0; + CFNumberRef numRef; + numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); + if (numRef != NULL) + CFNumberGetValue(numRef, kCFNumberLongType, &value); + return value; +} + +// some macros to make code more readable. +#define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth) +#define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight) +#define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel) + +#endif // defined(NL_OS_MAC) + // -------------------------------------------------- bool CDriverGL::getModes(std::vector &modes) { @@ -1611,7 +1780,71 @@ bool CDriverGL::getModes(std::vector &modes) #elif defined(NL_OS_MAC) - NL3D::MAC::getModes(modes); + static const CGDisplayCount kMaxDisplays = 16; + CGDirectDisplayID display[kMaxDisplays]; + CGDisplayCount numDisplays; + + CGDisplayErr err = CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays); + if(err != CGDisplayNoErr) + { + nlwarning("Cannot get displays (%d)", err); + return false; + } + + // nldebug("3D: %d displays found", (int)numDisplays); + + for (CGDisplayCount i = 0; i < numDisplays; ++i) + { + CGDirectDisplayID dspy = display[i]; + +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + CFArrayRef modeList = CGDisplayCopyAllDisplayModes(dspy, NULL); +#else + CFArrayRef modeList = CGDisplayAvailableModes(dspy); +#endif // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + + if (modeList == NULL) + { + nlwarning("Display is invalid"); + continue; + } + + for (CFIndex j = 0; j < CFArrayGetCount(modeList); ++j) + { +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modeList, j); + uint8 bpp = bppFromDisplayMode(mode); +#else + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(modeList, j); + uint8 bpp = (uint8)GetModeBitsPerPixel(mode); +#endif // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + + if (bpp >= 16) + { +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + uint16 w = CGDisplayModeGetWidth(mode); + uint16 h = CGDisplayModeGetHeight(mode); +#else + uint16 w = (uint16)GetModeWidth(mode); + uint16 h = (uint16)GetModeHeight(mode); +#endif // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + + // Add this mode + GfxMode mode; + mode.Width = w; + mode.Height = h; + mode.Depth = bpp; + + // Frequency stays at 0 because on mac cocoa, display resolution + // is never really changed. if rendering res < display res, + // cocoa interpolates and keeps the display at it's original res. + mode.Frequency = 0; + modes.push_back (mode); + + // nldebug(" Display 0x%x: Mode %dx%d, %d BPP", dspy, w, h, bpp); + } + } + } #elif defined (NL_OS_UNIX) @@ -1722,7 +1955,30 @@ bool CDriverGL::getCurrentScreenMode(GfxMode &mode) #elif defined(NL_OS_MAC) - NL3D::MAC::getCurrentScreenMode(_win, mode); + // the sceen with the menu bar + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + + mode.OffScreen = false; + mode.Frequency = 0; + mode.Depth = NSBitsPerPixelFromDepth([screen depth]); + + // in fullscreen mode + if([containerView() isInFullScreenMode]) + { + // return the size of the back buffer (like having switched monitor mode) + mode.Windowed = false; + mode.Width = _backBufferWidth; + mode.Height = _backBufferHeight; + } + + // in windowed mode + else + { + // return the size of the screen with menu bar + mode.Windowed = true; + mode.Width = (uint16)[screen frame].size.width; + mode.Height = (uint16)[screen frame].size.height; + } #elif defined(NL_OS_UNIX) @@ -1830,7 +2086,8 @@ void CDriverGL::setWindowTitle(const ucstring &title) #elif defined(NL_OS_MAC) - NL3D::MAC::setWindowTitle(_win, title); + [[containerView() window] setTitle: + [NSString stringWithUTF8String:title.toUtf8().c_str()]]; #elif defined (NL_OS_UNIX) @@ -1862,7 +2119,19 @@ void CDriverGL::setWindowPos(sint32 x, sint32 y) #elif defined(NL_OS_MAC) - NL3D::MAC::setWindowPos(_win, x, y); + nldebug("setting window pos to %d %d", x, y); + + // get the rect (position, size) of the screen with menu bar + NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; + + // get the rect (position, size) of the window + NSRect windowRect = [[containerView() window] frame]; + + // convert y from NeL coordinates to cocoa coordinates + y = screenRect.size.height - y; + + // tell cocoa to move the window + [[containerView() window] setFrameTopLeftPoint:NSMakePoint(x, y)]; #elif defined (NL_OS_UNIX) @@ -1895,7 +2164,7 @@ void CDriverGL::showWindow(bool show) #elif defined(NL_OS_MAC) - MAC::showWindow(show); + // TODO implement me #elif defined (NL_OS_UNIX) @@ -1940,11 +2209,8 @@ bool CDriverGL::activate() #elif defined(NL_OS_MAC) - if(!MAC::activate(_win)) - { - nlwarning("cannot activate"); - return false; - } + if([NSOpenGLContext currentContext] != _ctx) + [_ctx makeCurrentContext]; #elif defined (NL_OS_UNIX) @@ -2024,7 +2290,28 @@ void CDriverGL::showCursor(bool b) #elif defined(NL_OS_MAC) - NL3D::MAC::showCursor(b); + // Mac OS manages a show/hide counter for the cursor, so hiding the cursor + // twice requires two calls to "show" to make the cursor visible again. + // Since other platforms seem to not do this, the functionality is masked here + // by only calling hide if the cursor is visible and only calling show if + // the cursor was hidden. + + CGDisplayErr error = kCGErrorSuccess; + static bool visible = true; + + if(b && !visible) + { + error = CGDisplayShowCursor(kCGDirectMainDisplay); + visible = true; + } + else if(!b && visible) + { + error = CGDisplayHideCursor(kCGDirectMainDisplay); + visible = false; + } + + if(error != kCGErrorSuccess) + nlerror("cannot show / hide cursor"); #elif defined (NL_OS_UNIX) @@ -2077,7 +2364,30 @@ void CDriverGL::setMousePos(float x, float y) #elif defined(NL_OS_MAC) - NL3D::MAC::setMousePos(_win, x, y); + // CG wants absolute coordinates related to first screen's top left + + // get the first screen's (conaints menubar) rect (this is not mainScreen) + NSRect firstScreenRect = [[[NSScreen screens] objectAtIndex:0] frame]; + + // get the rect (position, size) of the window + NSRect windowRect; + if([containerView() isInFullScreenMode]) + windowRect = [[[containerView() window] screen] frame]; + else + windowRect = [[containerView() window] frame]; + + // get the view's rect for height and width + NSRect viewRect = [containerView() frame]; + + // set the cursor position + CGDisplayErr error = CGDisplayMoveCursorToPoint( + kCGDirectMainDisplay, CGPointMake( + windowRect.origin.x + (viewRect.size.width * x), + firstScreenRect.size.height - windowRect.origin.y - + viewRect.size.height + ((1.0 - y) * viewRect.size.height))); + + if(error != kCGErrorSuccess) + nlerror("cannot set mouse position"); #elif defined (NL_OS_UNIX) @@ -2092,7 +2402,32 @@ void CDriverGL::getWindowSize(uint32 &width, uint32 &height) #ifdef NL_OS_MAC - NL3D::MAC::getWindowSize(_win, width, height); + // TODO set them in windowproc, so no special impl is needed here + + // A cocoa fullscreen view stays at the native resolution of the display. + // When changing the rendering resolution, the size of the back buffer gets + // changed, but the view still stays at full resolution. So the scaling of + // the image from the rendered resolution to the view's resolution is done + // by cocoa automatically while flushing buffers. + // That's why, in fullscreen mode, return the resolution of the back buffer, + // not the one from the window. + + // in fullscreen mode + if([containerView() isInFullScreenMode]) + { + // use the size stored in setWindowSize() + width = _backBufferWidth; + height = _backBufferHeight; + } + + // in windowed mode + else + { + // use the size of the view + NSRect rect = [containerView() frame]; + width = rect.size.width; + height = rect.size.height; + } #else // NL_OS_MAC @@ -2146,8 +2481,44 @@ void CDriverGL::setWindowSize(uint32 width, uint32 height) #elif defined(NL_OS_MAC) - NL3D::MAC::setWindowSize(_win, width, height); + // for fullscreen mode, adjust the back buffer size to the desired resolution + if([containerView() isInFullScreenMode]) + { + // disable and re-enable fullscreen + // fixes #1062 (http://dev.ryzom.com/issues/1062) + setWindowStyle(EWSWindowed); + setWindowStyle(EWSFullscreen); + + // set the back buffer manually to match the desired rendering resolution + GLint dim[2] = { width, height }; + CGLError error = CGLSetParameter( + (CGLContextObj)[_ctx CGLContextObj], + kCGLCPSurfaceBackingSize, dim); + if(error != kCGLNoError) + nlerror("cannot set kCGLCPSurfaceBackingSize parameter (%s)", + CGLErrorString(error)); + + _backBufferWidth = width; + _backBufferHeight = height; + } + else + { + // only change the window size if the driver created the window itself + if(_DestroyWindow) + { + // get the windows current frame + NSRect rect = [[containerView() window] frame]; + + // convert the desired content size to window size + rect = [[containerView() window] frameRectForContentRect: + NSMakeRect(rect.origin.x, rect.origin.y, width, height)]; + + // update window dimensions + [[containerView() window] setFrame:rect display:YES]; + } + } + #elif defined(NL_OS_UNIX) if (width != _WindowWidth || height != _WindowHeight) @@ -2182,8 +2553,19 @@ void CDriverGL::getWindowPos(sint32 &x, sint32 &y) H_AUTO_OGL(CDriverGL_getWindowPos) #ifdef NL_OS_MAC + // TODO set them in window proc so no special impl is needed here - NL3D::MAC::getWindowPos(_win, x, y); + // get the rect (position, size) of the screen with menu bar + NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; + + // get the rect (position, size) of the window + NSRect windowRect = [[containerView() window] frame]; + + // simply return x + x = windowRect.origin.x; + + // map y from cocoa to NeL coordinates before returning + y = screenRect.size.height - windowRect.size.height - windowRect.origin.y; #else // NL_OS_MAC @@ -2219,9 +2601,7 @@ bool CDriverGL::isActive() res = (IsWindow(_win) != FALSE); #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - // nlwarning("OpenGL Driver: Missing Mac Implementation"); - +# warning "OpenGL Driver: Missing Mac Implementation for isActive" #elif defined (NL_OS_UNIX) #endif // NL_OS_UNIX @@ -2264,7 +2644,7 @@ void CDriverGL::setCapture (bool b) #elif defined(NL_OS_MAC) - NL3D::MAC::setCapture(b); + // no need to capture #elif defined (NL_OS_UNIX) @@ -2316,11 +2696,7 @@ NLMISC::IMouseDevice* CDriverGL::enableLowLevelMouse(bool enable, bool exclusive } #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - nlwarning("OpenGL Driver: Missing Mac Implementation"); - #elif defined (NL_OS_UNIX) - #endif return res; @@ -2358,11 +2734,7 @@ NLMISC::IKeyboardDevice* CDriverGL::enableLowLevelKeyboard(bool enable) } #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - nlwarning("OpenGL Driver: Missing Mac Implementation"); - #elif defined (NL_OS_UNIX) - #endif return res; @@ -2381,11 +2753,7 @@ NLMISC::IInputDeviceManager* CDriverGL::getLowLevelInputDeviceManager() res = NLMISC::safe_cast(_EventEmitter.getEmitter(1)); #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - nlwarning("OpenGL Driver: Missing Mac Implementation"); - #elif defined (NL_OS_UNIX) - #endif return res; @@ -2429,8 +2797,8 @@ uint CDriverGL::getDoubleClickDelay(bool hardwareMouse) } #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - nlwarning("OpenGL Driver: Missing Mac Implementation"); +# warning "OpenGL Driver: Missing Mac Implementation for getDoubleClickDelay" + nlwarning("OpenGL Driver: Missing Mac Implementation for getDoubleClickDelay"); #elif defined (NL_OS_UNIX) @@ -2492,11 +2860,10 @@ bool CDriverGL::setMonitorColorProperties (const CMonitorColorProperties &proper } #elif defined(NL_OS_MAC) -# warning "OpenGL Driver: Missing Mac Implementation" - nlwarning("OpenGL Driver: Missing Mac Implementation"); + // TODO for Mac: implement CDriverGL::setMonitorColorProperties + nlwarning ("CDriverGL::setMonitorColorProperties not implemented"); #elif defined (NL_OS_UNIX) - // TODO for Linux: implement CDriverGL::setMonitorColorProperties nlwarning ("CDriverGL::setMonitorColorProperties not implemented"); @@ -2505,4 +2872,64 @@ bool CDriverGL::setMonitorColorProperties (const CMonitorColorProperties &proper return false; } +#ifdef NL_OS_MAC +void CDriverGL::setupApplicationMenu() +{ + NSMenu* menu; + NSMenuItem* menuItem; + NSString* title; + NSString* appName; + + // get the applications name from it's process info + appName = [[NSProcessInfo processInfo] processName]; + + // create an empty menu object + menu = [[NSMenu alloc] initWithTitle:@""]; + + // add the about menu item + title = [@"About " stringByAppendingString:appName]; + [menu addItemWithTitle:title + action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + // separator + [menu addItem:[NSMenuItem separatorItem]]; + + // add the hide application menu item + title = [@"Hide " stringByAppendingString:appName]; + [menu addItemWithTitle:title + action:@selector(hide:) keyEquivalent:@"h"]; + + // add the hide others menu item + menuItem = [menu addItemWithTitle:@"Hide Others" + action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + // add the show all menu item + [menu addItemWithTitle:@"Show All" + action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + // separator + [menu addItem:[NSMenuItem separatorItem]]; + + /* + TODO on quit send EventDestroyWindowId + */ + // add the quit menu item + title = [@"Quit " stringByAppendingString:appName]; + [menu addItemWithTitle:title + action:@selector(terminate:) keyEquivalent:@"q"]; + + // create an empty menu item and put the new menu into it as a subitem + menuItem = [[NSMenuItem alloc] initWithTitle:@"" + action:nil keyEquivalent:@""]; + [menuItem setSubmenu:menu]; + + // create a menu for the application + [NSApp setMainMenu:[[NSMenu alloc] initWithTitle:@""]]; + + // attach the new menu to the applications menu + [[NSApp mainMenu] addItem:menuItem]; +} +#endif + } // NL3D diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.h b/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.h index d7e66cfe5..3b389f043 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.h +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.h @@ -16,103 +16,4 @@ // along with this program. If not, see . */ -#ifndef NL_DRIVER_OPENGL_MAC_COCOA_ADAPTER_H -#define NL_DRIVER_OPENGL_MAC_COCOA_ADAPTER_H - -#include "nel/misc/types_nl.h" -#include "nel/misc/event_server.h" -#include "nel/3d/driver.h" - -#include "cocoa_event_emitter.h" - -/* - * this cocoa adapter is a helper to call functions executing obj-c code - * from driver_opengl.cpp - * - * please see this as a temporary solution... there is some stuff concerning - * driver refactoring going on anyway as far as i know - * - * this can as well be seen as a preparation to pull platform specific code - * out of driver_opengl.cpp ;) - * - * btw: we cannot simply use a c++ class here, because then NSWindow* and friends - * would be members, but then we would need to add obj-c code here using an - * include or a forward declaration. this again would break compiling cpp files - * including this one (eg. driver_opengl.cpp) - */ - -namespace NL3D { namespace MAC { - -/// mac specific stuff while calling CDriverGL::CDriverGL() -void ctor(); - -/// mac specific stuff while calling CDriverGL::~CDriverGL() -void dtor(); - -/// mac specific stuff while calling CDriverGL::init() -bool init(uint windowIcon = 0, emptyProc exitFunc = 0); - -/// mac specific stuff while calling CDriverGL::unInit() -bool unInit(); - -/// mac specific stuff while calling CDriverGL::createWindow() -nlWindow createWindow(const GfxMode& mode); - -/// mac specific stuff while calling CDriverGL::destroyWindow() -bool destroyWindow(nlWindow wnd); - -/// mac specific stuff while calling CDriverGL::setDisplay() -nlWindow setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable); - -/// mac specific stuff while calling CDriverGL::setWindowStyle() -bool setWindowStyle(nlWindow wnd, bool fullscreen); - -/// mac specific stuff while calling CDriverGL::getCurrentScreenMode() -void getCurrentScreenMode(nlWindow wnd, GfxMode& mode); - -/// mac specific stuff while calling CDriverGL::getModes() -bool getModes(std::vector &modes); - -/// mac specific stuff while calling CDriverGL::getWindowSize() -void getWindowSize(nlWindow wnd, uint32 &width, uint32 &height); - -/// mac specific stuff while calling CDriverGL::setWindowSize() -void setWindowSize(nlWindow wnd, uint32 width, uint32 height); - -/// mac specific stuff while calling CDriverGL::getWindowPos() -void getWindowPos(nlWindow wnd, sint32 &x, sint32 &y); - -/// mac specific stuff while calling CDriverGL::setWindowPos() -void setWindowPos(nlWindow wnd, sint32 x, sint32 y); - -/// mac specific stuff while calling CDriverGL::setWindowTitle() -void setWindowTitle(nlWindow wnd, const ucstring& title); - -/// mac specific stuff while calling CDriverGL::showWindow() -void showWindow(bool show); - -/// mac specific stuff while calling CDriverGL::activate() -bool activate(nlWindow wnd); - -/// mac specific stuff while calling CDriverGL::swapBuffers() -void swapBuffers(nlWindow wnd); - -/// mac specific stuff while calling CDriverGL::setCapture() -void setCapture(bool capture); - -/// mac specific stuff while calling CDriverGL::showCursor() -void showCursor(bool show); - -/// mac specific stuff while calling CDriverGL::setMousePos() -void setMousePos(nlWindow wnd, float x, float y); - -/// mac specific stuff while calling CCocoaEventEmitter::submitEvents() -void submitEvents(NLMISC::CEventServer& server, - bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter); - -/// mac specific stuff while calling CCocoaEventEmitter::emulateMouseRawMode() -void emulateMouseRawMode(bool enable); - -}} - -#endif +/* TODO remove this file */ diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.mm b/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.mm index a0f2c3e81..3b389f043 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.mm +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_adapter.mm @@ -16,1135 +16,4 @@ // along with this program. If not, see . */ -#include "cocoa_adapter.h" - -#include "nel/misc/events.h" -#include "nel/misc/game_device_events.h" -#include "nel/3d/driver.h" - -#include "cocoa_event_emitter.h" -#include "cocoa_opengl_view.h" - -// Virtual key codes are only defined here. Still do not need to link carbon. -// see: http://lists.apple.com/archives/Cocoa-dev/2009/May/msg01180.html -#include - -#import -#import - -#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) - #define NL_USE_MAC_10_6_API 1 -#endif - -#ifndef NL_USE_MAC_10_6_API -long GetDictionaryLong(CFDictionaryRef theDict, const void* key) -{ - long value = 0; - CFNumberRef numRef; - numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key); - if (numRef != NULL) - CFNumberGetValue(numRef, kCFNumberLongType, &value); - return value; -} - -// some macros to make code more readable. -#define GetModeWidth(mode) GetDictionaryLong((mode), kCGDisplayWidth) -#define GetModeHeight(mode) GetDictionaryLong((mode), kCGDisplayHeight) -#define GetModeBitsPerPixel(mode) GetDictionaryLong((mode), kCGDisplayBitsPerPixel) - -#endif // NL_USE_MAC_10_6_API - -namespace NL3D { namespace MAC { - -// This cocoa adapter can be used in two environments: -// First: There is no other code which creates the NSApplication object, so -// NeL is completely in charge of starting and setting up the application. -// In this case, the NSAutoreleasePool needed to handle the cocoa style memory -// management is created by this code. -// Second: There is already a NSApplication set up. This could be the case if -// NeL is used for example in a Qt widget. So Qt already created all the -// NSApplication infrastructure, so it is not set up by this code again! -// -// Thats why, the g_pool variable (containing a pointer to the NSAutoreleasePool -// created by this code) can be used to check whether NeL created the -// NSApplication infrastructure itself or not. -// -// WARNING: -// Currently the NSApplication infrastructure is automatically created with the -// call to createWindow(). So if for example Qt already created NSApplication, -// createWindow() must not be called. Instead, setDisplay() can be provided with -// a window handle (on Mac OS Cocoa Qt this is a NSView*). In this case, this -// cocoa adapter will skip the NSApplication setup and embed itself into the -// provided view running in the already set up application. - -static NSAutoreleasePool* g_pool = nil; -/* - TODO move to event emitter class -*/ -static bool g_emulateRawMode = false; -static int g_bufferSize[2] = { 0, 0 }; - -/// setup an apple style application menu (located at the top bar of the screen) -static void setupApplicationMenu() -{ - NSMenu* menu; - NSMenuItem* menuItem; - NSString* title; - NSString* appName; - - // get the applications name from it's process info - appName = [[NSProcessInfo processInfo] processName]; - - // create an empty menu object - menu = [[NSMenu alloc] initWithTitle:@""]; - - // add the about menu item - title = [@"About " stringByAppendingString:appName]; - [menu addItemWithTitle:title - action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - - // separator - [menu addItem:[NSMenuItem separatorItem]]; - - // add the hide application menu item - title = [@"Hide " stringByAppendingString:appName]; - [menu addItemWithTitle:title - action:@selector(hide:) keyEquivalent:@"h"]; - - // add the hide others menu item - menuItem = [menu addItemWithTitle:@"Hide Others" - action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; - [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; - - // add the show all menu item - [menu addItemWithTitle:@"Show All" - action:@selector(unhideAllApplications:) keyEquivalent:@""]; - - // separator - [menu addItem:[NSMenuItem separatorItem]]; - - /* - TODO on quit send EventDestroyWindowId - */ - // add the quit menu item - title = [@"Quit " stringByAppendingString:appName]; - [menu addItemWithTitle:title - action:@selector(terminate:) keyEquivalent:@"q"]; - - // create an empty menu item and put the new menu into it as a subitem - menuItem = [[NSMenuItem alloc] initWithTitle:@"" - action:nil keyEquivalent:@""]; - [menuItem setSubmenu:menu]; - - // create a menu for the application - [NSApp setMainMenu:[[NSMenu alloc] initWithTitle:@""]]; - - // attach the new menu to the applications menu - [[NSApp mainMenu] addItem:menuItem]; -} - -/// set up the basic NSApplication and NSAutoreleasePool needed for Cocoa -static bool setupNSApplication() -{ - // if the pool was already created, return an error - if(g_pool) - return false; - - // create a pool, cocoa code would leak memory otherwise - g_pool = [[NSAutoreleasePool alloc] init]; - - // init the application object - [NSApplication sharedApplication]; - - // create the menu in the top screen bar - setupApplicationMenu(); - - // finish the application launching - [NSApp finishLaunching]; - - return true; -} - -/// setup an open gl view and embed it in the provided parent view -static void setupGLView(NSView* superview) -{ - /* - TODO use mode.Depth - TODO NSOpenGLPFAOffScreen - */ - - // setup opengl settings - NSOpenGLPixelFormatAttribute att[] = - { - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAColorSize, 24, - NSOpenGLPFADepthSize, 24, - NSOpenGLPFAAlphaSize, 8, - NSOpenGLPFAStencilSize, 8, - NSOpenGLPFANoRecovery, - NSOpenGLPFAAccelerated, - NSOpenGLPFABackingStore, - 0 - }; - - // put the settings into a format object - NSOpenGLPixelFormat* format = - [[NSOpenGLPixelFormat alloc] initWithAttributes:att]; - - if(!format) - nlerror("cannot create NSOpenGLPixelFormat"); - - // create a opengl view with the created format - NSOpenGLView* view = [[CocoaOpenGLView alloc] - initWithFrame:NSMakeRect(0, 0, 0, 0) pixelFormat: format]; - - if(!view) - nlerror("cannot create view"); - - // make the view automatically fit the super view - [view setAutoresizingMask: NSViewHeightSizable | NSViewWidthSizable]; - - // put the view into the superview - [superview addSubview:view]; - - [view setFrame: [superview frame]]; - - // create a opengl context for the view - NSOpenGLContext* ctx = [view openGLContext]; - - if(!ctx) - nlerror("cannot create context"); - - // free the pixel format object - [format release]; -} - -void ctor() -{ -} - -void dtor() -{ -} - -bool init(uint windowIcon, emptyProc exitFunc) -{ - return true; -} - -bool unInit() -{ - return true; -} - -/// setup the basic cocoa app infrastructure and create a window -nlWindow createWindow(const GfxMode& mode) -{ - if(!setupNSApplication()) - nlerror("createWindow must not be called before the old window was " - "destroyed using destroyWindow()!"); - - // describe how the window should look like and behave - unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask; - - // create a cocoa window with the size provided by the mode parameter - NSWindow* window = [[NSWindow alloc] - initWithContentRect:NSMakeRect(0, 0, mode.Width, mode.Height) - styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; - - if(!window) - nlerror("cannot create window"); - - // set the window to non transparent - [window setOpaque:YES]; - - // enable mouse move events, NeL wants them - [window setAcceptsMouseMovedEvents:YES]; - - // there are no overlapping subviews, can use the magical optimization :) - [window useOptimizedDrawing:YES]; - - // put the window to the front and make it the key window - [window makeKeyAndOrderFront:nil]; - - // this is our main window - [window makeMainWindow]; - - NSView* view = [[NSView alloc] init]; - - [window setContentView: view]; - - return view; -} - -/// destroy the given window -bool destroyWindow(nlWindow wnd) -{ - NSView* view = (NSView*)wnd; - - // release the window - [[view window] release]; - - // release the pool - [g_pool release]; - g_pool = nil; - - return true; -} - -/// set the displays settings, if no win is provided, a new one will be created -nlWindow setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable) -{ - NSView* view = (NSView*)wnd; - - if(view == EmptyWindow) - view = (NSView*)createWindow(mode); - - setupGLView(view); - - [[view window] makeFirstResponder:[[view subviews] lastObject]]; - - return view; -} - -/// switch between fullscreen and windowed mode -bool setWindowStyle(nlWindow wnd, bool fullscreen) -{ - if(wnd == EmptyWindow) - { - nlwarning("cannot set window style on an empty window"); - return false; - } - - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - - // leave fullscreen mode, enter windowed mode - if(!fullscreen && [superview isInFullScreenMode]) - { - // disable manual setting of back buffer size, cocoa handles this - // automatically as soon as the view gets resized - CGLError error = CGLDisable( - (CGLContextObj)[[view openGLContext] CGLContextObj], - kCGLCESurfaceBackingSize); - - if(error != kCGLNoError) - nlerror("cannot disable kCGLCESurfaceBackingSize (%s)", - CGLErrorString(error)); - - // pull the view back from fullscreen restoring window options - [superview exitFullScreenModeWithOptions:nil]; - - // let the gl view receive key events - [[view window] makeFirstResponder:view]; - - // bring the window containing the gl view to the front - [[view window] makeKeyAndOrderFront:nil]; - } - - // enter fullscreen, leave windowed mode - else if(fullscreen && ![superview isInFullScreenMode]) - { - // enable manual back buffer size for mode setting in fullscreen - CGLError error = CGLEnable( - (CGLContextObj)[[view openGLContext] CGLContextObj], - kCGLCESurfaceBackingSize); - - if(error != kCGLNoError) - nlerror("cannot enable kCGLCESurfaceBackingSize (%s)", - CGLErrorString(error)); - - // put the view in fullscreen mode, hiding the dock but enabling the menubar - // to pop up if the mouse hits the top screen border. - // NOTE: withOptions:nil disables + application switching! -#ifdef NL_USE_MAC_10_6_API - [superview enterFullScreenMode:[NSScreen mainScreen] withOptions: - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInt: - NSApplicationPresentationHideDock | - NSApplicationPresentationAutoHideMenuBar], - NSFullScreenModeApplicationPresentationOptions, nil]]; -#endif // NL_USE_MAC_10_6_API - /* - TODO check if simply using NSView enterFullScreenMode is a good idea. - the context can be set to full screen as well, performance differences? - */ - - // let the gl view receive key events - [[view window] makeFirstResponder:view]; - } - - return true; -} - -/// get the current mode of the screen -void getCurrentScreenMode(nlWindow wnd, GfxMode& mode) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - - // the sceen with the menu bar - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - - mode.OffScreen = false; - mode.Frequency = 0; - mode.Depth = NSBitsPerPixelFromDepth([screen depth]); - - // in fullscreen mode - if([superview isInFullScreenMode]) - { - // return the size of the back buffer (like having switched monitor mode) - mode.Windowed = false; - mode.Width = (uint16)g_bufferSize[0]; - mode.Height = (uint16)g_bufferSize[1]; - } - - // in windowed mode - else - { - // return the size of the screen with menu bar - mode.Windowed = true; - mode.Width = (uint16)[screen frame].size.width; - mode.Height = (uint16)[screen frame].size.height; - } -} - -#ifdef NL_USE_MAC_10_6_API -/// helper to extract bits per pixel value from screen mode, only 16 or 32 bits -static int bppFromDisplayMode(CGDisplayModeRef mode) -{ - CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding(mode); - - if(CFStringCompare(pixelEncoding, CFSTR(IO32BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) - return 32; - - else if(CFStringCompare(pixelEncoding, CFSTR(IO16BitDirectPixels), - kCFCompareCaseInsensitive) == kCFCompareEqualTo) - return 16; - - return 0; -} -#endif // NL_USE_MAC_10_6_API - -/// get the list of available screen modes -bool getModes(std::vector &modes) -{ - static const CGDisplayCount kMaxDisplays = 16; - CGDirectDisplayID display[kMaxDisplays]; - CGDisplayCount numDisplays; - - CGDisplayErr err = CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays); - if(err != CGDisplayNoErr) - { - nlwarning("Cannot get displays (%d)", err); - return false; - } - - nldebug("3D: %d displays found", (int)numDisplays); - - for (CGDisplayCount i = 0; i < numDisplays; ++i) - { - CGDirectDisplayID dspy = display[i]; - -#ifdef NL_USE_MAC_10_6_API - CFArrayRef modeList = CGDisplayCopyAllDisplayModes(dspy, NULL); -#else - CFArrayRef modeList = CGDisplayAvailableModes(dspy); -#endif // NL_USE_MAC_10_6_API - - if (modeList == NULL) - { - nlwarning("Display is invalid"); - continue; - } - - for (CFIndex j = 0; j < CFArrayGetCount(modeList); ++j) - { -#ifdef NL_USE_MAC_10_6_API - CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(modeList, j); - uint8 bpp = bppFromDisplayMode(mode); -#else - CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex(modeList, j); - uint8 bpp = (uint8)GetModeBitsPerPixel(mode); -#endif // NL_USE_MAC_10_6_API - - if (bpp >= 16) - { -#ifdef NL_USE_MAC_10_6_API - uint16 w = CGDisplayModeGetWidth(mode); - uint16 h = CGDisplayModeGetHeight(mode); -#else - uint16 w = (uint16)GetModeWidth(mode); - uint16 h = (uint16)GetModeHeight(mode); -#endif // NL_USE_MAC_10_6_API - - // Add this mode - GfxMode mode; - mode.Width = w; - mode.Height = h; - mode.Depth = bpp; - - // Frequency stays at 0 because on mac cocoa, display resolution - // is never really changed. if rendering res < display res, - // cocoa interpolates and keeps the display at it's original res. - mode.Frequency = 0; - modes.push_back (mode); - - nldebug(" Display 0x%x: Mode %dx%d, %d BPP", dspy, w, h, bpp); - } - } - } - - return true; -} - -/// get the size of the window's content area -void getWindowSize(nlWindow wnd, uint32 &width, uint32 &height) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - - // A cocoa fullscreen view stays at the native resolution of the display. - // When changing the rendering resolution, the size of the back buffer gets - // changed, but the view still stays at full resolution. So the scaling of - // the image from the rendered resolution to the view's resolution is done - // by cocoa automatically while flushing buffers. - // That's why, in fullscreen mode, return the resolution of the back buffer, - // not the one from the window. - - // in fullscreen mode - if([superview isInFullScreenMode]) - { - // use the size stored in setWindowSize() - width = g_bufferSize[0]; - height = g_bufferSize[1]; - } - - // in windowed mode - else - { - // use the size of the view - NSRect rect = [view frame]; - width = rect.size.width; - height = rect.size.height; - } -} - -/// set the size of the window's content area -void setWindowSize(nlWindow wnd, uint32 width, uint32 height) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - - // for fullscreen mode, adjust the back buffer size to the desired resolution - if([superview isInFullScreenMode]) - { - // disable and re-enable fullscreen - // fixes #1062 (http://dev.ryzom.com/issues/1062) - setWindowStyle(wnd, false); - setWindowStyle(wnd, true); - - // set the back buffer manually to match the desired rendering resolution - GLint dim[2] = { width, height }; - CGLError error = CGLSetParameter( - (CGLContextObj)[[view openGLContext] CGLContextObj], - kCGLCPSurfaceBackingSize, dim); - - if(error != kCGLNoError) - nlerror("cannot set kCGLCPSurfaceBackingSize parameter (%s)", - CGLErrorString(error)); - } - else - { - // there is only a pool if NeL created the window itself - // else, the window is not NeL's, so it must not be changed - if(g_pool) - { - NSWindow* window = [view window]; - - // get the windows current frame - NSRect rect = [window frame]; - - // convert the desired content size to window size - rect = [window frameRectForContentRect: - NSMakeRect(rect.origin.x, rect.origin.y, width, height)]; - - // update window dimensions - [window setFrame:rect display:YES]; - } - } - - // store the size - g_bufferSize[0] = width; - g_bufferSize[1] = height; -} - -/// get the position of the window -void getWindowPos(nlWindow wnd, sint32 &x, sint32 &y) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - NSWindow* window = [view window]; - - // for IDriver conformity - if([superview isInFullScreenMode]) - { - x = y = 0; - return; - } - - // get the rect (position, size) of the screen with menu bar - NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; - - // get the rect (position, size) of the window - NSRect windowRect = [window frame]; - - // simply return x - x = windowRect.origin.x; - - // map y from cocoa to NeL coordinates before returning - y = screenRect.size.height - windowRect.size.height - windowRect.origin.y; -} - -/// set the position of the window -void setWindowPos(nlWindow wnd, sint32 x, sint32 y) -{ - NSView* superview = (NSView*)wnd; - NSWindow* window = [superview window]; - - // get the rect (position, size) of the screen with menu bar - NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame]; - - // get the rect (position, size) of the window - NSRect windowRect = [window frame]; - - // convert y from NeL coordinates to cocoa coordinates - y = screenRect.size.height - y; - - // tell cocoa to move the window - [window setFrameTopLeftPoint:NSMakePoint(x, y)]; -} - -/// set the windows title (not the title of the application) -void setWindowTitle(nlWindow wnd, const ucstring& title) -{ - NSView* superview = (NSView*)wnd; - NSWindow* window = [superview window]; - - // well... set the title of the window - [window setTitle:[NSString stringWithUTF8String:title.toUtf8().c_str()]]; -} - -void showWindow(bool show) -{ - nldebug("show: %d - implement me!", show); -} - -/// make the opengl context the current one -bool activate(nlWindow wnd) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - NSOpenGLContext* ctx = [view openGLContext]; - - // if our context is not the current one, make it the current - if([NSOpenGLContext currentContext] != ctx) - [ctx makeCurrentContext]; - - return true; -} - -/// flush current back buffer to screen -void swapBuffers(nlWindow wnd) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - NSOpenGLContext* ctx = [view openGLContext]; - - // make cocoa draw buffer contents to the view - [ctx flushBuffer]; - [view display]; -} - -void setCapture(bool capture) -{ - // no need to capture -} - -/// show or hide the mouse cursor -void showCursor(bool show) -{ - // Mac OS manages a show/hide counter for the cursor, so hiding the cursor - // twice requires two calls to "show" to make the cursor visible again. - // Since other platforms seem to not do this, the functionality is masked here - // by only calling hide if the cursor is visible and only calling show if - // the cursor was hidden. - - CGDisplayErr error = kCGErrorSuccess; - static bool visible = true; - - if(show && !visible) - { - error = CGDisplayShowCursor(kCGDirectMainDisplay); - visible = true; - } - else if(!show && visible) - { - error = CGDisplayHideCursor(kCGDirectMainDisplay); - visible = false; - } - - if(error != kCGErrorSuccess) - nlerror("cannot show / hide cursor"); -} - -/// set the mouse position -void setMousePos(nlWindow wnd, float x, float y) -{ - NSView* superview = (NSView*)wnd; - NSOpenGLView* view = [[superview subviews] lastObject]; - NSWindow* window = [view window]; - - // CG wants absolute coordinates related to first screen's top left - - // get the first screen's (conaints menubar) rect (this is not mainScreen) - NSRect firstScreenRect = [[[NSScreen screens] objectAtIndex:0] frame]; - - // get the rect (position, size) of the window - NSRect windowRect; - if([superview isInFullScreenMode]) - windowRect = [[window screen] frame]; - else - windowRect = [window frame]; - - // get the gl view's rect for height and width - NSRect viewRect = [view frame]; - - // set the cursor position - CGDisplayErr error = CGDisplayMoveCursorToPoint( - kCGDirectMainDisplay, CGPointMake( - windowRect.origin.x + (viewRect.size.width * x), - firstScreenRect.size.height - windowRect.origin.y - - viewRect.size.height + ((1.0 - y) * viewRect.size.height))); - - if(error != kCGErrorSuccess) - nlerror("cannot set mouse position"); -} - -/* - TODO: this function has to be moved to a more central place to handle key - mapping on mac x11 as well -*/ -/// map from virtual key code to nel internal key code -static NLMISC::TKey virtualKeycodeToNelKey(unsigned short keycode) -{ - switch(keycode) - { - case kVK_ANSI_0: return NLMISC::Key0; - case kVK_ANSI_1: return NLMISC::Key1; - case kVK_ANSI_2: return NLMISC::Key2; - case kVK_ANSI_3: return NLMISC::Key3; - case kVK_ANSI_4: return NLMISC::Key4; - case kVK_ANSI_5: return NLMISC::Key5; - case kVK_ANSI_6: return NLMISC::Key6; - case kVK_ANSI_7: return NLMISC::Key7; - case kVK_ANSI_8: return NLMISC::Key8; - case kVK_ANSI_9: return NLMISC::Key9; - case kVK_ANSI_A: return NLMISC::KeyA; - case kVK_ANSI_B: return NLMISC::KeyB; - case kVK_ANSI_C: return NLMISC::KeyC; - case kVK_ANSI_D: return NLMISC::KeyD; - case kVK_ANSI_E: return NLMISC::KeyE; - case kVK_ANSI_F: return NLMISC::KeyF; - case kVK_ANSI_G: return NLMISC::KeyG; - case kVK_ANSI_H: return NLMISC::KeyH; - case kVK_ANSI_I: return NLMISC::KeyI; - case kVK_ANSI_J: return NLMISC::KeyJ; - case kVK_ANSI_K: return NLMISC::KeyK; - case kVK_ANSI_L: return NLMISC::KeyL; - case kVK_ANSI_M: return NLMISC::KeyM; - case kVK_ANSI_N: return NLMISC::KeyN; - case kVK_ANSI_O: return NLMISC::KeyO; - case kVK_ANSI_P: return NLMISC::KeyP; - case kVK_ANSI_Q: return NLMISC::KeyQ; - case kVK_ANSI_R: return NLMISC::KeyR; - case kVK_ANSI_S: return NLMISC::KeyS; - case kVK_ANSI_T: return NLMISC::KeyT; - case kVK_ANSI_U: return NLMISC::KeyU; - case kVK_ANSI_V: return NLMISC::KeyV; - case kVK_ANSI_W: return NLMISC::KeyW; - case kVK_ANSI_X: return NLMISC::KeyX; - case kVK_ANSI_Y: return NLMISC::KeyY; - case kVK_ANSI_Z: return NLMISC::KeyZ; - case kVK_ANSI_Equal: return NLMISC::KeyEQUALS; - case kVK_ANSI_Minus: return NLMISC::KeySUBTRACT; - case kVK_ANSI_RightBracket: return NLMISC::KeyRBRACKET; - case kVK_ANSI_LeftBracket: return NLMISC::KeyLBRACKET; - case kVK_ANSI_Quote: return NLMISC::KeyAPOSTROPHE; - case kVK_ANSI_Grave: return NLMISC::KeyPARAGRAPH; - case kVK_ANSI_Slash: return NLMISC::KeySLASH; - case kVK_ANSI_Backslash: return NLMISC::KeyBACKSLASH; - case kVK_ANSI_Comma: return NLMISC::KeyCOMMA; - case kVK_ANSI_Period: return NLMISC::KeyPERIOD; - case kVK_ANSI_Semicolon: return NLMISC::KeySEMICOLON; - case kVK_ANSI_KeypadDecimal: return NLMISC::KeyDECIMAL; - case kVK_ANSI_KeypadMultiply: return NLMISC::KeyMULTIPLY; - case kVK_ANSI_KeypadPlus: return NLMISC::KeyADD; - case kVK_ANSI_KeypadClear: return NLMISC::KeyDELETE; - case kVK_ANSI_KeypadDivide: return NLMISC::KeyDIVIDE; - case kVK_ANSI_KeypadEnter: return NLMISC::KeyRETURN; - case kVK_ANSI_KeypadMinus: return NLMISC::KeySUBTRACT; - case kVK_ANSI_KeypadEquals: return NLMISC::KeySEPARATOR; - case kVK_ANSI_Keypad0: return NLMISC::KeyNUMPAD0; - case kVK_ANSI_Keypad1: return NLMISC::KeyNUMPAD1; - case kVK_ANSI_Keypad2: return NLMISC::KeyNUMPAD2; - case kVK_ANSI_Keypad3: return NLMISC::KeyNUMPAD3; - case kVK_ANSI_Keypad4: return NLMISC::KeyNUMPAD4; - case kVK_ANSI_Keypad5: return NLMISC::KeyNUMPAD5; - case kVK_ANSI_Keypad6: return NLMISC::KeyNUMPAD6; - case kVK_ANSI_Keypad7: return NLMISC::KeyNUMPAD7; - case kVK_ANSI_Keypad8: return NLMISC::KeyNUMPAD8; - case kVK_ANSI_Keypad9: return NLMISC::KeyNUMPAD9; - case kVK_Return: return NLMISC::KeyRETURN; - case kVK_Tab: return NLMISC::KeyTAB; - case kVK_Space: return NLMISC::KeySPACE; - case kVK_Delete: return NLMISC::KeyBACK; - case kVK_ForwardDelete: return NLMISC::KeyDELETE; - case kVK_Escape: return NLMISC::KeyESCAPE; - case kVK_Shift: return NLMISC::KeySHIFT; - case kVK_RightShift: return NLMISC::KeyRSHIFT; - case kVK_CapsLock: return NLMISC::KeyCAPITAL; - case kVK_Control: return NLMISC::KeyCONTROL; - case kVK_RightControl: return NLMISC::KeyRCONTROL; - case kVK_F1: return NLMISC::KeyF1; - case kVK_F2: return NLMISC::KeyF2; - case kVK_F3: return NLMISC::KeyF3; - case kVK_F4: return NLMISC::KeyF4; - case kVK_F5: return NLMISC::KeyF5; - case kVK_F6: return NLMISC::KeyF6; - case kVK_F7: return NLMISC::KeyF7; - case kVK_F8: return NLMISC::KeyF8; - case kVK_F9: return NLMISC::KeyF9; - case kVK_F11: return NLMISC::KeyF11; - case kVK_F13: return NLMISC::KeyF13; - case kVK_F16: return NLMISC::KeyF16; - case kVK_F14: return NLMISC::KeyF14; - case kVK_F10: return NLMISC::KeyF10; - case kVK_F12: return NLMISC::KeyF12; - case kVK_F15: return NLMISC::KeyF15; - case kVK_F17: return NLMISC::KeyF17; - case kVK_F18: return NLMISC::KeyF18; - case kVK_F19: return NLMISC::KeyF19; - case kVK_F20: return NLMISC::KeyF20; - case kVK_Home: return NLMISC::KeyHOME; - case kVK_End: return NLMISC::KeyEND; - case kVK_PageUp: return NLMISC::KeyPRIOR; - case kVK_PageDown: return NLMISC::KeyNEXT; - case kVK_LeftArrow: return NLMISC::KeyLEFT; - case kVK_RightArrow: return NLMISC::KeyRIGHT; - case kVK_DownArrow: return NLMISC::KeyDOWN; - case kVK_UpArrow: return NLMISC::KeyUP; - case kVK_Command:break; - case kVK_Option:break; - case kVK_RightOption:break; - case kVK_Function:break; - case kVK_VolumeUp:break; - case kVK_VolumeDown:break; - case kVK_Mute:break; - case kVK_Help:break; - case kVK_ISO_Section:break; - case kVK_JIS_Yen:break; - case kVK_JIS_Underscore:break; - case kVK_JIS_KeypadComma:break; - case kVK_JIS_Eisu:break; - case kVK_JIS_Kana:break; - default:break; - } - return NLMISC::KeyNOKEY; -} - -/* - TODO: this function has to be moved to a more central place to handle key - mapping on mac x11 as well -*/ -/// convert modifier key state to nel internal modifier key state -static NLMISC::TKeyButton modifierFlagsToNelKeyButton(unsigned int modifierFlags) -{ - unsigned int buttons = 0; - if (modifierFlags & NSControlKeyMask) buttons |= NLMISC::ctrlKeyButton; - if (modifierFlags & NSShiftKeyMask) buttons |= NLMISC::shiftKeyButton; - if (modifierFlags & NSAlternateKeyMask) buttons |= NLMISC::altKeyButton; - return (NLMISC::TKeyButton)buttons; -} - -/// check whether a given event represents input text -static bool isTextKeyEvent(NSEvent* event) -{ - // if there are no characters provided with this event, it is not a text event - if([[event characters] length] == 0) - return false; - - NLMISC::TKey nelKey = virtualKeycodeToNelKey([event keyCode]); - - // ryzom ui wants to have "escape key string" to leave text box - if(nelKey == NLMISC::KeyESCAPE) - return true; - - // ryzom ui wants to have "return key string" to submit text box (send chat) - if(nelKey == NLMISC::KeyRETURN) - return true; - - // get the character reported by cocoa - unsigned int character = [[event characters] characterAtIndex:0]; - - // printable ascii characters - if(isprint(character)) - return true; - - /* - TODO check why iswprint(character) does not solve it. - it always returns false, even for π, é, ... - */ - // characters > 127 but not printable - if( nelKey == NLMISC::KeyF1 || nelKey == NLMISC::KeyF2 || - nelKey == NLMISC::KeyF3 || nelKey == NLMISC::KeyF4 || - nelKey == NLMISC::KeyF5 || nelKey == NLMISC::KeyF6 || - nelKey == NLMISC::KeyF7 || nelKey == NLMISC::KeyF8 || - nelKey == NLMISC::KeyF9 || nelKey == NLMISC::KeyF10 || - nelKey == NLMISC::KeyF11 || nelKey == NLMISC::KeyF12 || - nelKey == NLMISC::KeyF13 || nelKey == NLMISC::KeyF14 || - nelKey == NLMISC::KeyF15 || nelKey == NLMISC::KeyF16 || - nelKey == NLMISC::KeyF17 || nelKey == NLMISC::KeyF18 || - nelKey == NLMISC::KeyF19 || nelKey == NLMISC::KeyF20 || - nelKey == NLMISC::KeyUP || nelKey == NLMISC::KeyDOWN || - nelKey == NLMISC::KeyLEFT || nelKey == NLMISC::KeyRIGHT || - nelKey == NLMISC::KeyHOME || nelKey == NLMISC::KeyEND || - nelKey == NLMISC::KeyPRIOR || nelKey == NLMISC::KeyNEXT || - nelKey == NLMISC::KeyDELETE) - return false; - - // all the fancy wide characters - if(character > 127) - return true; - - return false; -} - -/// switch between raw mode emulation, see IEventEmitter::emulateMouseRawMode() -void emulateMouseRawMode(bool enable) -{ - g_emulateRawMode = enable; -} - -/// submit events provided by the application to an event server -void submitEvents(NLMISC::CEventServer& server, - bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter) -{ - // if there is a pool, NeL needs to clean it up - // otherwise, other code must have created it (for example Qt) - if(g_pool) - { - // cocoa style memory cleanup - [g_pool release]; - g_pool = [[NSAutoreleasePool alloc] init]; - } - - // break if there was no event to handle - /* TODO maximum number of events processed in one update? */ - while(true) - { - // get the next event to handle - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil /*[NSDate distantFuture]*/ - inMode:NSDefaultRunLoopMode dequeue:YES]; - - // stop, if there was no event - if(!event) - break; - - NSView* glView = [[[[event window] contentView] subviews] lastObject]; - NSRect viewRect = [glView frame]; - - // TODO this code assumes, that the view fills the window - // convert the mouse position to NeL style (relative) - float mouseX = event.locationInWindow.x / (float)viewRect.size.width; - float mouseY = event.locationInWindow.y / (float)viewRect.size.height; - - // if the mouse event was placed outside the view, don't tell NeL :) - if((mouseX < 0.0 || mouseX > 1.0 || mouseY < 0.0 || mouseY > 1.0) && - event.type != NSKeyDown && event.type != NSKeyUp) - { - [NSApp sendEvent:event]; - continue; - } - - // convert the modifiers for nel to pass them with the events - NLMISC::TKeyButton modifiers = - modifierFlagsToNelKeyButton([event modifierFlags]); - - switch(event.type) - { - case NSLeftMouseDown: - { - server.postEvent(new NLMISC::CEventMouseDown( - mouseX, mouseY, - (NLMISC::TMouseButton)(NLMISC::leftButton | modifiers), - eventEmitter)); - } - break; - case NSLeftMouseUp: - { - server.postEvent(new NLMISC::CEventMouseUp( - mouseX, mouseY, - (NLMISC::TMouseButton)(NLMISC::leftButton | modifiers), - eventEmitter)); - break; - } - case NSRightMouseDown: - { - server.postEvent(new NLMISC::CEventMouseDown( - mouseX, mouseY, - (NLMISC::TMouseButton)(NLMISC::rightButton | modifiers), - eventEmitter)); - break; - } - case NSRightMouseUp: - { - server.postEvent(new NLMISC::CEventMouseUp( - mouseX, mouseY, - (NLMISC::TMouseButton)(NLMISC::rightButton | modifiers), - eventEmitter)); - break; - } - case NSMouseMoved: - { - NLMISC::CEvent* nelEvent; - - // when emulating raw mode, send the delta in a CGDMouseMove event - if(g_emulateRawMode) - nelEvent = new NLMISC::CGDMouseMove( - eventEmitter, NULL /* no mouse device */, event.deltaX, -event.deltaY); - - // normally send position in a CEventMouseMove - else - nelEvent = new NLMISC::CEventMouseMove( - mouseX, mouseY, (NLMISC::TMouseButton)modifiers, eventEmitter); - - server.postEvent(nelEvent); - break; - } - case NSLeftMouseDragged: - { - NLMISC::CEvent* nelEvent; - - // when emulating raw mode, send the delta in a CGDMouseMove event - if(g_emulateRawMode) - nelEvent = new NLMISC::CGDMouseMove( - eventEmitter, NULL /* no mouse device */, event.deltaX, -event.deltaY); - - // normally send position in a CEventMouseMove - else - nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY, - (NLMISC::TMouseButton)(NLMISC::leftButton | modifiers), - eventEmitter); - - server.postEvent(nelEvent); - break; - } - case NSRightMouseDragged: - { - NLMISC::CEvent* nelEvent; - - // when emulating raw mode, send the delta in a CGDMouseMove event - if(g_emulateRawMode) - nelEvent = new NLMISC::CGDMouseMove( - eventEmitter, NULL /* no mouse device */, event.deltaX, -event.deltaY); - - // normally send position in a CEventMouseMove - else - nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY, - (NLMISC::TMouseButton)(NLMISC::rightButton | modifiers), - eventEmitter); - - server.postEvent(nelEvent); - break; - } - case NSMouseEntered:break; - case NSMouseExited:break; - case NSKeyDown: - { - // push the key press event to the event server - server.postEvent(new NLMISC::CEventKeyDown( - virtualKeycodeToNelKey([event keyCode]), - modifierFlagsToNelKeyButton([event modifierFlags]), - [event isARepeat] == NO, - eventEmitter)); - - // if this was a text event - if(isTextKeyEvent(event)) - { - ucstring ucstr; - - // get the string associated with the key press event - ucstr.fromUtf8([[event characters] UTF8String]); - - // push the text event to event server as well - server.postEvent(new NLMISC::CEventChar( - ucstr[0], - NLMISC::noKeyButton, - eventEmitter)); - } - break; - } - case NSKeyUp: - { - // push the key release event to the event server - server.postEvent(new NLMISC::CEventKeyUp( - virtualKeycodeToNelKey([event keyCode]), - modifierFlagsToNelKeyButton([event modifierFlags]), - eventEmitter)); - break; - } - case NSFlagsChanged:break; - case NSAppKitDefined:break; - case NSSystemDefined:break; - case NSApplicationDefined:break; - case NSPeriodic:break; - case NSCursorUpdate:break; - case NSScrollWheel: - { - if(fabs(event.deltaY) > 0.1) - server.postEvent(new NLMISC::CEventMouseWheel( - mouseX, mouseY, (NLMISC::TMouseButton)modifiers, - (event.deltaY > 0), eventEmitter)); - - break; - } - case NSTabletPoint:break; - case NSTabletProximity:break; - case NSOtherMouseDown:break; - case NSOtherMouseUp:break; - case NSOtherMouseDragged:break; -#ifdef MAC_OS_X_VERSION_10_6 - case NSEventTypeGesture:break; - case NSEventTypeMagnify:break; - case NSEventTypeSwipe:break; - case NSEventTypeRotate:break; - case NSEventTypeBeginGesture:break; - case NSEventTypeEndGesture:break; -#endif // MAC_OS_X_VERSION_10_6 - default: - { - nlwarning("Unknown event type. dropping."); - // NSLog(@"%@", event); - break; - } - } - - [NSApp sendEvent:event]; - } -} - -}} +/* TODO remove this file */ diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp index 81225ab9a..86014e6cb 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp @@ -16,21 +16,397 @@ #include "cocoa_event_emitter.h" -#include "cocoa_adapter.h" +#include "nel/misc/event_server.h" +#include "nel/misc/events.h" +#include "nel/misc/game_device_events.h" + +#include +#import namespace NLMISC { -void CCocoaEventEmitter::submitEvents(CEventServer & server, bool allWindows) +/// map from virtual key code to nel internal key code +static NLMISC::TKey virtualKeycodeToNelKey(unsigned short keycode) { - // just forwarding to our cocoa adapter - NL3D::MAC::submitEvents(server, allWindows, this); + switch(keycode) + { + case kVK_ANSI_0: return NLMISC::Key0; + case kVK_ANSI_1: return NLMISC::Key1; + case kVK_ANSI_2: return NLMISC::Key2; + case kVK_ANSI_3: return NLMISC::Key3; + case kVK_ANSI_4: return NLMISC::Key4; + case kVK_ANSI_5: return NLMISC::Key5; + case kVK_ANSI_6: return NLMISC::Key6; + case kVK_ANSI_7: return NLMISC::Key7; + case kVK_ANSI_8: return NLMISC::Key8; + case kVK_ANSI_9: return NLMISC::Key9; + case kVK_ANSI_A: return NLMISC::KeyA; + case kVK_ANSI_B: return NLMISC::KeyB; + case kVK_ANSI_C: return NLMISC::KeyC; + case kVK_ANSI_D: return NLMISC::KeyD; + case kVK_ANSI_E: return NLMISC::KeyE; + case kVK_ANSI_F: return NLMISC::KeyF; + case kVK_ANSI_G: return NLMISC::KeyG; + case kVK_ANSI_H: return NLMISC::KeyH; + case kVK_ANSI_I: return NLMISC::KeyI; + case kVK_ANSI_J: return NLMISC::KeyJ; + case kVK_ANSI_K: return NLMISC::KeyK; + case kVK_ANSI_L: return NLMISC::KeyL; + case kVK_ANSI_M: return NLMISC::KeyM; + case kVK_ANSI_N: return NLMISC::KeyN; + case kVK_ANSI_O: return NLMISC::KeyO; + case kVK_ANSI_P: return NLMISC::KeyP; + case kVK_ANSI_Q: return NLMISC::KeyQ; + case kVK_ANSI_R: return NLMISC::KeyR; + case kVK_ANSI_S: return NLMISC::KeyS; + case kVK_ANSI_T: return NLMISC::KeyT; + case kVK_ANSI_U: return NLMISC::KeyU; + case kVK_ANSI_V: return NLMISC::KeyV; + case kVK_ANSI_W: return NLMISC::KeyW; + case kVK_ANSI_X: return NLMISC::KeyX; + case kVK_ANSI_Y: return NLMISC::KeyY; + case kVK_ANSI_Z: return NLMISC::KeyZ; + case kVK_ANSI_Equal: return NLMISC::KeyEQUALS; + case kVK_ANSI_Minus: return NLMISC::KeySUBTRACT; + case kVK_ANSI_RightBracket: return NLMISC::KeyRBRACKET; + case kVK_ANSI_LeftBracket: return NLMISC::KeyLBRACKET; + case kVK_ANSI_Quote: return NLMISC::KeyAPOSTROPHE; + case kVK_ANSI_Grave: return NLMISC::KeyPARAGRAPH; + case kVK_ANSI_Slash: return NLMISC::KeySLASH; + case kVK_ANSI_Backslash: return NLMISC::KeyBACKSLASH; + case kVK_ANSI_Comma: return NLMISC::KeyCOMMA; + case kVK_ANSI_Period: return NLMISC::KeyPERIOD; + case kVK_ANSI_Semicolon: return NLMISC::KeySEMICOLON; + case kVK_ANSI_KeypadDecimal: return NLMISC::KeyDECIMAL; + case kVK_ANSI_KeypadMultiply: return NLMISC::KeyMULTIPLY; + case kVK_ANSI_KeypadPlus: return NLMISC::KeyADD; + case kVK_ANSI_KeypadClear: return NLMISC::KeyDELETE; + case kVK_ANSI_KeypadDivide: return NLMISC::KeyDIVIDE; + case kVK_ANSI_KeypadEnter: return NLMISC::KeyRETURN; + case kVK_ANSI_KeypadMinus: return NLMISC::KeySUBTRACT; + case kVK_ANSI_KeypadEquals: return NLMISC::KeySEPARATOR; + case kVK_ANSI_Keypad0: return NLMISC::KeyNUMPAD0; + case kVK_ANSI_Keypad1: return NLMISC::KeyNUMPAD1; + case kVK_ANSI_Keypad2: return NLMISC::KeyNUMPAD2; + case kVK_ANSI_Keypad3: return NLMISC::KeyNUMPAD3; + case kVK_ANSI_Keypad4: return NLMISC::KeyNUMPAD4; + case kVK_ANSI_Keypad5: return NLMISC::KeyNUMPAD5; + case kVK_ANSI_Keypad6: return NLMISC::KeyNUMPAD6; + case kVK_ANSI_Keypad7: return NLMISC::KeyNUMPAD7; + case kVK_ANSI_Keypad8: return NLMISC::KeyNUMPAD8; + case kVK_ANSI_Keypad9: return NLMISC::KeyNUMPAD9; + case kVK_Return: return NLMISC::KeyRETURN; + case kVK_Tab: return NLMISC::KeyTAB; + case kVK_Space: return NLMISC::KeySPACE; + case kVK_Delete: return NLMISC::KeyBACK; + case kVK_ForwardDelete: return NLMISC::KeyDELETE; + case kVK_Escape: return NLMISC::KeyESCAPE; + case kVK_Shift: return NLMISC::KeySHIFT; + case kVK_RightShift: return NLMISC::KeyRSHIFT; + case kVK_CapsLock: return NLMISC::KeyCAPITAL; + case kVK_Control: return NLMISC::KeyCONTROL; + case kVK_RightControl: return NLMISC::KeyRCONTROL; + case kVK_F1: return NLMISC::KeyF1; + case kVK_F2: return NLMISC::KeyF2; + case kVK_F3: return NLMISC::KeyF3; + case kVK_F4: return NLMISC::KeyF4; + case kVK_F5: return NLMISC::KeyF5; + case kVK_F6: return NLMISC::KeyF6; + case kVK_F7: return NLMISC::KeyF7; + case kVK_F8: return NLMISC::KeyF8; + case kVK_F9: return NLMISC::KeyF9; + case kVK_F11: return NLMISC::KeyF11; + case kVK_F13: return NLMISC::KeyF13; + case kVK_F16: return NLMISC::KeyF16; + case kVK_F14: return NLMISC::KeyF14; + case kVK_F10: return NLMISC::KeyF10; + case kVK_F12: return NLMISC::KeyF12; + case kVK_F15: return NLMISC::KeyF15; + case kVK_F17: return NLMISC::KeyF17; + case kVK_F18: return NLMISC::KeyF18; + case kVK_F19: return NLMISC::KeyF19; + case kVK_F20: return NLMISC::KeyF20; + case kVK_Home: return NLMISC::KeyHOME; + case kVK_End: return NLMISC::KeyEND; + case kVK_PageUp: return NLMISC::KeyPRIOR; + case kVK_PageDown: return NLMISC::KeyNEXT; + case kVK_LeftArrow: return NLMISC::KeyLEFT; + case kVK_RightArrow: return NLMISC::KeyRIGHT; + case kVK_DownArrow: return NLMISC::KeyDOWN; + case kVK_UpArrow: return NLMISC::KeyUP; + case kVK_Command:break; + case kVK_Option:break; + case kVK_RightOption:break; + case kVK_Function:break; + case kVK_VolumeUp:break; + case kVK_VolumeDown:break; + case kVK_Mute:break; + case kVK_Help:break; + case kVK_ISO_Section:break; + case kVK_JIS_Yen:break; + case kVK_JIS_Underscore:break; + case kVK_JIS_KeypadComma:break; + case kVK_JIS_Eisu:break; + case kVK_JIS_Kana:break; + default:break; + } + return NLMISC::KeyNOKEY; +} + +/// convert modifier key state to nel internal modifier key state +static NLMISC::TKeyButton modifierFlagsToNelKeyButton(unsigned int modifierFlags) +{ + unsigned int buttons = 0; + if (modifierFlags & NSControlKeyMask) buttons |= NLMISC::ctrlKeyButton; + if (modifierFlags & NSShiftKeyMask) buttons |= NLMISC::shiftKeyButton; + if (modifierFlags & NSAlternateKeyMask) buttons |= NLMISC::altKeyButton; + return (NLMISC::TKeyButton)buttons; +} + +/// check whether a given event represents input text +static bool isTextKeyEvent(NSEvent* event) +{ + // if there are no characters provided with this event, it is not a text event + if([[event characters] length] == 0) + return false; + + NLMISC::TKey nelKey = virtualKeycodeToNelKey([event keyCode]); + + // ryzom ui wants to have "escape key string" to leave text box + if(nelKey == NLMISC::KeyESCAPE) + return true; + + // ryzom ui wants to have "return key string" to submit text box (send chat) + if(nelKey == NLMISC::KeyRETURN) + return true; + + // get the character reported by cocoa + unsigned int character = [[event characters] characterAtIndex:0]; + + // printable ascii characters + if(isprint(character)) + return true; + + /* + TODO check why iswprint(character) does not solve it. + it always returns false, even for π, é, ... + */ + // characters > 127 but not printable + if( nelKey == NLMISC::KeyF1 || nelKey == NLMISC::KeyF2 || + nelKey == NLMISC::KeyF3 || nelKey == NLMISC::KeyF4 || + nelKey == NLMISC::KeyF5 || nelKey == NLMISC::KeyF6 || + nelKey == NLMISC::KeyF7 || nelKey == NLMISC::KeyF8 || + nelKey == NLMISC::KeyF9 || nelKey == NLMISC::KeyF10 || + nelKey == NLMISC::KeyF11 || nelKey == NLMISC::KeyF12 || + nelKey == NLMISC::KeyF13 || nelKey == NLMISC::KeyF14 || + nelKey == NLMISC::KeyF15 || nelKey == NLMISC::KeyF16 || + nelKey == NLMISC::KeyF17 || nelKey == NLMISC::KeyF18 || + nelKey == NLMISC::KeyF19 || nelKey == NLMISC::KeyF20 || + nelKey == NLMISC::KeyUP || nelKey == NLMISC::KeyDOWN || + nelKey == NLMISC::KeyLEFT || nelKey == NLMISC::KeyRIGHT || + nelKey == NLMISC::KeyHOME || nelKey == NLMISC::KeyEND || + nelKey == NLMISC::KeyPRIOR || nelKey == NLMISC::KeyNEXT || + nelKey == NLMISC::KeyDELETE) + return false; + + // all the fancy wide characters + if(character > 127) + return true; + + return false; +} + +void CCocoaEventEmitter::submitEvents(CEventServer& server, bool /* allWins */) +{ + // break if there was no event to handle + while(true) + { + // get the next event to handle + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil /*[NSDate distantFuture]*/ + inMode:NSDefaultRunLoopMode dequeue:YES]; + + // stop, if there was no event + if(!event) + break; + + NSView* glView = [[[[event window] contentView] subviews] lastObject]; + NSRect viewRect = [glView frame]; + + // TODO this code assumes, that the view fills the window + // convert the mouse position to NeL style (relative) + float mouseX = event.locationInWindow.x / (float)viewRect.size.width; + float mouseY = event.locationInWindow.y / (float)viewRect.size.height; + + // if the mouse event was placed outside the view, don't tell NeL :) + if((mouseX < 0.0 || mouseX > 1.0 || mouseY < 0.0 || mouseY > 1.0) && + event.type != NSKeyDown && event.type != NSKeyUp) + { + [NSApp sendEvent:event]; + continue; + } + + // convert the modifiers for nel to pass them with the events + NLMISC::TKeyButton modifiers = + modifierFlagsToNelKeyButton([event modifierFlags]); + + switch(event.type) + { + case NSLeftMouseDown: + { + server.postEvent(new NLMISC::CEventMouseDown( + mouseX, mouseY, + (NLMISC::TMouseButton)(NLMISC::leftButton | modifiers), this)); + } + break; + case NSLeftMouseUp: + { + server.postEvent(new NLMISC::CEventMouseUp( + mouseX, mouseY, + (NLMISC::TMouseButton)(NLMISC::leftButton | modifiers), this)); + break; + } + case NSRightMouseDown: + { + server.postEvent(new NLMISC::CEventMouseDown( + mouseX, mouseY, + (NLMISC::TMouseButton)(NLMISC::rightButton | modifiers), this)); + break; + } + case NSRightMouseUp: + { + server.postEvent(new NLMISC::CEventMouseUp( + mouseX, mouseY, + (NLMISC::TMouseButton)(NLMISC::rightButton | modifiers), this)); + break; + } + case NSMouseMoved: + { + NLMISC::CEvent* nelEvent; + + // when emulating raw mode, send the delta in a CGDMouseMove event + if(_emulateRawMode) + nelEvent = new NLMISC::CGDMouseMove( + this, NULL /* no mouse device */, event.deltaX, -event.deltaY); + + // normally send position in a CEventMouseMove + else + nelEvent = new NLMISC::CEventMouseMove( + mouseX, mouseY, (NLMISC::TMouseButton)modifiers, this); + + server.postEvent(nelEvent); + break; + } + case NSLeftMouseDragged: + { + NLMISC::CEvent* nelEvent; + + // when emulating raw mode, send the delta in a CGDMouseMove event + if(_emulateRawMode) + nelEvent = new NLMISC::CGDMouseMove( + this, NULL /* no mouse device */, event.deltaX, -event.deltaY); + + // normally send position in a CEventMouseMove + else + nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY, + (NLMISC::TMouseButton)(NLMISC::leftButton | modifiers), this); + + server.postEvent(nelEvent); + break; + } + case NSRightMouseDragged: + { + NLMISC::CEvent* nelEvent; + + // when emulating raw mode, send the delta in a CGDMouseMove event + if(_emulateRawMode) + nelEvent = new NLMISC::CGDMouseMove( + this, NULL /* no mouse device */, event.deltaX, -event.deltaY); + + // normally send position in a CEventMouseMove + else + nelEvent = new NLMISC::CEventMouseMove(mouseX, mouseY, + (NLMISC::TMouseButton)(NLMISC::rightButton | modifiers), this); + + server.postEvent(nelEvent); + break; + } + case NSMouseEntered:break; + case NSMouseExited:break; + case NSKeyDown: + { + // push the key press event to the event server + server.postEvent(new NLMISC::CEventKeyDown( + virtualKeycodeToNelKey([event keyCode]), + modifierFlagsToNelKeyButton([event modifierFlags]), + [event isARepeat] == NO, this)); + + // if this was a text event + if(isTextKeyEvent(event)) + { + ucstring ucstr; + + // get the string associated with the key press event + ucstr.fromUtf8([[event characters] UTF8String]); + + // push the text event to event server as well + server.postEvent(new NLMISC::CEventChar( + ucstr[0], NLMISC::noKeyButton, this)); + } + break; + } + case NSKeyUp: + { + // push the key release event to the event server + server.postEvent(new NLMISC::CEventKeyUp( + virtualKeycodeToNelKey([event keyCode]), + modifierFlagsToNelKeyButton([event modifierFlags]), this)); + break; + } + case NSFlagsChanged:break; + case NSAppKitDefined:break; + case NSSystemDefined:break; + case NSApplicationDefined:break; + case NSPeriodic:break; + case NSCursorUpdate:break; + case NSScrollWheel: + { + if(fabs(event.deltaY) > 0.1) + server.postEvent(new NLMISC::CEventMouseWheel( + mouseX, mouseY, (NLMISC::TMouseButton)modifiers, + (event.deltaY > 0), this)); + + break; + } + case NSTabletPoint:break; + case NSTabletProximity:break; + case NSOtherMouseDown:break; + case NSOtherMouseUp:break; + case NSOtherMouseDragged:break; +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + case NSEventTypeGesture:break; + case NSEventTypeMagnify:break; + case NSEventTypeSwipe:break; + case NSEventTypeRotate:break; + case NSEventTypeBeginGesture:break; + case NSEventTypeEndGesture:break; +#endif // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER + default: + { + nlwarning("Unknown event type. dropping."); + // NSLog(@"%@", event); + break; + } + } + + [NSApp sendEvent:event]; + } } void CCocoaEventEmitter::emulateMouseRawMode(bool enable) { - // just forwarding to our cocoa adapter - NL3D::MAC::emulateMouseRawMode(enable); + _emulateRawMode = enable; } } diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h index b31272b8f..72bfbb718 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h @@ -24,7 +24,11 @@ namespace NLMISC class CCocoaEventEmitter : public IEventEmitter { + bool _emulateRawMode; + public: + CCocoaEventEmitter() : _emulateRawMode(false) { } + virtual void submitEvents(CEventServer & server, bool allWindows); virtual void emulateMouseRawMode(bool enable); }; diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.h b/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.h index 11bb87cc7..1a4bc76f0 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.h +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.h @@ -18,9 +18,6 @@ #import -/** - * derived to configure the NSOpenGLView - */ @interface CocoaOpenGLView : NSOpenGLView { NSMutableAttributedString* characterStorage; diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m b/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m index 1510b2eb8..cc0a83800 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m @@ -18,15 +18,11 @@ #import "cocoa_opengl_view.h" -#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) - #define NL_USE_MAC_10_6_API 1 -#endif - @implementation CocoaOpenGLView -(id)initWithFrame:(NSRect)frame { - if(self = [super initWithFrame:frame]) + if((self = [super initWithFrame:frame])) { characterStorage = [[NSMutableAttributedString alloc] initWithString:@""]; return self; @@ -42,9 +38,9 @@ -(void)keyDown:(NSEvent*)event { -#ifdef NL_USE_MAC_10_6_API +#ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER [[self inputContext] handleEvent:event]; -#endif // NL_USE_MAC_10_6_API +#endif // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER } /******************************************************************************/ @@ -80,7 +76,8 @@ else { markedRange = NSMakeRange(replacementRange.location, [aString length]); - [characterStorage replaceCharactersInRange:replacementRange withString:aString]; + [characterStorage replaceCharactersInRange:replacementRange + withString:aString]; } } @@ -108,7 +105,8 @@ if(replacementRange.location == NSNotFound) replacementRange = markedRange; - [characterStorage replaceCharactersInRange:replacementRange withString:aString]; + [characterStorage replaceCharactersInRange:replacementRange + withString:aString]; } -(NSUInteger)characterIndexForPoint:(NSPoint)aPoint