/indra/llwindow/llwindowmacosx.cpp
C++ | 2391 lines | 1740 code | 375 blank | 276 comment | 322 complexity | 344ddd084fdb6cbaf077b053b7b08935 MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /**
- * @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 "llwindowmacosx-objc.h"
- #include "llpreeditor.h"
- #include "llerror.h"
- #include "llgl.h"
- #include "llstring.h"
- #include "lldir.h"
- #include "indra_constants.h"
- #include <Carbon/Carbon.h>
- #include <OpenGL/OpenGL.h>
- extern BOOL gDebugWindowProc;
- // culled from winuser.h
- //const S32 WHEEL_DELTA = 120; /* Value for rolling one detent */
- // On the Mac, the scroll wheel reports a delta of 1 for each detent.
- // There's also acceleration for faster scrolling, based on a slider in the system preferences.
- const S32 WHEEL_DELTA = 1; /* Value for rolling one detent */
- const S32 BITS_PER_PIXEL = 32;
- const S32 MAX_NUM_RESOLUTIONS = 32;
- //
- // LLWindowMacOSX
- //
- BOOL LLWindowMacOSX::sUseMultGL = FALSE;
- WindowRef LLWindowMacOSX::sMediaWindow = NULL;
- // 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);
- // CarbonEvents we're interested in.
- static EventTypeSpec WindowHandlerEventList[] =
- {
- // Window-related events
- { kEventClassWindow, kEventWindowActivated },
- { kEventClassWindow, kEventWindowDeactivated },
- { kEventClassWindow, kEventWindowShown },
- { kEventClassWindow, kEventWindowHidden },
- { kEventClassWindow, kEventWindowCollapsed },
- { kEventClassWindow, kEventWindowExpanded },
- { kEventClassWindow, kEventWindowGetClickActivation },
- { kEventClassWindow, kEventWindowClose },
- { kEventClassWindow, kEventWindowBoundsChanging },
- { kEventClassWindow, kEventWindowBoundsChanged },
- { kEventClassWindow, kEventWindowGetIdealSize },
- // Mouse events
- { kEventClassMouse, kEventMouseDown },
- { kEventClassMouse, kEventMouseUp },
- { kEventClassMouse, kEventMouseDragged },
- { kEventClassMouse, kEventMouseWheelMoved },
- { kEventClassMouse, kEventMouseMoved },
- // Keyboard events
- // No longer handle raw key down events directly.
- // When text input events come in, extract the raw key events from them and process at that point.
- // This allows input methods to eat keystrokes the way they're supposed to.
- // { kEventClassKeyboard, kEventRawKeyDown },
- // { kEventClassKeyboard, kEventRawKeyRepeat },
- { kEventClassKeyboard, kEventRawKeyUp },
- { kEventClassKeyboard, kEventRawKeyModifiersChanged },
- // Text input events
- { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
- { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
- { kEventClassTextInput, kEventTextInputOffsetToPos },
- { kEventClassTextInput, kEventTextInputPosToOffset },
- { kEventClassTextInput, kEventTextInputShowHideBottomWindow },
- { kEventClassTextInput, kEventTextInputGetSelectedText },
- { kEventClassTextInput, kEventTextInputFilterText },
- // TSM Document Access events (advanced input method support)
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
- };
- static EventTypeSpec GlobalHandlerEventList[] =
- {
- // Mouse events
- { kEventClassMouse, kEventMouseDown },
- { kEventClassMouse, kEventMouseUp },
- { kEventClassMouse, kEventMouseDragged },
- { kEventClassMouse, kEventMouseWheelMoved },
- { kEventClassMouse, kEventMouseMoved },
- // Keyboard events
- // No longer handle raw key down events directly.
- // When text input events come in, extract the raw key events from them and process at that point.
- // This allows input methods to eat keystrokes the way they're supposed to.
- // { kEventClassKeyboard, kEventRawKeyDown },
- // { kEventClassKeyboard, kEventRawKeyRepeat },
- { kEventClassKeyboard, kEventRawKeyUp },
- { kEventClassKeyboard, kEventRawKeyModifiersChanged },
- // Text input events
- { kEventClassTextInput, kEventTextInputUpdateActiveInputArea },
- { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
- { kEventClassTextInput, kEventTextInputOffsetToPos },
- { kEventClassTextInput, kEventTextInputPosToOffset },
- { kEventClassTextInput, kEventTextInputShowHideBottomWindow },
- { kEventClassTextInput, kEventTextInputGetSelectedText },
- { kEventClassTextInput, kEventTextInputFilterText },
- // TSM Document Access events (advanced input method support)
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetLength },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetSelectedRange },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetCharacters },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetFont },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessGetGlyphInfo },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessLockDocument },
- { kEventClassTSMDocumentAccess, kEventTSMDocumentAccessUnlockDocument }
- };
- static EventTypeSpec CommandHandlerEventList[] =
- {
- { kEventClassCommand, kEventCommandProcess }
- };
- // 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 disable_vsync, BOOL use_gl,
- BOOL ignore_pixel_depth,
- U32 fsaa_samples)
- : 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();
- mOldDisplayMode = NULL;
- mTimer = NULL;
- mSimulatedRightClick = FALSE;
- mLastModifiers = 0;
- mHandsOffEvents = FALSE;
- mCursorDecoupled = FALSE;
- mCursorLastEventDeltaX = 0;
- mCursorLastEventDeltaY = 0;
- mCursorIgnoreNextDelta = FALSE;
- mNeedsResize = FALSE;
- mOverrideAspectRatio = 0.f;
- mMaximized = FALSE;
- mMinimized = FALSE;
- mTSMDocument = NULL; // Just in case.
- mLanguageTextInputAllowed = FALSE;
- mTSMScriptCode = 0;
- mTSMLangCode = 0;
- mPreeditor = NULL;
- mRawKeyEvent = NULL;
- mFSAASamples = fsaa_samples;
- mForceRebuild = FALSE;
- // For reasons that aren't clear to me, LLTimers seem to be created in the "started" state.
- // Since the started state of this one is used to track whether the NMRec has been installed, it wants to start out in the "stopped" state.
- mBounceTimer.stop();
- // Get the original aspect ratio of the main device.
- mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay);
- // Stash the window title
- strcpy((char*)mWindowTitle + 1, title.c_str()); /* Flawfinder: ignore */
- mWindowTitle[0] = title.length();
- mEventHandlerUPP = NewEventHandlerUPP(staticEventHandler);
- mMoveEventCampartorUPP = NewEventComparatorUPP(staticMoveEventComparator);
- mGlobalHandlerRef = NULL;
- mWindowHandlerRef = NULL;
- mDragOverrideCursor = -1;
- // We're not clipping yet
- SetRect( &mOldMouseClip, 0, 0, 0, 0 );
- // 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, disable_vsync))
- {
- if(mWindow != NULL)
- {
- // MBW -- XXX -- I think we can now do this here?
- // Constrain the window to the screen it's mostly on, resizing if necessary.
- ConstrainWindowToScreen(
- mWindow,
- kWindowStructureRgn,
- kWindowConstrainMayResize |
- // kWindowConstrainStandardOptions |
- 0,
- NULL,
- NULL);
- MacShowWindow(mWindow);
- BringToFront(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 );
- }
- mCallbacks = callbacks;
- stop_glerror();
- }
- BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync)
- {
- OSStatus err;
- BOOL glNeedsInit = FALSE;
- if(mGlobalHandlerRef == NULL)
- {
- InstallApplicationEventHandler(mEventHandlerUPP, GetEventTypeCount (CommandHandlerEventList), CommandHandlerEventList, (void*)this, &mGlobalHandlerRef);
- }
- mFullscreen = fullscreen;
- if (mFullscreen && (mOldDisplayMode == NULL))
- {
- LL_INFOS("Window") << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL;
- // NOTE: The refresh rate will be REPORTED AS 0 for many DVI and notebook displays. Plan accordingly.
- double refresh = getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate);
- // If the requested width or height is 0, find the best default for the monitor.
- if((width == 0) || (height == 0))
- {
- // Scan through the list of modes, looking for one which has:
- // height between 700 and 800
- // aspect ratio closest to the user's original mode
- S32 resolutionCount = 0;
- LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount);
- if(resolutionList != NULL)
- {
- F32 closestAspect = 0;
- U32 closestHeight = 0;
- U32 closestWidth = 0;
- int i;
- LL_DEBUGS("Window") << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << LL_ENDL;
- for(i=0; i < resolutionCount; i++)
- {
- F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight;
- LL_DEBUGS("Window") << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << LL_ENDL;
- if( (resolutionList[i].mHeight >= 700) && (resolutionList[i].mHeight <= 800) &&
- (fabs(aspect - mOriginalAspectRatio) < fabs(closestAspect - mOriginalAspectRatio)))
- {
- LL_DEBUGS("Window") << " (new closest mode) " << LL_ENDL;
- // This is the closest mode we've seen yet.
- closestWidth = resolutionList[i].mWidth;
- closestHeight = resolutionList[i].mHeight;
- closestAspect = aspect;
- }
- }
- width = closestWidth;
- height = closestHeight;
- }
- }
- if((width == 0) || (height == 0))
- {
- // Mode search failed for some reason. Use the old-school default.
- width = 1024;
- height = 768;
- }
- if (true)
- {
- // Fullscreen support
- CFDictionaryRef refDisplayMode = 0;
- boolean_t exactMatch = false;
- #if CAPTURE_ALL_DISPLAYS
- // Capture all displays (may want to do this for final build)
- CGCaptureAllDisplays ();
- #else
- // Capture only the main display (useful for debugging)
- CGDisplayCapture (mDisplay);
- #endif
- // Switch the display to the desired resolution and refresh
- refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate(
- mDisplay,
- BITS_PER_PIXEL,
- width,
- height,
- refresh,
- &exactMatch);
- if (refDisplayMode)
- {
- LL_DEBUGS("Window") << "createContext: switching display resolution" << LL_ENDL;
- mOldDisplayMode = CGDisplayCurrentMode (mDisplay);
- CGDisplaySwitchToMode (mDisplay, refDisplayMode);
- // CFRelease(refDisplayMode);
- AddEventTypesToHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList);
- }
- mFullscreen = TRUE;
- mFullscreenWidth = CGDisplayPixelsWide(mDisplay);
- mFullscreenHeight = CGDisplayPixelsHigh(mDisplay);
- mFullscreenBits = CGDisplayBitsPerPixel(mDisplay);
- mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate));
- LL_INFOS("Window") << "Running at " << mFullscreenWidth
- << "x" << mFullscreenHeight
- << "x" << mFullscreenBits
- << " @ " << mFullscreenRefresh
- << LL_ENDL;
- }
- else
- {
- // No fullscreen support
- mFullscreen = FALSE;
- mFullscreenWidth = -1;
- mFullscreenHeight = -1;
- mFullscreenBits = -1;
- mFullscreenRefresh = -1;
- std::string error= llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height);
- OSMessageBox(error, "Error", OSMB_OK);
- }
- }
- if(!mFullscreen && (mWindow == NULL))
- {
- //int displayWidth = CGDisplayPixelsWide(mDisplay);
- //int displayHeight = CGDisplayPixelsHigh(mDisplay);
- //const int menuBarPlusTitleBar = 44; // Ugly magic number.
- LL_DEBUGS("Window") << "createContext: creating window" << LL_ENDL;
- mPreviousWindowRect.left = (long) x;
- mPreviousWindowRect.right = (long) x + width;
- mPreviousWindowRect.top = (long) y;
- mPreviousWindowRect.bottom = (long) y + height;
- //-----------------------------------------------------------------------
- // Create the window
- //-----------------------------------------------------------------------
- mWindow = NewCWindow(
- NULL,
- &mPreviousWindowRect,
- mWindowTitle,
- false, // Create the window invisible. Whoever calls createContext() should show it after any moving/resizing.
- // noGrowDocProc, // Window with no grow box and no zoom box
- zoomDocProc, // Window with a grow box and a zoom box
- // zoomNoGrow, // Window with a zoom box but no grow box
- kFirstWindowOfClass,
- true,
- (long)this);
- if (!mWindow)
- {
- setupFailure("Window creation error", "Error", OSMB_OK);
- return FALSE;
- }
- // Turn on live resize.
- // For this to work correctly, we need to be able to call LLViewerWindow::draw from
- // the event handler for kEventWindowBoundsChanged. It's not clear that we have access from here.
- // err = ChangeWindowAttributes(mWindow, kWindowLiveResizeAttribute, 0);
- // Set up window event handlers (some window-related events ONLY go to window handlers.)
- InstallStandardEventHandler(GetWindowEventTarget(mWindow));
- InstallWindowEventHandler(mWindow, mEventHandlerUPP, GetEventTypeCount (WindowHandlerEventList), WindowHandlerEventList, (void*)this, &mWindowHandlerRef); // add event handler
- #if LL_OS_DRAGDROP_ENABLED
- InstallTrackingHandler( dragTrackingHandler, mWindow, (void*)this );
- InstallReceiveHandler( dragReceiveHandler, mWindow, (void*)this );
- #endif // LL_OS_DRAGDROP_ENABLED
- }
- {
- // Create and initialize our TSM document for language text input.
- // If an error occured, we can do nothing better than simply ignore it.
- // mTSMDocument will be kept NULL in case.
- if (mTSMDocument)
- {
- DeactivateTSMDocument(mTSMDocument);
- DeleteTSMDocument(mTSMDocument);
- mTSMDocument = NULL;
- }
- static InterfaceTypeList types = { kUnicodeDocument };
- err = NewTSMDocument(1, types, &mTSMDocument, 0);
- if (err != noErr)
- {
- LL_WARNS("Window") << "createContext: couldn't create a TSMDocument (" << err << ")" << LL_ENDL;
- }
- if (mTSMDocument)
- {
- ActivateTSMDocument(mTSMDocument);
- allowLanguageTextInput(NULL, FALSE);
- }
- }
- if(mContext == NULL)
- {
- AGLRendererInfo rendererInfo = NULL;
- //-----------------------------------------------------------------------
- // Create GL drawing context
- //-----------------------------------------------------------------------
- if(mPixelFormat == NULL)
- {
- if(mFullscreen)
- {
- GLint fullscreenAttrib[] =
- {
- AGL_RGBA,
- AGL_FULLSCREEN,
- AGL_NO_RECOVERY,
- AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
- AGL_SAMPLES_ARB, mFSAASamples,
- AGL_DOUBLEBUFFER,
- AGL_CLOSEST_POLICY,
- AGL_ACCELERATED,
- AGL_RED_SIZE, 8,
- AGL_GREEN_SIZE, 8,
- AGL_BLUE_SIZE, 8,
- AGL_ALPHA_SIZE, 8,
- AGL_DEPTH_SIZE, 24,
- AGL_STENCIL_SIZE, 8,
- AGL_NONE
- };
- LL_DEBUGS("Window") << "createContext: creating fullscreen pixelformat" << LL_ENDL;
- GDHandle gdhDisplay = NULL;
- err = DMGetGDeviceByDisplayID ((DisplayIDType)mDisplay, &gdhDisplay, false);
- mPixelFormat = aglChoosePixelFormat(&gdhDisplay, 1, fullscreenAttrib);
- rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1);
- }
- else
- {
- // NOTE from Leslie:
- //
- // AGL_NO_RECOVERY, when combined with AGL_ACCELERATED prevents software rendering
- // fallback which means we won't hvae shaders that compile and link but then don't
- // work. The drawback is that our shader compilation will be a bit more finicky though.
- GLint windowedAttrib[] =
- {
- AGL_RGBA,
- AGL_NO_RECOVERY,
- AGL_DOUBLEBUFFER,
- AGL_CLOSEST_POLICY,
- AGL_ACCELERATED,
- AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0,
- AGL_SAMPLES_ARB, mFSAASamples,
- AGL_RED_SIZE, 8,
- AGL_GREEN_SIZE, 8,
- AGL_BLUE_SIZE, 8,
- AGL_ALPHA_SIZE, 8,
- AGL_DEPTH_SIZE, 24,
- AGL_STENCIL_SIZE, 8,
- AGL_NONE
- };
- LL_DEBUGS("Window") << "createContext: creating windowed pixelformat" << LL_ENDL;
- mPixelFormat = aglChoosePixelFormat(NULL, 0, windowedAttrib);
- GDHandle gdhDisplay = GetMainDevice();
- rendererInfo = aglQueryRendererInfo(&gdhDisplay, 1);
- }
- // May want to get the real error text like this:
- // (char *) aglErrorString(aglGetError());
- if(aglGetError() != AGL_NO_ERROR)
- {
- setupFailure("Can't find suitable pixel format", "Error", OSMB_OK);
- return FALSE;
- }
- }
- if(mPixelFormat)
- {
- LL_DEBUGS("Window") << "createContext: creating GL context" << LL_ENDL;
- mContext = aglCreateContext(mPixelFormat, NULL);
- }
- if(mContext == NULL)
- {
- setupFailure("Can't make GL context", "Error", OSMB_OK);
- return FALSE;
- }
- gGLManager.mVRAM = 0;
- if(rendererInfo != NULL)
- {
- GLint result;
- if(aglDescribeRenderer(rendererInfo, AGL_VIDEO_MEMORY, &result))
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) returned " << result << llendl;
- gGLManager.mVRAM = result / (1024 * 1024);
- }
- else
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_VIDEO_MEMORY) failed." << llendl;
- }
- // This could be useful at some point, if it takes into account the memory already used by screen buffers, etc...
- if(aglDescribeRenderer(rendererInfo, AGL_TEXTURE_MEMORY, &result))
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) returned " << result << llendl;
- }
- else
- {
- // llinfos << "createContext: aglDescribeRenderer(AGL_TEXTURE_MEMORY) failed." << llendl;
- }
- aglDestroyRendererInfo(rendererInfo);
- }
- // Since we just created the context, it needs to be set up.
- glNeedsInit = TRUE;
- }
- // Hook up the context to a drawable
- if (mFullscreen && (mOldDisplayMode != NULL))
- {
- // We successfully captured the display. Use a fullscreen drawable
- LL_DEBUGS("Window") << "createContext: attaching fullscreen drawable" << LL_ENDL;
- #if CAPTURE_ALL_DISPLAYS
- // Capture all displays (may want to do this for final build)
- aglDisable (mContext, AGL_FS_CAPTURE_SINGLE);
- #else
- // Capture only the main display (useful for debugging)
- aglEnable (mContext, AGL_FS_CAPTURE_SINGLE);
- #endif
- if (!aglSetFullScreen (mContext, 0, 0, 0, 0))
- {
- setupFailure("Can't set GL fullscreen", "Error", OSMB_OK);
- return FALSE;
- }
- }
- else if(!mFullscreen && (mWindow != NULL))
- {
- LL_DEBUGS("Window") << "createContext: attaching windowed drawable" << LL_ENDL;
- // We created a window. Use it as the drawable.
- if(!aglSetDrawable(mContext, GetWindowPort (mWindow)))
- {
- setupFailure("Can't set GL drawable", "Error", OSMB_OK);
- return FALSE;
- }
- }
- else
- {
- setupFailure("Can't get fullscreen or windowed drawable.", "Error", OSMB_OK);
- return FALSE;
- }
- if(mContext != NULL)
- {
- LL_DEBUGS("Window") << "createContext: setting current context" << LL_ENDL;
- if (!aglSetCurrentContext(mContext))
- {
- setupFailure("Can't activate GL rendering context", "Error", OSMB_OK);
- return FALSE;
- }
- }
- if(glNeedsInit)
- {
- // Check for some explicitly unsupported cards.
- const char* RENDERER = (const char*) glGetString(GL_RENDERER);
- const char* CARD_LIST[] =
- { "RAGE 128",
- "RIVA TNT2",
- "Intel 810",
- "3Dfx/Voodoo3",
- "Radeon 7000",
- "Radeon 7200",
- "Radeon 7500",
- "Radeon DDR",
- "Radeon VE",
- "GDI Generic" };
- const S32 CARD_COUNT = LL_ARRAY_SIZE(CARD_LIST);
- // Future candidates:
- // ProSavage/Twister
- // SuperSavage
- S32 i;
- for (i = 0; i < CARD_COUNT; i++)
- {
- if (check_for_card(RENDERER, CARD_LIST[i]))
- {
- close();
- return FALSE;
- }
- }
- }
- GLint colorBits, alphaBits, depthBits, stencilBits;
- if( !aglDescribePixelFormat(mPixelFormat, AGL_BUFFER_SIZE, &colorBits) ||
- !aglDescribePixelFormat(mPixelFormat, AGL_ALPHA_SIZE, &alphaBits) ||
- !aglDescribePixelFormat(mPixelFormat, AGL_DEPTH_SIZE, &depthBits) ||
- !aglDescribePixelFormat(mPixelFormat, AGL_STENCIL_SIZE, &stencilBits))
- {
- close();
- setupFailure("Can't get pixel format description", "Error", OSMB_OK);
- return FALSE;
- }
- LL_INFOS("GLInit") << "GL buffer: Color Bits " << S32(colorBits)
- << " Alpha Bits " << S32(alphaBits)
- << " Depth Bits " << S32(depthBits)
- << " Stencil Bits" << S32(stencilBits)
- << LL_ENDL;
- if (colorBits < 32)
- {
- close();
- setupFailure(
- "Second Life requires True Color (32-bit) to run in a window.\n"
- "Please go to Control Panels -> Display -> Settings and\n"
- "set the screen to 32-bit color.\n"
- "Alternately, if you choose to run fullscreen, Second Life\n"
- "will automatically adjust the screen each time it runs.",
- "Error",
- OSMB_OK);
- return FALSE;
- }
- if (alphaBits < 8)
- {
- close();
- setupFailure(
- "Second Life is unable to run because it can't get an 8 bit alpha\n"
- "channel. Usually this is due to video card driver issues.\n"
- "Please make sure you have the latest video card drivers installed.\n"
- "Also be sure your monitor is set to True Color (32-bit) in\n"
- "Control Panels -> Display -> Settings.\n"
- "If you continue to receive this message, contact customer service.",
- "Error",
- OSMB_OK);
- return FALSE;
- }
- // Disable vertical sync for swap
- GLint frames_per_swap = 0;
- if (disable_vsync)
- {
- LL_DEBUGS("GLInit") << "Disabling vertical sync" << LL_ENDL;
- frames_per_swap = 0;
- }
- else
- {
- LL_DEBUGS("GLinit") << "Keeping vertical sync" << LL_ENDL;
- frames_per_swap = 1;
- }
- aglSetInteger(mContext, AGL_SWAP_INTERVAL, &frames_per_swap);
- //enable multi-threaded OpenGL
- if (sUseMultGL)
- {
- CGLError cgl_err;
- CGLContextObj ctx = CGLGetCurrentContext();
- cgl_err = CGLEnable( ctx, kCGLCEMPEngine);
- if (cgl_err != kCGLNoError )
- {
- LL_DEBUGS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL;
- }
- else
- {
- LL_DEBUGS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL;
- }
- }
- // Don't need to get the current gamma, since there's a call that restores it to the system defaults.
- return TRUE;
- }
- // changing fullscreen resolution, or switching between windowed and fullscreen mode.
- BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)
- {
- BOOL needsRebuild = FALSE;
- BOOL result = true;
- if(fullscreen)
- {
- if(mFullscreen)
- {
- // Switching resolutions in fullscreen mode. Don't need to rebuild for this.
- // Fullscreen support
- CFDictionaryRef refDisplayMode = 0;
- boolean_t exactMatch = false;
- // Switch the display to the desired resolution and refresh
- refDisplayMode = CGDisplayBestModeForParametersAndRefreshRate(
- mDisplay,
- BITS_PER_PIXEL,
- size.mX,
- size.mY,
- getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate),
- &exactMatch);
- if (refDisplayMode)
- {
- CGDisplaySwitchToMode (mDisplay, refDisplayMode);
- // CFRelease(refDisplayMode);
- }
- mFullscreenWidth = CGDisplayPixelsWide(mDisplay);
- mFullscreenHeight = CGDisplayPixelsHigh(mDisplay);
- mFullscreenBits = CGDisplayBitsPerPixel(mDisplay);
- mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate));
- LL_INFOS("Window") << "Switched resolution to " << mFullscreenWidth
- << "x" << mFullscreenHeight
- << "x" << mFullscreenBits
- << " @ " << mFullscreenRefresh
- << LL_ENDL;
- // Update the GL context to the new screen size
- if (!aglUpdateContext(mContext))
- {
- setupFailure("Can't set GL fullscreen", "Error", OSMB_OK);
- result = FALSE;
- }
- }
- else
- {
- // Switching from windowed to fullscreen
- needsRebuild = TRUE;
- }
- }
- else
- {
- if(mFullscreen)
- {
- // Switching from fullscreen to windowed
- needsRebuild = TRUE;
- }
- else
- {
- // Windowed to windowed -- not sure why we would be called like this. Just change the window size.
- // The bounds changed event handler will do the rest.
- if(mWindow != NULL)
- {
- ::SizeWindow(mWindow, size.mX, size.mY, true);
- }
- }
- }
- stop_glerror();
- if(needsRebuild || mForceRebuild)
- {
- mForceRebuild = FALSE;
- destroyContext();
- result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync);
- if (result)
- {
- if(mWindow != NULL)
- {
- MacShowWindow(mWindow);
- BringToFront(mWindow);
- }
- llverify(gGLManager.initGL());
- //start with arrow cursor
- initCursors();
- setCursor( UI_CURSOR_ARROW );
- }
- }
- stop_glerror();
- return result;
- }
- 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;
- aglSetCurrentContext (NULL);
- aglSetDrawable(mContext, NULL);
- }
- // Make sure the display resolution gets restored
- if(mOldDisplayMode != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: restoring display resolution " << LL_ENDL;
- CGDisplaySwitchToMode (mDisplay, mOldDisplayMode);
- #if CAPTURE_ALL_DISPLAYS
- // Uncapture all displays (may want to do this for final build)
- CGReleaseAllDisplays ();
- #else
- // Uncapture only the main display (useful for debugging)
- CGDisplayRelease (mDisplay);
- #endif
- // CFRelease(mOldDisplayMode);
- mOldDisplayMode = NULL;
- // Remove the global event handlers the fullscreen case needed
- RemoveEventTypesFromHandler(mGlobalHandlerRef, GetEventTypeCount (GlobalHandlerEventList), GlobalHandlerEventList);
- }
- // Clean up remaining GL state before blowing away window
- gGLManager.shutdownGL();
- // Clean up the pixel format
- if(mPixelFormat != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: destroying pixel format " << LL_ENDL;
- aglDestroyPixelFormat(mPixelFormat);
- mPixelFormat = NULL;
- }
- // Remove any Carbon Event handlers we installed
- if(mGlobalHandlerRef != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: removing global event handler" << LL_ENDL;
- RemoveEventHandler(mGlobalHandlerRef);
- mGlobalHandlerRef = NULL;
- }
- if(mWindowHandlerRef != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: removing window event handler" << LL_ENDL;
- RemoveEventHandler(mWindowHandlerRef);
- mWindowHandlerRef = NULL;
- }
- // Cleanup any TSM document we created.
- if(mTSMDocument != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: deleting TSM document" << LL_ENDL;
- DeactivateTSMDocument(mTSMDocument);
- DeleteTSMDocument(mTSMDocument);
- mTSMDocument = NULL;
- }
- // Close the window
- if(mWindow != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: disposing window" << LL_ENDL;
- DisposeWindow(mWindow);
- mWindow = NULL;
- }
- // Clean up the GL context
- if(mContext != NULL)
- {
- LL_DEBUGS("Window") << "destroyContext: destroying GL context" << LL_ENDL;
- aglDestroyContext(mContext);
- mContext = NULL;
- }
- }
- LLWindowMacOSX::~LLWindowMacOSX()
- {
- destroyContext();
- if(mSupportedResolutions != NULL)
- {
- delete []mSupportedResolutions;
- }
- gWindowImplementation = NULL;
- }
- void LLWindowMacOSX::show()
- {
- if(IsWindowCollapsed(mWindow))
- CollapseWindow(mWindow, false);
- MacShowWindow(mWindow);
- BringToFront(mWindow);
- }
- void LLWindowMacOSX::hide()
- {
- setMouseClipping(FALSE);
- HideWindow(mWindow);
- }
- //virtual
- void LLWindowMacOSX::minimize()
- {
- setMouseClipping(FALSE);
- showCursor();
- CollapseWindow(mWindow, true);
- }
- //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)
- {
- if(MacIsWindowVisible(mWindow))
- result = TRUE;
- }
- return(result);
- }
- BOOL LLWindowMacOSX::getMinimized()
- {
- return mMinimized;
- }
- BOOL LLWindowMacOSX::getMaximized()
- {
- return mMaximized;
- }
- BOOL LLWindowMacOSX::maximize()
- {
- if (mWindow && !mMaximized)
- {
- ZoomWindow(mWindow, inContent, true);
- }
- return mMaximized;
- }
- BOOL LLWindowMacOSX::getFullscreen()
- {
- return mFullscreen;
- }
- void LLWindowMacOSX::gatherInput()
- {
- // stop bouncing icon after fixed period of time
- if (mBounceTimer.getStarted() && mBounceTimer.getElapsedTimeF32() > mBounceTime)
- {
- stopDockTileBounce();
- }
- // Use the old-school version so we get AppleEvent handler dispatch and menuselect handling.
- // Anything that has an event handler will get processed inside WaitNextEvent, so we only need to handle
- // the odd stuff here.
- EventRecord evt;
- while(WaitNextEvent(everyEvent, &evt, 0, NULL))
- {
- // printf("WaitNextEvent returned true, event is %d.\n", evt.what);
- switch(evt.what)
- {
- case mouseDown:
- {
- short part;
- WindowRef window;
- long selectResult;
- part = FindWindow(evt.where, &window);
- switch ( part )
- {
- case inMenuBar:
- selectResult = MenuSelect(evt.where);
- HiliteMenu(0);
- break;
- }
- }
- break;
- case kHighLevelEvent:
- AEProcessAppleEvent (&evt);
- break;
- case updateEvt:
- // We shouldn't be getting these regularly (since our window will be buffered), but we need to handle them correctly...
- BeginUpdate((WindowRef)evt.message);
- EndUpdate((WindowRef)evt.message);
- break;
- }
- }
-
- updateCursor();
- }
- BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position)
- {
- Rect window_rect;
- OSStatus err = -1;
- if(mFullscreen)
- {
- position->mX = 0;
- position->mY = 0;
- err = noErr;
- }
- else if(mWindow)
- {
- err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect);
- position->mX = window_rect.left;
- position->mY = window_rect.top;
- }
- else
- {
- llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl;
- }
- return (err == noErr);
- }
- BOOL LLWindowMacOSX::getSize(LLCoordScreen *size)
- {
- Rect window_rect;
- OSStatus err = -1;
- if(mFullscreen)
- {
- size->mX = mFullscreenWidth;
- size->mY = mFullscreenHeight;
- err = noErr;
- }
- else if(mWindow)
- {
- err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect);
- size->mX = window_rect.right - window_rect.left;
- size->mY = window_rect.bottom - window_rect.top;
- }
- else
- {
- llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl;
- }
- return (err == noErr);
- }
- BOOL LLWindowMacOSX::getSize(LLCoordWindow *size)
- {
- Rect window_rect;
- OSStatus err = -1;
- if(mFullscreen)
- {
- size->mX = mFullscreenWidth;
- size->mY = mFullscreenHeight;
- err = noErr;
- }
- else if(mWindow)
- {
- err = GetWindowBounds(mWindow, kWindowContentRgn, &window_rect);
- size->mX = window_rect.right - window_rect.left;
- size->mY = window_rect.bottom - window_rect.top;
- }
- else
- {
- llerrs << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << llendl;
- }
- return (err == noErr);
- }
- BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position)
- {
- if(mWindow)
- {
- MacMoveWindow(mWindow, position.mX, position.mY, false);
- }
- return TRUE;
- }
- BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size)
- {
- if(mWindow)
- {
- SizeWindow(mWindow, size.mX, size.mY, true);
- }
- return TRUE;
- }
- void LLWindowMacOSX::swapBuffers()
- {
- aglSwapBuffers(mContext);
- }
- F32 LLWindowMacOSX::getGamma()
- {
- F32 result = 1.8; // 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)
- {
- // llinfos << "setMouseClipping(TRUE)" << llendl;
- }
- else
- {
- // llinfos << "setMouseClipping(FALSE)" << llendl;
- }
- adjustCursorDecouple();
- }
- BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
- {
- BOOL result = FALSE;
- LLCoordScreen screen_pos;
- if (!convertCoords(position, &screen_pos))
- {
- return FALSE;
- }
- CGPoint newPosition;
- // llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl;
- 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);
- mCallbacks->handleMouseMove(this, gl_pos, (MASK)0);
- return result;
- }
- static void fixOrigin(void)
- {
- GrafPtr port;
- Rect portrect;
- ::GetPort(&port);
- ::GetPortBounds(port, &portrect);
- if((portrect.left != 0) || (portrect.top != 0))
- {
- // Mozilla sometimes changes our port origin.
- ::SetOrigin(0,0);
- }
- }
- BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position)
- {
- Point cursor_point;
- LLCoordScreen screen_pos;
- GrafPtr save;
- if(mWindow == NULL)
- return FALSE;
- ::GetPort(&save);
- ::SetPort(GetWindowPort(mWindow));
- fixOrigin();
- // gets the mouse location in local coordinates
- ::GetMouse(&cursor_point);
- // lldebugs << "getCursorPosition(): cursor is at " << cursor_point.h << ", " << cursor_point.v << " port origin: " << portrect.left << ", " << portrect.top << llendl;
- ::SetPort(save);
- 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.h += mCursorLastEventDeltaX;
- cursor_point.v += mCursorLastEventDeltaY;
- }
- position->mX = cursor_point.h;
- position->mY = cursor_point.v;
- return TRUE;
- }
- void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse)
- {
- if(mIsMouseClipping && mCursorHidden)
- {
- if(warpingMouse)
- {
- // The cursor should be decoupled. Make sure it is.
- if(!mCursorDecoupled)
- {
- // llinfos << "adjustCursorDecouple: decoupling cursor" << llendl;
- CGAssociateMouseAndMouseCursorPosition(false);
- mCursorDecoupled = true;
- FlushSpecificEventsFromQueue(GetCurrentEventQueue(), mMoveEventCampartorUPP, NULL);
- mCursorIgnoreNextDelta = TRUE;
- }
- }
- }
- else
- {
- // The cursor should not be decoupled. Make sure it isn't.
- if(mCursorDecoupled)
- {
- // llinfos << "adjustCursorDecouple: recoupling cursor" << llendl;
- 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()
- {
- //OS X 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...
- void LLWindowMacOSX::beforeDialog()
- {
- if(mFullscreen)
- {
- #if CAPTURE_ALL_DISPLAYS
- // Uncapture all displays (may want to do this for final build)
- CGReleaseAllDisplays ();
- #else
- // Uncapture only the main display (useful for debugging)
- CGDisplayRelease (mDisplay);
- #endif
- // kDocumentWindowClass
- // kMovableModalWindowClass
- // kAllWindowClasses
- // GLint order = 0;
- // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order);
- aglSetDrawable(mContext, NULL);
- // GetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), &oldWindowLevel);
- // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), CGShieldingWindowLevel());
- mHandsOffEvents = TRUE;
- }
- }
- void LLWindowMacOSX::afterDialog()
- {
- if(mFullscreen)
- {
- mHandsOffEvents = FALSE;
- // SetWindowGroupLevel(GetWindowGroupOfClass(kAllWindowClasses), oldWindowLevel);
- aglSetFullScreen(mContext, 0, 0, 0, 0);
- // GLint order = 1;
- // aglSetInteger(mContext, AGL_ORDER_CONTEXT_TO_FRONT, &order);
- #if CAPTURE_ALL_DISPLAYS
- // Capture all displays (may want to do this for final build)
- CGCaptureAllDisplays ();
- #else
- // Capture only the main display (useful for debugging)
- CGDisplayCapture (mDisplay);
- #endif
- }
- }
- void LLWindowMacOSX::flashIcon(F32 seconds)
- {
- // Don't do this if we're already started, since this would try to install the NMRec twice.
- if(!mBounceTimer.getStarted())
- {
- OSErr err;
- mBounceTime = seconds;
- memset(&mBounceRec, 0, sizeof(mBounceRec));
- mBounceRec.qType = nmType;
- mBounceRec.nmMark = 1;
- err = NMInstall(&mBounceRec);
- if(err == noErr)
- {
- mBounceTimer.start();
- }
- else
- {
- // This is very not-fatal (only problem is the icon will not bounce), but we'd like to find out about it somehow...
- llinfos << "NMInstall failed with error code " << err << llendl;
- }
- }
- }
- BOOL LLWindowMacOSX::isClipboardTextAvailable()
- {
- OSStatus err;
- ScrapRef scrap;
- ScrapFlavorFlags flags;
- BOOL result = false;
- err = GetCurrentScrap(&scrap);
- if(err == noErr)
- {
- err = GetScrapFlavorFlags(scrap, kScrapFlavorTypeUnicode, &flags);
- }
- if(err == noErr)
- result = true;
- return result;
- }
- BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst)
- {
- OSStatus err;
- ScrapRef scrap;
- Size len;
- BOOL result = false;
- err = GetCurrentScrap(&scrap);
- if(err == noErr)
- {
- err = GetScrapFlavorSize(scrap, kScrapFlavorTypeUnicode, &len);
- }
- if((err == noErr) && (len > 0))
- {
- int u16len = len / sizeof(U16);
- U16 *temp = new U16[u16len + 1];
- if (temp)
- {
- memset(temp, 0, (u16len + 1) * sizeof(temp[0]));
- err = GetScrapFlavorData(scrap, kScrapFlavorTypeUnicode, &len, temp);
- if (err == noErr)
- {
- // convert \r\n to \n and \r to \n in the incoming text.
- U16 *s, *d;
- for(s = d = temp; s[0] != '\0'; s++, d++)
- {
- if(s[0] == '\r')
- {
- if(s[1] == '\n')
- {
- // CRLF, a.k.a. DOS newline. Collapse to a single '\n'.
- s++;
- }
- d[0] = '\n';
- }
- else
- {
- d[0] = s[0];
- }
- }
- d[0] = '\0';
- dst = utf16str_to_wstring(temp);
- result = true;
- }
- delete[] temp;
- }
- }
- return result;
- }
- BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s)
- {
- OSStatus err;
- ScrapRef scrap;
- //Size len;
- //char *temp;
- BOOL result = false;
- if (!s.empty())
- {
- err = GetCurrentScrap(&scrap);
- if (err == noErr)
- err = ClearScrap(&scrap);
- if (err == noErr)
- {
- llutf16string utf16str = wstring_to_utf16str(s);
- size_t u16len = utf16str.length() * sizeof(U16);
- err = PutScrapFlavor(scrap, kScrapFlavorTypeUnicode, kScrapFlavorMaskNone, u16len, utf16str.data());
- if (err == noErr)
- result = true;
- }
- }
- 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 = CGDisplayAvailableModes(mDisplay);
- 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++;
- }
- }
- }
- }
- }
- num_resolutions = mNumSupportedResolutions;
- return mSupportedResolutions;
- }
- BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to)
- {
- S32 client_height;
- Rect client_rect;
- if(mFullscreen)
- {
- // In the fullscreen case, the "window" is the entire screen.
- client_rect.left = 0;
- client_rect.top = 0;
- client_rect.right = mFullscreenWidth;
- client_rect.bottom = mFullscreenHeight;
- }
- else if (!mWindow ||
- (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) ||
- NULL == to)
- {
- return FALSE;
- }
- to->mX = from.mX;
- client_height = client_rect.bottom - client_rect.top;
- to->mY = client_height - from.mY - 1;
- return TRUE;
- }
- BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to)
- {
- S32 client_height;
- Rect client_rect;
- if(mFullscreen)
- {
- // In the fullscreen case, the "window" is the entire screen.
- client_rect.left = 0;
- client_rect.top = 0;
- client_rect.right = mFullscreenWidth;
- client_rect.bottom = mFullscreenHeight;
- }
- else if (!mWindow ||
- (GetWindowBounds(mWindow, kWindowContentRgn, &client_rect) != noErr) ||
- NULL == to)
- {
- return FALSE;
- }
- to->mX = from.mX;
- client_height = client_rect.bottom - client_rect.top;
- to->mY = client_height - from.mY - 1;
- return TRUE;
- }
- BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to)
- {
- if(mFullscreen)
- {
- // In the fullscreen case, window and screen coordinates are the same.
- to->mX = from.mX;
- to->mY = from.mY;
- return TRUE;
- }
- else if(mWindow)
- {
- GrafPtr save;
- Point mouse_point;
- mouse_point.h = from.mX;
- mouse_point.v = from.mY;
- ::GetPort(&save);
- ::SetPort(GetWindowPort(mWindow));
- fixOrigin();
- ::GlobalToLocal(&mouse_point);
- to->mX = mouse_point.h;
- to->mY = mouse_point.v;
- ::SetPort(save);
- return TRUE;
- }
- return FALSE;
- }
- BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to)
- {
- if(mFullscreen)
- {
- // In the fullscreen case, window and screen coordinates are the same.
- to->mX = from.mX;
- to->mY = from.mY;
- return TRUE;
- }
- else if(mWindow)
- {
- GrafPtr save;
- Point mouse_point;
- mouse_point.h = from.mX;
- mouse_point.v = from.mY;
- ::GetPort(&save);
- ::SetPort(GetWindowPort(mWindow));
- fixOrigin();
- LocalToGlobal(&mouse_point);
- to->mX = mouse_point.h;
- to->mY = mouse_point.v;
- ::SetPort(save);
- 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);
- }
- pascal Boolean LLWindowMacOSX::staticMoveEventComparator( EventRef event, void* data)
- {
- UInt32 evtClass = GetEventClass (event);
- UInt32 evtKind = GetEventKind (event);
- if ((evtClass == kEventClassMouse) && ((evtKind == kEventMouseDragged) || (evtKind == kEventMouseMoved)))
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- pascal OSStatus LLWindowMacOSX::staticEventHandler(EventHandlerCallRef myHandler, EventRef event, void* userData)
- {
- LLWindowMacOSX *self = (LLWindowMacOSX*)userData;
- return(self->eventHandler(myHandler, event));
- }
- OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef event)
- {
- OSStatus result = eventNotHandledErr;
- UInt32 evtClass = GetEventClass (event);
- UInt32 evtKind = GetEventKind (event);
- // Always handle command events, even in hands-off mode.
- if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
- {
- HICommand command;
- GetEventParameter (event, kEventParamDirec…
Large files files are truncated, but you can click here to view the full file