diff options
Diffstat (limited to 'indra/llwindow/llwindowmacosx.cpp')
-rw-r--r-- | indra/llwindow/llwindowmacosx.cpp | 655 |
1 files changed, 455 insertions, 200 deletions
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index a1d97429e1..affd7276cc 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -2,54 +2,45 @@ * @file llwindowmacosx.cpp * @brief Platform-dependent implementation of llwindow * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * 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. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * 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. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * 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$ */ -#if LL_DARWIN - #include "linden_common.h" -#include <Carbon/Carbon.h> -#include <OpenGL/OpenGL.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 "llviewercontrol.h" - -#include "llglheaders.h" - #include "indra_constants.h" -#include "llwindowmacosx-objc.h" -#include "llpreeditor.h" +#include <Carbon/Carbon.h> +#include <OpenGL/OpenGL.h> extern BOOL gDebugWindowProc; @@ -66,37 +57,16 @@ const S32 MAX_NUM_RESOLUTIONS = 32; // LLWindowMacOSX // -// Cross-platform bits: +BOOL LLWindowMacOSX::sUseMultGL = FALSE; +WindowRef LLWindowMacOSX::sMediaWindow = NULL; -void show_window_creation_error(const char* title) -{ - llwarns << title << llendl; - /* - OSMessageBox( - "Second Life is unable to run because it can't set up your display.\n" - "We need to be able to make a 32-bit color window at 1024x768, with\n" - "an 8 bit alpha channel.\n" - "\n" - "First, be sure your monitor is set to True Color (32-bit) in\n" - "Start -> Control Panels -> Display -> Settings.\n" - "\n" - "Otherwise, this may be due to video card driver issues.\n" - "Please make sure you have the latest video card drivers installed.\n" - "ATI drivers are available at http://www.ati.com/\n" - "nVidia drivers are available at http://www.nvidia.com/\n" - "\n" - "If you continue to receive this message, contact customer service.", - title, - OSMB_OK); - */ -} +// Cross-platform bits: BOOL check_for_card(const char* RENDERER, const char* bad_card) { if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) { - char buffer[1024];/* Flawfinder: ignore */ - snprintf(buffer, sizeof(buffer), + 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" @@ -110,7 +80,7 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card) "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, "Unsupported video card", OSMB_YESNO); + S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); if (OSBTN_YES == button) { return FALSE; @@ -124,8 +94,6 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card) 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... @@ -242,18 +210,27 @@ static LLWindowMacOSX *gWindowImplementation = NULL; -LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width, +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) - : LLWindow(fullscreen, flags) -{ + 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; @@ -277,6 +254,9 @@ LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width, 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. @@ -286,12 +266,15 @@ LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width, mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); // Stash the window title - strcpy((char*)mWindowTitle + 1, title); /* Flawfinder: ignore */ - mWindowTitle[0] = strlen(title); /* Flawfinder: ignore */ + 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 ); @@ -339,6 +322,7 @@ LLWindowMacOSX::LLWindowMacOSX(char *title, char *name, S32 x, S32 y, S32 width, setCursor( UI_CURSOR_ARROW ); } + mCallbacks = callbacks; stop_glerror(); } @@ -356,7 +340,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if (mFullscreen && (mOldDisplayMode == NULL)) { - llinfos << "createContext: setting up fullscreen " << width << "x" << height << llendl; + 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); @@ -377,18 +361,18 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits U32 closestWidth = 0; int i; - llinfos << "createContext: searching for a display mode, original aspect is " << mOriginalAspectRatio << llendl; + 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; - llinfos << "createContext: width " << resolutionList[i].mWidth << " height " << resolutionList[i].mHeight << " aspect " << aspect << llendl; + 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))) { - llinfos << " (new closest mode) " << llendl; + LL_DEBUGS("Window") << " (new closest mode) " << LL_ENDL; // This is the closest mode we've seen yet. closestWidth = resolutionList[i].mWidth; @@ -434,7 +418,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if (refDisplayMode) { - llinfos << "createContext: switching display resolution" << llendl; + LL_DEBUGS("Window") << "createContext: switching display resolution" << LL_ENDL; mOldDisplayMode = CGDisplayCurrentMode (mDisplay); CGDisplaySwitchToMode (mDisplay, refDisplayMode); // CFRelease(refDisplayMode); @@ -449,11 +433,11 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits mFullscreenBits = CGDisplayBitsPerPixel(mDisplay); mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate)); - llinfos << "Running at " << mFullscreenWidth + LL_INFOS("Window") << "Running at " << mFullscreenWidth << "x" << mFullscreenHeight << "x" << mFullscreenBits << " @ " << mFullscreenRefresh - << llendl; + << LL_ENDL; } else { @@ -464,8 +448,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits mFullscreenBits = -1; mFullscreenRefresh = -1; - char error[256]; /* Flawfinder: ignore */ - snprintf(error, sizeof(error), "Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); + std::string error= llformat("Unable to run fullscreen at %d x %d.\nRunning in window.", width, height); OSMessageBox(error, "Error", OSMB_OK); } } @@ -477,7 +460,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits //int displayHeight = CGDisplayPixelsHigh(mDisplay); //const int menuBarPlusTitleBar = 44; // Ugly magic number. - llinfos << "createContext: creating window" << llendl; + LL_DEBUGS("Window") << "createContext: creating window" << LL_ENDL; window_rect.left = (long) x; window_rect.right = (long) x + width; @@ -513,8 +496,11 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // 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 - + 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 } { @@ -531,12 +517,11 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits err = NewTSMDocument(1, types, &mTSMDocument, 0); if (err != noErr) { - llwarns << "createContext: couldn't create a TSMDocument (" << err << ")" << llendl; + LL_WARNS("Window") << "createContext: couldn't create a TSMDocument (" << err << ")" << LL_ENDL; } if (mTSMDocument) { ActivateTSMDocument(mTSMDocument); - UseInputWindow(mTSMDocument, FALSE); allowLanguageTextInput(NULL, FALSE); } } @@ -558,6 +543,8 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits AGL_RGBA, AGL_FULLSCREEN, // AGL_NO_RECOVERY, // MBW -- XXX -- Not sure if we want this attribute + AGL_SAMPLE_BUFFERS_ARB, mFSAASamples > 0 ? 1 : 0, + AGL_SAMPLES_ARB, mFSAASamples, AGL_DOUBLEBUFFER, AGL_CLOSEST_POLICY, AGL_ACCELERATED, @@ -570,7 +557,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits AGL_NONE }; - llinfos << "createContext: creating fullscreen pixelformat" << llendl; + LL_DEBUGS("Window") << "createContext: creating fullscreen pixelformat" << LL_ENDL; GDHandle gdhDisplay = NULL; err = DMGetGDeviceByDisplayID ((DisplayIDType)mDisplay, &gdhDisplay, false); @@ -586,6 +573,8 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits 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, @@ -595,7 +584,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits AGL_NONE }; - llinfos << "createContext: creating windowed pixelformat" << llendl; + LL_DEBUGS("Window") << "createContext: creating windowed pixelformat" << LL_ENDL; mPixelFormat = aglChoosePixelFormat(NULL, 0, windowedAttrib); @@ -615,7 +604,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if(mPixelFormat) { - llinfos << "createContext: creating GL context" << llendl; + LL_DEBUGS("Window") << "createContext: creating GL context" << LL_ENDL; mContext = aglCreateContext(mPixelFormat, NULL); } @@ -663,7 +652,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits { // We successfully captured the display. Use a fullscreen drawable - llinfos << "createContext: attaching fullscreen drawable" << llendl; + LL_DEBUGS("Window") << "createContext: attaching fullscreen drawable" << LL_ENDL; #if CAPTURE_ALL_DISPLAYS // Capture all displays (may want to do this for final build) @@ -681,7 +670,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits } else if(!mFullscreen && (mWindow != NULL)) { - llinfos << "createContext: attaching windowed drawable" << llendl; + LL_DEBUGS("Window") << "createContext: attaching windowed drawable" << LL_ENDL; // We created a window. Use it as the drawable. if(!aglSetDrawable(mContext, GetWindowPort (mWindow))) @@ -698,7 +687,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if(mContext != NULL) { - llinfos << "createContext: setting current context" << llendl; + LL_DEBUGS("Window") << "createContext: setting current context" << LL_ENDL; if (!aglSetCurrentContext(mContext)) { @@ -723,7 +712,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits "Radeon DDR", "Radeon VE", "GDI Generic" }; - const S32 CARD_COUNT = sizeof(CARD_LIST)/sizeof(char*); + const S32 CARD_COUNT = LL_ARRAY_SIZE(CARD_LIST); // Future candidates: // ProSavage/Twister @@ -752,11 +741,11 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits return FALSE; } - llinfos << "GL buffer: Color Bits " << S32(colorBits) + LL_INFOS("GLInit") << "GL buffer: Color Bits " << S32(colorBits) << " Alpha Bits " << S32(alphaBits) << " Depth Bits " << S32(depthBits) << " Stencil Bits" << S32(stencilBits) - << llendl; + << LL_ENDL; if (colorBits < 32) { @@ -791,18 +780,18 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits GLint frames_per_swap = 0; if (disable_vsync) { - llinfos << "Disabling vertical sync" << llendl; + LL_DEBUGS("GLInit") << "Disabling vertical sync" << LL_ENDL; frames_per_swap = 0; } else { - llinfos << "Keeping vertical sync" << llendl; + 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 (gSavedSettings.getBOOL("RenderAppleUseMultGL")) + if (sUseMultGL) { CGLError cgl_err; CGLContextObj ctx = CGLGetCurrentContext(); @@ -811,11 +800,11 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if (cgl_err != kCGLNoError ) { - llinfos << "Multi-threaded OpenGL not available." << llendl; + LL_DEBUGS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; } else { - llinfos << "Multi-threaded OpenGL enabled." << llendl; + LL_DEBUGS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; } } @@ -825,7 +814,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // changing fullscreen resolution, or switching between windowed and fullscreen mode. -BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync) +BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) { BOOL needsRebuild = FALSE; BOOL result = true; @@ -859,11 +848,11 @@ BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL dis mFullscreenBits = CGDisplayBitsPerPixel(mDisplay); mFullscreenRefresh = llround(getDictDouble (CGDisplayCurrentMode (mDisplay), kCGDisplayRefreshRate)); - llinfos << "Switched resolution to " << mFullscreenWidth + LL_INFOS("Window") << "Switched resolution to " << mFullscreenWidth << "x" << mFullscreenHeight << "x" << mFullscreenBits << " @ " << mFullscreenRefresh - << llendl; + << LL_ENDL; // Update the GL context to the new screen size if (!aglUpdateContext(mContext)) @@ -897,8 +886,9 @@ BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, LLCoordScreen size, BOOL dis } stop_glerror(); - if(needsRebuild) + if(needsRebuild || mForceRebuild) { + mForceRebuild = FALSE; destroyContext(); result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); if (result) @@ -932,7 +922,7 @@ void LLWindowMacOSX::destroyContext() // Unhook the GL context from any drawable it may have if(mContext != NULL) { - llinfos << "destroyContext: unhooking drawable " << llendl; + LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; aglSetCurrentContext (NULL); aglSetDrawable(mContext, NULL); @@ -941,7 +931,7 @@ void LLWindowMacOSX::destroyContext() // Make sure the display resolution gets restored if(mOldDisplayMode != NULL) { - llinfos << "destroyContext: restoring display resolution " << llendl; + LL_DEBUGS("Window") << "destroyContext: restoring display resolution " << LL_ENDL; CGDisplaySwitchToMode (mDisplay, mOldDisplayMode); @@ -967,7 +957,7 @@ void LLWindowMacOSX::destroyContext() // Clean up the pixel format if(mPixelFormat != NULL) { - llinfos << "destroyContext: destroying pixel format " << llendl; + LL_DEBUGS("Window") << "destroyContext: destroying pixel format " << LL_ENDL; aglDestroyPixelFormat(mPixelFormat); mPixelFormat = NULL; } @@ -975,14 +965,14 @@ void LLWindowMacOSX::destroyContext() // Remove any Carbon Event handlers we installed if(mGlobalHandlerRef != NULL) { - llinfos << "destroyContext: removing global event handler" << llendl; + LL_DEBUGS("Window") << "destroyContext: removing global event handler" << LL_ENDL; RemoveEventHandler(mGlobalHandlerRef); mGlobalHandlerRef = NULL; } if(mWindowHandlerRef != NULL) { - llinfos << "destroyContext: removing window event handler" << llendl; + LL_DEBUGS("Window") << "destroyContext: removing window event handler" << LL_ENDL; RemoveEventHandler(mWindowHandlerRef); mWindowHandlerRef = NULL; } @@ -990,7 +980,7 @@ void LLWindowMacOSX::destroyContext() // Cleanup any TSM document we created. if(mTSMDocument != NULL) { - llinfos << "destroyContext: deleting TSM document" << llendl; + LL_DEBUGS("Window") << "destroyContext: deleting TSM document" << LL_ENDL; DeactivateTSMDocument(mTSMDocument); DeleteTSMDocument(mTSMDocument); mTSMDocument = NULL; @@ -999,7 +989,7 @@ void LLWindowMacOSX::destroyContext() // Close the window if(mWindow != NULL) { - llinfos << "destroyContext: disposing window" << llendl; + LL_DEBUGS("Window") << "destroyContext: disposing window" << LL_ENDL; DisposeWindow(mWindow); mWindow = NULL; } @@ -1007,7 +997,7 @@ void LLWindowMacOSX::destroyContext() // Clean up the GL context if(mContext != NULL) { - llinfos << "destroyContext: destroying GL context" << llendl; + LL_DEBUGS("Window") << "destroyContext: destroying GL context" << LL_ENDL; aglDestroyContext(mContext); mContext = NULL; } @@ -1043,6 +1033,7 @@ void LLWindowMacOSX::hide() HideWindow(mWindow); } +//virtual void LLWindowMacOSX::minimize() { setMouseClipping(FALSE); @@ -1050,6 +1041,7 @@ void LLWindowMacOSX::minimize() CollapseWindow(mWindow, true); } +//virtual void LLWindowMacOSX::restore() { show(); @@ -1318,6 +1310,17 @@ F32 LLWindowMacOSX::getGamma() return result; } +U32 LLWindowMacOSX::getFSAASamples() +{ + return mFSAASamples; +} + +void LLWindowMacOSX::setFSAASamples(const U32 samples) +{ + mFSAASamples = samples; + mForceRebuild = TRUE; +} + BOOL LLWindowMacOSX::restoreGamma() { CGDisplayRestoreColorSyncSettings(); @@ -1387,11 +1390,11 @@ void LLWindowMacOSX::setMouseClipping( BOOL b ) if(b) { - // llinfos << "setMouseClipping(TRUE)" << llendl + // llinfos << "setMouseClipping(TRUE)" << llendl; } else { - // llinfos << "setMouseClipping(FALSE)" << llendl + // llinfos << "setMouseClipping(FALSE)" << llendl; } adjustCursorDecouple(); @@ -1409,7 +1412,7 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) CGPoint newPosition; - // llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl + // llinfos << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << llendl; newPosition.x = screen_pos.mX; newPosition.y = screen_pos.mY; @@ -1423,6 +1426,11 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) // 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; } @@ -1435,7 +1443,7 @@ static void fixOrigin(void) ::GetPortBounds(port, &portrect); if((portrect.left != 0) || (portrect.top != 0)) { - // Mozilla sometimes changes our port origin. Fuckers. + // Mozilla sometimes changes our port origin. ::SetOrigin(0,0); } } @@ -1493,6 +1501,7 @@ void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) // llinfos << "adjustCursorDecouple: decoupling cursor" << llendl; CGAssociateMouseAndMouseCursorPosition(false); mCursorDecoupled = true; + FlushSpecificEventsFromQueue(GetCurrentEventQueue(), mMoveEventCampartorUPP, NULL); mCursorIgnoreNextDelta = TRUE; } } @@ -1588,11 +1597,6 @@ void LLWindowMacOSX::afterDialog() } -S32 LLWindowMacOSX::stat(const char* file_name, struct stat* stat_info) -{ - return ::stat( file_name, stat_info ); -} - void LLWindowMacOSX::flashIcon(F32 seconds) { // Don't do this if we're already started, since this would try to install the NMRec twice. @@ -1722,15 +1726,6 @@ BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) } -BOOL LLWindowMacOSX::sendEmail(const char* address, const char* subject, const char* body_text, - const char* attachment, const char* attachment_displayed_name ) -{ - // MBW -- XXX -- Um... yeah. I'll get to this later. - - return false; -} - - // protected BOOL LLWindowMacOSX::resetDisplayResolution() { @@ -1927,13 +1922,30 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) -void LLWindowMacOSX::setupFailure(const char* text, const char* caption, U32 type) +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; @@ -2005,7 +2017,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e // Although the spec. is unclear, replace range should // not present when there is an active preedit. We just // ignore the case. markAsPreedit will detect the case and warn it. - const LLWString & text = mPreeditor->getWText(); + const LLWString & text = mPreeditor->getPreeditString(); const S32 location = wstring_wstring_length_from_utf16_length(text, 0, range.location); const S32 length = wstring_wstring_length_from_utf16_length(text, location, range.length); mPreeditor->markAsPreedit(location, length); @@ -2031,7 +2043,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e { for (LLWString::const_iterator i = fix_string.begin(); i != fix_string.end(); i++) { - mPreeditor->handleUnicodeCharHere(*i, FALSE); + mPreeditor->handleUnicodeCharHere(*i); } } @@ -2123,10 +2135,11 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e { UInt32 modifiers = 0; + // First, process the raw event. { - EventRef rawEvent; - + EventRef rawEvent = NULL; + // Get the original event and extract the modifier keys, so we can ignore command-key events. if (GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, NULL, sizeof(rawEvent), NULL, &rawEvent) == noErr) { @@ -2135,6 +2148,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e // and call this function recursively to handle the raw key event. eventHandler (myHandler, rawEvent); + + // save the raw event until we're done processing the unicode input as well. + mRawKeyEvent = rawEvent; } } @@ -2162,11 +2178,8 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e } else { - MASK mask = 0; - if(modifiers & shiftKey) { mask |= MASK_SHIFT; } - if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } - if(modifiers & optionKey) { mask |= MASK_ALT; } - + MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); + llassert( actualType == typeUnicodeText ); // The result is a UTF16 buffer. Pass the characters in turn to handleUnicodeChar. @@ -2188,6 +2201,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e delete[] buffer; } + mRawKeyEvent = NULL; result = err; } break; @@ -2203,7 +2217,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e { S32 preedit, preedit_length; mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getWText(); + const LLWString & text = mPreeditor->getPreeditString(); LLCoordGL caret_coord; LLRect preedit_bounds; @@ -2240,7 +2254,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e mPreeditor->getSelectionRange(&selection, &selection_length); if (selection_length) { - const LLWString text = mPreeditor->getWText().substr(selection, selection_length); + const LLWString text = mPreeditor->getPreeditString().substr(selection, selection_length); const llutf16string text_utf16 = wstring_to_utf16str(text); result = SetEventParameter(event, kEventParamTextInputReplyText, typeUnicodeText, text_utf16.length() * sizeof(U16), text_utf16.c_str()); @@ -2262,6 +2276,9 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e GetEventParameter (event, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &keyCode); GetEventParameter (event, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + // save the raw event so getNativeKeyData can use it. + mRawKeyEvent = event; + // printf("key event, key code = 0x%08x, char code = 0x%02x (%c), modifiers = 0x%08x\n", keyCode, charCode, (char)charCode, modifiers); // fflush(stdout); @@ -2357,6 +2374,8 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e result = eventNotHandledErr; break; } + + mRawKeyEvent = NULL; } break; @@ -2527,19 +2546,33 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e } mCallbacks->handleFocusLost(this); break; + case kEventWindowBoundsChanging: { + // This is where we would constrain move/resize to a particular screen + + const S32 MIN_WIDTH = 320; + const S32 MIN_HEIGHT = 240; + Rect currentBounds; Rect previousBounds; GetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds); GetEventParameter(event, kEventParamPreviousBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &previousBounds); - // This is where we would constrain move/resize to a particular screen - if(0) + + if ((currentBounds.right - currentBounds.left) < MIN_WIDTH) + { + currentBounds.right = currentBounds.left + MIN_WIDTH; + } + + if ((currentBounds.bottom - currentBounds.top) < MIN_HEIGHT) { - SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), ¤tBounds); + currentBounds.bottom = currentBounds.top + MIN_HEIGHT; } + + SetEventParameter(event, kEventParamCurrentBounds, typeQDRectangle, sizeof(Rect), ¤tBounds); + result = noErr; } break; @@ -2597,7 +2630,6 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e // BringToFront(mWindow); // result = noErr; break; - } break; @@ -2613,7 +2645,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e S32 preedit, preedit_length; mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getWText(); + const LLWString & text = mPreeditor->getPreeditString(); const CFIndex length = wstring_utf16_length(text, 0, preedit) + wstring_utf16_length(text, preedit + preedit_length, text.length()); result = SetEventParameter(event, kEventParamTSMDocAccessCharacterCount, typeCFIndex, sizeof(length), &length); @@ -2630,7 +2662,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e S32 preedit, preedit_length; mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getWText(); + const LLWString & text = mPreeditor->getPreeditString(); CFRange range; if (preedit_length) @@ -2664,7 +2696,7 @@ OSStatus LLWindowMacOSX::eventHandler (EventHandlerCallRef myHandler, EventRef e { S32 preedit, preedit_length; mPreeditor->getPreeditRange(&preedit, &preedit_length); - const LLWString & text = mPreeditor->getWText(); + const LLWString & text = mPreeditor->getPreeditString(); // The GetCharacters event of TSMDA has a fundamental flaw; // An input method need to decide the starting offset and length @@ -2739,14 +2771,13 @@ const char* cursorIDToName(int id) case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; - case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; - case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLPAY: return "UI_CURSOR_TOOLPAY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; 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"; } llerrs << "cursorIDToName: unknown cursor id" << id << llendl; @@ -2774,6 +2805,14 @@ void LLWindowMacOSX::setCursor(ECursorType cursor) { OSStatus result = noErr; + if (mDragOverrideCursor != -1) + { + // A drag is in progress...remember the requested cursor and we'll + // restore it when it is done + mCurrentCursor = cursor; + return; + } + if (cursor == UI_CURSOR_ARROW && mBusyCount > 0) { @@ -2838,13 +2877,12 @@ void LLWindowMacOSX::setCursor(ECursorType cursor) case UI_CURSOR_TOOLPAN: case UI_CURSOR_TOOLZOOMIN: case UI_CURSOR_TOOLPICKOBJECT3: - case UI_CURSOR_TOOLSIT: - case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLPAY: - case UI_CURSOR_TOOLOPEN: case UI_CURSOR_TOOLPLAY: case UI_CURSOR_TOOLPAUSE: case UI_CURSOR_TOOLMEDIAOPEN: + case UI_CURSOR_TOOLSIT: + case UI_CURSOR_TOOLBUY: + case UI_CURSOR_TOOLOPEN: result = setImageCursor(gCursors[cursor]); break; @@ -2858,7 +2896,7 @@ void LLWindowMacOSX::setCursor(ECursorType cursor) mCurrentCursor = cursor; } -ECursorType LLWindowMacOSX::getCursor() +ECursorType LLWindowMacOSX::getCursor() const { return mCurrentCursor; } @@ -2883,13 +2921,12 @@ void LLWindowMacOSX::initCursors() initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSIT, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLBUY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPAY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLOPEN, 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_SIZENWSE, 10, 10); initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); @@ -2998,20 +3035,13 @@ void LLSplashScreenMacOSX::showImpl() #endif } -void LLSplashScreenMacOSX::updateImpl(const char* mesg) +void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) { if(mWindow != NULL) { CFStringRef string = NULL; - if(mesg != NULL) - { - string = CFStringCreateWithCString(NULL, mesg, kCFStringEncodingUTF8); - } - else - { - string = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); - } + string = CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); if(string != NULL) { @@ -3046,7 +3076,7 @@ void LLSplashScreenMacOSX::hideImpl() -S32 OSMessageBoxMacOSX(const char* text, const char* caption, U32 type) +S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) { S32 result = OSBTN_CANCEL; SInt16 retval_mac = 1; @@ -3057,23 +3087,8 @@ S32 OSMessageBoxMacOSX(const char* text, const char* caption, U32 type) AlertType alertType = kAlertCautionAlert; OSStatus err; - if(text != NULL) - { - explanationString = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); - } - else - { - explanationString = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); - } - - if(caption != NULL) - { - errorString = CFStringCreateWithCString(NULL, caption, kCFStringEncodingUTF8); - } - else - { - errorString = CFStringCreateWithCString(NULL, "", kCFStringEncodingUTF8); - } + explanationString = CFStringCreateWithCString(NULL, text.c_str(), kCFStringEncodingUTF8); + errorString = CFStringCreateWithCString(NULL, caption.c_str(), kCFStringEncodingUTF8); params.version = kStdCFStringAlertVersionOne; params.movable = false; @@ -3157,15 +3172,13 @@ S32 OSMessageBoxMacOSX(const char* text, const char* caption, U32 type) // Open a URL with the user's default web browser. // Must begin with protocol identifier. -void spawn_web_browser(const char* escaped_url) +void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) { bool found = false; S32 i; for (i = 0; i < gURLProtocolWhitelistCount; i++) { - S32 len = strlen(gURLProtocolWhitelist[i]); /* Flawfinder: ignore */ - if (!strncmp(escaped_url, gURLProtocolWhitelist[i], len) - && escaped_url[len] == ':') + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) { found = true; break; @@ -3174,7 +3187,7 @@ void spawn_web_browser(const char* escaped_url) if (!found) { - llwarns << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << llendl; + llwarns << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << llendl; return; } @@ -3183,7 +3196,7 @@ void spawn_web_browser(const char* escaped_url) llinfos << "Opening URL " << escaped_url << llendl; - CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url, kCFStringEncodingUTF8); + CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); if (stringRef) { // This will succeed if the string is a full URL, including the http:// @@ -3212,8 +3225,62 @@ void spawn_web_browser(const char* escaped_url) } } +LLSD LLWindowMacOSX::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + if(mRawKeyEvent) + { + char char_code = 0; + UInt32 key_code = 0; + UInt32 modifiers = 0; + UInt32 keyboard_type = 0; + + GetEventParameter (mRawKeyEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof(char), NULL, &char_code); + GetEventParameter (mRawKeyEvent, kEventParamKeyCode, typeUInt32, NULL, sizeof(UInt32), NULL, &key_code); + GetEventParameter (mRawKeyEvent, kEventParamKeyModifiers, typeUInt32, NULL, sizeof(UInt32), NULL, &modifiers); + GetEventParameter (mRawKeyEvent, kEventParamKeyboardType, typeUInt32, NULL, sizeof(UInt32), NULL, &keyboard_type); + + result["char_code"] = (S32)char_code; + result["key_code"] = (S32)key_code; + result["modifiers"] = (S32)modifiers; + result["keyboard_type"] = (S32)keyboard_type; + +#if 0 + // This causes trouble for control characters -- apparently character codes less than 32 (escape, control-A, etc) + // cause llsd serialization to create XML that the llsd deserializer won't parse! + std::string unicode; + OSStatus err = noErr; + EventParamType actualType = typeUTF8Text; + UInt32 actualSize = 0; + char *buffer = NULL; + + err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, 0, &actualSize, NULL); + if(err == noErr) + { + // allocate a buffer and get the actual data. + buffer = new char[actualSize]; + err = GetEventParameter (mRawKeyEvent, kEventParamKeyUnicodes, typeUTF8Text, &actualType, actualSize, &actualSize, buffer); + if(err == noErr) + { + unicode.assign(buffer, actualSize); + } + delete[] buffer; + } + + result["unicode"] = unicode; +#endif + + } + + + lldebugs << "native key data is: " << result << llendl; + + return result; +} + -BOOL LLWindowMacOSX::dialog_color_picker ( F32 *r, F32 *g, F32 *b) +BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { BOOL retval = FALSE; OSErr error = noErr; @@ -3246,25 +3313,34 @@ BOOL LLWindowMacOSX::dialog_color_picker ( F32 *r, F32 *g, F32 *b) return (retval); } -static WindowRef dummywindowref = NULL; void *LLWindowMacOSX::getPlatformWindow() { - if(mWindow != NULL) - return (void*)mWindow; + // NOTE: this will be NULL in fullscreen mode. Plan accordingly. + return (void*)mWindow; +} + +void *LLWindowMacOSX::getMediaWindow() +{ + /* + Mozilla needs to be initialized with a WindowRef to function properly. + (There's no good reason for this, since it shouldn't be interacting with our window in any way, but that's another issue.) + If we're in windowed mode, we _could_ hand it our actual window pointer, but a subsequent switch to fullscreen will destroy that window, + which trips up Mozilla. + Instead of using our actual window, we create an invisible window which will persist for the lifetime of the application and pass that to Mozilla. + This satisfies its deep-seated need to latch onto a WindowRef and solves the issue with switching between fullscreen and windowed modes. - // If we're in fullscreen mode, there's no window pointer available. - // Since Mozilla needs one to function, create a dummy window here. - // Note that we will never destroy it, but since only one will be created per run of the application, that's okay. + Note that we will never destroy this window (by design!), but since only one will ever be created per run of the application, that's okay. + */ - if(dummywindowref == NULL) + if(sMediaWindow == NULL) { Rect window_rect = {100, 100, 200, 200}; - dummywindowref = NewCWindow( + sMediaWindow = NewCWindow( NULL, &window_rect, - "\p", + (ConstStr255Param) "\p", false, // Create the window invisible. zoomDocProc, // Window with a grow box and a zoom box kLastWindowOfClass, // create it behind other windows @@ -3272,7 +3348,7 @@ void *LLWindowMacOSX::getPlatformWindow() 0); } - return (void*)dummywindowref; + return (void*)sMediaWindow; } void LLWindowMacOSX::stopDockTileBounce() @@ -3320,6 +3396,8 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) return; } + UseInputWindow(mTSMDocument, !b); + // Take care of old and new preeditors. if (preeditor != mPreeditor || !b) { @@ -3372,4 +3450,181 @@ void LLWindowMacOSX::interruptLanguageTextInput() // Well, if Apple's TSM document is correct, we don't. } -#endif // LL_DARWIN +//static +std::vector<std::string> LLWindowMacOSX::getDynamicFallbackFontList() +{ + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector<std::string>(); +} + +// static +MASK LLWindowMacOSX::modifiersToMask(SInt16 modifiers) +{ + MASK mask = 0; + if(modifiers & shiftKey) { mask |= MASK_SHIFT; } + if(modifiers & (cmdKey | controlKey)) { mask |= MASK_CONTROL; } + if(modifiers & optionKey) { mask |= MASK_ALT; } + return mask; +} + +#if LL_OS_DRAGDROP_ENABLED + +OSErr LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, + void * handlerRefCon, DragRef drag) +{ + OSErr result = noErr; + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + + lldebugs << "drag tracking handler, message = " << message << llendl; + + 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); + +} + +OSErr LLWindowMacOSX::handleDragNDrop(DragRef drag, LLWindowCallbacks::DragNDropAction action) +{ + OSErr result = dragNotAcceptedErr; // overall function result + OSErr err = noErr; // for local error handling + + // Get the mouse position and modifiers of this drag. + SInt16 modifiers, mouseDownModifiers, mouseUpModifiers; + ::GetDragModifiers(drag, &modifiers, &mouseDownModifiers, &mouseUpModifiers); + MASK mask = LLWindowMacOSX::modifiersToMask(modifiers); + + Point mouse_point; + // This will return the mouse point in global screen coords + ::GetDragMouse(drag, &mouse_point, NULL); + LLCoordScreen screen_coords(mouse_point.h, mouse_point.v); + LLCoordGL gl_pos; + convertCoords(screen_coords, &gl_pos); + + // Look at the pasteboard and try to extract an URL from it + PasteboardRef pasteboard; + if(GetDragPasteboard(drag, &pasteboard) == noErr) + { + ItemCount num_items = 0; + // Treat an error here as an item count of 0 + (void)PasteboardGetItemCount(pasteboard, &num_items); + + // Only deal with single-item drags. + if(num_items == 1) + { + PasteboardItemID item_id = NULL; + CFArrayRef flavors = NULL; + CFDataRef data = NULL; + + err = PasteboardGetItemIdentifier(pasteboard, 1, &item_id); // Yes, this really is 1-based. + + // Try to extract an URL from the pasteboard + if(err == noErr) + { + err = PasteboardCopyItemFlavors( pasteboard, item_id, &flavors); + } + + if(err == noErr) + { + if(CFArrayContainsValue(flavors, CFRangeMake(0, CFArrayGetCount(flavors)), kUTTypeURL)) + { + // This is an URL. + err = PasteboardCopyItemFlavorData(pasteboard, item_id, kUTTypeURL, &data); + } + else if(CFArrayContainsValue(flavors, CFRangeMake(0, CFArrayGetCount(flavors)), kUTTypeUTF8PlainText)) + { + // This is a string that might be an URL. + err = PasteboardCopyItemFlavorData(pasteboard, item_id, kUTTypeUTF8PlainText, &data); + } + + } + + if(flavors != NULL) + { + CFRelease(flavors); + } + + if(data != NULL) + { + std::string url; + url.assign((char*)CFDataGetBytePtr(data), CFDataGetLength(data)); + CFRelease(data); + + 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 = kThemeNotAllowedCursor; + } + else { + mDragOverrideCursor = -1; + } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = kThemePointingHandCursor; + result = noErr; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = kThemeCopyArrowCursor; + result = noErr; + break; + case LLWindowCallbacks::DND_LINK: // Drop accepted would result in a "link" operation: + mDragOverrideCursor = kThemeAliasArrowCursor; + result = noErr; + 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 + SetThemeCursor(mDragOverrideCursor); + } + + } + } + } + } + + return result; +} + +#endif // LL_OS_DRAGDROP_ENABLED |