From da967da9c7aa0d88f478d476e8bb059ba79ca818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 11:32:15 +0100 Subject: Rename OS X to macOS, mostly in comments We only support 10.13+ now, and it's been called macOS since 10.12. References in code to older versions are unchanged. --- indra/llwindow/llwindowmacosx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llwindow/llwindowmacosx.cpp') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 778e5d3898..b317f00ae7 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1249,7 +1249,7 @@ F32 LLWindowMacOSX::getNativeAspectRatio() F32 LLWindowMacOSX::getPixelAspectRatio() { - //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode + //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode return 1.f; } @@ -1281,7 +1281,7 @@ void LLWindowMacOSX::afterDialog() void LLWindowMacOSX::flashIcon(F32 seconds) { - // For consistency with OS X conventions, the number of seconds given is ignored and + // For consistency with macOS conventions, the number of seconds given is ignored and // left up to the OS (which will actually bounce it for one second). requestUserAttention(); } -- cgit v1.2.3 From a2971d84d5aba0c2dcda9ec8274a5c5b72ccd67c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 14 Feb 2024 02:46:24 +0200 Subject: Viewer#779 Make RenderMaxVRAMBudget more consistent --- indra/llwindow/llwindowmacosx.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'indra/llwindow/llwindowmacosx.cpp') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index b317f00ae7..9f71b80e74 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -115,8 +115,10 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, - U32 fsaa_samples) + U32 fsaa_samples, + U32 max_vram) : LLWindow(NULL, fullscreen, flags) + , mMaxVRAM(max_vram) { // *HACK: During window construction we get lots of OS events for window // reshape, activate, etc. that the viewer isn't ready to handle. @@ -1260,7 +1262,12 @@ U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { static const U32 mb = 1024*1024; // We're asked for total available gpu memory, but we only have allocation info on texture usage. So estimate by doubling that. static const U32 total_factor = 2; // estimated total/textures - return gGLManager.mVRAM - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); + U32 total_vram = gGLManager.mVRAM; + if (mMaxVRAM) + { + total_vram = llmin(mMaxVRAM, total_vram); + } + return total_vram - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); } //static SInt32 oldWindowLevel; -- cgit v1.2.3 From c285f59ce2a05703e3a1232fcaf3ee3aea714b3f Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 18 Feb 2024 12:52:19 +0100 Subject: Replace BOOL with bool in llwindow and dependent classes --- indra/llwindow/llwindowmacosx.cpp | 200 +++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 100 deletions(-) (limited to 'indra/llwindow/llwindowmacosx.cpp') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 9f71b80e74..bfa893fff8 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -43,8 +43,8 @@ #include #include -extern BOOL gDebugWindowProc; -BOOL gHiDPISupport = TRUE; +extern bool gDebugWindowProc; +bool gHiDPISupport = true; const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; @@ -59,11 +59,11 @@ namespace // LLWindowMacOSX // -BOOL LLWindowMacOSX::sUseMultGL = FALSE; +bool LLWindowMacOSX::sUseMultGL = false; // Cross-platform bits: -BOOL check_for_card(const char* RENDERER, const char* bad_card) +bool check_for_card(const char* RENDERER, const char* bad_card) { if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) { @@ -84,15 +84,15 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card) S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); if (OSBTN_YES == button) { - return FALSE; + return false; } else { - return TRUE; + return true; } } - return FALSE; + return false; } // Switch to determine whether we capture all displays, or just the main one. @@ -112,9 +112,9 @@ static LLWindowMacOSX *gWindowImplementation = NULL; LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_vram) : LLWindow(NULL, fullscreen, flags) @@ -138,21 +138,21 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mContext = NULL; mPixelFormat = NULL; mDisplay = CGMainDisplayID(); - mSimulatedRightClick = FALSE; + mSimulatedRightClick = false; mLastModifiers = 0; - mHandsOffEvents = FALSE; - mCursorDecoupled = FALSE; + mHandsOffEvents = false; + mCursorDecoupled = false; mCursorLastEventDeltaX = 0; mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - mNeedsResize = FALSE; + mCursorIgnoreNextDelta = false; + mNeedsResize = false; mOverrideAspectRatio = 0.f; - mMaximized = FALSE; - mMinimized = FALSE; - mLanguageTextInputAllowed = FALSE; + mMaximized = false; + mMinimized = false; + mLanguageTextInputAllowed = false; mPreeditor = NULL; mFSAASamples = fsaa_samples; - mForceRebuild = FALSE; + mForceRebuild = false; // Get the original aspect ratio of the main device. mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); @@ -192,7 +192,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, initCursors(); setCursor( UI_CURSOR_ARROW ); - allowLanguageTextInput(NULL, FALSE); + allowLanguageTextInput(NULL, false); } mCallbacks = callbacks; @@ -281,7 +281,7 @@ void callRightMouseDown(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callRightMouseUp(float *pos, MASK mask) @@ -294,7 +294,7 @@ void callRightMouseUp(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callLeftMouseDown(float *pos, MASK mask) @@ -307,7 +307,7 @@ void callLeftMouseDown(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callLeftMouseUp(float *pos, MASK mask) @@ -320,7 +320,7 @@ void callLeftMouseUp(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } @@ -334,7 +334,7 @@ void callDoubleClick(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callResize(unsigned int width, unsigned int height) @@ -354,7 +354,7 @@ void callMouseMoved(float *pos, MASK mask) gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); } @@ -367,7 +367,7 @@ void callMouseDragged(float *pos, MASK mask) gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callScrollMoved(float deltaX, float deltaY) @@ -609,7 +609,7 @@ void LLWindowMacOSX::updateMouseDeltas(float* deltas) { mCursorLastEventDeltaX = 0; mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; + mCursorIgnoreNextDelta = false; } } else { mCursorLastEventDeltaX = 0; @@ -623,7 +623,7 @@ void LLWindowMacOSX::getMouseDeltas(float* delta) delta[1] = mCursorLastEventDeltaY; } -BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync) +bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { mFullscreen = fullscreen; @@ -682,7 +682,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if (err != kCGLNoError) { setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return FALSE; + return false; } } @@ -715,15 +715,15 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits } makeFirstResponder(mWindow, mGLView); - return TRUE; + return true; } // We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. // This makes this method obsolete. -BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp) +bool LLWindowMacOSX::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) { - return FALSE; + return false; } void LLWindowMacOSX::destroyContext() @@ -793,13 +793,13 @@ void LLWindowMacOSX::show() void LLWindowMacOSX::hide() { - setMouseClipping(FALSE); + setMouseClipping(false); } //virtual void LLWindowMacOSX::minimize() { - setMouseClipping(FALSE); + setMouseClipping(false); showCursor(); } @@ -821,48 +821,48 @@ void LLWindowMacOSX::close() // } // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(FALSE); + setMouseClipping(false); showCursor(); destroyContext(); } -BOOL LLWindowMacOSX::isValid() +bool LLWindowMacOSX::isValid() { if(mFullscreen) { - return(TRUE); + return(true); } return (mWindow != NULL); } -BOOL LLWindowMacOSX::getVisible() +bool LLWindowMacOSX::getVisible() { - BOOL result = FALSE; + bool result = false; if(mFullscreen) { - result = TRUE; + result = true; }if (mWindow) { - result = TRUE; + result = true; } return(result); } -BOOL LLWindowMacOSX::getMinimized() +bool LLWindowMacOSX::getMinimized() { return mMinimized; } -BOOL LLWindowMacOSX::getMaximized() +bool LLWindowMacOSX::getMaximized() { return mMaximized; } -BOOL LLWindowMacOSX::maximize() +bool LLWindowMacOSX::maximize() { if (mWindow && !mMaximized) { @@ -871,7 +871,7 @@ BOOL LLWindowMacOSX::maximize() return mMaximized; } -BOOL LLWindowMacOSX::getFullscreen() +bool LLWindowMacOSX::getFullscreen() { return mFullscreen; } @@ -881,7 +881,7 @@ void LLWindowMacOSX::gatherInput() updateCursor(); } -BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) +bool LLWindowMacOSX::getPosition(LLCoordScreen *position) { S32 err = -1; @@ -908,7 +908,7 @@ BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) return (err == noErr); } -BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) +bool LLWindowMacOSX::getSize(LLCoordScreen *size) { S32 err = -1; @@ -934,7 +934,7 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) return (err == noErr); } -BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) +bool LLWindowMacOSX::getSize(LLCoordWindow *size) { S32 err = -1; @@ -962,7 +962,7 @@ BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) return (err == noErr); } -BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) +bool LLWindowMacOSX::setPosition(const LLCoordScreen position) { if(mWindow) { @@ -970,32 +970,32 @@ BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) setWindowPos(mWindow, pos); } - return TRUE; + return true; } -BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) +bool LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) { if(mWindow) { LLCoordWindow to; convertCoords(size, &to); setWindowSize(mWindow, to.mX, to.mY); - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) +bool LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) { if (mWindow) { const int titlePadding = 22; setWindowSize(mWindow, size.mX, size.mY + titlePadding); - return TRUE; + return true; } - return FALSE; + return false; } void LLWindowMacOSX::swapBuffers() @@ -1050,16 +1050,16 @@ U32 LLWindowMacOSX::getFSAASamples() void LLWindowMacOSX::setFSAASamples(const U32 samples) { mFSAASamples = samples; - mForceRebuild = TRUE; + mForceRebuild = true; } -BOOL LLWindowMacOSX::restoreGamma() +bool LLWindowMacOSX::restoreGamma() { CGDisplayRestoreColorSyncSettings(); return true; } -BOOL LLWindowMacOSX::setGamma(const F32 gamma) +bool LLWindowMacOSX::setGamma(const F32 gamma) { CGGammaValue redMin; CGGammaValue redMax; @@ -1107,7 +1107,7 @@ BOOL LLWindowMacOSX::setGamma(const F32 gamma) return true; } -BOOL LLWindowMacOSX::isCursorHidden() +bool LLWindowMacOSX::isCursorHidden() { return mCursorHidden; } @@ -1115,31 +1115,31 @@ BOOL LLWindowMacOSX::isCursorHidden() // Constrains the mouse to the window. -void LLWindowMacOSX::setMouseClipping( BOOL b ) +void LLWindowMacOSX::setMouseClipping( bool b ) { // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. mIsMouseClipping = b; if(b) { - // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; + // LL_INFOS() << "setMouseClipping(true)" << LL_ENDL; } else { - // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; + // LL_INFOS() << "setMouseClipping(false)" << LL_ENDL; } adjustCursorDecouple(); } -BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) +bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) { - BOOL result = FALSE; + bool result = false; LLCoordScreen screen_pos; if (!convertCoords(position, &screen_pos)) { - return FALSE; + return false; } CGPoint newPosition; @@ -1152,7 +1152,7 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) CGSetLocalEventsSuppressionInterval(0.0); if(CGWarpMouseCursorPosition(newPosition) == noErr) { - result = TRUE; + result = true; } // Under certain circumstances, this will trigger us to decouple the cursor. @@ -1169,13 +1169,13 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) return result; } -BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) +bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) { float cursor_point[2]; LLCoordScreen screen_pos; if(mWindow == NULL) - return FALSE; + return false; getCursorPos(mWindow, cursor_point); @@ -1198,7 +1198,7 @@ BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) position->mX = cursor_point[0] * scale; position->mY = cursor_point[1] * scale; - return TRUE; + return true; } void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) @@ -1213,7 +1213,7 @@ void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; CGAssociateMouseAndMouseCursorPosition(false); mCursorDecoupled = true; - mCursorIgnoreNextDelta = TRUE; + mCursorIgnoreNextDelta = true; } } } @@ -1293,12 +1293,12 @@ void LLWindowMacOSX::flashIcon(F32 seconds) requestUserAttention(); } -BOOL LLWindowMacOSX::isClipboardTextAvailable() +bool LLWindowMacOSX::isClipboardTextAvailable() { return pasteBoardAvailable(); } -BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) +bool LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) { unsigned short* pboard_data = copyFromPBoard(); // must free returned data llutf16string str(pboard_data); @@ -1313,9 +1313,9 @@ BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) } } -BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) +bool LLWindowMacOSX::copyTextToClipboard(const LLWString &s) { - BOOL result = false; + bool result = false; llutf16string utf16str = wstring_to_utf16str(s); result = copyToPBoard(utf16str.data(), utf16str.length()); @@ -1325,7 +1325,7 @@ BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) // protected -BOOL LLWindowMacOSX::resetDisplayResolution() +bool LLWindowMacOSX::resetDisplayResolution() { // This is only called from elsewhere in this class, and it's not used by the Mac implementation. return true; @@ -1358,13 +1358,13 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) { - BOOL resolution_exists = FALSE; + bool resolution_exists = false; for(S32 i = 0; i < mNumSupportedResolutions; i++) { if (mSupportedResolutions[i].mWidth == width && mSupportedResolutions[i].mHeight == height) { - resolution_exists = TRUE; + resolution_exists = true; } } if (!resolution_exists) @@ -1383,21 +1383,21 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r return mSupportedResolutions; } -BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) { to->mX = from.mX; to->mY = from.mY; - return TRUE; + return true; } -BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) { to->mX = from.mX; to->mY = from.mY; - return TRUE; + return true; } -BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) { if(mWindow) { @@ -1411,12 +1411,12 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) to->mX = mouse_point[0]; to->mY = mouse_point[1]; - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) { if(mWindow) { @@ -1430,19 +1430,19 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) to->mX = mouse_point[0]; to->mY = mouse_point[1]; - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) { LLCoordWindow window_coord; return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } -BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) { LLCoordWindow window_coord; @@ -1704,8 +1704,8 @@ void LLWindowMacOSX::hideCursor() if(!mCursorHidden) { // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; + mCursorHidden = true; + mHideCursorPermanent = true; hideNSCursor(); } else @@ -1721,8 +1721,8 @@ void LLWindowMacOSX::showCursor() if(mCursorHidden || !isCGCursorVisible()) { // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; + mCursorHidden = false; + mHideCursorPermanent = false; showNSCursor(); } else @@ -1746,7 +1746,7 @@ void LLWindowMacOSX::hideCursorUntilMouseMove() if (!mHideCursorPermanent) { hideCursor(); - mHideCursorPermanent = FALSE; + mHideCursorPermanent = false; } } @@ -1867,9 +1867,9 @@ LLSD LLWindowMacOSX::getNativeKeyData() return result; } -BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) +bool LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - BOOL retval = FALSE; + bool retval = false; OSErr error = noErr; NColorPickerInfo info; @@ -1926,12 +1926,12 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key) return int_value; // otherwise return the long value } -void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) +void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, bool b) { if (preeditor != mPreeditor && !b) { // This condition may occur by a call to - // setEnabled(BOOL) against LLTextEditor or LLLineEditor + // setEnabled(bool) against LLTextEditor or LLLineEditor // when the control is not focused. // We need to silently ignore the case so that // the language input status of the focused control -- cgit v1.2.3 From ea268fcd48550f98baceef0294fd977ff12d2b35 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 6 May 2024 22:48:24 +0300 Subject: viewer#799 getAvailableVRAMMegabytes cleanup --- indra/llwindow/llwindowmacosx.cpp | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'indra/llwindow/llwindowmacosx.cpp') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index bfa893fff8..73230805b4 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -118,7 +118,6 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, U32 fsaa_samples, U32 max_vram) : LLWindow(NULL, fullscreen, flags) - , mMaxVRAM(max_vram) { // *HACK: During window construction we get lots of OS events for window // reshape, activate, etc. that the viewer isn't ready to handle. @@ -1255,21 +1254,6 @@ F32 LLWindowMacOSX::getPixelAspectRatio() return 1.f; } -U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { - // MTL (and MoltenVK) has some additional gpu data, such as recommendedMaxWorkingSetSize and currentAllocatedSize. - // But these are not available for OpenGL and/or our current mimimum OS version. - // So we will estimate. - static const U32 mb = 1024*1024; - // We're asked for total available gpu memory, but we only have allocation info on texture usage. So estimate by doubling that. - static const U32 total_factor = 2; // estimated total/textures - U32 total_vram = gGLManager.mVRAM; - if (mMaxVRAM) - { - total_vram = llmin(mMaxVRAM, total_vram); - } - return total_vram - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); -} - //static SInt32 oldWindowLevel; // MBW -- XXX -- There's got to be a better way than this. Find it, please... -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/llwindow/llwindowmacosx.cpp | 5324 ++++++++++++++++++------------------- 1 file changed, 2662 insertions(+), 2662 deletions(-) (limited to 'indra/llwindow/llwindowmacosx.cpp') diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index fee74a9c25..cd00f4d33c 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1,2662 +1,2662 @@ -/** - * @file llwindowmacosx.cpp - * @brief Platform-dependent implementation of llwindow - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llwindowmacosx.h" - -#include "llkeyboardmacosx.h" -#include "llwindowcallbacks.h" -#include "llpreeditor.h" - -#include "llerror.h" -#include "llgl.h" -#include "llstring.h" -#include "lldir.h" -#include "indra_constants.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -extern bool gDebugWindowProc; -bool gHiDPISupport = true; - -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; - -const S32 DEFAULT_REFRESH_RATE = 60; - -namespace -{ - NSKeyEventRef mRawKeyEvent = NULL; -} -// -// LLWindowMacOSX -// - -bool LLWindowMacOSX::sUseMultGL = false; - -// Cross-platform bits: - -bool check_for_card(const char* RENDERER, const char* bad_card) -{ - if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) - { - std::string buffer = llformat( - "Your video card appears to be a %s, which Second Life does not support.\n" - "\n" - "Second Life requires a video card with 32 Mb of memory or more, as well as\n" - "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" - "and ATI Radeon 8500 or better.\n" - "\n" - "If you own a supported card and continue to receive this message, try \n" - "updating to the latest video card drivers. Otherwise look in the\n" - "secondlife.com support section or e-mail technical support\n" - "\n" - "You can try to run Second Life, but it will probably crash or run\n" - "very slowly. Try anyway?", - bad_card); - S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); - if (OSBTN_YES == button) - { - return false; - } - else - { - return true; - } - } - - return false; -} - -// Switch to determine whether we capture all displays, or just the main one. -// We may want to base this on the setting of _DEBUG... - -#define CAPTURE_ALL_DISPLAYS 0 -//static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); -static long getDictLong (CFDictionaryRef refDict, CFStringRef key); - -// MBW -- HACK ALERT -// On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. -// The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these -// require a pointer to the LLWindowMacOSX object. Stash it here and maintain in the constructor and destructor. -// This assumes that there will be only one object of this class at any time. Hopefully this is true. -static LLWindowMacOSX *gWindowImplementation = NULL; - -LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - bool fullscreen, bool clearBg, - bool enable_vsync, bool use_gl, - bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_vram) - : LLWindow(NULL, fullscreen, flags) -{ - // *HACK: During window construction we get lots of OS events for window - // reshape, activate, etc. that the viewer isn't ready to handle. - // Route them to a dummy callback structure until the end of constructor. - LLWindowCallbacks null_callbacks; - mCallbacks = &null_callbacks; - - // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). - setupCocoa(); - - // Initialize the keyboard - gKeyboard = new LLKeyboardMacOSX(); - gKeyboard->setCallbacks(callbacks); - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mContext = NULL; - mPixelFormat = NULL; - mDisplay = CGMainDisplayID(); - mSimulatedRightClick = false; - mLastModifiers = 0; - mHandsOffEvents = false; - mCursorDecoupled = false; - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = false; - mNeedsResize = false; - mOverrideAspectRatio = 0.f; - mMaximized = false; - mMinimized = false; - mLanguageTextInputAllowed = false; - mPreeditor = NULL; - mFSAASamples = fsaa_samples; - mForceRebuild = false; - - // Get the original aspect ratio of the main device. - mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); - - // Stash the window title - mWindowTitle = title; - //mWindowTitle[0] = title.length(); - - mDragOverrideCursor = -1; - - // Set up global event handlers (the fullscreen case needs this) - //InstallStandardEventHandler(GetApplicationEventTarget()); - - // Stash an object pointer for OSMessageBox() - gWindowImplementation = this; - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) - { - if(mWindow != NULL) - { - makeWindowOrderFront(mWindow); - } - - if (!gGLManager.initGL()) - { - setupFailure( - "Second Life is unable to run because your video card drivers\n" - "are out of date or unsupported. Please make sure you have\n" - "the latest video card drivers installed.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - - allowLanguageTextInput(NULL, false); - } - - mCallbacks = callbacks; - stop_glerror(); - - -} - -// These functions are used as wrappers for our internal event handling callbacks. -// It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow. - -bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) -{ - mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyUp(key, mask); - mRawKeyEvent = NULL; - return retVal; -} - -bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) -{ - //if (mask!=MASK_NONE) - { - if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) - { - key = gKeyboard->inverseTranslateKey('Y'); - } - else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) - { - key = gKeyboard->inverseTranslateKey('Z'); - } - } - - mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyDown(key, mask); - mRawKeyEvent = NULL; - return retVal; -} - -void callResetKeys() -{ - gKeyboard->resetKeys(); -} - -bool callUnicodeCallback(wchar_t character, unsigned int mask) -{ - NativeKeyEventData eventData; - - memset(&eventData, 0, sizeof(NativeKeyEventData)); - - eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; - eventData.mEventType = 0; - eventData.mEventModifiers = mask; - eventData.mEventKeyCode = 0; - eventData.mEventChars = character; - eventData.mEventUnmodChars = character; - eventData.mEventRepeat = false; - - mRawKeyEvent = &eventData; - - bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); - mRawKeyEvent = NULL; - return result; -} - -void callFocus() -{ - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); - } -} - -void callFocusLost() -{ - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } -} - -void callRightMouseDown(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callRightMouseUp(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callLeftMouseDown(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callLeftMouseUp(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); - -} - -void callDoubleClick(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callResize(unsigned int width, unsigned int height) -{ - if (gWindowImplementation != NULL) - { - gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); - } -} - -void callMouseMoved(float *pos, MASK mask) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); - //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); -} - -void callMouseDragged(float *pos, MASK mask) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callScrollMoved(float deltaX, float deltaY) -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); - } -} - -void callMouseExit() -{ - gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); -} - -void callWindowFocus() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); - } - else - { - LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; - } - - -} - -void callWindowUnfocus() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } -} - -void callWindowHide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); - } -} - -void callWindowUnhide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); - } -} - -void callWindowDidChangeScreen() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); - } -} - -void callDeltaUpdate(float *delta, MASK mask) -{ - gWindowImplementation->updateMouseDeltas(delta); -} - -void callOtherMouseDown(float *pos, MASK mask, int button) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - - if (button == 2) - { - gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); - } - else - { - gWindowImplementation->getCallbacks()->handleOtherMouseDown(gWindowImplementation, outCoords, mask, button + 1); - } -} - -void callOtherMouseUp(float *pos, MASK mask, int button) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - if (button == 2) - { - gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); - } - else - { - gWindowImplementation->getCallbacks()->handleOtherMouseUp(gWindowImplementation, outCoords, mask, button + 1); - } -} - -void callModifier(MASK mask) -{ - gKeyboard->handleModifier(mask); -} - -void callHandleDragEntered(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); -} - -void callHandleDragExited(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); -} - -void callHandleDragUpdated(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); -} - -void callHandleDragDropped(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); -} - -void callQuitHandler() -{ - if (gWindowImplementation) - { - if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) - { - gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); - } - } -} - -void getPreeditSelectionRange(int *position, int *length) -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getSelectionRange(position, length); - } -} - -void getPreeditMarkedRange(int *position, int *length) -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getPreeditRange(position, length); - } -} - -void setPreeditMarkedRange(int position, int length) -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->markAsPreedit(position, length); - } -} - -bool handleUnicodeCharacter(wchar_t c) -{ - bool success = false; - if (gWindowImplementation->getPreeditor()) - { - success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); - } - - return success; -} - -void resetPreedit() -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->resetPreedit(); - } -} - -// For reasons of convenience, handle IME updates here. -// This largely mirrors the old implementation, only sans the carbon parameters. -void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments) -{ - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - preeditor->resetPreedit(); - // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. - if (replacementRange[0] < replacementRange[1]) - { - const LLWString& text = preeditor->getPreeditString(); - const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); - const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); - preeditor->markAsPreedit(location, length); - } - - LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); - - S32 caret_position = fix_str.length(); - - preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); - } -} - -void getPreeditLocation(float *location, unsigned int length) -{ - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - LLCoordGL coord; - LLCoordScreen screen; - LLRect rect; - - preeditor->getPreeditLocation(length, &coord, &rect, NULL); - - float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; - - convertRectToScreen(gWindowImplementation->getWindow(), c); - - location[0] = c[0]; - location[1] = c[1]; - } -} - -void LLWindowMacOSX::updateMouseDeltas(float* deltas) -{ - if (mCursorDecoupled) - { - mCursorLastEventDeltaX = ll_round(deltas[0]); - mCursorLastEventDeltaY = ll_round(-deltas[1]); - - if (mCursorIgnoreNextDelta) - { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = false; - } - } else { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - } -} - -void LLWindowMacOSX::getMouseDeltas(float* delta) -{ - delta[0] = mCursorLastEventDeltaX; - delta[1] = mCursorLastEventDeltaY; -} - -bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) -{ - mFullscreen = fullscreen; - - if (mWindow == NULL) - { - mWindow = getMainAppWindow(); - } - - if(mContext == NULL) - { - // Our OpenGL view is already defined within SecondLife.xib. - // Get the view instead. - mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); - mContext = getCGLContextObj(mGLView); - gGLManager.mVRAM = getVramSize(mGLView); - - if(!mPixelFormat) - { - CGLPixelFormatAttribute attribs[] = - { - kCGLPFANoRecovery, - kCGLPFADoubleBuffer, - kCGLPFAClosestPolicy, - kCGLPFAAccelerated, - kCGLPFAMultisample, - kCGLPFASampleBuffers, static_cast((mFSAASamples > 0 ? 1 : 0)), - kCGLPFASamples, static_cast(mFSAASamples), - kCGLPFAStencilSize, static_cast(8), - kCGLPFADepthSize, static_cast(24), - kCGLPFAAlphaSize, static_cast(8), - kCGLPFAColorSize, static_cast(24), - kCGLPFAOpenGLProfile, static_cast(kCGLOGLPVersion_GL4_Core), - static_cast(0) - }; - - GLint numPixelFormats; - CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); - - if(mPixelFormat == NULL) { - CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); - } - } - - } - - // This sets up our view to recieve text from our non-inline text input window. - setupInputWindow(mWindow, mGLView); - - // Hook up the context to a drawable - - if(mContext != NULL) - { - - - U32 err = CGLSetCurrentContext(mContext); - if (err != kCGLNoError) - { - setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return false; - } - } - - mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); - if(mRefreshRate == 0) - { - //consider adding more appropriate fallback later - mRefreshRate = DEFAULT_REFRESH_RATE; - } - - // Disable vertical sync for swap - toggleVSync(enable_vsync); - - //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); - - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - makeFirstResponder(mWindow, mGLView); - - return true; -} - - -// We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. -// This makes this method obsolete. -bool LLWindowMacOSX::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) -{ - return false; -} - -void LLWindowMacOSX::destroyContext() -{ - if (!mContext) - { - // We don't have a context - return; - } - // Unhook the GL context from any drawable it may have - if(mContext != NULL) - { - LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; - CGLSetCurrentContext(NULL); - } - - // Clean up remaining GL state before blowing away window - gGLManager.shutdownGL(); - - // Clean up the pixel format - if(mPixelFormat != NULL) - { - CGLDestroyPixelFormat(mPixelFormat); - mPixelFormat = NULL; - } - - // Clean up the GL context - if(mContext != NULL) - { - CGLDestroyContext(mContext); - } - - // Destroy our LLOpenGLView - if(mGLView != NULL) - { - removeGLView(mGLView); - mGLView = NULL; - } - - // Close the window - if(mWindow != NULL) - { - NSWindowRef dead_window = mWindow; - mWindow = NULL; - closeWindow(dead_window); - } - -} - -LLWindowMacOSX::~LLWindowMacOSX() -{ - destroyContext(); - - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } - - gWindowImplementation = NULL; - -} - - -void LLWindowMacOSX::show() -{ -} - -void LLWindowMacOSX::hide() -{ - setMouseClipping(false); -} - -//virtual -void LLWindowMacOSX::minimize() -{ - setMouseClipping(false); - showCursor(); -} - -//virtual -void LLWindowMacOSX::restore() -{ - show(); -} - - -// close() destroys all OS-specific code associated with a window. -// Usually called from LLWindowManager::destroyWindow() -void LLWindowMacOSX::close() -{ - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } - - // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(false); - showCursor(); - - destroyContext(); -} - -bool LLWindowMacOSX::isValid() -{ - if(mFullscreen) - { - return(true); - } - - return (mWindow != NULL); -} - -bool LLWindowMacOSX::getVisible() -{ - bool result = false; - - if(mFullscreen) - { - result = true; - }if (mWindow) - { - result = true; - } - - return(result); -} - -bool LLWindowMacOSX::getMinimized() -{ - return mMinimized; -} - -bool LLWindowMacOSX::getMaximized() -{ - return mMaximized; -} - -bool LLWindowMacOSX::maximize() -{ - if (mWindow && !mMaximized) - { - } - - return mMaximized; -} - -bool LLWindowMacOSX::getFullscreen() -{ - return mFullscreen; -} - -void LLWindowMacOSX::gatherInput() -{ - updateCursor(); -} - -bool LLWindowMacOSX::getPosition(LLCoordScreen *position) -{ - S32 err = -1; - - if(mFullscreen) - { - position->mX = 0; - position->mY = 0; - err = noErr; - } - else if(mWindow) - { - const CGPoint & pos = getContentViewBoundsPosition(mWindow); - - position->mX = pos.x; - position->mY = pos.y; - - err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); -} - -bool LLWindowMacOSX::getSize(LLCoordScreen *size) -{ - S32 err = -1; - - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - - size->mX = sz.width; - size->mY = sz.height; - err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); -} - -bool LLWindowMacOSX::getSize(LLCoordWindow *size) -{ - S32 err = -1; - - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - - size->mX = sz.width; - size->mY = sz.height; - err = noErr; - - - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); -} - -bool LLWindowMacOSX::setPosition(const LLCoordScreen position) -{ - if(mWindow) - { - float pos[2] = {float(position.mX), float(position.mY)}; - setWindowPos(mWindow, pos); - } - - return true; -} - -bool LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) -{ - if(mWindow) - { - LLCoordWindow to; - convertCoords(size, &to); - setWindowSize(mWindow, to.mX, to.mY); - return true; - } - - return false; -} - -bool LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) -{ - if (mWindow) - { - const int titlePadding = 22; - setWindowSize(mWindow, size.mX, size.mY + titlePadding); - return true; - } - - return false; -} - -void LLWindowMacOSX::swapBuffers() -{ - CGLFlushDrawable(mContext); -} - -void LLWindowMacOSX::restoreGLContext() -{ - CGLSetCurrentContext(mContext); -} - -F32 LLWindowMacOSX::getGamma() -{ - F32 result = 2.2; // Default to something sane - - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) == noErr) - { - // So many choices... - // Let's just return the green channel gamma for now. - result = greenGamma; - } - - return result; -} - -U32 LLWindowMacOSX::getFSAASamples() -{ - return mFSAASamples; -} - -void LLWindowMacOSX::setFSAASamples(const U32 samples) -{ - mFSAASamples = samples; - mForceRebuild = true; -} - -bool LLWindowMacOSX::restoreGamma() -{ - CGDisplayRestoreColorSyncSettings(); - return true; -} - -bool LLWindowMacOSX::setGamma(const F32 gamma) -{ - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - // MBW -- XXX -- Should we allow this in windowed mode? - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) != noErr) - { - return false; - } - - if(CGSetDisplayTransferByFormula( - mDisplay, - redMin, - redMax, - gamma, - greenMin, - greenMax, - gamma, - blueMin, - blueMax, - gamma) != noErr) - { - return false; - } - - - return true; -} - -bool LLWindowMacOSX::isCursorHidden() -{ - return mCursorHidden; -} - - - -// Constrains the mouse to the window. -void LLWindowMacOSX::setMouseClipping( bool b ) -{ - // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. - mIsMouseClipping = b; - - if(b) - { - // LL_INFOS() << "setMouseClipping(true)" << LL_ENDL; - } - else - { - // LL_INFOS() << "setMouseClipping(false)" << LL_ENDL; - } - - adjustCursorDecouple(); -} - -bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) -{ - bool result = false; - LLCoordScreen screen_pos; - - if (!convertCoords(position, &screen_pos)) - { - return false; - } - - CGPoint newPosition; - - // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; - - newPosition.x = screen_pos.mX; - newPosition.y = screen_pos.mY; - - CGSetLocalEventsSuppressionInterval(0.0); - if(CGWarpMouseCursorPosition(newPosition) == noErr) - { - result = true; - } - - // Under certain circumstances, this will trigger us to decouple the cursor. - adjustCursorDecouple(true); - - // trigger mouse move callback - LLCoordGL gl_pos; - convertCoords(position, &gl_pos); - float scale = getSystemUISize(); - gl_pos.mX *= scale; - gl_pos.mY *= scale; - mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); - - return result; -} - -bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) -{ - float cursor_point[2]; - LLCoordScreen screen_pos; - - if(mWindow == NULL) - return false; - - getCursorPos(mWindow, cursor_point); - - if(mCursorDecoupled) - { - // CGMouseDelta x, y; - - // If the cursor's decoupled, we need to read the latest movement delta as well. - // CGGetLastMouseDelta( &x, &y ); - // cursor_point.h += x; - // cursor_point.v += y; - - // CGGetLastMouseDelta may behave strangely when the cursor's first captured. - // Stash in the event handler instead. - cursor_point[0] += mCursorLastEventDeltaX; - cursor_point[1] += mCursorLastEventDeltaY; - } - - float scale = getSystemUISize(); - position->mX = cursor_point[0] * scale; - position->mY = cursor_point[1] * scale; - - return true; -} - -void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) -{ - if(mIsMouseClipping && mCursorHidden) - { - if(warpingMouse) - { - // The cursor should be decoupled. Make sure it is. - if(!mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(false); - mCursorDecoupled = true; - mCursorIgnoreNextDelta = true; - } - } - } - else - { - // The cursor should not be decoupled. Make sure it isn't. - if(mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(true); - mCursorDecoupled = false; - } - } -} - -F32 LLWindowMacOSX::getNativeAspectRatio() -{ - if (mFullscreen) - { - return (F32)mFullscreenWidth / (F32)mFullscreenHeight; - } - else - { - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } - - return mOriginalAspectRatio; - } -} - -F32 LLWindowMacOSX::getPixelAspectRatio() -{ - //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode - return 1.f; -} - -//static SInt32 oldWindowLevel; - -// MBW -- XXX -- There's got to be a better way than this. Find it, please... - -// Since we're no longer supporting the "typical" fullscreen mode with CGL or NSOpenGL anymore, these are unnecessary. -Geenz -void LLWindowMacOSX::beforeDialog() -{ -} - -void LLWindowMacOSX::afterDialog() -{ - //For fix problem with Core Flow view on OSX - restoreGLContext(); -} - - -void LLWindowMacOSX::flashIcon(F32 seconds) -{ - // For consistency with macOS conventions, the number of seconds given is ignored and - // left up to the OS (which will actually bounce it for one second). - requestUserAttention(); -} - -bool LLWindowMacOSX::isClipboardTextAvailable() -{ - return pasteBoardAvailable(); -} - -bool LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) -{ - unsigned short* pboard_data = copyFromPBoard(); // must free returned data - llutf16string str(pboard_data); - free(pboard_data); - - dst = utf16str_to_wstring(str); - if (dst != L"") - { - return true; - } else { - return false; - } -} - -bool LLWindowMacOSX::copyTextToClipboard(const LLWString &s) -{ - bool result = false; - llutf16string utf16str = wstring_to_utf16str(s); - - result = copyToPBoard(utf16str.data(), utf16str.length()); - - return result; -} - - -// protected -bool LLWindowMacOSX::resetDisplayResolution() -{ - // This is only called from elsewhere in this class, and it's not used by the Mac implementation. - return true; -} - - -LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) -{ - if (!mSupportedResolutions) - { - CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); - - if(modes != NULL) - { - CFIndex index, cnt; - - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - mNumSupportedResolutions = 0; - - // Examine each mode - cnt = CFArrayGetCount( modes ); - - for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) - { - // Pull the mode dictionary out of the CFArray - CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); - long width = getDictLong(mode, kCGDisplayWidth); - long height = getDictLong(mode, kCGDisplayHeight); - long bits = getDictLong(mode, kCGDisplayBitsPerPixel); - - if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) - { - bool resolution_exists = false; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == width && - mSupportedResolutions[i].mHeight == height) - { - resolution_exists = true; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = width; - mSupportedResolutions[mNumSupportedResolutions].mHeight = height; - mNumSupportedResolutions++; - } - } - } - CFRelease(modes); - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; -} - -bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ - to->mX = from.mX; - to->mY = from.mY; - return true; -} - -bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ - to->mX = from.mX; - to->mY = from.mY; - return true; -} - -bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - if(mWindow) - { - float mouse_point[2]; - - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; - - convertScreenToWindow(mWindow, mouse_point); - - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; - - return true; - } - return false; -} - -bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ - if(mWindow) - { - float mouse_point[2]; - - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; - - convertWindowToScreen(mWindow, mouse_point); - - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; - - return true; - } - return false; -} - -bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - -bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - - - - -void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) -{ - destroyContext(); - - OSMessageBox(text, caption, type); -} - - // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature - // it is handled at a very low-level -const char* cursorIDToName(int id) -{ - switch (id) - { - case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; - case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; - case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; - case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; - case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; - case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; - case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; - case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; - case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; - case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; - case UI_CURSOR_NO: return "UI_CURSOR_NO"; - case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; - case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; - case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; - case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; - case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; - case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; - case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; - case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; - case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; - case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; - case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; - case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; - case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; - case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; - case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; - case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; - case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; - case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; - case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; - case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; - case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; - case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; - case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; - case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; - case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; - case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; - case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; - case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; - } - - LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; - - return "UI_CURSOR_ARROW"; -} - -static CursorRef gCursors[UI_CURSOR_COUNT]; - - -static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) -{ - // cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif - std::string fullpath = gDirUtilp->add( - gDirUtilp->getAppRODataDir(), - "cursors_mac", - cursorIDToName(cursorid) + std::string(".tif")); - - gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); -} - -void LLWindowMacOSX::updateCursor() -{ - S32 result = 0; - - if (mDragOverrideCursor != -1) - { - // A drag is in progress...remember the requested cursor and we'll - // restore it when it is done - mCurrentCursor = mNextCursor; - return; - } - - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - - if(mCurrentCursor == mNextCursor) - { - if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) - { - hideNSCursor(); - adjustCursorDecouple(); - } - return; - } - - // RN: replace multi-drag cursors with single versions - if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) - { - mNextCursor = UI_CURSOR_ARROWDRAG; - } - else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) - { - mNextCursor = UI_CURSOR_ARROWCOPY; - } - - switch(mNextCursor) - { - default: - case UI_CURSOR_ARROW: - setArrowCursor(); - if(mCursorHidden) - { - // Since InitCursor resets the hide level, correct for it here. - hideNSCursor(); - } - break; - - // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. - // Find out what they look like and replicate them. - - // These are essentially correct - case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; - case UI_CURSOR_IBEAM: setIBeamCursor(); break; - case UI_CURSOR_CROSS: setCrossCursor(); break; - case UI_CURSOR_HAND: setPointingHandCursor(); break; - // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; - case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; - - // Double-check these - case UI_CURSOR_NO: - case UI_CURSOR_SIZEWE: - case UI_CURSOR_SIZENS: - case UI_CURSOR_SIZENWSE: - case UI_CURSOR_SIZENESW: - case UI_CURSOR_WORKING: - case UI_CURSOR_TOOLGRAB: - case UI_CURSOR_TOOLLAND: - case UI_CURSOR_TOOLFOCUS: - case UI_CURSOR_TOOLCREATE: - case UI_CURSOR_ARROWDRAG: - case UI_CURSOR_NOLOCKED: - case UI_CURSOR_ARROWLOCKED: - case UI_CURSOR_GRABLOCKED: - case UI_CURSOR_PIPETTE: - case UI_CURSOR_TOOLTRANSLATE: - case UI_CURSOR_TOOLROTATE: - case UI_CURSOR_TOOLSCALE: - case UI_CURSOR_TOOLCAMERA: - case UI_CURSOR_TOOLPAN: - case UI_CURSOR_TOOLZOOMIN: - case UI_CURSOR_TOOLPICKOBJECT3: - case UI_CURSOR_TOOLPLAY: - case UI_CURSOR_TOOLPAUSE: - case UI_CURSOR_TOOLMEDIAOPEN: - case UI_CURSOR_TOOLSIT: - case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLOPEN: - case UI_CURSOR_TOOLPATHFINDING: - case UI_CURSOR_TOOLPATHFINDING_PATH_START: - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: - case UI_CURSOR_TOOLPATHFINDING_PATH_END: - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: - case UI_CURSOR_TOOLNO: - result = setImageCursor(gCursors[mNextCursor]); - break; - - } - - if(result != noErr) - { - setArrowCursor(); - } - - mCurrentCursor = mNextCursor; -} - -ECursorType LLWindowMacOSX::getCursor() const -{ - return mCurrentCursor; -} - -void LLWindowMacOSX::initCursors() -{ - initPixmapCursor(UI_CURSOR_NO, 8, 8); - initPixmapCursor(UI_CURSOR_WORKING, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); - initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); - initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); - initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); - initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); - initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); - initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); - initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); - initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); - initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); - - initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); - initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); - initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10); - -} - -void LLWindowMacOSX::captureMouse() -{ - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. -} - -void LLWindowMacOSX::releaseMouse() -{ - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. -} - -void LLWindowMacOSX::hideCursor() -{ - if(!mCursorHidden) - { - // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = true; - mHideCursorPermanent = true; - hideNSCursor(); - } - else - { - // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; - } - - adjustCursorDecouple(); -} - -void LLWindowMacOSX::showCursor() -{ - if(mCursorHidden || !isCGCursorVisible()) - { - // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = false; - mHideCursorPermanent = false; - showNSCursor(); - } - else - { - // LL_INFOS() << "showCursor: already visible" << LL_ENDL; - } - - adjustCursorDecouple(); -} - -void LLWindowMacOSX::showCursorFromMouseMove() -{ - if (!mHideCursorPermanent) - { - showCursor(); - } -} - -void LLWindowMacOSX::hideCursorUntilMouseMove() -{ - if (!mHideCursorPermanent) - { - hideCursor(); - mHideCursorPermanent = false; - } -} - - - -// -// LLSplashScreenMacOSX -// -LLSplashScreenMacOSX::LLSplashScreenMacOSX() -{ - mWindow = NULL; -} - -LLSplashScreenMacOSX::~LLSplashScreenMacOSX() -{ -} - -void LLSplashScreenMacOSX::showImpl() -{ - // This code _could_ be used to display a spash screen... -} - -void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) -{ - if(mWindow != NULL) - { - CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); - } -} - - -void LLSplashScreenMacOSX::hideImpl() -{ - if(mWindow != NULL) - { - mWindow = NULL; - } -} - -S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) -{ - return showAlert(text, caption, type); -} - -// Open a URL with the user's default web browser. -// Must begin with protocol identifier. -void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) -{ - // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. - - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - S32 result = 0; - CFURLRef urlRef = NULL; - - LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; - - CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); - if (stringRef) - { - // This will succeed if the string is a full URL, including the http:// - // Note that URLs specified this way need to be properly percent-escaped. - urlRef = CFURLCreateWithString(NULL, stringRef, NULL); - - // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs - - CFRelease(stringRef); - } - - if (urlRef) - { - result = LSOpenCFURLRef(urlRef, NULL); - - if (result != noErr) - { - LL_INFOS() << "Error " << result << " on open." << LL_ENDL; - } - - CFRelease(urlRef); - } - else - { - LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; - } -} - -// String should match ndof, so string mapping code was copied as is -static char mapChar( char c ) -{ - unsigned char uc = ( unsigned char ) c; - - switch( uc ) - { - case '/': return '-'; // use dash instead of slash - - case 0x7F: return ' '; - case 0x80: return 'A'; - case 0x81: return 'A'; - case 0x82: return 'C'; - case 0x83: return 'E'; - case 0x84: return 'N'; - case 0x85: return 'O'; - case 0x86: return 'U'; - case 0x87: return 'a'; - case 0x88: return 'a'; - case 0x89: return 'a'; - case 0x8A: return 'a'; - case 0x8B: return 'a'; - case 0x8C: return 'a'; - case 0x8D: return 'c'; - case 0x8E: return 'e'; - case 0x8F: return 'e'; - case 0x90: return ' '; - case 0x91: return ' '; // ? ' - case 0x92: return ' '; // ? ' - case 0x93: return ' '; // ? " - case 0x94: return ' '; // ? " - case 0x95: return ' '; - case 0x96: return ' '; - case 0x97: return ' '; - case 0x98: return ' '; - case 0x99: return ' '; - case 0x9A: return ' '; - case 0x9B: return 0x27; - case 0x9C: return 0x22; - case 0x9D: return ' '; - case 0x9E: return ' '; - case 0x9F: return ' '; - case 0xA0: return ' '; - case 0xA1: return ' '; - case 0xA2: return ' '; - case 0xA3: return ' '; - case 0xA4: return ' '; - case 0xA5: return ' '; - case 0xA6: return ' '; - case 0xA7: return ' '; - case 0xA8: return ' '; - case 0xA9: return ' '; - case 0xAA: return ' '; - case 0xAB: return ' '; - case 0xAC: return ' '; - case 0xAD: return ' '; - case 0xAE: return ' '; - case 0xAF: return ' '; - case 0xB0: return ' '; - case 0xB1: return ' '; - case 0xB2: return ' '; - case 0xB3: return ' '; - case 0xB4: return ' '; - case 0xB5: return ' '; - case 0xB6: return ' '; - case 0xB7: return ' '; - case 0xB8: return ' '; - case 0xB9: return ' '; - case 0xBA: return ' '; - case 0xBB: return ' '; - case 0xBC: return ' '; - case 0xBD: return ' '; - case 0xBE: return ' '; - case 0xBF: return ' '; - case 0xC0: return ' '; - case 0xC1: return ' '; - case 0xC2: return ' '; - case 0xC3: return ' '; - case 0xC4: return ' '; - case 0xC5: return ' '; - case 0xC6: return ' '; - case 0xC7: return ' '; - case 0xC8: return ' '; - case 0xC9: return ' '; - case 0xCA: return ' '; - case 0xCB: return 'A'; - case 0xCC: return 'A'; - case 0xCD: return 'O'; - case 0xCE: return ' '; - case 0xCF: return ' '; - case 0xD0: return '-'; - case 0xD1: return '-'; - case 0xD2: return 0x22; - case 0xD3: return 0x22; - case 0xD4: return 0x27; - case 0xD5: return 0x27; - case 0xD6: return '-'; // use dash instead of slash - case 0xD7: return ' '; - case 0xD8: return 'y'; - case 0xD9: return 'Y'; - case 0xDA: return '-'; // use dash instead of slash - case 0xDB: return ' '; - case 0xDC: return '<'; - case 0xDD: return '>'; - case 0xDE: return ' '; - case 0xDF: return ' '; - case 0xE0: return ' '; - case 0xE1: return ' '; - case 0xE2: return ','; - case 0xE3: return ','; - case 0xE4: return ' '; - case 0xE5: return 'A'; - case 0xE6: return 'E'; - case 0xE7: return 'A'; - case 0xE8: return 'E'; - case 0xE9: return 'E'; - case 0xEA: return 'I'; - case 0xEB: return 'I'; - case 0xEC: return 'I'; - case 0xED: return 'I'; - case 0xEE: return 'O'; - case 0xEF: return 'O'; - case 0xF0: return ' '; - case 0xF1: return 'O'; - case 0xF2: return 'U'; - case 0xF3: return 'U'; - case 0xF4: return 'U'; - case 0xF5: return '|'; - case 0xF6: return ' '; - case 0xF7: return ' '; - case 0xF8: return ' '; - case 0xF9: return ' '; - case 0xFA: return '.'; - case 0xFB: return ' '; - case 0xFC: return ' '; - case 0xFD: return 0x22; - case 0xFE: return ' '; - case 0xFF: return ' '; - } - return c; -} - -// String should match ndof for manufacturer based search to work -static void sanitizeString( char* inCStr ) -{ - char* charIt = inCStr; - while ( *charIt ) - { - *charIt = mapChar( *charIt ); - charIt++; - } -} - -struct HidDevice -{ - long mAxis; - long mLocalID; - char mProduct[256]; - char mManufacturer[256]; - long mUsage; - long mUsagePage; -}; - -static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) -{ - CFMutableDictionaryRef io_properties = nil; - io_registry_entry_t entry1; - io_registry_entry_t entry2; - kern_return_t rc; - - // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also - // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties - // try to get parent1 - rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); - if ( KERN_SUCCESS == rc ) - { - rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); - - IOObjectRelease( entry1 ); - - if ( KERN_SUCCESS == rc ) - { - rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); - // either way, release parent2 - IOObjectRelease( entry2 ); - } - } - if ( KERN_SUCCESS == rc ) - { - // IORegistryEntryCreateCFProperties() succeeded - if ( io_properties != nil ) - { - CFTypeRef dict_element = 0; - // get device info - // try hid dictionary first, if fail then go to usb dictionary - - - dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); - if ( !dict_element ) - { - dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); - } - if ( dict_element ) - { - bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); - sanitizeString(devicep->mProduct); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; - } - } - - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); - if ( !dict_element ) - { - dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); - } - if ( dict_element ) - { - bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); - sanitizeString(devicep->mManufacturer); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; - } - } - - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); - if ( !dict_element ) - { - dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); - } - if ( dict_element ) - { - bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; - } - } - - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); - if ( dict_element ) - { - bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; - } - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); - if ( dict_element ) - { - if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) - { - LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; - } - } - } - - //Add axis, because ndof lib checks sutability by axises as well as other elements - devicep->mAxis = 0; - CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); - if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) - { - long count = CFArrayGetCount( (CFArrayRef) hid_elements ); - for (int i = 0; i < count; ++i) - { - CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); - if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) - { - long type = 0, usage_page = 0, usage = 0; - - CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); - if ( ref_value ) - { - CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); - } - - ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); - if ( ref_value ) - { - CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); - } - - ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); - if ( ref_value ) - { - CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); - } - if ( type != 0 - && type != kIOHIDElementTypeCollection - && usage_page == kHIDPage_GenericDesktop) - { - switch( usage ) - { - case kHIDUsage_GD_X: - case kHIDUsage_GD_Y: - case kHIDUsage_GD_Z: - case kHIDUsage_GD_Rx: - case kHIDUsage_GD_Ry: - case kHIDUsage_GD_Rz: - devicep->mAxis++; - break; - default: - break; - } - } - } - } - } - - CFRelease(io_properties); - } - else - { - LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; - } - } -} - -HidDevice populate_device( io_object_t io_obj ) -{ - void* interfacep = nullptr; - HidDevice device; - memset( &device, 0, sizeof( HidDevice ) ); - CFMutableDictionaryRef device_dic = 0; - kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); - - if ( KERN_SUCCESS == result - && device_dic ) - { - IOReturn io_result = kIOReturnSuccess; - HRESULT query_result = S_OK; - SInt32 the_score = 0; - IOCFPlugInInterface **the_interface = NULL; - - - io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &the_interface, &the_score ); - if ( io_result == kIOReturnSuccess ) - { - query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); - if ( query_result != S_OK ) - { - LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; - } - IODestroyPlugInInterface( the_interface ); - } - else - { - LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; - } - - if ( interfacep ) - { - result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); - - if ( result != kIOReturnSuccess) - { - LL_WARNS("Joystick") << "open failed" << LL_ENDL; - } - } - // extract needed fields - populate_device_info( io_obj, device_dic, &device ); - - // Release interface - if ( interfacep ) - { - ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); - - ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); - - interfacep = NULL; - } - - CFRelease( device_dic ); - } - else - { - LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; - } - - return device; -} - -static void get_devices(std::list &list_of_devices, - io_iterator_t inIODeviceIterator) -{ - IOReturn result = kIOReturnSuccess; // assume success( optimist! ) - io_object_t io_obj = 0; - - while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) - { - HidDevice device = populate_device( io_obj ); - - // Should match ndof - if (device.mAxis >= 3 - || (device.mUsagePage == kHIDPage_GenericDesktop - && (device.mUsage == kHIDUsage_GD_MultiAxisController - || device.mUsage == kHIDUsage_GD_GamePad - || device.mUsage == kHIDUsage_GD_Joystick)) - || (device.mUsagePage == kHIDPage_Game - && device.mUsage == kHIDUsage_Game_3DGameController) - || strstr(device.mManufacturer, "3Dconnexion")) - { - list_of_devices.push_back(device); - } - else - { - LL_DEBUGS("Joystick"); - list_of_devices.push_back(device); - LL_CONT << "Device axes: " << (S32)device.mAxis - << " Device HIDUsepage: " << (S32)device.mUsagePage - << " Device HIDUsage: " << (S32)device.mUsage; - LL_ENDL; - } - - - // release the device object, it is no longer needed - result = IOObjectRelease( io_obj ); - if ( KERN_SUCCESS != result ) - { - LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; - } - } -} - -bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, - std::function osx_callback, - void* win_callback, - void* userdata) -{ - bool return_value = false; - CFMutableDictionaryRef device_dict_ref; - IOReturn result = kIOReturnSuccess; // assume success( optimist! ) - - // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. - - // A dictionary to match devices to? - device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); - - // BUG FIX! one reference is consumed by IOServiceGetMatchingServices - CFRetain( device_dict_ref ); - io_iterator_t io_iter = 0; - - // create an IO object iterator - result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); - if ( kIOReturnSuccess != result ) - { - LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; - } - - if ( io_iter ) - { - // add all existing devices - std::list device_list; - - get_devices(device_list, io_iter); - - std::list::iterator iter; - - for (iter = device_list.begin(); iter != device_list.end(); ++iter) - { - std::string label(iter->mProduct); - LLSD data; - data["manufacturer"] = std::string(iter->mManufacturer); - data["product"] = label; - - if (osx_callback(label, data, userdata)) - { - break; //found device - } - } - return_value = true; - } - - CFRelease( device_dict_ref ); - return return_value; -} - -LLSD LLWindowMacOSX::getNativeKeyData() -{ - LLSD result = LLSD::emptyMap(); - - if(mRawKeyEvent) - { - result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); - result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); - result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); - result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); - result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); - result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); - } - - LL_DEBUGS() << "native key data is: " << result << LL_ENDL; - - return result; -} - -bool LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - bool retval = false; - OSErr error = noErr; - NColorPickerInfo info; - - memset(&info, 0, sizeof(info)); - info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); - info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); - info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); - info.placeWhere = kCenterOnMainScreen; - - error = NPickColor(&info); - - if (error == noErr) - { - retval = info.newColorChosen; - if (info.newColorChosen) - { - *r = ((float) info.theColor.color.rgb.red) / 65535.0; - *g = ((float) info.theColor.color.rgb.green) / 65535.0; - *b = ((float) info.theColor.color.rgb.blue) / 65535.0; - } - } - - return (retval); -} - -void *LLWindowMacOSX::getPlatformWindow() -{ - // NOTE: this will be NULL in fullscreen mode. Plan accordingly. - return (void*)mWindow; -} - -// get a double value from a dictionary -/* -static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) -{ - double double_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it - return -1; // fail - return double_value; // otherwise return the long value -}*/ - -// get a long value from a dictionary -static long getDictLong (CFDictionaryRef refDict, CFStringRef key) -{ - long int_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it - return -1; // fail - return int_value; // otherwise return the long value -} - -void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, bool b) -{ - if (preeditor != mPreeditor && !b) - { - // This condition may occur by a call to - // setEnabled(bool) against LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - // We need to interrupt before updating mPreeditor, - // so that the fix string from input method goes to - // the old preeditor. - if (mLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - if (b == mLanguageTextInputAllowed) - { - return; - } - mLanguageTextInputAllowed = b; - allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit -} - -class sharedContext -{ -public: - CGLContextObj mContext; -}; - -void* LLWindowMacOSX::createSharedContext() -{ - sharedContext* sc = new sharedContext(); - CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); - - if (sUseMultGL) - { - CGLEnable(mContext, kCGLCEMPEngine); - } - - return (void *)sc; -} - -void LLWindowMacOSX::makeContextCurrent(void* context) -{ - CGLSetCurrentContext(((sharedContext*)context)->mContext); - - //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); - - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - -} - -void LLWindowMacOSX::destroySharedContext(void* context) -{ - sharedContext* sc = (sharedContext*)context; - - CGLDestroyContext(sc->mContext); - - delete sc; -} - -void LLWindowMacOSX::toggleVSync(bool enable_vsync) -{ - GLint frames_per_swap = 0; - if (!enable_vsync) - { - frames_per_swap = 0; - } - else - { - frames_per_swap = 1; - } - - CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); -} - -void LLWindowMacOSX::interruptLanguageTextInput() -{ - commitCurrentPreedit(mGLView); -} - -std::vector LLWindowMacOSX::getDisplaysResolutionList() -{ - std::vector resolution_list; - - CGDirectDisplayID display_ids[10]; - uint32_t found_displays = 0; - CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); - - if (kCGErrorSuccess != err) - { - LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; - return std::vector(); - } - - for (uint32_t i = 0; i < found_displays; i++) - { - S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); - S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); - - resolution_list.push_back(res); - } - - return resolution_list; -} - -//static -std::vector LLWindowMacOSX::getDynamicFallbackFontList() -{ - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector(); -} - -// static -MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) -{ - MASK mask = 0; - if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } - if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } - if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } - return mask; -} - -F32 LLWindowMacOSX::getSystemUISize() -{ - return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); -} - -#if LL_OS_DRAGDROP_ENABLED -/* -S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, - void * handlerRefCon, DragRef drag) -{ - S16 result = 0; - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - - LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; - - switch(message) - { - case kDragTrackingInWindow: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); - break; - - case kDragTrackingEnterHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); - break; - - case kDragTrackingLeaveHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); - break; - - default: - break; - } - - return result; -} -OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, - DragRef drag) -{ - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); - -} -*/ -void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) -{ - MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); - - float mouse_point[2]; - // This will return the mouse point in window coords - getCursorPos(mWindow, mouse_point); - LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); - LLCoordGL gl_pos; - convertCoords(window_coords, &gl_pos); - - if(!url.empty()) - { - LLWindowCallbacks::DragNDropResult res = - mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); - - switch (res) { - case LLWindowCallbacks::DND_NONE: // No drop allowed - if (action == LLWindowCallbacks::DNDA_TRACK) - { - mDragOverrideCursor = 0; - } - else { - mDragOverrideCursor = -1; - } - break; - case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation - mDragOverrideCursor = UI_CURSOR_NO; - break; - case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation - mDragOverrideCursor = UI_CURSOR_ARROWCOPY; - break; - default: - mDragOverrideCursor = -1; - break; - } - // This overrides the cursor being set by setCursor. - // This is a bit of a hack workaround because lots of areas - // within the viewer just blindly set the cursor. - if (mDragOverrideCursor == -1) - { - // Restore the cursor - ECursorType temp_cursor = mCurrentCursor; - // get around the "setting the same cursor" code in setCursor() - mCurrentCursor = UI_CURSOR_COUNT; - setCursor(temp_cursor); - } - else { - // Override the cursor - switch (mDragOverrideCursor) { - case 0: - setArrowCursor(); - break; - case UI_CURSOR_NO: - setNotAllowedCursor(); - case UI_CURSOR_ARROWCOPY: - setCopyCursor(); - default: - break; - }; - } - } -} - -#endif // LL_OS_DRAGDROP_ENABLED +/** + * @file llwindowmacosx.cpp + * @brief Platform-dependent implementation of llwindow + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llwindowmacosx.h" + +#include "llkeyboardmacosx.h" +#include "llwindowcallbacks.h" +#include "llpreeditor.h" + +#include "llerror.h" +#include "llgl.h" +#include "llstring.h" +#include "lldir.h" +#include "indra_constants.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern bool gDebugWindowProc; +bool gHiDPISupport = true; + +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; + +const S32 DEFAULT_REFRESH_RATE = 60; + +namespace +{ + NSKeyEventRef mRawKeyEvent = NULL; +} +// +// LLWindowMacOSX +// + +bool LLWindowMacOSX::sUseMultGL = false; + +// Cross-platform bits: + +bool check_for_card(const char* RENDERER, const char* bad_card) +{ + if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) + { + std::string buffer = llformat( + "Your video card appears to be a %s, which Second Life does not support.\n" + "\n" + "Second Life requires a video card with 32 Mb of memory or more, as well as\n" + "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" + "and ATI Radeon 8500 or better.\n" + "\n" + "If you own a supported card and continue to receive this message, try \n" + "updating to the latest video card drivers. Otherwise look in the\n" + "secondlife.com support section or e-mail technical support\n" + "\n" + "You can try to run Second Life, but it will probably crash or run\n" + "very slowly. Try anyway?", + bad_card); + S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); + if (OSBTN_YES == button) + { + return false; + } + else + { + return true; + } + } + + return false; +} + +// Switch to determine whether we capture all displays, or just the main one. +// We may want to base this on the setting of _DEBUG... + +#define CAPTURE_ALL_DISPLAYS 0 +//static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); +static long getDictLong (CFDictionaryRef refDict, CFStringRef key); + +// MBW -- HACK ALERT +// On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. +// The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these +// require a pointer to the LLWindowMacOSX object. Stash it here and maintain in the constructor and destructor. +// This assumes that there will be only one object of this class at any time. Hopefully this is true. +static LLWindowMacOSX *gWindowImplementation = NULL; + +LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, + U32 fsaa_samples, + U32 max_vram) + : LLWindow(NULL, fullscreen, flags) +{ + // *HACK: During window construction we get lots of OS events for window + // reshape, activate, etc. that the viewer isn't ready to handle. + // Route them to a dummy callback structure until the end of constructor. + LLWindowCallbacks null_callbacks; + mCallbacks = &null_callbacks; + + // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). + setupCocoa(); + + // Initialize the keyboard + gKeyboard = new LLKeyboardMacOSX(); + gKeyboard->setCallbacks(callbacks); + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mContext = NULL; + mPixelFormat = NULL; + mDisplay = CGMainDisplayID(); + mSimulatedRightClick = false; + mLastModifiers = 0; + mHandsOffEvents = false; + mCursorDecoupled = false; + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = false; + mNeedsResize = false; + mOverrideAspectRatio = 0.f; + mMaximized = false; + mMinimized = false; + mLanguageTextInputAllowed = false; + mPreeditor = NULL; + mFSAASamples = fsaa_samples; + mForceRebuild = false; + + // Get the original aspect ratio of the main device. + mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); + + // Stash the window title + mWindowTitle = title; + //mWindowTitle[0] = title.length(); + + mDragOverrideCursor = -1; + + // Set up global event handlers (the fullscreen case needs this) + //InstallStandardEventHandler(GetApplicationEventTarget()); + + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) + { + if(mWindow != NULL) + { + makeWindowOrderFront(mWindow); + } + + if (!gGLManager.initGL()) + { + setupFailure( + "Second Life is unable to run because your video card drivers\n" + "are out of date or unsupported. Please make sure you have\n" + "the latest video card drivers installed.\n" + "If you continue to receive this message, contact customer service.", + "Error", + OSMB_OK); + return; + } + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + + allowLanguageTextInput(NULL, false); + } + + mCallbacks = callbacks; + stop_glerror(); + + +} + +// These functions are used as wrappers for our internal event handling callbacks. +// It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow. + +bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) +{ + mRawKeyEvent = event; + bool retVal = gKeyboard->handleKeyUp(key, mask); + mRawKeyEvent = NULL; + return retVal; +} + +bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) +{ + //if (mask!=MASK_NONE) + { + if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + { + key = gKeyboard->inverseTranslateKey('Y'); + } + else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + { + key = gKeyboard->inverseTranslateKey('Z'); + } + } + + mRawKeyEvent = event; + bool retVal = gKeyboard->handleKeyDown(key, mask); + mRawKeyEvent = NULL; + return retVal; +} + +void callResetKeys() +{ + gKeyboard->resetKeys(); +} + +bool callUnicodeCallback(wchar_t character, unsigned int mask) +{ + NativeKeyEventData eventData; + + memset(&eventData, 0, sizeof(NativeKeyEventData)); + + eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; + eventData.mEventType = 0; + eventData.mEventModifiers = mask; + eventData.mEventKeyCode = 0; + eventData.mEventChars = character; + eventData.mEventUnmodChars = character; + eventData.mEventRepeat = false; + + mRawKeyEvent = &eventData; + + bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); + mRawKeyEvent = NULL; + return result; +} + +void callFocus() +{ + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); + } +} + +void callFocusLost() +{ + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } +} + +void callRightMouseDown(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callRightMouseUp(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callLeftMouseDown(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callLeftMouseUp(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); + +} + +void callDoubleClick(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callResize(unsigned int width, unsigned int height) +{ + if (gWindowImplementation != NULL) + { + gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); + } +} + +void callMouseMoved(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); + //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); +} + +void callMouseDragged(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callScrollMoved(float deltaX, float deltaY) +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } +} + +void callMouseExit() +{ + gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); +} + +void callWindowFocus() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); + } + else + { + LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; + } + + +} + +void callWindowUnfocus() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } +} + +void callWindowHide() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); + } +} + +void callWindowUnhide() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); + } +} + +void callWindowDidChangeScreen() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); + } +} + +void callDeltaUpdate(float *delta, MASK mask) +{ + gWindowImplementation->updateMouseDeltas(delta); +} + +void callOtherMouseDown(float *pos, MASK mask, int button) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseDown(gWindowImplementation, outCoords, mask, button + 1); + } +} + +void callOtherMouseUp(float *pos, MASK mask, int button) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseUp(gWindowImplementation, outCoords, mask, button + 1); + } +} + +void callModifier(MASK mask) +{ + gKeyboard->handleModifier(mask); +} + +void callHandleDragEntered(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); +} + +void callHandleDragExited(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); +} + +void callHandleDragUpdated(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); +} + +void callHandleDragDropped(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); +} + +void callQuitHandler() +{ + if (gWindowImplementation) + { + if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) + { + gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); + } + } +} + +void getPreeditSelectionRange(int *position, int *length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getSelectionRange(position, length); + } +} + +void getPreeditMarkedRange(int *position, int *length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getPreeditRange(position, length); + } +} + +void setPreeditMarkedRange(int position, int length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->markAsPreedit(position, length); + } +} + +bool handleUnicodeCharacter(wchar_t c) +{ + bool success = false; + if (gWindowImplementation->getPreeditor()) + { + success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); + } + + return success; +} + +void resetPreedit() +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->resetPreedit(); + } +} + +// For reasons of convenience, handle IME updates here. +// This largely mirrors the old implementation, only sans the carbon parameters. +void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + preeditor->resetPreedit(); + // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. + if (replacementRange[0] < replacementRange[1]) + { + const LLWString& text = preeditor->getPreeditString(); + const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); + const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); + preeditor->markAsPreedit(location, length); + } + + LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); + + S32 caret_position = fix_str.length(); + + preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); + } +} + +void getPreeditLocation(float *location, unsigned int length) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + LLCoordGL coord; + LLCoordScreen screen; + LLRect rect; + + preeditor->getPreeditLocation(length, &coord, &rect, NULL); + + float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; + + convertRectToScreen(gWindowImplementation->getWindow(), c); + + location[0] = c[0]; + location[1] = c[1]; + } +} + +void LLWindowMacOSX::updateMouseDeltas(float* deltas) +{ + if (mCursorDecoupled) + { + mCursorLastEventDeltaX = ll_round(deltas[0]); + mCursorLastEventDeltaY = ll_round(-deltas[1]); + + if (mCursorIgnoreNextDelta) + { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = false; + } + } else { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + } +} + +void LLWindowMacOSX::getMouseDeltas(float* delta) +{ + delta[0] = mCursorLastEventDeltaX; + delta[1] = mCursorLastEventDeltaY; +} + +bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) +{ + mFullscreen = fullscreen; + + if (mWindow == NULL) + { + mWindow = getMainAppWindow(); + } + + if(mContext == NULL) + { + // Our OpenGL view is already defined within SecondLife.xib. + // Get the view instead. + mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); + mContext = getCGLContextObj(mGLView); + gGLManager.mVRAM = getVramSize(mGLView); + + if(!mPixelFormat) + { + CGLPixelFormatAttribute attribs[] = + { + kCGLPFANoRecovery, + kCGLPFADoubleBuffer, + kCGLPFAClosestPolicy, + kCGLPFAAccelerated, + kCGLPFAMultisample, + kCGLPFASampleBuffers, static_cast((mFSAASamples > 0 ? 1 : 0)), + kCGLPFASamples, static_cast(mFSAASamples), + kCGLPFAStencilSize, static_cast(8), + kCGLPFADepthSize, static_cast(24), + kCGLPFAAlphaSize, static_cast(8), + kCGLPFAColorSize, static_cast(24), + kCGLPFAOpenGLProfile, static_cast(kCGLOGLPVersion_GL4_Core), + static_cast(0) + }; + + GLint numPixelFormats; + CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); + + if(mPixelFormat == NULL) { + CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); + } + } + + } + + // This sets up our view to recieve text from our non-inline text input window. + setupInputWindow(mWindow, mGLView); + + // Hook up the context to a drawable + + if(mContext != NULL) + { + + + U32 err = CGLSetCurrentContext(mContext); + if (err != kCGLNoError) + { + setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); + return false; + } + } + + mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); + if(mRefreshRate == 0) + { + //consider adding more appropriate fallback later + mRefreshRate = DEFAULT_REFRESH_RATE; + } + + // Disable vertical sync for swap + toggleVSync(enable_vsync); + + //enable multi-threaded OpenGL + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; + } + } + makeFirstResponder(mWindow, mGLView); + + return true; +} + + +// We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. +// This makes this method obsolete. +bool LLWindowMacOSX::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) +{ + return false; +} + +void LLWindowMacOSX::destroyContext() +{ + if (!mContext) + { + // We don't have a context + return; + } + // Unhook the GL context from any drawable it may have + if(mContext != NULL) + { + LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; + CGLSetCurrentContext(NULL); + } + + // Clean up remaining GL state before blowing away window + gGLManager.shutdownGL(); + + // Clean up the pixel format + if(mPixelFormat != NULL) + { + CGLDestroyPixelFormat(mPixelFormat); + mPixelFormat = NULL; + } + + // Clean up the GL context + if(mContext != NULL) + { + CGLDestroyContext(mContext); + } + + // Destroy our LLOpenGLView + if(mGLView != NULL) + { + removeGLView(mGLView); + mGLView = NULL; + } + + // Close the window + if(mWindow != NULL) + { + NSWindowRef dead_window = mWindow; + mWindow = NULL; + closeWindow(dead_window); + } + +} + +LLWindowMacOSX::~LLWindowMacOSX() +{ + destroyContext(); + + if(mSupportedResolutions != NULL) + { + delete []mSupportedResolutions; + } + + gWindowImplementation = NULL; + +} + + +void LLWindowMacOSX::show() +{ +} + +void LLWindowMacOSX::hide() +{ + setMouseClipping(false); +} + +//virtual +void LLWindowMacOSX::minimize() +{ + setMouseClipping(false); + showCursor(); +} + +//virtual +void LLWindowMacOSX::restore() +{ + show(); +} + + +// close() destroys all OS-specific code associated with a window. +// Usually called from LLWindowManager::destroyWindow() +void LLWindowMacOSX::close() +{ + // Is window is already closed? + // if (!mWindow) + // { + // return; + // } + + // Make sure cursor is visible and we haven't mangled the clipping state. + setMouseClipping(false); + showCursor(); + + destroyContext(); +} + +bool LLWindowMacOSX::isValid() +{ + if(mFullscreen) + { + return(true); + } + + return (mWindow != NULL); +} + +bool LLWindowMacOSX::getVisible() +{ + bool result = false; + + if(mFullscreen) + { + result = true; + }if (mWindow) + { + result = true; + } + + return(result); +} + +bool LLWindowMacOSX::getMinimized() +{ + return mMinimized; +} + +bool LLWindowMacOSX::getMaximized() +{ + return mMaximized; +} + +bool LLWindowMacOSX::maximize() +{ + if (mWindow && !mMaximized) + { + } + + return mMaximized; +} + +bool LLWindowMacOSX::getFullscreen() +{ + return mFullscreen; +} + +void LLWindowMacOSX::gatherInput() +{ + updateCursor(); +} + +bool LLWindowMacOSX::getPosition(LLCoordScreen *position) +{ + S32 err = -1; + + if(mFullscreen) + { + position->mX = 0; + position->mY = 0; + err = noErr; + } + else if(mWindow) + { + const CGPoint & pos = getContentViewBoundsPosition(mWindow); + + position->mX = pos.x; + position->mY = pos.y; + + err = noErr; + } + else + { + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); +} + +bool LLWindowMacOSX::getSize(LLCoordScreen *size) +{ + S32 err = -1; + + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + + size->mX = sz.width; + size->mY = sz.height; + err = noErr; + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); +} + +bool LLWindowMacOSX::getSize(LLCoordWindow *size) +{ + S32 err = -1; + + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + + size->mX = sz.width; + size->mY = sz.height; + err = noErr; + + + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); +} + +bool LLWindowMacOSX::setPosition(const LLCoordScreen position) +{ + if(mWindow) + { + float pos[2] = {float(position.mX), float(position.mY)}; + setWindowPos(mWindow, pos); + } + + return true; +} + +bool LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) +{ + if(mWindow) + { + LLCoordWindow to; + convertCoords(size, &to); + setWindowSize(mWindow, to.mX, to.mY); + return true; + } + + return false; +} + +bool LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) +{ + if (mWindow) + { + const int titlePadding = 22; + setWindowSize(mWindow, size.mX, size.mY + titlePadding); + return true; + } + + return false; +} + +void LLWindowMacOSX::swapBuffers() +{ + CGLFlushDrawable(mContext); +} + +void LLWindowMacOSX::restoreGLContext() +{ + CGLSetCurrentContext(mContext); +} + +F32 LLWindowMacOSX::getGamma() +{ + F32 result = 2.2; // Default to something sane + + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) == noErr) + { + // So many choices... + // Let's just return the green channel gamma for now. + result = greenGamma; + } + + return result; +} + +U32 LLWindowMacOSX::getFSAASamples() +{ + return mFSAASamples; +} + +void LLWindowMacOSX::setFSAASamples(const U32 samples) +{ + mFSAASamples = samples; + mForceRebuild = true; +} + +bool LLWindowMacOSX::restoreGamma() +{ + CGDisplayRestoreColorSyncSettings(); + return true; +} + +bool LLWindowMacOSX::setGamma(const F32 gamma) +{ + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + // MBW -- XXX -- Should we allow this in windowed mode? + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) != noErr) + { + return false; + } + + if(CGSetDisplayTransferByFormula( + mDisplay, + redMin, + redMax, + gamma, + greenMin, + greenMax, + gamma, + blueMin, + blueMax, + gamma) != noErr) + { + return false; + } + + + return true; +} + +bool LLWindowMacOSX::isCursorHidden() +{ + return mCursorHidden; +} + + + +// Constrains the mouse to the window. +void LLWindowMacOSX::setMouseClipping( bool b ) +{ + // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. + mIsMouseClipping = b; + + if(b) + { + // LL_INFOS() << "setMouseClipping(true)" << LL_ENDL; + } + else + { + // LL_INFOS() << "setMouseClipping(false)" << LL_ENDL; + } + + adjustCursorDecouple(); +} + +bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) +{ + bool result = false; + LLCoordScreen screen_pos; + + if (!convertCoords(position, &screen_pos)) + { + return false; + } + + CGPoint newPosition; + + // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + + newPosition.x = screen_pos.mX; + newPosition.y = screen_pos.mY; + + CGSetLocalEventsSuppressionInterval(0.0); + if(CGWarpMouseCursorPosition(newPosition) == noErr) + { + result = true; + } + + // Under certain circumstances, this will trigger us to decouple the cursor. + adjustCursorDecouple(true); + + // trigger mouse move callback + LLCoordGL gl_pos; + convertCoords(position, &gl_pos); + float scale = getSystemUISize(); + gl_pos.mX *= scale; + gl_pos.mY *= scale; + mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); + + return result; +} + +bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) +{ + float cursor_point[2]; + LLCoordScreen screen_pos; + + if(mWindow == NULL) + return false; + + getCursorPos(mWindow, cursor_point); + + if(mCursorDecoupled) + { + // CGMouseDelta x, y; + + // If the cursor's decoupled, we need to read the latest movement delta as well. + // CGGetLastMouseDelta( &x, &y ); + // cursor_point.h += x; + // cursor_point.v += y; + + // CGGetLastMouseDelta may behave strangely when the cursor's first captured. + // Stash in the event handler instead. + cursor_point[0] += mCursorLastEventDeltaX; + cursor_point[1] += mCursorLastEventDeltaY; + } + + float scale = getSystemUISize(); + position->mX = cursor_point[0] * scale; + position->mY = cursor_point[1] * scale; + + return true; +} + +void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) +{ + if(mIsMouseClipping && mCursorHidden) + { + if(warpingMouse) + { + // The cursor should be decoupled. Make sure it is. + if(!mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(false); + mCursorDecoupled = true; + mCursorIgnoreNextDelta = true; + } + } + } + else + { + // The cursor should not be decoupled. Make sure it isn't. + if(mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(true); + mCursorDecoupled = false; + } + } +} + +F32 LLWindowMacOSX::getNativeAspectRatio() +{ + if (mFullscreen) + { + return (F32)mFullscreenWidth / (F32)mFullscreenHeight; + } + else + { + // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution + // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. + + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + + return mOriginalAspectRatio; + } +} + +F32 LLWindowMacOSX::getPixelAspectRatio() +{ + //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode + return 1.f; +} + +//static SInt32 oldWindowLevel; + +// MBW -- XXX -- There's got to be a better way than this. Find it, please... + +// Since we're no longer supporting the "typical" fullscreen mode with CGL or NSOpenGL anymore, these are unnecessary. -Geenz +void LLWindowMacOSX::beforeDialog() +{ +} + +void LLWindowMacOSX::afterDialog() +{ + //For fix problem with Core Flow view on OSX + restoreGLContext(); +} + + +void LLWindowMacOSX::flashIcon(F32 seconds) +{ + // For consistency with macOS conventions, the number of seconds given is ignored and + // left up to the OS (which will actually bounce it for one second). + requestUserAttention(); +} + +bool LLWindowMacOSX::isClipboardTextAvailable() +{ + return pasteBoardAvailable(); +} + +bool LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) +{ + unsigned short* pboard_data = copyFromPBoard(); // must free returned data + llutf16string str(pboard_data); + free(pboard_data); + + dst = utf16str_to_wstring(str); + if (dst != L"") + { + return true; + } else { + return false; + } +} + +bool LLWindowMacOSX::copyTextToClipboard(const LLWString &s) +{ + bool result = false; + llutf16string utf16str = wstring_to_utf16str(s); + + result = copyToPBoard(utf16str.data(), utf16str.length()); + + return result; +} + + +// protected +bool LLWindowMacOSX::resetDisplayResolution() +{ + // This is only called from elsewhere in this class, and it's not used by the Mac implementation. + return true; +} + + +LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) +{ + if (!mSupportedResolutions) + { + CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); + + if(modes != NULL) + { + CFIndex index, cnt; + + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + mNumSupportedResolutions = 0; + + // Examine each mode + cnt = CFArrayGetCount( modes ); + + for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) + { + // Pull the mode dictionary out of the CFArray + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); + long width = getDictLong(mode, kCGDisplayWidth); + long height = getDictLong(mode, kCGDisplayHeight); + long bits = getDictLong(mode, kCGDisplayBitsPerPixel); + + if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) + { + bool resolution_exists = false; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == width && + mSupportedResolutions[i].mHeight == height) + { + resolution_exists = true; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = width; + mSupportedResolutions[mNumSupportedResolutions].mHeight = height; + mNumSupportedResolutions++; + } + } + } + CFRelease(modes); + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + to->mX = from.mX; + to->mY = from.mY; + return true; +} + +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + to->mX = from.mX; + to->mY = from.mY; + return true; +} + +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + if(mWindow) + { + float mouse_point[2]; + + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertScreenToWindow(mWindow, mouse_point); + + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; + + return true; + } + return false; +} + +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + if(mWindow) + { + float mouse_point[2]; + + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertWindowToScreen(mWindow, mouse_point); + + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; + + return true; + } + return false; +} + +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + + + + +void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) +{ + destroyContext(); + + OSMessageBox(text, caption, type); +} + + // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature + // it is handled at a very low-level +const char* cursorIDToName(int id) +{ + switch (id) + { + case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; + case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; + case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; + case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; + case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; + case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; + case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; + case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; + case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; + case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; + case UI_CURSOR_NO: return "UI_CURSOR_NO"; + case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; + case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; + case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; + case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; + case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; + case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; + case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; + case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; + case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; + case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; + case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; + case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; + case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; + case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; + case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; + case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; + case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; + case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; + case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; + case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; + case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; + case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; + case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; + case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; + case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; + case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; + case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; + case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; + case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; + } + + LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; + + return "UI_CURSOR_ARROW"; +} + +static CursorRef gCursors[UI_CURSOR_COUNT]; + + +static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) +{ + // cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif + std::string fullpath = gDirUtilp->add( + gDirUtilp->getAppRODataDir(), + "cursors_mac", + cursorIDToName(cursorid) + std::string(".tif")); + + gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); +} + +void LLWindowMacOSX::updateCursor() +{ + S32 result = 0; + + if (mDragOverrideCursor != -1) + { + // A drag is in progress...remember the requested cursor and we'll + // restore it when it is done + mCurrentCursor = mNextCursor; + return; + } + + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + + if(mCurrentCursor == mNextCursor) + { + if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) + { + hideNSCursor(); + adjustCursorDecouple(); + } + return; + } + + // RN: replace multi-drag cursors with single versions + if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) + { + mNextCursor = UI_CURSOR_ARROWDRAG; + } + else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) + { + mNextCursor = UI_CURSOR_ARROWCOPY; + } + + switch(mNextCursor) + { + default: + case UI_CURSOR_ARROW: + setArrowCursor(); + if(mCursorHidden) + { + // Since InitCursor resets the hide level, correct for it here. + hideNSCursor(); + } + break; + + // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. + // Find out what they look like and replicate them. + + // These are essentially correct + case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; + case UI_CURSOR_IBEAM: setIBeamCursor(); break; + case UI_CURSOR_CROSS: setCrossCursor(); break; + case UI_CURSOR_HAND: setPointingHandCursor(); break; + // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; + case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; + + // Double-check these + case UI_CURSOR_NO: + case UI_CURSOR_SIZEWE: + case UI_CURSOR_SIZENS: + case UI_CURSOR_SIZENWSE: + case UI_CURSOR_SIZENESW: + case UI_CURSOR_WORKING: + case UI_CURSOR_TOOLGRAB: + case UI_CURSOR_TOOLLAND: + case UI_CURSOR_TOOLFOCUS: + case UI_CURSOR_TOOLCREATE: + case UI_CURSOR_ARROWDRAG: + case UI_CURSOR_NOLOCKED: + case UI_CURSOR_ARROWLOCKED: + case UI_CURSOR_GRABLOCKED: + case UI_CURSOR_PIPETTE: + case UI_CURSOR_TOOLTRANSLATE: + case UI_CURSOR_TOOLROTATE: + case UI_CURSOR_TOOLSCALE: + case UI_CURSOR_TOOLCAMERA: + case UI_CURSOR_TOOLPAN: + case UI_CURSOR_TOOLZOOMIN: + case UI_CURSOR_TOOLPICKOBJECT3: + case UI_CURSOR_TOOLPLAY: + case UI_CURSOR_TOOLPAUSE: + case UI_CURSOR_TOOLMEDIAOPEN: + case UI_CURSOR_TOOLSIT: + case UI_CURSOR_TOOLBUY: + case UI_CURSOR_TOOLOPEN: + case UI_CURSOR_TOOLPATHFINDING: + case UI_CURSOR_TOOLPATHFINDING_PATH_START: + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: + case UI_CURSOR_TOOLPATHFINDING_PATH_END: + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: + case UI_CURSOR_TOOLNO: + result = setImageCursor(gCursors[mNextCursor]); + break; + + } + + if(result != noErr) + { + setArrowCursor(); + } + + mCurrentCursor = mNextCursor; +} + +ECursorType LLWindowMacOSX::getCursor() const +{ + return mCurrentCursor; +} + +void LLWindowMacOSX::initCursors() +{ + initPixmapCursor(UI_CURSOR_NO, 8, 8); + initPixmapCursor(UI_CURSOR_WORKING, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); + initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); + initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); + initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); + initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); + initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); + initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); + initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); + initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); + initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); + + initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); + initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); + initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10); + +} + +void LLWindowMacOSX::captureMouse() +{ + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. +} + +void LLWindowMacOSX::releaseMouse() +{ + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. +} + +void LLWindowMacOSX::hideCursor() +{ + if(!mCursorHidden) + { + // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; + mCursorHidden = true; + mHideCursorPermanent = true; + hideNSCursor(); + } + else + { + // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; + } + + adjustCursorDecouple(); +} + +void LLWindowMacOSX::showCursor() +{ + if(mCursorHidden || !isCGCursorVisible()) + { + // LL_INFOS() << "showCursor: showing" << LL_ENDL; + mCursorHidden = false; + mHideCursorPermanent = false; + showNSCursor(); + } + else + { + // LL_INFOS() << "showCursor: already visible" << LL_ENDL; + } + + adjustCursorDecouple(); +} + +void LLWindowMacOSX::showCursorFromMouseMove() +{ + if (!mHideCursorPermanent) + { + showCursor(); + } +} + +void LLWindowMacOSX::hideCursorUntilMouseMove() +{ + if (!mHideCursorPermanent) + { + hideCursor(); + mHideCursorPermanent = false; + } +} + + + +// +// LLSplashScreenMacOSX +// +LLSplashScreenMacOSX::LLSplashScreenMacOSX() +{ + mWindow = NULL; +} + +LLSplashScreenMacOSX::~LLSplashScreenMacOSX() +{ +} + +void LLSplashScreenMacOSX::showImpl() +{ + // This code _could_ be used to display a spash screen... +} + +void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) +{ + if(mWindow != NULL) + { + CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); + } +} + + +void LLSplashScreenMacOSX::hideImpl() +{ + if(mWindow != NULL) + { + mWindow = NULL; + } +} + +S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) +{ + return showAlert(text, caption, type); +} + +// Open a URL with the user's default web browser. +// Must begin with protocol identifier. +void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) +{ + // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. + + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + S32 result = 0; + CFURLRef urlRef = NULL; + + LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; + + CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); + if (stringRef) + { + // This will succeed if the string is a full URL, including the http:// + // Note that URLs specified this way need to be properly percent-escaped. + urlRef = CFURLCreateWithString(NULL, stringRef, NULL); + + // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs + + CFRelease(stringRef); + } + + if (urlRef) + { + result = LSOpenCFURLRef(urlRef, NULL); + + if (result != noErr) + { + LL_INFOS() << "Error " << result << " on open." << LL_ENDL; + } + + CFRelease(urlRef); + } + else + { + LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; + } +} + +// String should match ndof, so string mapping code was copied as is +static char mapChar( char c ) +{ + unsigned char uc = ( unsigned char ) c; + + switch( uc ) + { + case '/': return '-'; // use dash instead of slash + + case 0x7F: return ' '; + case 0x80: return 'A'; + case 0x81: return 'A'; + case 0x82: return 'C'; + case 0x83: return 'E'; + case 0x84: return 'N'; + case 0x85: return 'O'; + case 0x86: return 'U'; + case 0x87: return 'a'; + case 0x88: return 'a'; + case 0x89: return 'a'; + case 0x8A: return 'a'; + case 0x8B: return 'a'; + case 0x8C: return 'a'; + case 0x8D: return 'c'; + case 0x8E: return 'e'; + case 0x8F: return 'e'; + case 0x90: return ' '; + case 0x91: return ' '; // ? ' + case 0x92: return ' '; // ? ' + case 0x93: return ' '; // ? " + case 0x94: return ' '; // ? " + case 0x95: return ' '; + case 0x96: return ' '; + case 0x97: return ' '; + case 0x98: return ' '; + case 0x99: return ' '; + case 0x9A: return ' '; + case 0x9B: return 0x27; + case 0x9C: return 0x22; + case 0x9D: return ' '; + case 0x9E: return ' '; + case 0x9F: return ' '; + case 0xA0: return ' '; + case 0xA1: return ' '; + case 0xA2: return ' '; + case 0xA3: return ' '; + case 0xA4: return ' '; + case 0xA5: return ' '; + case 0xA6: return ' '; + case 0xA7: return ' '; + case 0xA8: return ' '; + case 0xA9: return ' '; + case 0xAA: return ' '; + case 0xAB: return ' '; + case 0xAC: return ' '; + case 0xAD: return ' '; + case 0xAE: return ' '; + case 0xAF: return ' '; + case 0xB0: return ' '; + case 0xB1: return ' '; + case 0xB2: return ' '; + case 0xB3: return ' '; + case 0xB4: return ' '; + case 0xB5: return ' '; + case 0xB6: return ' '; + case 0xB7: return ' '; + case 0xB8: return ' '; + case 0xB9: return ' '; + case 0xBA: return ' '; + case 0xBB: return ' '; + case 0xBC: return ' '; + case 0xBD: return ' '; + case 0xBE: return ' '; + case 0xBF: return ' '; + case 0xC0: return ' '; + case 0xC1: return ' '; + case 0xC2: return ' '; + case 0xC3: return ' '; + case 0xC4: return ' '; + case 0xC5: return ' '; + case 0xC6: return ' '; + case 0xC7: return ' '; + case 0xC8: return ' '; + case 0xC9: return ' '; + case 0xCA: return ' '; + case 0xCB: return 'A'; + case 0xCC: return 'A'; + case 0xCD: return 'O'; + case 0xCE: return ' '; + case 0xCF: return ' '; + case 0xD0: return '-'; + case 0xD1: return '-'; + case 0xD2: return 0x22; + case 0xD3: return 0x22; + case 0xD4: return 0x27; + case 0xD5: return 0x27; + case 0xD6: return '-'; // use dash instead of slash + case 0xD7: return ' '; + case 0xD8: return 'y'; + case 0xD9: return 'Y'; + case 0xDA: return '-'; // use dash instead of slash + case 0xDB: return ' '; + case 0xDC: return '<'; + case 0xDD: return '>'; + case 0xDE: return ' '; + case 0xDF: return ' '; + case 0xE0: return ' '; + case 0xE1: return ' '; + case 0xE2: return ','; + case 0xE3: return ','; + case 0xE4: return ' '; + case 0xE5: return 'A'; + case 0xE6: return 'E'; + case 0xE7: return 'A'; + case 0xE8: return 'E'; + case 0xE9: return 'E'; + case 0xEA: return 'I'; + case 0xEB: return 'I'; + case 0xEC: return 'I'; + case 0xED: return 'I'; + case 0xEE: return 'O'; + case 0xEF: return 'O'; + case 0xF0: return ' '; + case 0xF1: return 'O'; + case 0xF2: return 'U'; + case 0xF3: return 'U'; + case 0xF4: return 'U'; + case 0xF5: return '|'; + case 0xF6: return ' '; + case 0xF7: return ' '; + case 0xF8: return ' '; + case 0xF9: return ' '; + case 0xFA: return '.'; + case 0xFB: return ' '; + case 0xFC: return ' '; + case 0xFD: return 0x22; + case 0xFE: return ' '; + case 0xFF: return ' '; + } + return c; +} + +// String should match ndof for manufacturer based search to work +static void sanitizeString( char* inCStr ) +{ + char* charIt = inCStr; + while ( *charIt ) + { + *charIt = mapChar( *charIt ); + charIt++; + } +} + +struct HidDevice +{ + long mAxis; + long mLocalID; + char mProduct[256]; + char mManufacturer[256]; + long mUsage; + long mUsagePage; +}; + +static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) +{ + CFMutableDictionaryRef io_properties = nil; + io_registry_entry_t entry1; + io_registry_entry_t entry2; + kern_return_t rc; + + // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + // try to get parent1 + rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); + + IOObjectRelease( entry1 ); + + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); + // either way, release parent2 + IOObjectRelease( entry2 ); + } + } + if ( KERN_SUCCESS == rc ) + { + // IORegistryEntryCreateCFProperties() succeeded + if ( io_properties != nil ) + { + CFTypeRef dict_element = 0; + // get device info + // try hid dictionary first, if fail then go to usb dictionary + + + dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); + sanitizeString(devicep->mProduct); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); + sanitizeString(devicep->mManufacturer); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); + } + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; + } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); + if ( dict_element ) + { + if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) + { + LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; + } + } + } + + //Add axis, because ndof lib checks sutability by axises as well as other elements + devicep->mAxis = 0; + CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); + if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) + { + long count = CFArrayGetCount( (CFArrayRef) hid_elements ); + for (int i = 0; i < count; ++i) + { + CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); + if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) + { + long type = 0, usage_page = 0, usage = 0; + + CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); + } + if ( type != 0 + && type != kIOHIDElementTypeCollection + && usage_page == kHIDPage_GenericDesktop) + { + switch( usage ) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + devicep->mAxis++; + break; + default: + break; + } + } + } + } + } + + CFRelease(io_properties); + } + else + { + LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; + } + } +} + +HidDevice populate_device( io_object_t io_obj ) +{ + void* interfacep = nullptr; + HidDevice device; + memset( &device, 0, sizeof( HidDevice ) ); + CFMutableDictionaryRef device_dic = 0; + kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); + + if ( KERN_SUCCESS == result + && device_dic ) + { + IOReturn io_result = kIOReturnSuccess; + HRESULT query_result = S_OK; + SInt32 the_score = 0; + IOCFPlugInInterface **the_interface = NULL; + + + io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &the_interface, &the_score ); + if ( io_result == kIOReturnSuccess ) + { + query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); + if ( query_result != S_OK ) + { + LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; + } + IODestroyPlugInInterface( the_interface ); + } + else + { + LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; + } + + if ( interfacep ) + { + result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); + + if ( result != kIOReturnSuccess) + { + LL_WARNS("Joystick") << "open failed" << LL_ENDL; + } + } + // extract needed fields + populate_device_info( io_obj, device_dic, &device ); + + // Release interface + if ( interfacep ) + { + ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); + + ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); + + interfacep = NULL; + } + + CFRelease( device_dic ); + } + else + { + LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; + } + + return device; +} + +static void get_devices(std::list &list_of_devices, + io_iterator_t inIODeviceIterator) +{ + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + io_object_t io_obj = 0; + + while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) + { + HidDevice device = populate_device( io_obj ); + + // Should match ndof + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && device.mUsage == kHIDUsage_Game_3DGameController) + || strstr(device.mManufacturer, "3Dconnexion")) + { + list_of_devices.push_back(device); + } + else + { + LL_DEBUGS("Joystick"); + list_of_devices.push_back(device); + LL_CONT << "Device axes: " << (S32)device.mAxis + << " Device HIDUsepage: " << (S32)device.mUsagePage + << " Device HIDUsage: " << (S32)device.mUsage; + LL_ENDL; + } + + + // release the device object, it is no longer needed + result = IOObjectRelease( io_obj ); + if ( KERN_SUCCESS != result ) + { + LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; + } + } +} + +bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) +{ + bool return_value = false; + CFMutableDictionaryRef device_dict_ref; + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + + // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. + + // A dictionary to match devices to? + device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); + + // BUG FIX! one reference is consumed by IOServiceGetMatchingServices + CFRetain( device_dict_ref ); + io_iterator_t io_iter = 0; + + // create an IO object iterator + result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + if ( kIOReturnSuccess != result ) + { + LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; + } + + if ( io_iter ) + { + // add all existing devices + std::list device_list; + + get_devices(device_list, io_iter); + + std::list::iterator iter; + + for (iter = device_list.begin(); iter != device_list.end(); ++iter) + { + std::string label(iter->mProduct); + LLSD data; + data["manufacturer"] = std::string(iter->mManufacturer); + data["product"] = label; + + if (osx_callback(label, data, userdata)) + { + break; //found device + } + } + return_value = true; + } + + CFRelease( device_dict_ref ); + return return_value; +} + +LLSD LLWindowMacOSX::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + if(mRawKeyEvent) + { + result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); + result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); + result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); + result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); + result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); + result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); + } + + LL_DEBUGS() << "native key data is: " << result << LL_ENDL; + + return result; +} + +bool LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) +{ + bool retval = false; + OSErr error = noErr; + NColorPickerInfo info; + + memset(&info, 0, sizeof(info)); + info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); + info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); + info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); + info.placeWhere = kCenterOnMainScreen; + + error = NPickColor(&info); + + if (error == noErr) + { + retval = info.newColorChosen; + if (info.newColorChosen) + { + *r = ((float) info.theColor.color.rgb.red) / 65535.0; + *g = ((float) info.theColor.color.rgb.green) / 65535.0; + *b = ((float) info.theColor.color.rgb.blue) / 65535.0; + } + } + + return (retval); +} + +void *LLWindowMacOSX::getPlatformWindow() +{ + // NOTE: this will be NULL in fullscreen mode. Plan accordingly. + return (void*)mWindow; +} + +// get a double value from a dictionary +/* +static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) +{ + double double_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it + return -1; // fail + return double_value; // otherwise return the long value +}*/ + +// get a long value from a dictionary +static long getDictLong (CFDictionaryRef refDict, CFStringRef key) +{ + long int_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it + return -1; // fail + return int_value; // otherwise return the long value +} + +void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, bool b) +{ + if (preeditor != mPreeditor && !b) + { + // This condition may occur by a call to + // setEnabled(bool) against LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + // We need to interrupt before updating mPreeditor, + // so that the fix string from input method goes to + // the old preeditor. + if (mLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + if (b == mLanguageTextInputAllowed) + { + return; + } + mLanguageTextInputAllowed = b; + allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit +} + +class sharedContext +{ +public: + CGLContextObj mContext; +}; + +void* LLWindowMacOSX::createSharedContext() +{ + sharedContext* sc = new sharedContext(); + CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); + + if (sUseMultGL) + { + CGLEnable(mContext, kCGLCEMPEngine); + } + + return (void *)sc; +} + +void LLWindowMacOSX::makeContextCurrent(void* context) +{ + CGLSetCurrentContext(((sharedContext*)context)->mContext); + + //enable multi-threaded OpenGL + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; + } + } + +} + +void LLWindowMacOSX::destroySharedContext(void* context) +{ + sharedContext* sc = (sharedContext*)context; + + CGLDestroyContext(sc->mContext); + + delete sc; +} + +void LLWindowMacOSX::toggleVSync(bool enable_vsync) +{ + GLint frames_per_swap = 0; + if (!enable_vsync) + { + frames_per_swap = 0; + } + else + { + frames_per_swap = 1; + } + + CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); +} + +void LLWindowMacOSX::interruptLanguageTextInput() +{ + commitCurrentPreedit(mGLView); +} + +std::vector LLWindowMacOSX::getDisplaysResolutionList() +{ + std::vector resolution_list; + + CGDirectDisplayID display_ids[10]; + uint32_t found_displays = 0; + CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); + + if (kCGErrorSuccess != err) + { + LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; + return std::vector(); + } + + for (uint32_t i = 0; i < found_displays; i++) + { + S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); + S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + resolution_list.push_back(res); + } + + return resolution_list; +} + +//static +std::vector LLWindowMacOSX::getDynamicFallbackFontList() +{ + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector(); +} + +// static +MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) +{ + MASK mask = 0; + if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } + if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } + if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } + return mask; +} + +F32 LLWindowMacOSX::getSystemUISize() +{ + return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); +} + +#if LL_OS_DRAGDROP_ENABLED +/* +S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, + void * handlerRefCon, DragRef drag) +{ + S16 result = 0; + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + + LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; + + switch(message) + { + case kDragTrackingInWindow: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); + break; + + case kDragTrackingEnterHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); + break; + + case kDragTrackingLeaveHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); + break; + + default: + break; + } + + return result; +} +OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, + DragRef drag) +{ + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); + +} +*/ +void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) +{ + MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); + + float mouse_point[2]; + // This will return the mouse point in window coords + getCursorPos(mWindow, mouse_point); + LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); + LLCoordGL gl_pos; + convertCoords(window_coords, &gl_pos); + + if(!url.empty()) + { + LLWindowCallbacks::DragNDropResult res = + mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); + + switch (res) { + case LLWindowCallbacks::DND_NONE: // No drop allowed + if (action == LLWindowCallbacks::DNDA_TRACK) + { + mDragOverrideCursor = 0; + } + else { + mDragOverrideCursor = -1; + } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = UI_CURSOR_NO; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = UI_CURSOR_ARROWCOPY; + break; + default: + mDragOverrideCursor = -1; + break; + } + // This overrides the cursor being set by setCursor. + // This is a bit of a hack workaround because lots of areas + // within the viewer just blindly set the cursor. + if (mDragOverrideCursor == -1) + { + // Restore the cursor + ECursorType temp_cursor = mCurrentCursor; + // get around the "setting the same cursor" code in setCursor() + mCurrentCursor = UI_CURSOR_COUNT; + setCursor(temp_cursor); + } + else { + // Override the cursor + switch (mDragOverrideCursor) { + case 0: + setArrowCursor(); + break; + case UI_CURSOR_NO: + setNotAllowedCursor(); + case UI_CURSOR_ARROWCOPY: + setCopyCursor(); + default: + break; + }; + } + } +} + +#endif // LL_OS_DRAGDROP_ENABLED -- cgit v1.2.3