From da967da9c7aa0d88f478d476e8bb059ba79ca818 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20N=C3=A6sbye=20Christensen?= Date: Thu, 11 Jan 2024 11:32:15 +0100 Subject: Rename OS X to macOS, mostly in comments We only support 10.13+ now, and it's been called macOS since 10.12. References in code to older versions are unchanged. --- indra/llwindow/llkeyboard.h | 2 +- indra/llwindow/llwindowmacosx.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index dad150e3c1..2f80a9e89a 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -77,7 +77,7 @@ public: virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; #ifdef LL_DARWIN - // We only actually use this for OS X. + // We only actually use this for macOS. virtual void handleModifier(MASK mask) = 0; #endif // LL_DARWIN diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 778e5d3898..b317f00ae7 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1249,7 +1249,7 @@ F32 LLWindowMacOSX::getNativeAspectRatio() F32 LLWindowMacOSX::getPixelAspectRatio() { - //OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode + //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode return 1.f; } @@ -1281,7 +1281,7 @@ void LLWindowMacOSX::afterDialog() void LLWindowMacOSX::flashIcon(F32 seconds) { - // For consistency with OS X conventions, the number of seconds given is ignored and + // For consistency with macOS conventions, the number of seconds given is ignored and // left up to the OS (which will actually bounce it for one second). requestUserAttention(); } -- cgit v1.2.3 From a2971d84d5aba0c2dcda9ec8274a5c5b72ccd67c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 14 Feb 2024 02:46:24 +0200 Subject: Viewer#779 Make RenderMaxVRAMBudget more consistent --- indra/llwindow/llwindow.cpp | 2 +- indra/llwindow/llwindow.h | 1 + indra/llwindow/llwindowheadless.h | 1 + indra/llwindow/llwindowmacosx.cpp | 11 +++++++++-- indra/llwindow/llwindowmacosx.h | 5 ++++- indra/llwindow/llwindowwin32.cpp | 8 ++++++++ indra/llwindow/llwindowwin32.h | 1 + 7 files changed, 25 insertions(+), 4 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 9e281dfc99..6cfa9cd16d 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -431,7 +431,7 @@ LLWindow* LLWindowManager::createWindow( #elif LL_DARWIN new_window = new LLWindowMacOSX(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_vram); #endif } else diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index f435d46584..b53cda6150 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -166,6 +166,7 @@ public: // query VRAM usage virtual U32 getAvailableVRAMMegabytes() = 0; + virtual void setMaxVRAMMegabytes(U32 max_vram) = 0; virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) virtual void afterDialog() {}; // undo whatever was done in beforeDialog() diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 2f2c0de5bd..10b3c66f93 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -102,6 +102,7 @@ public: /*virtual*/ void setNativeAspectRatio(F32 ratio) override {} U32 getAvailableVRAMMegabytes() override { return 4096; } + void setMaxVRAMMegabytes(U32 max_vram) override {} /*virtual*/ void *getPlatformWindow() override { return 0; } /*virtual*/ void bringToFront() override {} diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index b317f00ae7..9f71b80e74 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -115,8 +115,10 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, - U32 fsaa_samples) + U32 fsaa_samples, + U32 max_vram) : LLWindow(NULL, fullscreen, flags) + , mMaxVRAM(max_vram) { // *HACK: During window construction we get lots of OS events for window // reshape, activate, etc. that the viewer isn't ready to handle. @@ -1260,7 +1262,12 @@ U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { static const U32 mb = 1024*1024; // We're asked for total available gpu memory, but we only have allocation info on texture usage. So estimate by doubling that. static const U32 total_factor = 2; // estimated total/textures - return gGLManager.mVRAM - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); + U32 total_vram = gGLManager.mVRAM; + if (mMaxVRAM) + { + total_vram = llmin(mMaxVRAM, total_vram); + } + return total_vram - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); } //static SInt32 oldWindowLevel; diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 7614167213..3b13f60f77 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -102,6 +102,7 @@ public: // query VRAM usage /*virtual*/ U32 getAvailableVRAMMegabytes() override; + virtual void setMaxVRAMMegabytes(U32 max_vram) override { mMaxVRAM = max_vram; } void beforeDialog() override; void afterDialog() override; @@ -150,7 +151,8 @@ protected: const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, - U32 fsaa_samples); + U32 fsaa_samples, + U32 max_vram); ~LLWindowMacOSX(); void initCursors(); @@ -224,6 +226,7 @@ protected: BOOL mMinimized; U32 mFSAASamples; BOOL mForceRebuild; + U32 mMaxVRAM; S32 mDragOverrideCursor; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 057d7a700e..0dbb5b64c1 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4586,6 +4586,14 @@ U32 LLWindowWin32::getAvailableVRAMMegabytes() return mWindowThread ? mWindowThread->getAvailableVRAMMegabytes() : 0; } +void LLWindowWin32::setMaxVRAMMegabytes(U32 max_vram) +{ + if (mWindowThread) + { + mWindowThread->mMaxVRAM = max_vram; + } +} + #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index ff287a140e..c8ce507c8b 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -109,6 +109,7 @@ public: /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } U32 getAvailableVRAMMegabytes() override; + /*virtual*/ void setMaxVRAMMegabytes(U32 max_vram) override; /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); -- cgit v1.2.3 From c285f59ce2a05703e3a1232fcaf3ee3aea714b3f Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 18 Feb 2024 12:52:19 +0100 Subject: Replace BOOL with bool in llwindow and dependent classes --- indra/llwindow/lldragdropwin32.cpp | 10 +- indra/llwindow/lldxhardware.cpp | 20 +- indra/llwindow/lldxhardware.h | 10 +- indra/llwindow/llkeyboard.cpp | 84 +++---- indra/llwindow/llkeyboard.h | 28 +-- indra/llwindow/llkeyboardheadless.cpp | 14 +- indra/llwindow/llkeyboardheadless.h | 6 +- indra/llwindow/llkeyboardmacosx.cpp | 24 +- indra/llwindow/llkeyboardmacosx.h | 10 +- indra/llwindow/llkeyboardsdl.cpp | 22 +- indra/llwindow/llkeyboardsdl.h | 10 +- indra/llwindow/llkeyboardwin32.cpp | 26 +- indra/llwindow/llkeyboardwin32.h | 10 +- indra/llwindow/llmousehandler.cpp | 4 +- indra/llwindow/llmousehandler.h | 26 +- indra/llwindow/llpreeditor.h | 8 +- indra/llwindow/llwindow.cpp | 66 ++--- indra/llwindow/llwindow.h | 106 ++++---- indra/llwindow/llwindowcallbacks.cpp | 82 +++---- indra/llwindow/llwindowcallbacks.h | 44 ++-- indra/llwindow/llwindowheadless.cpp | 4 +- indra/llwindow/llwindowheadless.h | 60 ++--- indra/llwindow/llwindowmacosx.cpp | 200 +++++++-------- indra/llwindow/llwindowmacosx.h | 94 ++++---- indra/llwindow/llwindowmesaheadless.cpp | 4 +- indra/llwindow/llwindowmesaheadless.h | 56 ++--- indra/llwindow/llwindowsdl.cpp | 280 ++++++++++----------- indra/llwindow/llwindowsdl.h | 86 +++---- indra/llwindow/llwindowwin32.cpp | 416 ++++++++++++++++---------------- indra/llwindow/llwindowwin32.h | 92 +++---- 30 files changed, 951 insertions(+), 951 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index 0d1a47408b..51c3938ebc 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -124,7 +124,7 @@ class LLDragDropWin32Target: ScreenToClient( mAppWindowHandle, &pt2 ); LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask, LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl ); @@ -179,7 +179,7 @@ class LLDragDropWin32Target: ScreenToClient( mAppWindowHandle, &pt2 ); LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask, LLWindowCallbacks::DNDA_TRACK, mDropUrl ); @@ -219,7 +219,7 @@ class LLDragDropWin32Target: if (NULL != window_imp) { LLCoordGL gl_coord( 0, 0 ); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_STOP_TRACKING, mDropUrl ); }; return S_OK; @@ -249,7 +249,7 @@ class LLDragDropWin32Target: LL_INFOS() << LL_ENDL; // no keyboard modifier option yet but we could one day - MASK mask = gKeyboard->currentMask( TRUE ); + MASK mask = gKeyboard->currentMask( true ); // actually do the drop LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, @@ -312,7 +312,7 @@ LLDragDropWin32::~LLDragDropWin32() bool LLDragDropWin32::init( HWND hWnd ) { if ( NOERROR != OleInitialize( NULL ) ) - return FALSE; + return false; mDropTarget = new LLDragDropWin32Target( hWnd ); if ( mDropTarget ) diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index 391a377280..603f33e400 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -486,7 +486,7 @@ std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName) LLVersion::LLVersion() { - mValid = FALSE; + mValid = false; S32 i; for (i = 0; i < 4; i++) { @@ -494,7 +494,7 @@ LLVersion::LLVersion() } } -BOOL LLVersion::set(const std::string &version_string) +bool LLVersion::set(const std::string &version_string) { S32 i; for (i = 0; i < 4; i++) @@ -521,11 +521,11 @@ BOOL LLVersion::set(const std::string &version_string) { mFields[i] = 0; } - mValid = FALSE; + mValid = false; } else { - mValid = TRUE; + mValid = true; } return mValid; } @@ -681,10 +681,10 @@ LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::strin } */ -BOOL LLDXHardware::getInfo(BOOL vram_only) +bool LLDXHardware::getInfo(bool vram_only) { LLTimer hw_timer; - BOOL ok = FALSE; + bool ok = false; HRESULT hr; CoInitialize(NULL); @@ -811,7 +811,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) if (vram_only) { - ok = TRUE; + ok = true; goto LCleanup; } @@ -871,7 +871,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) tokenizer::iterator iter = tokens.begin(); S32 count = 0; - BOOL valid = TRUE; + bool valid = true; for (;(iter != tokens.end()) && (count < 3);++iter) { switch (count) @@ -879,7 +879,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) case 0: if (strcmp(iter->c_str(), "PCI")) { - valid = FALSE; + valid = false; } break; case 1: @@ -950,7 +950,7 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) } // dumpDevices(); - ok = TRUE; + ok = true; LCleanup: if (!ok) diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index 9cec3e2f1b..85b4bffd71 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -37,12 +37,12 @@ class LLVersion { public: LLVersion(); - BOOL set(const std::string &version_string); + bool set(const std::string &version_string); S32 getField(const S32 field_num); protected: std::string mVersionString; S32 mFields[4]; - BOOL mValid; + bool mValid; }; class LLDXDriverFile @@ -84,9 +84,9 @@ public: void setWriteDebugFunc(void (*func)(const char*)); void cleanup(); - // Returns TRUE on success. - // vram_only TRUE does a "light" probe. - BOOL getInfo(BOOL vram_only); + // Returns true on success. + // vram_only true does a "light" probe. + bool getInfo(bool vram_only); // WMI can return multiple GPU drivers // specify which one to output diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index 34720ff64e..e014a33231 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -55,10 +55,10 @@ LLKeyboard::LLKeyboard() : mCallbacks(NULL) for (i = 0; i < KEY_COUNT; i++) { mKeyLevelFrameCount[i] = 0; - mKeyLevel[i] = FALSE; - mKeyUp[i] = FALSE; - mKeyDown[i] = FALSE; - mKeyRepeated[i] = FALSE; + mKeyLevel[i] = false; + mKeyUp[i] = false; + mKeyDown[i] = false; + mKeyRepeated[i] = false; } mInsertMode = LL_KIM_INSERT; @@ -150,14 +150,14 @@ void LLKeyboard::addKeyName(KEY key, const std::string& name) void LLKeyboard::resetKeyDownAndHandle() { - MASK mask = currentMask(FALSE); + MASK mask = currentMask(false); for (S32 i = 0; i < KEY_COUNT; i++) { if (mKeyLevel[i]) { - mKeyDown[i] = FALSE; - mKeyLevel[i] = FALSE; - mKeyUp[i] = TRUE; + mKeyDown[i] = false; + mKeyLevel[i] = false; + mKeyUp[i] = true; mCurTranslatedKey = (KEY)i; mCallbacks->handleTranslatedKeyUp(i, mask); } @@ -174,28 +174,28 @@ void LLKeyboard::resetKeys() { if( mKeyLevel[i] ) { - mKeyLevel[i] = FALSE; + mKeyLevel[i] = false; } } for (i = 0; i < KEY_COUNT; i++) { - mKeyUp[i] = FALSE; + mKeyUp[i] = false; } for (i = 0; i < KEY_COUNT; i++) { - mKeyDown[i] = FALSE; + mKeyDown[i] = false; } for (i = 0; i < KEY_COUNT; i++) { - mKeyRepeated[i] = FALSE; + mKeyRepeated[i] = false; } } -BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) { std::map::iterator iter; @@ -205,12 +205,12 @@ BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) { //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; *out_key = 0; - return FALSE; + return false; } else { *out_key = iter->second; - return TRUE; + return true; } } @@ -230,47 +230,47 @@ U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) } -BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) { - BOOL handled = FALSE; - BOOL repeated = FALSE; + bool handled = false; + bool repeated = false; // is this the first time the key went down? // if so, generate "character" message if( !mKeyLevel[translated_key] ) { - mKeyLevel[translated_key] = TRUE; + mKeyLevel[translated_key] = true; mKeyLevelTimer[translated_key].reset(); mKeyLevelFrameCount[translated_key] = 0; - mKeyRepeated[translated_key] = FALSE; + mKeyRepeated[translated_key] = false; } else { // Level is already down, assume it's repeated. - repeated = TRUE; - mKeyRepeated[translated_key] = TRUE; + repeated = true; + mKeyRepeated[translated_key] = true; } - mKeyDown[translated_key] = TRUE; + mKeyDown[translated_key] = true; mCurTranslatedKey = (KEY)translated_key; handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated); return handled; } -BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) +bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) { - BOOL handled = FALSE; + bool handled = false; if( mKeyLevel[translated_key] ) { - mKeyLevel[translated_key] = FALSE; + mKeyLevel[translated_key] = false; // Only generate key up events if the key is thought to // be down. This allows you to call resetKeys() in the // middle of a frame and ignore subsequent KEY_UP // messages in the same frame. This was causing the // sequence W in chat to move agents forward. JC - mKeyUp[translated_key] = TRUE; + mKeyUp[translated_key] = true; handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask); } @@ -306,14 +306,14 @@ S32 LLKeyboard::getKeyElapsedFrameCount(KEY key) } // static -BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key) +bool LLKeyboard::keyFromString(const std::string& str, KEY *key) { std::string instring(str); size_t length = instring.size(); if (length < 1) { - return FALSE; + return false; } if (length == 1) { @@ -326,7 +326,7 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key) ('{' <= ch && ch <= '~')) // {|}~ { *key = ch; - return TRUE; + return true; } } @@ -335,10 +335,10 @@ BOOL LLKeyboard::keyFromString(const std::string& str, KEY *key) if (res != 0) { *key = res; - return TRUE; + return true; } LL_WARNS() << "keyFromString failed: " << str << LL_ENDL; - return FALSE; + return false; } @@ -486,52 +486,52 @@ std::string LLKeyboard::stringFromAccelerator(MASK accel_mask, EMouseClickType c } //static -BOOL LLKeyboard::maskFromString(const std::string& str, MASK *mask) +bool LLKeyboard::maskFromString(const std::string& str, MASK *mask) { std::string instring(str); if (instring == "NONE") { *mask = MASK_NONE; - return TRUE; + return true; } else if (instring == "SHIFT") { *mask = MASK_SHIFT; - return TRUE; + return true; } else if (instring == "CTL") { *mask = MASK_CONTROL; - return TRUE; + return true; } else if (instring == "ALT") { *mask = MASK_ALT; - return TRUE; + return true; } else if (instring == "CTL_SHIFT") { *mask = MASK_CONTROL | MASK_SHIFT; - return TRUE; + return true; } else if (instring == "ALT_SHIFT") { *mask = MASK_ALT | MASK_SHIFT; - return TRUE; + return true; } else if (instring == "CTL_ALT") { *mask = MASK_CONTROL | MASK_ALT; - return TRUE; + return true; } else if (instring == "CTL_ALT_SHIFT") { *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT; - return TRUE; + return true; } else { - return FALSE; + return false; } } diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 2f80a9e89a..117ae797c5 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -64,17 +64,17 @@ public: F32 getCurKeyElapsedTime() { return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; } F32 getCurKeyElapsedFrameCount() { return getKeyDown(mCurScanKey) ? (F32)getKeyElapsedFrameCount( mCurScanKey ) : 0.f; } - BOOL getKeyDown(const KEY key) { return mKeyLevel[key]; } - BOOL getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } + bool getKeyDown(const KEY key) { return mKeyLevel[key]; } + bool getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } - BOOL translateKey(const U16 os_key, KEY *translated_key); + bool translateKey(const U16 os_key, KEY *translated_key); U16 inverseTranslateKey(const KEY translated_key); - BOOL handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - BOOL handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes + bool handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes + bool handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - virtual BOOL handleKeyUp(const U16 key, MASK mask) = 0; - virtual BOOL handleKeyDown(const U16 key, MASK mask) = 0; + virtual bool handleKeyUp(const U16 key, MASK mask) = 0; + virtual bool handleKeyDown(const U16 key, MASK mask) = 0; #ifdef LL_DARWIN // We only actually use this for macOS. @@ -87,14 +87,14 @@ public: virtual void scanKeyboard() = 0; // scans keyboard, calls functions as necessary // Mac must differentiate between Command = Control for keyboard events // and Command != Control for mouse events. - virtual MASK currentMask(BOOL for_mouse_event) = 0; + virtual MASK currentMask(bool for_mouse_event) = 0; virtual KEY currentKey() { return mCurTranslatedKey; } EKeyboardInsertMode getInsertMode() { return mInsertMode; } void toggleInsertMode(); - static BOOL maskFromString(const std::string& str, MASK *mask); // False on failure - static BOOL keyFromString(const std::string& str, KEY *key); // False on failure + static bool maskFromString(const std::string& str, MASK *mask); // False on failure + static bool keyFromString(const std::string& str, KEY *key); // False on failure static std::string stringFromKey(KEY key, bool translate = true); static std::string stringFromMouse(EMouseClickType click, bool translate = true); static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... @@ -117,10 +117,10 @@ protected: LLTimer mKeyLevelTimer[KEY_COUNT]; // Time since level was set S32 mKeyLevelFrameCount[KEY_COUNT]; // Frames since level was set - BOOL mKeyLevel[KEY_COUNT]; // Levels - BOOL mKeyRepeated[KEY_COUNT]; // Key was repeated - BOOL mKeyUp[KEY_COUNT]; // Up edge - BOOL mKeyDown[KEY_COUNT]; // Down edge + bool mKeyLevel[KEY_COUNT]; // Levels + bool mKeyRepeated[KEY_COUNT]; // Key was repeated + bool mKeyUp[KEY_COUNT]; // Up edge + bool mKeyDown[KEY_COUNT]; // Down edge KEY mCurTranslatedKey; KEY mCurScanKey; // Used during the scanKeyboard() diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index a1b6b294e0..32d094e046 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -35,14 +35,14 @@ void LLKeyboardHeadless::resetMaskKeys() { } -BOOL LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) -{ return FALSE; } +bool LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) +{ return false; } -BOOL LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) -{ return FALSE; } +bool LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) +{ return false; } -MASK LLKeyboardHeadless::currentMask(BOOL for_mouse_event) +MASK LLKeyboardHeadless::currentMask(bool for_mouse_event) { return MASK_NONE; } #ifdef LL_DARWIN @@ -69,8 +69,8 @@ void LLKeyboardHeadless::scanKeyboard() // Reset edges for next frame for (S32 key = 0; key < KEY_COUNT; key++) { - mKeyUp[key] = FALSE; - mKeyDown[key] = FALSE; + mKeyUp[key] = false; + mKeyDown[key] = false; if (mKeyLevel[key]) { mKeyLevelFrameCount[key]++; diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index 8ed28ace90..da5972883a 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -35,10 +35,10 @@ public: LLKeyboardHeadless(); /*virtual*/ ~LLKeyboardHeadless() {}; - /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); - /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(BOOL for_mouse_event); + /*virtual*/ MASK currentMask(bool for_mouse_event); /*virtual*/ void scanKeyboard(); #ifdef LL_DARWIN /*virtual*/ void handleModifier(MASK mask); diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp index 85bb7b9aeb..1ebe868798 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -172,22 +172,22 @@ void LLKeyboardMacOSX::resetMaskKeys() if(mask & MAC_SHIFT_KEY) { - mKeyLevel[KEY_SHIFT] = TRUE; + mKeyLevel[KEY_SHIFT] = true; } if(mask & MAC_CTRL_KEY) { - mKeyLevel[KEY_CONTROL] = TRUE; + mKeyLevel[KEY_CONTROL] = true; } if(mask & MAC_ALT_KEY) { - mKeyLevel[KEY_ALT] = TRUE; + mKeyLevel[KEY_ALT] = true; } } /* -static BOOL translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) +static bool translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) { // Translate the virtual keycode into the keycodes the keyboard system expects. U16 virtualKey = (mask >> 24) & 0x0000007F; @@ -226,11 +226,11 @@ MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) return out_mask; } -BOOL LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) +bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) { KEY translated_key = 0; U32 translated_mask = 0; - BOOL handled = FALSE; + bool handled = false; translated_mask = updateModifiers(mask); @@ -243,11 +243,11 @@ BOOL LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) } -BOOL LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) +bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) { KEY translated_key = 0; U32 translated_mask = 0; - BOOL handled = FALSE; + bool handled = false; translated_mask = updateModifiers(mask); @@ -259,7 +259,7 @@ BOOL LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) return handled; } -MASK LLKeyboardMacOSX::currentMask(BOOL for_mouse_event) +MASK LLKeyboardMacOSX::currentMask(bool for_mouse_event) { MASK result = MASK_NONE; U32 mask = getModifiers(); @@ -295,8 +295,8 @@ void LLKeyboardMacOSX::scanKeyboard() // Reset edges for next frame for (key = 0; key < KEY_COUNT; key++) { - mKeyUp[key] = FALSE; - mKeyDown[key] = FALSE; + mKeyUp[key] = false; + mKeyDown[key] = false; if (mKeyLevel[key]) { mKeyLevelFrameCount[key]++; @@ -304,7 +304,7 @@ void LLKeyboardMacOSX::scanKeyboard() } } -BOOL LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key ) +bool LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key ) { return translateKey(os_key, translated_key); } diff --git a/indra/llwindow/llkeyboardmacosx.h b/indra/llwindow/llkeyboardmacosx.h index f9d014ab70..27346cbeac 100644 --- a/indra/llwindow/llkeyboardmacosx.h +++ b/indra/llwindow/llkeyboardmacosx.h @@ -44,17 +44,17 @@ public: LLKeyboardMacOSX(); /*virtual*/ ~LLKeyboardMacOSX() {}; - /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); - /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(BOOL for_mouse_event); + /*virtual*/ MASK currentMask(bool for_mouse_event); /*virtual*/ void scanKeyboard(); /*virtual*/ void handleModifier(MASK mask); protected: MASK updateModifiers(const U32 mask); - void setModifierKeyLevel( KEY key, BOOL new_state ); - BOOL translateNumpadKey( const U16 os_key, KEY *translated_key ); + void setModifierKeyLevel( KEY key, bool new_state ); + bool translateNumpadKey( const U16 os_key, KEY *translated_key ); U16 inverseTranslateNumpadKey(const KEY translated_key); private: std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index 7c9aa1d340..e850bd4d2b 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -162,17 +162,17 @@ void LLKeyboardSDL::resetMaskKeys() if(mask & KMOD_SHIFT) { - mKeyLevel[KEY_SHIFT] = TRUE; + mKeyLevel[KEY_SHIFT] = true; } if(mask & KMOD_CTRL) { - mKeyLevel[KEY_CONTROL] = TRUE; + mKeyLevel[KEY_CONTROL] = true; } if(mask & KMOD_ALT) { - mKeyLevel[KEY_ALT] = TRUE; + mKeyLevel[KEY_ALT] = true; } } @@ -226,12 +226,12 @@ static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) } -BOOL LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) +bool LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) { U16 adjusted_nativekey; KEY translated_key = 0; U32 translated_mask = MASK_NONE; - BOOL handled = FALSE; + bool handled = false; adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -246,12 +246,12 @@ BOOL LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) } -BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) { U16 adjusted_nativekey; KEY translated_key = 0; U32 translated_mask = MASK_NONE; - BOOL handled = FALSE; + bool handled = false; adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); @@ -265,7 +265,7 @@ BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) return handled; } -MASK LLKeyboardSDL::currentMask(BOOL for_mouse_event) +MASK LLKeyboardSDL::currentMask(bool for_mouse_event) { MASK result = MASK_NONE; SDLMod mask = SDL_GetModState(); @@ -300,8 +300,8 @@ void LLKeyboardSDL::scanKeyboard() // Reset edges for next frame for (S32 key = 0; key < KEY_COUNT; key++) { - mKeyUp[key] = FALSE; - mKeyDown[key] = FALSE; + mKeyUp[key] = false; + mKeyDown[key] = false; if (mKeyLevel[key]) { mKeyLevelFrameCount[key]++; @@ -310,7 +310,7 @@ void LLKeyboardSDL::scanKeyboard() } -BOOL LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) +bool LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) { return translateKey(os_key, translated_key); } diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index 02a71425f1..760e4a2e78 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -36,16 +36,16 @@ public: LLKeyboardSDL(); /*virtual*/ ~LLKeyboardSDL() {}; - /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); - /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(BOOL for_mouse_event); + /*virtual*/ MASK currentMask(bool for_mouse_event); /*virtual*/ void scanKeyboard(); protected: MASK updateModifiers(const U32 mask); - void setModifierKeyLevel( KEY key, BOOL new_state ); - BOOL translateNumpadKey( const U16 os_key, KEY *translated_key ); + void setModifierKeyLevel( KEY key, bool new_state ); + bool translateNumpadKey( const U16 os_key, KEY *translated_key ); U16 inverseTranslateNumpadKey(const KEY translated_key); private: std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index 4c207faa81..497e000357 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -152,22 +152,22 @@ void LLKeyboardWin32::resetMaskKeys() // bit to indicate that the key is down. if (GetAsyncKeyState(VK_SHIFT) & 0x8000) { - mKeyLevel[KEY_SHIFT] = TRUE; + mKeyLevel[KEY_SHIFT] = true; } if (GetAsyncKeyState(VK_CONTROL) & 0x8000) { - mKeyLevel[KEY_CONTROL] = TRUE; + mKeyLevel[KEY_CONTROL] = true; } if (GetAsyncKeyState(VK_MENU) & 0x8000) { - mKeyLevel[KEY_ALT] = TRUE; + mKeyLevel[KEY_ALT] = true; } } -//void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state ) +//void LLKeyboardWin32::setModifierKeyLevel( KEY key, bool new_state ) //{ // if( mKeyLevel[key] != new_state ) // { @@ -191,17 +191,17 @@ MASK LLKeyboardWin32::updateModifiers() // (keydown encoded in high order bit of short) mKeyLevel[KEY_CAPSLOCK] = (GetKeyState(VK_CAPITAL) & 0x0001) != 0; // Low order bit carries the toggle state. // Get mask for keyboard events - MASK mask = currentMask(FALSE); + MASK mask = currentMask(false); return mask; } // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) +bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) { KEY translated_key; U32 translated_mask; - BOOL handled = FALSE; + bool handled = false; translated_mask = updateModifiers(); @@ -214,11 +214,11 @@ BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) } // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) +bool LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) { KEY translated_key; U32 translated_mask; - BOOL handled = FALSE; + bool handled = false; translated_mask = updateModifiers(); @@ -231,7 +231,7 @@ BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) } -MASK LLKeyboardWin32::currentMask(BOOL) +MASK LLKeyboardWin32::currentMask(bool) { MASK mask = MASK_NONE; @@ -263,8 +263,8 @@ void LLKeyboardWin32::scanKeyboard() // Reset edges for next frame for (key = 0; key < KEY_COUNT; key++) { - mKeyUp[key] = FALSE; - mKeyDown[key] = FALSE; + mKeyUp[key] = false; + mKeyDown[key] = false; if (mKeyLevel[key]) { mKeyLevelFrameCount[key]++; @@ -272,7 +272,7 @@ void LLKeyboardWin32::scanKeyboard() } } -BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) +bool LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) { return translateKey(os_key, translated_key); } diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h index b7da450164..d7752b7f6f 100644 --- a/indra/llwindow/llkeyboardwin32.h +++ b/indra/llwindow/llkeyboardwin32.h @@ -39,17 +39,17 @@ public: LLKeyboardWin32(); /*virtual*/ ~LLKeyboardWin32() {}; - /*virtual*/ BOOL handleKeyUp(const U16 key, MASK mask); - /*virtual*/ BOOL handleKeyDown(const U16 key, MASK mask); + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(BOOL for_mouse_event); + /*virtual*/ MASK currentMask(bool for_mouse_event); /*virtual*/ void scanKeyboard(); - BOOL translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); + bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); U16 inverseTranslateExtendedKey(const KEY translated_key); protected: MASK updateModifiers(); - //void setModifierKeyLevel( KEY key, BOOL new_state ); + //void setModifierKeyLevel( KEY key, bool new_state ); private: std::map mTranslateNumpadMap; std::map mInvTranslateNumpadMap; diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index e41ebd42f3..fe421fc492 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -27,9 +27,9 @@ #include "llmousehandler.h" //virtual -BOOL LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down) +bool LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down) { - BOOL handled = FALSE; + bool handled = false; if (down) { switch (clicktype) diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h index d221dd117c..1097894c32 100644 --- a/indra/llwindow/llmousehandler.h +++ b/indra/llwindow/llmousehandler.h @@ -47,19 +47,19 @@ public: SHOW_ALWAYS, } EShowToolTip; - virtual BOOL handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, BOOL down); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask) = 0; + virtual bool handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down); + virtual bool handleMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual bool handleMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual bool handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual bool handleMiddleMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleHover(S32 x, S32 y, MASK mask) = 0; - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; - virtual BOOL handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; - virtual BOOL handleToolTip(S32 x, S32 y, MASK mask) = 0; + virtual bool handleHover(S32 x, S32 y, MASK mask) = 0; + virtual bool handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; + virtual bool handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; + virtual bool handleToolTip(S32 x, S32 y, MASK mask) = 0; virtual const std::string& getName() const = 0; virtual void onMouseCaptureLost() = 0; @@ -67,7 +67,7 @@ public: virtual void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const = 0; virtual void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const = 0; - virtual BOOL hasMouseCapture() = 0; + virtual bool hasMouseCapture() = 0; }; #endif diff --git a/indra/llwindow/llpreeditor.h b/indra/llwindow/llpreeditor.h index 9802fd8606..2be1290c02 100644 --- a/indra/llwindow/llpreeditor.h +++ b/indra/llwindow/llpreeditor.h @@ -34,7 +34,7 @@ class LLPreeditor public: typedef std::vector segment_lengths_t; - typedef std::vector standouts_t; + typedef std::vector standouts_t; // We don't delete against LLPreeditor, but compilers complain without this... @@ -79,7 +79,7 @@ public: // Locations are relative to the app window and measured in GL coordinate space (before scaling.) // query_position is IN argument, and other three are OUT. - virtual BOOL getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const = 0; + virtual bool getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const = 0; // Get the size (height) of the current font used in this preeditor. @@ -93,9 +93,9 @@ public: // Handle a UTF-32 char on this preeditor, i.e., add the character // to the contents. // This is a back door of the method of same name of LLWindowCallback. - // called_from_parent should be set to FALSE if calling through LLPreeditor. + // called_from_parent should be set to false if calling through LLPreeditor. - virtual BOOL handleUnicodeCharHere(llwchar uni_char) = 0; + virtual bool handleUnicodeCharHere(llwchar uni_char) = 0; }; #endif diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 6cfa9cd16d..d951f7f676 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -46,8 +46,8 @@ // Globals // LLSplashScreen *gSplashScreenp = NULL; -BOOL gDebugClicks = FALSE; -BOOL gDebugWindowProc = FALSE; +bool gDebugClicks = false; +bool gDebugWindowProc = false; const S32 gURLProtocolWhitelistCount = 5; const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" }; @@ -63,10 +63,10 @@ const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) { // Properly hide the splash screen when displaying the message box - BOOL was_visible = FALSE; + bool was_visible = false; if (LLSplashScreen::isVisible()) { - was_visible = TRUE; + was_visible = true; LLSplashScreen::hide(); } @@ -97,9 +97,9 @@ S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) // LLWindow // -LLWindow::LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags) +LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags) : mCallbacks(callbacks), - mPostQuit(TRUE), + mPostQuit(true), mFullscreen(fullscreen), mFullscreenWidth(0), mFullscreenHeight(0), @@ -109,13 +109,13 @@ LLWindow::LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags) mNumSupportedResolutions(0), mCurrentCursor(UI_CURSOR_ARROW), mNextCursor(UI_CURSOR_ARROW), - mCursorHidden(FALSE), + mCursorHidden(false), mBusyCount(0), - mIsMouseClipping(FALSE), + mIsMouseClipping(false), mMinWindowWidth(0), mMinWindowHeight(0), mSwapMethod(SWAP_METHOD_UNDEFINED), - mHideCursorPermanent(FALSE), + mHideCursorPermanent(false), mFlags(flags), mHighSurrogate(0), mRefreshRate(0) @@ -127,15 +127,15 @@ LLWindow::~LLWindow() } //virtual -BOOL LLWindow::isValid() +bool LLWindow::isValid() { - return TRUE; + return true; } //virtual -BOOL LLWindow::canDelete() +bool LLWindow::canDelete() { - return TRUE; + return true; } //virtual @@ -178,9 +178,9 @@ ECursorType LLWindow::getCursor() const } //virtual -BOOL LLWindow::dialogColorPicker(F32 *r, F32 *g, F32 *b) +bool LLWindow::dialogColorPicker(F32 *r, F32 *g, F32 *b) { - return FALSE; + return false; } void *LLWindow::getMediaWindow() @@ -189,7 +189,7 @@ void *LLWindow::getMediaWindow() return getPlatformWindow(); } -BOOL LLWindow::setSize(LLCoordScreen size) +bool LLWindow::setSize(LLCoordScreen size) { if (!getMaximized()) { @@ -199,7 +199,7 @@ BOOL LLWindow::setSize(LLCoordScreen size) return setSizeImpl(size); } -BOOL LLWindow::setSize(LLCoordWindow size) +bool LLWindow::setSize(LLCoordWindow size) { //HACK: we are inconsistently using minimum window dimensions // in this case, we are constraining the inner "client" rect and other times @@ -241,19 +241,19 @@ void LLWindow::processMiscNativeEvents() } //virtual -BOOL LLWindow::isPrimaryTextAvailable() +bool LLWindow::isPrimaryTextAvailable() { - return FALSE; // no + return false; // no } //virtual -BOOL LLWindow::pasteTextFromPrimary(LLWString &dst) +bool LLWindow::pasteTextFromPrimary(LLWString &dst) { - return FALSE; // fail + return false; // fail } // virtual -BOOL LLWindow::copyTextToPrimary(const LLWString &src) +bool LLWindow::copyTextToPrimary(const LLWString &src) { - return FALSE; // fail + return false; // fail } // static @@ -402,11 +402,11 @@ static std::set sWindowList; LLWindow* LLWindowManager::createWindow( LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, - BOOL fullscreen, - BOOL clearBg, - BOOL enable_vsync, - BOOL use_gl, - BOOL ignore_pixel_depth, + bool fullscreen, + bool clearBg, + bool enable_vsync, + bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, @@ -441,7 +441,7 @@ LLWindow* LLWindowManager::createWindow( fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); } - if (FALSE == new_window->isValid()) + if (false == new_window->isValid()) { delete new_window; LL_WARNS() << "LLWindowManager::create() : Error creating window." << LL_ENDL; @@ -451,13 +451,13 @@ LLWindow* LLWindowManager::createWindow( return new_window; } -BOOL LLWindowManager::destroyWindow(LLWindow* window) +bool LLWindowManager::destroyWindow(LLWindow* window) { if (sWindowList.find(window) == sWindowList.end()) { LL_ERRS() << "LLWindowManager::destroyWindow() : Window pointer not valid, this window doesn't exist!" << LL_ENDL; - return FALSE; + return false; } window->close(); @@ -466,10 +466,10 @@ BOOL LLWindowManager::destroyWindow(LLWindow* window) delete window; - return TRUE; + return true; } -BOOL LLWindowManager::isWindowValid(LLWindow *window) +bool LLWindowManager::isWindowValid(LLWindow *window) { return sWindowList.find(window) != sWindowList.end(); } diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index b53cda6150..1c41c1f627 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -63,21 +63,21 @@ public: virtual void show() = 0; virtual void hide() = 0; virtual void close() = 0; - virtual BOOL getVisible() = 0; - virtual BOOL getMinimized() = 0; - virtual BOOL getMaximized() = 0; - virtual BOOL maximize() = 0; + virtual bool getVisible() = 0; + virtual bool getMinimized() = 0; + virtual bool getMaximized() = 0; + virtual bool maximize() = 0; virtual void minimize() = 0; virtual void restore() = 0; - BOOL getFullscreen() { return mFullscreen; }; - virtual BOOL getPosition(LLCoordScreen *position) = 0; - virtual BOOL getSize(LLCoordScreen *size) = 0; - virtual BOOL getSize(LLCoordWindow *size) = 0; - virtual BOOL setPosition(LLCoordScreen position) = 0; - BOOL setSize(LLCoordScreen size); - BOOL setSize(LLCoordWindow size); + bool getFullscreen() { return mFullscreen; }; + virtual bool getPosition(LLCoordScreen *position) = 0; + virtual bool getSize(LLCoordScreen *size) = 0; + virtual bool getSize(LLCoordWindow *size) = 0; + virtual bool setPosition(LLCoordScreen position) = 0; + bool setSize(LLCoordScreen size); + bool setSize(LLCoordWindow size); virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0; + virtual bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) = 0; //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread // returns a pointer to be handed back to destroySharedConext/makeContextCurrent @@ -90,14 +90,14 @@ public: virtual void toggleVSync(bool enable_vsync) = 0; - virtual BOOL setCursorPosition(LLCoordWindow position) = 0; - virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; + virtual bool setCursorPosition(LLCoordWindow position) = 0; + virtual bool getCursorPosition(LLCoordWindow *position) = 0; #if LL_WINDOWS - virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0; + virtual bool getCursorDelta(LLCoordCommon* delta) = 0; #endif virtual void showCursor() = 0; virtual void hideCursor() = 0; - virtual BOOL isCursorHidden() = 0; + virtual bool isCursorHidden() = 0; virtual void showCursorFromMouseMove() = 0; virtual void hideCursorUntilMouseMove() = 0; @@ -124,22 +124,22 @@ public: virtual void captureMouse() = 0; virtual void releaseMouse() = 0; - virtual void setMouseClipping( BOOL b ) = 0; + virtual void setMouseClipping( bool b ) = 0; - virtual BOOL isClipboardTextAvailable() = 0; - virtual BOOL pasteTextFromClipboard(LLWString &dst) = 0; - virtual BOOL copyTextToClipboard(const LLWString &src) = 0; + virtual bool isClipboardTextAvailable() = 0; + virtual bool pasteTextFromClipboard(LLWString &dst) = 0; + virtual bool copyTextToClipboard(const LLWString &src) = 0; - virtual BOOL isPrimaryTextAvailable(); - virtual BOOL pasteTextFromPrimary(LLWString &dst); - virtual BOOL copyTextToPrimary(const LLWString &src); + virtual bool isPrimaryTextAvailable(); + virtual bool pasteTextFromPrimary(LLWString &dst); + virtual bool copyTextToPrimary(const LLWString &src); virtual void flashIcon(F32 seconds) = 0; virtual F32 getGamma() = 0; - virtual BOOL setGamma(const F32 gamma) = 0; // Set the gamma + virtual bool setGamma(const F32 gamma) = 0; // Set the gamma virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples virtual U32 getFSAASamples() = 0; - virtual BOOL restoreGamma() = 0; // Restore original gamma table (before updating gamma) + virtual bool restoreGamma() = 0; // Restore original gamma table (before updating gamma) virtual ESwapMethod getSwapMethod() { return mSwapMethod; } virtual void processMiscNativeEvents(); virtual void gatherInput() = 0; @@ -151,12 +151,12 @@ public: // handy coordinate space conversion routines // NB: screen to window and vice verse won't work on width/height coordinate pairs, // as the conversion must take into account left AND right border widths, etc. - virtual BOOL convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; - virtual BOOL convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; - virtual BOOL convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; - virtual BOOL convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; - virtual BOOL convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; - virtual BOOL convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; + virtual bool convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; + virtual bool convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; + virtual bool convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; + virtual bool convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; + virtual bool convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; + virtual bool convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; // query supported resolutions virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; @@ -172,8 +172,8 @@ public: virtual void afterDialog() {}; // undo whatever was done in beforeDialog() // opens system default color picker, modally - // Returns TRUE if valid color selected - virtual BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); + // Returns true if valid color selected + virtual bool dialogColorPicker(F32 *r, F32 *g, F32 *b); // return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) virtual void *getPlatformWindow() = 0; @@ -182,7 +182,7 @@ public: virtual void *getMediaWindow(); // control platform's Language Text Input mechanisms. - virtual void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) {} + virtual void allowLanguageTextInput(LLPreeditor *preeditor, bool b) {} virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; virtual void updateLanguageTextInputArea() {} virtual void interruptLanguageTextInput() {} @@ -204,21 +204,21 @@ public: virtual S32 getRefreshRate() { return mRefreshRate; } protected: - LLWindow(LLWindowCallbacks* callbacks, BOOL fullscreen, U32 flags); + LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags); virtual ~LLWindow(); // Defaults to true - virtual BOOL isValid(); + virtual bool isValid(); // Defaults to true - virtual BOOL canDelete(); + virtual bool canDelete(); - virtual BOOL setSizeImpl(LLCoordScreen size) = 0; - virtual BOOL setSizeImpl(LLCoordWindow size) = 0; + virtual bool setSizeImpl(LLCoordScreen size) = 0; + virtual bool setSizeImpl(LLCoordWindow size) = 0; protected: LLWindowCallbacks* mCallbacks; - BOOL mPostQuit; // should this window post a quit message when destroyed? - BOOL mFullscreen; + bool mPostQuit; // should this window post a quit message when destroyed? + bool mFullscreen; S32 mFullscreenWidth; S32 mFullscreenHeight; S32 mFullscreenBits; @@ -227,11 +227,11 @@ protected: S32 mNumSupportedResolutions; ECursorType mCurrentCursor; ECursorType mNextCursor; - BOOL mCursorHidden; + bool mCursorHidden; S32 mBusyCount; // how deep is the "cursor busy" stack? - BOOL mIsMouseClipping; // Is this window currently clipping the mouse + bool mIsMouseClipping; // Is this window currently clipping the mouse ESwapMethod mSwapMethod; - BOOL mHideCursorPermanent; + bool mHideCursorPermanent; U32 mFlags; U16 mHighSurrogate; S32 mMinWindowWidth; @@ -276,7 +276,7 @@ protected: virtual void updateImpl(const std::string& string) = 0; virtual void hideImpl() = 0; - static BOOL sVisible; + static bool sVisible; }; @@ -302,23 +302,23 @@ public: LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags = 0, - BOOL fullscreen = FALSE, - BOOL clearBg = FALSE, - BOOL enable_vsync = FALSE, - BOOL use_gl = TRUE, - BOOL ignore_pixel_depth = FALSE, + bool fullscreen = false, + bool clearBg = false, + bool enable_vsync = false, + bool use_gl = true, + bool ignore_pixel_depth = false, U32 fsaa_samples = 0, U32 max_cores = 0, U32 max_vram = 0, F32 max_gl_version = 4.6f); - static BOOL destroyWindow(LLWindow* window); - static BOOL isWindowValid(LLWindow *window); + static bool destroyWindow(LLWindow* window); + static bool isWindowValid(LLWindow *window); }; // // helper funcs // -extern BOOL gDebugWindowProc; +extern bool gDebugWindowProc; // Protocols, like "http" and "https" we support in URLs extern const S32 gURLProtocolWhitelistCount; diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index be61e1e16c..2b5899b774 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -32,35 +32,35 @@ // LLWindowCallbacks // -BOOL LLWindowCallbacks::handleTranslatedKeyDown(const KEY key, const MASK mask, BOOL repeated) +bool LLWindowCallbacks::handleTranslatedKeyDown(const KEY key, const MASK mask, bool repeated) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleTranslatedKeyUp(const KEY key, const MASK mask) +bool LLWindowCallbacks::handleTranslatedKeyUp(const KEY key, const MASK mask) { - return FALSE; + return false; } -void LLWindowCallbacks::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level) +void LLWindowCallbacks::handleScanKey(KEY key, bool key_down, bool key_up, bool key_level) { } -BOOL LLWindowCallbacks::handleUnicodeChar(llwchar uni_char, MASK mask) +bool LLWindowCallbacks::handleUnicodeChar(llwchar uni_char, MASK mask) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } void LLWindowCallbacks::handleMouseLeave(LLWindow *window) @@ -68,54 +68,54 @@ void LLWindowCallbacks::handleMouseLeave(LLWindow *window) return; } -BOOL LLWindowCallbacks::handleCloseRequest(LLWindow *window) +bool LLWindowCallbacks::handleCloseRequest(LLWindow *window) { //allow the window to close - return TRUE; + return true; } void LLWindowCallbacks::handleQuit(LLWindow *window) { } -BOOL LLWindowCallbacks::handleRightMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleRightMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleRightMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleRightMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleMiddleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleMiddleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleMiddleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleMiddleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleOtherMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +bool LLWindowCallbacks::handleOtherMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleOtherMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +bool LLWindowCallbacks::handleOtherMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleActivate(LLWindow *window, BOOL activated) +bool LLWindowCallbacks::handleActivate(LLWindow *window, bool activated) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleActivateApp(LLWindow *window, BOOL activating) +bool LLWindowCallbacks::handleActivateApp(LLWindow *window, bool activating) { - return FALSE; + return false; } void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, MASK mask) @@ -151,15 +151,15 @@ void LLWindowCallbacks::handleMenuSelect(LLWindow *window, const S32 menu_item) { } -BOOL LLWindowCallbacks::handlePaint(LLWindow *window, const S32 x, const S32 y, +bool LLWindowCallbacks::handlePaint(LLWindow *window, const S32 x, const S32 y, const S32 width, const S32 height) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleDoubleClick(LLWindow *window, const LLCoordGL pos, MASK mask) +bool LLWindowCallbacks::handleDoubleClick(LLWindow *window, const LLCoordGL pos, MASK mask) { - return FALSE; + return false; } void LLWindowCallbacks::handleWindowBlock(LLWindow *window) @@ -179,24 +179,24 @@ LLWindowCallbacks::DragNDropResult LLWindowCallbacks::handleDragNDrop(LLWindow * return LLWindowCallbacks::DND_NONE; } -BOOL LLWindowCallbacks::handleTimerEvent(LLWindow *window) +bool LLWindowCallbacks::handleTimerEvent(LLWindow *window) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleDeviceChange(LLWindow *window) +bool LLWindowCallbacks::handleDeviceChange(LLWindow *window) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) +bool LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) { - return FALSE; + return false; } -BOOL LLWindowCallbacks::handleWindowDidChangeScreen(LLWindow *window) +bool LLWindowCallbacks::handleWindowDidChangeScreen(LLWindow *window) { - return FALSE; + return false; } void LLWindowCallbacks::handlePingWatchdog(LLWindow *window, const char * msg) diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 3b18648138..f729e95f9e 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -33,26 +33,26 @@ class LLWindowCallbacks { public: virtual ~LLWindowCallbacks() {} - virtual BOOL handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated); - virtual BOOL handleTranslatedKeyUp(KEY key, MASK mask); - virtual void handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level); - virtual BOOL handleUnicodeChar(llwchar uni_char, MASK mask); + virtual bool handleTranslatedKeyDown(KEY key, MASK mask, bool repeated); + virtual bool handleTranslatedKeyUp(KEY key, MASK mask); + virtual void handleScanKey(KEY key, bool key_down, bool key_up, bool key_level); + virtual bool handleUnicodeChar(llwchar uni_char, MASK mask); - virtual BOOL handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - virtual BOOL handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleMouseLeave(LLWindow *window); - // return TRUE to allow window to close, which will then cause handleQuit to be called - virtual BOOL handleCloseRequest(LLWindow *window); + // return true to allow window to close, which will then cause handleQuit to be called + virtual bool handleCloseRequest(LLWindow *window); // window is about to be destroyed, clean up your business virtual void handleQuit(LLWindow *window); - virtual BOOL handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - virtual BOOL handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - virtual BOOL handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - virtual BOOL handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - virtual BOOL handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); - virtual BOOL handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); - virtual BOOL handleActivate(LLWindow *window, BOOL activated); - virtual BOOL handleActivateApp(LLWindow *window, BOOL activating); + virtual bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + virtual bool handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + virtual bool handleActivate(LLWindow *window, bool activated); + virtual bool handleActivateApp(LLWindow *window, bool activating); virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); virtual void handleScrollWheel(LLWindow *window, S32 clicks); @@ -61,15 +61,15 @@ public: virtual void handleFocus(LLWindow *window); virtual void handleFocusLost(LLWindow *window); virtual void handleMenuSelect(LLWindow *window, S32 menu_item); - virtual BOOL handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); - virtual BOOL handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); // double-click of left mouse button + virtual bool handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); + virtual bool handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); // double-click of left mouse button virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); - virtual BOOL handleTimerEvent(LLWindow *window); - virtual BOOL handleDeviceChange(LLWindow *window); - virtual BOOL handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); - virtual BOOL handleWindowDidChangeScreen(LLWindow *window); + virtual bool handleTimerEvent(LLWindow *window); + virtual bool handleDeviceChange(LLWindow *window); + virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); + virtual bool handleWindowDidChangeScreen(LLWindow *window); enum DragNDropAction { DNDA_START_TRACKING = 0,// Start tracking an incoming drag diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index c3738af6ca..ad278b38c8 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -34,8 +34,8 @@ // LLWindowHeadless // LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) + U32 flags, bool fullscreen, bool clear_background, + bool enable_vsync, bool use_gl, bool ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { // Initialize a headless keyboard. diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 10b3c66f93..06e6b2783d 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -35,10 +35,10 @@ public: /*virtual*/ void show() override {} /*virtual*/ void hide() override {} /*virtual*/ void close() override {} - /*virtual*/ BOOL getVisible() override {return FALSE;} - /*virtual*/ BOOL getMinimized() override {return FALSE;} - /*virtual*/ BOOL getMaximized() override {return FALSE;} - /*virtual*/ BOOL maximize() override {return FALSE;} + /*virtual*/ bool getVisible() override {return false;} + /*virtual*/ bool getMinimized() override {return false;} + /*virtual*/ bool getMaximized() override {return false;} + /*virtual*/ bool maximize() override {return false;} /*virtual*/ void minimize() override {} /*virtual*/ void restore() override {} // TODO: LLWindow::getFullscreen() is (intentionally?) NOT virtual. @@ -46,42 +46,42 @@ public: // mistake to shadow the base-class method with an LLWindowHeadless // override when called on the subclass, yet call the base-class method // when indirecting through a polymorphic pointer or reference? - BOOL getFullscreen() {return FALSE;} - /*virtual*/ BOOL getPosition(LLCoordScreen *position) override {return FALSE;} - /*virtual*/ BOOL getSize(LLCoordScreen *size) override {return FALSE;} - /*virtual*/ BOOL getSize(LLCoordWindow *size) override {return FALSE;} - /*virtual*/ BOOL setPosition(LLCoordScreen position) override {return FALSE;} - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) override {return FALSE;} - /*virtual*/ BOOL setSizeImpl(LLCoordWindow size) override {return FALSE;} - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override {return FALSE;} + bool getFullscreen() {return false;} + /*virtual*/ bool getPosition(LLCoordScreen *position) override {return false;} + /*virtual*/ bool getSize(LLCoordScreen *size) override {return false;} + /*virtual*/ bool getSize(LLCoordWindow *size) override {return false;} + /*virtual*/ bool setPosition(LLCoordScreen position) override {return false;} + /*virtual*/ bool setSizeImpl(LLCoordScreen size) override {return false;} + /*virtual*/ bool setSizeImpl(LLCoordWindow size) override {return false;} + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override {return false;} void* createSharedContext() override { return nullptr; } void makeContextCurrent(void*) override {} void destroySharedContext(void*) override {} /*virtual*/ void toggleVSync(bool enable_vsync) override { } - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) override {return FALSE;} - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) override {return FALSE;} + /*virtual*/ bool setCursorPosition(LLCoordWindow position) override {return false;} + /*virtual*/ bool getCursorPosition(LLCoordWindow *position) override {return false;} #if LL_WINDOWS - /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) override { return FALSE; } + /*virtual*/ bool getCursorDelta(LLCoordCommon* delta) override { return false; } #endif /*virtual*/ void showCursor() override {} /*virtual*/ void hideCursor() override {} /*virtual*/ void showCursorFromMouseMove() override {} /*virtual*/ void hideCursorUntilMouseMove() override {} - /*virtual*/ BOOL isCursorHidden() override {return FALSE;} + /*virtual*/ bool isCursorHidden() override {return false;} /*virtual*/ void updateCursor() override {} //virtual ECursorType getCursor() override { return mCurrentCursor; } /*virtual*/ void captureMouse() override {} /*virtual*/ void releaseMouse() override {} - /*virtual*/ void setMouseClipping( BOOL b ) override {} - /*virtual*/ BOOL isClipboardTextAvailable() override {return FALSE; } - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) override {return FALSE; } - /*virtual*/ BOOL copyTextToClipboard(const LLWString &src) override {return FALSE; } + /*virtual*/ void setMouseClipping( bool b ) override {} + /*virtual*/ bool isClipboardTextAvailable() override {return false; } + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) override {return false; } + /*virtual*/ bool copyTextToClipboard(const LLWString &src) override {return false; } /*virtual*/ void flashIcon(F32 seconds) override {} /*virtual*/ F32 getGamma() override {return 1.0f; } - /*virtual*/ BOOL setGamma(const F32 gamma) override {return FALSE; } // Set the gamma + /*virtual*/ bool setGamma(const F32 gamma) override {return false; } // Set the gamma /*virtual*/ void setFSAASamples(const U32 fsaa_samples) override { } /*virtual*/ U32 getFSAASamples() override { return 0; } - /*virtual*/ BOOL restoreGamma() override {return FALSE; } // Restore original gamma table (before updating gamma) + /*virtual*/ bool restoreGamma() override {return false; } // Restore original gamma table (before updating gamma) //virtual ESwapMethod getSwapMethod() override { return mSwapMethod; } /*virtual*/ void gatherInput() override {} /*virtual*/ void delayInputProcessing() override {} @@ -89,12 +89,12 @@ public: // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return FALSE; } - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return FALSE; } - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override { return FALSE; } - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override { return FALSE; } - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override { return FALSE; } - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override { return FALSE; } + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) override { return false; } /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override { return NULL; } /*virtual*/ F32 getNativeAspectRatio() override { return 1.0f; } @@ -111,8 +111,8 @@ public: const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth); + U32 flags, bool fullscreen, bool clear_background, + bool enable_vsync, bool use_gl, bool ignore_pixel_depth); virtual ~LLWindowHeadless(); private: diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 9f71b80e74..bfa893fff8 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -43,8 +43,8 @@ #include #include -extern BOOL gDebugWindowProc; -BOOL gHiDPISupport = TRUE; +extern bool gDebugWindowProc; +bool gHiDPISupport = true; const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; @@ -59,11 +59,11 @@ namespace // LLWindowMacOSX // -BOOL LLWindowMacOSX::sUseMultGL = FALSE; +bool LLWindowMacOSX::sUseMultGL = false; // Cross-platform bits: -BOOL check_for_card(const char* RENDERER, const char* bad_card) +bool check_for_card(const char* RENDERER, const char* bad_card) { if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) { @@ -84,15 +84,15 @@ BOOL check_for_card(const char* RENDERER, const char* bad_card) S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); if (OSBTN_YES == button) { - return FALSE; + return false; } else { - return TRUE; + return true; } } - return FALSE; + return false; } // Switch to determine whether we capture all displays, or just the main one. @@ -112,9 +112,9 @@ static LLWindowMacOSX *gWindowImplementation = NULL; LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_vram) : LLWindow(NULL, fullscreen, flags) @@ -138,21 +138,21 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, mContext = NULL; mPixelFormat = NULL; mDisplay = CGMainDisplayID(); - mSimulatedRightClick = FALSE; + mSimulatedRightClick = false; mLastModifiers = 0; - mHandsOffEvents = FALSE; - mCursorDecoupled = FALSE; + mHandsOffEvents = false; + mCursorDecoupled = false; mCursorLastEventDeltaX = 0; mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; - mNeedsResize = FALSE; + mCursorIgnoreNextDelta = false; + mNeedsResize = false; mOverrideAspectRatio = 0.f; - mMaximized = FALSE; - mMinimized = FALSE; - mLanguageTextInputAllowed = FALSE; + mMaximized = false; + mMinimized = false; + mLanguageTextInputAllowed = false; mPreeditor = NULL; mFSAASamples = fsaa_samples; - mForceRebuild = FALSE; + mForceRebuild = false; // Get the original aspect ratio of the main device. mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); @@ -192,7 +192,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, initCursors(); setCursor( UI_CURSOR_ARROW ); - allowLanguageTextInput(NULL, FALSE); + allowLanguageTextInput(NULL, false); } mCallbacks = callbacks; @@ -281,7 +281,7 @@ void callRightMouseDown(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callRightMouseUp(float *pos, MASK mask) @@ -294,7 +294,7 @@ void callRightMouseUp(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callLeftMouseDown(float *pos, MASK mask) @@ -307,7 +307,7 @@ void callLeftMouseDown(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callLeftMouseUp(float *pos, MASK mask) @@ -320,7 +320,7 @@ void callLeftMouseUp(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } @@ -334,7 +334,7 @@ void callDoubleClick(float *pos, MASK mask) LLCoordGL outCoords; outCoords.mX = ll_round(pos[0]); outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callResize(unsigned int width, unsigned int height) @@ -354,7 +354,7 @@ void callMouseMoved(float *pos, MASK mask) gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); } @@ -367,7 +367,7 @@ void callMouseDragged(float *pos, MASK mask) gWindowImplementation->getMouseDeltas(deltas); outCoords.mX += deltas[0]; outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(TRUE)); + gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); } void callScrollMoved(float deltaX, float deltaY) @@ -609,7 +609,7 @@ void LLWindowMacOSX::updateMouseDeltas(float* deltas) { mCursorLastEventDeltaX = 0; mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = FALSE; + mCursorIgnoreNextDelta = false; } } else { mCursorLastEventDeltaX = 0; @@ -623,7 +623,7 @@ void LLWindowMacOSX::getMouseDeltas(float* delta) delta[1] = mCursorLastEventDeltaY; } -BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync) +bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { mFullscreen = fullscreen; @@ -682,7 +682,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits if (err != kCGLNoError) { setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return FALSE; + return false; } } @@ -715,15 +715,15 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits } makeFirstResponder(mWindow, mGLView); - return TRUE; + return true; } // We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. // This makes this method obsolete. -BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp) +bool LLWindowMacOSX::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) { - return FALSE; + return false; } void LLWindowMacOSX::destroyContext() @@ -793,13 +793,13 @@ void LLWindowMacOSX::show() void LLWindowMacOSX::hide() { - setMouseClipping(FALSE); + setMouseClipping(false); } //virtual void LLWindowMacOSX::minimize() { - setMouseClipping(FALSE); + setMouseClipping(false); showCursor(); } @@ -821,48 +821,48 @@ void LLWindowMacOSX::close() // } // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(FALSE); + setMouseClipping(false); showCursor(); destroyContext(); } -BOOL LLWindowMacOSX::isValid() +bool LLWindowMacOSX::isValid() { if(mFullscreen) { - return(TRUE); + return(true); } return (mWindow != NULL); } -BOOL LLWindowMacOSX::getVisible() +bool LLWindowMacOSX::getVisible() { - BOOL result = FALSE; + bool result = false; if(mFullscreen) { - result = TRUE; + result = true; }if (mWindow) { - result = TRUE; + result = true; } return(result); } -BOOL LLWindowMacOSX::getMinimized() +bool LLWindowMacOSX::getMinimized() { return mMinimized; } -BOOL LLWindowMacOSX::getMaximized() +bool LLWindowMacOSX::getMaximized() { return mMaximized; } -BOOL LLWindowMacOSX::maximize() +bool LLWindowMacOSX::maximize() { if (mWindow && !mMaximized) { @@ -871,7 +871,7 @@ BOOL LLWindowMacOSX::maximize() return mMaximized; } -BOOL LLWindowMacOSX::getFullscreen() +bool LLWindowMacOSX::getFullscreen() { return mFullscreen; } @@ -881,7 +881,7 @@ void LLWindowMacOSX::gatherInput() updateCursor(); } -BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) +bool LLWindowMacOSX::getPosition(LLCoordScreen *position) { S32 err = -1; @@ -908,7 +908,7 @@ BOOL LLWindowMacOSX::getPosition(LLCoordScreen *position) return (err == noErr); } -BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) +bool LLWindowMacOSX::getSize(LLCoordScreen *size) { S32 err = -1; @@ -934,7 +934,7 @@ BOOL LLWindowMacOSX::getSize(LLCoordScreen *size) return (err == noErr); } -BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) +bool LLWindowMacOSX::getSize(LLCoordWindow *size) { S32 err = -1; @@ -962,7 +962,7 @@ BOOL LLWindowMacOSX::getSize(LLCoordWindow *size) return (err == noErr); } -BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) +bool LLWindowMacOSX::setPosition(const LLCoordScreen position) { if(mWindow) { @@ -970,32 +970,32 @@ BOOL LLWindowMacOSX::setPosition(const LLCoordScreen position) setWindowPos(mWindow, pos); } - return TRUE; + return true; } -BOOL LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) +bool LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) { if(mWindow) { LLCoordWindow to; convertCoords(size, &to); setWindowSize(mWindow, to.mX, to.mY); - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) +bool LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) { if (mWindow) { const int titlePadding = 22; setWindowSize(mWindow, size.mX, size.mY + titlePadding); - return TRUE; + return true; } - return FALSE; + return false; } void LLWindowMacOSX::swapBuffers() @@ -1050,16 +1050,16 @@ U32 LLWindowMacOSX::getFSAASamples() void LLWindowMacOSX::setFSAASamples(const U32 samples) { mFSAASamples = samples; - mForceRebuild = TRUE; + mForceRebuild = true; } -BOOL LLWindowMacOSX::restoreGamma() +bool LLWindowMacOSX::restoreGamma() { CGDisplayRestoreColorSyncSettings(); return true; } -BOOL LLWindowMacOSX::setGamma(const F32 gamma) +bool LLWindowMacOSX::setGamma(const F32 gamma) { CGGammaValue redMin; CGGammaValue redMax; @@ -1107,7 +1107,7 @@ BOOL LLWindowMacOSX::setGamma(const F32 gamma) return true; } -BOOL LLWindowMacOSX::isCursorHidden() +bool LLWindowMacOSX::isCursorHidden() { return mCursorHidden; } @@ -1115,31 +1115,31 @@ BOOL LLWindowMacOSX::isCursorHidden() // Constrains the mouse to the window. -void LLWindowMacOSX::setMouseClipping( BOOL b ) +void LLWindowMacOSX::setMouseClipping( bool b ) { // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. mIsMouseClipping = b; if(b) { - // LL_INFOS() << "setMouseClipping(TRUE)" << LL_ENDL; + // LL_INFOS() << "setMouseClipping(true)" << LL_ENDL; } else { - // LL_INFOS() << "setMouseClipping(FALSE)" << LL_ENDL; + // LL_INFOS() << "setMouseClipping(false)" << LL_ENDL; } adjustCursorDecouple(); } -BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) +bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) { - BOOL result = FALSE; + bool result = false; LLCoordScreen screen_pos; if (!convertCoords(position, &screen_pos)) { - return FALSE; + return false; } CGPoint newPosition; @@ -1152,7 +1152,7 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) CGSetLocalEventsSuppressionInterval(0.0); if(CGWarpMouseCursorPosition(newPosition) == noErr) { - result = TRUE; + result = true; } // Under certain circumstances, this will trigger us to decouple the cursor. @@ -1169,13 +1169,13 @@ BOOL LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) return result; } -BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) +bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) { float cursor_point[2]; LLCoordScreen screen_pos; if(mWindow == NULL) - return FALSE; + return false; getCursorPos(mWindow, cursor_point); @@ -1198,7 +1198,7 @@ BOOL LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) position->mX = cursor_point[0] * scale; position->mY = cursor_point[1] * scale; - return TRUE; + return true; } void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) @@ -1213,7 +1213,7 @@ void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; CGAssociateMouseAndMouseCursorPosition(false); mCursorDecoupled = true; - mCursorIgnoreNextDelta = TRUE; + mCursorIgnoreNextDelta = true; } } } @@ -1293,12 +1293,12 @@ void LLWindowMacOSX::flashIcon(F32 seconds) requestUserAttention(); } -BOOL LLWindowMacOSX::isClipboardTextAvailable() +bool LLWindowMacOSX::isClipboardTextAvailable() { return pasteBoardAvailable(); } -BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) +bool LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) { unsigned short* pboard_data = copyFromPBoard(); // must free returned data llutf16string str(pboard_data); @@ -1313,9 +1313,9 @@ BOOL LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) } } -BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) +bool LLWindowMacOSX::copyTextToClipboard(const LLWString &s) { - BOOL result = false; + bool result = false; llutf16string utf16str = wstring_to_utf16str(s); result = copyToPBoard(utf16str.data(), utf16str.length()); @@ -1325,7 +1325,7 @@ BOOL LLWindowMacOSX::copyTextToClipboard(const LLWString &s) // protected -BOOL LLWindowMacOSX::resetDisplayResolution() +bool LLWindowMacOSX::resetDisplayResolution() { // This is only called from elsewhere in this class, and it's not used by the Mac implementation. return true; @@ -1358,13 +1358,13 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) { - BOOL resolution_exists = FALSE; + bool resolution_exists = false; for(S32 i = 0; i < mNumSupportedResolutions; i++) { if (mSupportedResolutions[i].mWidth == width && mSupportedResolutions[i].mHeight == height) { - resolution_exists = TRUE; + resolution_exists = true; } } if (!resolution_exists) @@ -1383,21 +1383,21 @@ LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_r return mSupportedResolutions; } -BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) { to->mX = from.mX; to->mY = from.mY; - return TRUE; + return true; } -BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) { to->mX = from.mX; to->mY = from.mY; - return TRUE; + return true; } -BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) { if(mWindow) { @@ -1411,12 +1411,12 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) to->mX = mouse_point[0]; to->mY = mouse_point[1]; - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) { if(mWindow) { @@ -1430,19 +1430,19 @@ BOOL LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) to->mX = mouse_point[0]; to->mY = mouse_point[1]; - return TRUE; + return true; } - return FALSE; + return false; } -BOOL LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) { LLCoordWindow window_coord; return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } -BOOL LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) { LLCoordWindow window_coord; @@ -1704,8 +1704,8 @@ void LLWindowMacOSX::hideCursor() if(!mCursorHidden) { // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; + mCursorHidden = true; + mHideCursorPermanent = true; hideNSCursor(); } else @@ -1721,8 +1721,8 @@ void LLWindowMacOSX::showCursor() if(mCursorHidden || !isCGCursorVisible()) { // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; + mCursorHidden = false; + mHideCursorPermanent = false; showNSCursor(); } else @@ -1746,7 +1746,7 @@ void LLWindowMacOSX::hideCursorUntilMouseMove() if (!mHideCursorPermanent) { hideCursor(); - mHideCursorPermanent = FALSE; + mHideCursorPermanent = false; } } @@ -1867,9 +1867,9 @@ LLSD LLWindowMacOSX::getNativeKeyData() return result; } -BOOL LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) +bool LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - BOOL retval = FALSE; + bool retval = false; OSErr error = noErr; NColorPickerInfo info; @@ -1926,12 +1926,12 @@ static long getDictLong (CFDictionaryRef refDict, CFStringRef key) return int_value; // otherwise return the long value } -void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) +void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, bool b) { if (preeditor != mPreeditor && !b) { // This condition may occur by a call to - // setEnabled(BOOL) against LLTextEditor or LLLineEditor + // setEnabled(bool) against LLTextEditor or LLLineEditor // when the control is not focused. // We need to silently ignore the case so that // the language input status of the focused control diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 3b13f60f77..7b0695bc79 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -47,53 +47,53 @@ public: void show() override; void hide() override; void close() override; - BOOL getVisible() override; - BOOL getMinimized() override; - BOOL getMaximized() override; - BOOL maximize() override; + bool getVisible() override; + bool getMinimized() override; + bool getMaximized() override; + bool maximize() override; void minimize() override; void restore() override; - BOOL getFullscreen(); - BOOL getPosition(LLCoordScreen *position) override; - BOOL getSize(LLCoordScreen *size) override; - BOOL getSize(LLCoordWindow *size) override; - BOOL setPosition(LLCoordScreen position) override; - BOOL setSizeImpl(LLCoordScreen size) override; - BOOL setSizeImpl(LLCoordWindow size) override; - BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override; - BOOL setCursorPosition(LLCoordWindow position) override; - BOOL getCursorPosition(LLCoordWindow *position) override; + bool getFullscreen(); + bool getPosition(LLCoordScreen *position) override; + bool getSize(LLCoordScreen *size) override; + bool getSize(LLCoordWindow *size) override; + bool setPosition(LLCoordScreen position) override; + bool setSizeImpl(LLCoordScreen size) override; + bool setSizeImpl(LLCoordWindow size) override; + bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override; + bool setCursorPosition(LLCoordWindow position) override; + bool getCursorPosition(LLCoordWindow *position) override; void showCursor() override; void hideCursor() override; void showCursorFromMouseMove() override; void hideCursorUntilMouseMove() override; - BOOL isCursorHidden() override; + bool isCursorHidden() override; void updateCursor() override; ECursorType getCursor() const override; void captureMouse() override; void releaseMouse() override; - void setMouseClipping( BOOL b ) override; - BOOL isClipboardTextAvailable() override; - BOOL pasteTextFromClipboard(LLWString &dst) override; - BOOL copyTextToClipboard(const LLWString & src) override; + void setMouseClipping( bool b ) override; + bool isClipboardTextAvailable() override; + bool pasteTextFromClipboard(LLWString &dst) override; + bool copyTextToClipboard(const LLWString & src) override; void flashIcon(F32 seconds) override; F32 getGamma() override; - BOOL setGamma(const F32 gamma) override; // Set the gamma + bool setGamma(const F32 gamma) override; // Set the gamma U32 getFSAASamples() override; void setFSAASamples(const U32 fsaa_samples) override; - BOOL restoreGamma() override; // Restore original gamma table (before updating gamma) + bool restoreGamma() override; // Restore original gamma table (before updating gamma) ESwapMethod getSwapMethod() override { return mSwapMethod; } void gatherInput() override; void delayInputProcessing() override {}; void swapBuffers() override; // handy coordinate space conversion routines - BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; - BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; - BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; - BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; - BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; - BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; + bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + bool convertCoords(LLCoordWindow from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordWindow *to) override; + bool convertCoords(LLCoordScreen from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordScreen *to) override; LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; F32 getNativeAspectRatio() override; @@ -107,12 +107,12 @@ public: void beforeDialog() override; void afterDialog() override; - BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; + bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; void *getPlatformWindow() override; void bringToFront() override {}; - void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override; + void allowLanguageTextInput(LLPreeditor *preeditor, bool b) override; void interruptLanguageTextInput() override; void spawnWebBrowser(const std::string& escaped_url, bool async) override; F32 getSystemUISize() override; @@ -149,27 +149,27 @@ public: protected: LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, + bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_vram); ~LLWindowMacOSX(); void initCursors(); - BOOL isValid() override; + bool isValid() override; void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); + bool setFullscreenResolution(); // Restore the display resolution to its value before we ran the app. - BOOL resetDisplayResolution(); + bool resetDisplayResolution(); - BOOL shouldPostQuit() { return mPostQuit; } + bool shouldPostQuit() { return mPostQuit; } //Satisfy MAINT-3135 and MAINT-3288 with a flag. /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } @@ -183,7 +183,7 @@ protected: // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync); + bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); void adjustCursorDecouple(bool warpingMouse = false); @@ -211,31 +211,31 @@ protected: LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() std::string mWindowTitle; double mOriginalAspectRatio; - BOOL mSimulatedRightClick; + bool mSimulatedRightClick; U32 mLastModifiers; - BOOL mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. + bool mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. // Used to allow event processing when putting up dialogs in fullscreen mode. - BOOL mCursorDecoupled; + bool mCursorDecoupled; S32 mCursorLastEventDeltaX; S32 mCursorLastEventDeltaY; - BOOL mCursorIgnoreNextDelta; - BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + bool mCursorIgnoreNextDelta; + bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. LLCoordScreen mNeedsResizeSize; F32 mOverrideAspectRatio; - BOOL mMaximized; - BOOL mMinimized; + bool mMaximized; + bool mMinimized; U32 mFSAASamples; - BOOL mForceRebuild; + bool mForceRebuild; U32 mMaxVRAM; S32 mDragOverrideCursor; // Input method management through Text Service Manager. - BOOL mLanguageTextInputAllowed; + bool mLanguageTextInputAllowed; LLPreeditor* mPreeditor; public: - static BOOL sUseMultGL; + static bool sUseMultGL; friend class LLWindowManager; diff --git a/indra/llwindow/llwindowmesaheadless.cpp b/indra/llwindow/llwindowmesaheadless.cpp index 4b01f7a979..4b28587048 100644 --- a/indra/llwindow/llwindowmesaheadless.cpp +++ b/indra/llwindow/llwindowmesaheadless.cpp @@ -40,8 +40,8 @@ U16 *gMesaBuffer = NULL; // LLWindowMesaHeadless::LLWindowMesaHeadless(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 flags, bool fullscreen, bool clearBg, + bool disable_vsync, bool use_gl, bool ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { if (use_gl) diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h index 00e42240e6..1cb364a0ff 100644 --- a/indra/llwindow/llwindowmesaheadless.h +++ b/indra/llwindow/llwindowmesaheadless.h @@ -39,38 +39,38 @@ public: /*virtual*/ void show() {}; /*virtual*/ void hide() {}; /*virtual*/ void close() {}; - /*virtual*/ BOOL getVisible() {return FALSE;}; - /*virtual*/ BOOL getMinimized() {return FALSE;}; - /*virtual*/ BOOL getMaximized() {return FALSE;}; - /*virtual*/ BOOL maximize() {return FALSE;}; + /*virtual*/ bool getVisible() {return false;}; + /*virtual*/ bool getMinimized() {return false;}; + /*virtual*/ bool getMaximized() {return false;}; + /*virtual*/ bool maximize() {return false;}; /*virtual*/ void minimize() {}; /*virtual*/ void restore() {}; - /*virtual*/ BOOL getFullscreen() {return FALSE;}; - /*virtual*/ BOOL getPosition(LLCoordScreen *position) {return FALSE;}; - /*virtual*/ BOOL getSize(LLCoordScreen *size) {return FALSE;}; - /*virtual*/ BOOL getSize(LLCoordWindow *size) {return FALSE;}; - /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; + /*virtual*/ bool getFullscreen() {return false;}; + /*virtual*/ bool getPosition(LLCoordScreen *position) {return false;}; + /*virtual*/ bool getSize(LLCoordScreen *size) {return false;}; + /*virtual*/ bool getSize(LLCoordWindow *size) {return false;}; + /*virtual*/ bool setPosition(LLCoordScreen position) {return false;}; + /*virtual*/ bool setSizeImpl(LLCoordScreen size) {return false;}; + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) {return false;}; + /*virtual*/ bool setCursorPosition(LLCoordWindow position) {return false;}; + /*virtual*/ bool getCursorPosition(LLCoordWindow *position) {return false;}; /*virtual*/ void showCursor() {}; /*virtual*/ void hideCursor() {}; /*virtual*/ void showCursorFromMouseMove() {}; /*virtual*/ void hideCursorUntilMouseMove() {}; - /*virtual*/ BOOL isCursorHidden() {return FALSE;}; + /*virtual*/ bool isCursorHidden() {return false;}; /*virtual*/ void updateCursor() {}; //virtual ECursorType getCursor() { return mCurrentCursor; }; /*virtual*/ void captureMouse() {}; /*virtual*/ void releaseMouse() {}; - /*virtual*/ void setMouseClipping( BOOL b ) {}; - /*virtual*/ BOOL isClipboardTextAvailable() {return FALSE; }; - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst) {return FALSE; }; - /*virtual*/ BOOL copyTextToClipboard(const LLWString &src) {return FALSE; }; + /*virtual*/ void setMouseClipping( bool b ) {}; + /*virtual*/ bool isClipboardTextAvailable() {return false; }; + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) {return false; }; + /*virtual*/ bool copyTextToClipboard(const LLWString &src) {return false; }; /*virtual*/ void flashIcon(F32 seconds) {}; /*virtual*/ F32 getGamma() {return 1.0f; }; - /*virtual*/ BOOL setGamma(const F32 gamma) {return FALSE; }; // Set the gamma - /*virtual*/ BOOL restoreGamma() {return FALSE; }; // Restore original gamma table (before updating gamma) + /*virtual*/ bool setGamma(const F32 gamma) {return false; }; // Set the gamma + /*virtual*/ bool restoreGamma() {return false; }; // Restore original gamma table (before updating gamma) /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } /*virtual*/ U32 getFSAASamples() { return 0; } //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } @@ -80,12 +80,12 @@ public: /*virtual*/ void restoreGLContext() {}; // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) { return FALSE; }; - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) { return FALSE; }; - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) { return FALSE; }; - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) { return FALSE; }; - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) { return FALSE; }; - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) { return FALSE; }; + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) { return false; }; /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; @@ -97,8 +97,8 @@ public: LLWindowMesaHeadless(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 flags, bool fullscreen, bool clearBg, + bool disable_vsync, bool use_gl, bool ignore_pixel_depth); ~LLWindowMesaHeadless(); private: diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 7ea87f5884..a0a8252e77 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -59,7 +59,7 @@ extern "C" { # include #endif // LL_LINUX -extern BOOL gDebugWindowProc; +extern bool gDebugWindowProc; const S32 MAX_NUM_RESOLUTIONS = 200; @@ -102,10 +102,10 @@ void maybe_unlock_display(void) // static bool LLWindowSDL::ll_try_gtk_init(void) { - static BOOL done_gtk_diag = FALSE; - static BOOL gtk_is_good = FALSE; - static BOOL done_setlocale = FALSE; - static BOOL tried_gtk_init = FALSE; + static bool done_gtk_diag = false; + static bool gtk_is_good = false; + static bool done_setlocale = false; + static bool tried_gtk_init = false; if (!done_setlocale) { @@ -113,12 +113,12 @@ bool LLWindowSDL::ll_try_gtk_init(void) maybe_lock_display(); gtk_disable_setlocale(); maybe_unlock_display(); - done_setlocale = TRUE; + done_setlocale = true; } if (!tried_gtk_init) { - tried_gtk_init = TRUE; + tried_gtk_init = true; if (!g_thread_supported ()) g_thread_init (NULL); maybe_lock_display(); gtk_is_good = gtk_init_check(NULL, NULL); @@ -148,12 +148,12 @@ bool LLWindowSDL::ll_try_gtk_init(void) { LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << gtk_warning << LL_ENDL; - gtk_is_good = FALSE; + gtk_is_good = false; } else { LL_INFOS() << "- GTK version is good." << LL_ENDL; } - done_gtk_diag = TRUE; + done_gtk_diag = true; } return gtk_is_good; @@ -185,9 +185,9 @@ Display* LLWindowSDL::get_SDL_Display(void) LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, 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) + bool fullscreen, bool clearBg, + bool disable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags), Lock_Display(NULL), Unlock_Display(NULL), mGamma(1.0f) @@ -199,7 +199,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, // Ignore use_gl for now, only used for drones on PC mWindow = NULL; - mNeedsResize = FALSE; + mNeedsResize = false; mOverrideAspectRatio = 0.f; mGrabbyKeyFlags = 0; mReallyCapturedCount = 0; @@ -243,7 +243,7 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, gWindowImplementation = this; #if LL_X11 - mFlashing = FALSE; + mFlashing = false; #endif // LL_X11 mKeyScanCode = 0; @@ -406,7 +406,7 @@ static int x11_detect_VRAM_kb() } #endif // LL_X11 -BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) +bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync) { //bool glneedsinit = false; @@ -442,7 +442,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B { LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); - return FALSE; + return false; } if (video_info->current_h > 0) @@ -560,7 +560,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B if (mWindow) { - mFullscreen = TRUE; + mFullscreen = true; mFullscreenWidth = mWindow->w; mFullscreenHeight = mWindow->h; mFullscreenBits = mWindow->format->BitsPerPixel; @@ -576,7 +576,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B { LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; // No fullscreen support - mFullscreen = FALSE; + mFullscreen = false; mFullscreenWidth = -1; mFullscreenHeight = -1; mFullscreenBits = -1; @@ -606,7 +606,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B { LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; setupFailure("Window creation error", "Error", OSMB_OK); - return FALSE; + return false; } } else if (!mFullscreen && (mWindow != NULL)) { @@ -669,7 +669,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B "will automatically adjust the screen each time it runs.", "Error", OSMB_OK); - return FALSE; + return false; } #if 0 // *FIX: we're going to brave it for now... @@ -685,7 +685,7 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B "If you continue to receive this message, contact customer service.", "Error", OSMB_OK); - return FALSE; + return false; } #endif @@ -726,15 +726,15 @@ BOOL LLWindowSDL::createContext(int x, int y, int width, int height, int bits, B LL_WARNS() << "Couldn't enable key-repeat: " << SDL_GetError() <mX = from.mX; to->mY = mWindow->h - from.mY - 1; - return TRUE; + return true; } -BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) +bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) { if (!to) - return FALSE; + return false; to->mX = from.mX; to->mY = mWindow->h - from.mY - 1; - return TRUE; + return true; } -BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) +bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) { if (!to) - return FALSE; + return false; // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (TRUE); + return (true); } -BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) +bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) { if (!to) - return FALSE; + return false; // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (TRUE); + return (true); } -BOOL LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) +bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) { LLCoordWindow window_coord; return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); } -BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) +bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) { LLCoordWindow window_coord; @@ -1472,7 +1472,7 @@ void LLWindowSDL::setupFailure(const std::string& text, const std::string& capti OSMessageBox(text, caption, type); } -BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) +bool LLWindowSDL::SDLReallyCaptureInput(bool capture) { // note: this used to be safe to call nestedly, but in the // end that's not really a wise usage pattern, so don't. @@ -1554,7 +1554,7 @@ BOOL LLWindowSDL::SDLReallyCaptureInput(BOOL capture) (!capture && SDL_GRAB_OFF==newmode); } -U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain) +U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) { /* part of the fix for SL-13243: Some popular window managers like to totally eat alt-drag for the purposes of moving windows. We @@ -1714,7 +1714,7 @@ void LLWindowSDL::processMiscNativeEvents() pump_timer.setTimerExpirySec(1.0f / 15.0f); do { // Always do at least one non-blocking pump - gtk_main_iteration_do(FALSE); + gtk_main_iteration_do(false); } while (gtk_events_pending() && !pump_timer.hasExpired()); @@ -1748,7 +1748,7 @@ void LLWindowSDL::gatherInput() LLCoordWindow winCoord(event.button.x, event.button.y); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); mCallbacks->handleMouseMove(this, openGlCoord, mask); break; } @@ -1760,13 +1760,13 @@ void LLWindowSDL::gatherInput() gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); // part of the fix for SL-13243 - if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) - SDLReallyCaptureInput(TRUE); + if (SDLCheckGrabbyKeys(event.key.keysym.sym, true) != 0) + SDLReallyCaptureInput(true); if (event.key.keysym.unicode) { handleUnicodeUTF16(event.key.keysym.unicode, - gKeyboard->currentMask(FALSE)); + gKeyboard->currentMask(false)); } break; @@ -1775,8 +1775,8 @@ void LLWindowSDL::gatherInput() mKeyVirtualKey = event.key.keysym.unicode; mKeyModifiers = event.key.keysym.mod; - if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0) - SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 + if (SDLCheckGrabbyKeys(event.key.keysym.sym, false) == 0) + SDLReallyCaptureInput(false); // part of the fix for SL-13243 gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); break; @@ -1787,7 +1787,7 @@ void LLWindowSDL::gatherInput() LLCoordWindow winCoord(event.button.x, event.button.y); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... { @@ -1850,7 +1850,7 @@ void LLWindowSDL::gatherInput() LLCoordWindow winCoord(event.button.x, event.button.y); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); if (event.button.button == SDL_BUTTON_LEFT) // left mCallbacks->handleMouseUp(this, openGlCoord, mask); @@ -1921,11 +1921,11 @@ void LLWindowSDL::gatherInput() mIsMinimized = (!event.active.gain); mCallbacks->handleActivate(this, !mIsMinimized); - LL_INFOS() << "SDL deiconification state switched to " << BOOL(event.active.gain) << LL_ENDL; + LL_INFOS() << "SDL deiconification state switched to " << bool(event.active.gain) << LL_ENDL; } else { - LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << BOOL(event.active.gain) << LL_ENDL; + LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << bool(event.active.gain) << LL_ENDL; } } break; @@ -1951,8 +1951,8 @@ void LLWindowSDL::gatherInput() // expired. if (mFlashing && mFlashTimer.hasExpired()) { - x11_set_urgent(FALSE); - mFlashing = FALSE; + x11_set_urgent(false); + mFlashing = false; } #endif // LL_X11 } @@ -2003,10 +2003,10 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty U8 srcred = pixelp[0]; U8 srcgreen = pixelp[1]; U8 srcblue = pixelp[2]; - BOOL mask_bit = (srcred != 200) + bool mask_bit = (srcred != 200) || (srcgreen != 200) || (srcblue != 200); - BOOL data_bit = mask_bit && (srcgreen <= 80);//not 0x80 + bool data_bit = mask_bit && (srcgreen <= 80);//not 0x80 unsigned char bit_offset = (cursurface->w/8) * i + j/8; cursor_data[bit_offset] |= (data_bit) << (7 - (j&7)); @@ -2165,8 +2165,8 @@ void LLWindowSDL::hideCursor() if(!mCursorHidden) { // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; + mCursorHidden = true; + mHideCursorPermanent = true; SDL_ShowCursor(0); } else @@ -2180,8 +2180,8 @@ void LLWindowSDL::showCursor() if(mCursorHidden) { // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; + mCursorHidden = false; + mHideCursorPermanent = false; SDL_ShowCursor(1); } else @@ -2203,7 +2203,7 @@ void LLWindowSDL::hideCursorUntilMouseMove() if (!mHideCursorPermanent) { hideCursor(); - mHideCursorPermanent = FALSE; + mHideCursorPermanent = false; } } @@ -2385,9 +2385,9 @@ LLSD LLWindowSDL::getNativeKeyData() } -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) +bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - BOOL rtn = FALSE; + bool rtn = false; beforeDialog(); @@ -2421,8 +2421,8 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) gtk_color_selection_set_previous_color (colorsel, &color); gtk_color_selection_set_current_color (colorsel, &color); - gtk_color_selection_set_has_palette (colorsel, TRUE); - gtk_color_selection_set_has_opacity_control(colorsel, FALSE); + gtk_color_selection_set_has_palette (colorsel, true); + gtk_color_selection_set_has_opacity_control(colorsel, false); gint response = GTK_RESPONSE_NONE; g_signal_connect (win, @@ -2434,7 +2434,7 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) G_CALLBACK (color_changed_callback), &color); - gtk_window_set_modal(GTK_WINDOW(win), TRUE); + gtk_window_set_modal(GTK_WINDOW(win), true); gtk_widget_show_all(win); // hide the help button - we don't service it. gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); @@ -2448,7 +2448,7 @@ BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) *r = color.red / 65535.0f; *g = color.green / 65535.0f; *b = color.blue / 65535.0f; - rtn = TRUE; + rtn = true; } } @@ -2463,9 +2463,9 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ return 0; } -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) +bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - return (FALSE); + return (false); } #endif // LL_GTK diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 7193e6f45a..c780975c04 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -52,47 +52,47 @@ public: /*virtual*/ void show(); /*virtual*/ void hide(); /*virtual*/ void close(); - /*virtual*/ BOOL getVisible(); - /*virtual*/ BOOL getMinimized(); - /*virtual*/ BOOL getMaximized(); - /*virtual*/ BOOL maximize(); + /*virtual*/ bool getVisible(); + /*virtual*/ bool getMinimized(); + /*virtual*/ bool getMaximized(); + /*virtual*/ bool maximize(); /*virtual*/ void minimize(); /*virtual*/ void restore(); - /*virtual*/ BOOL getFullscreen(); - /*virtual*/ BOOL getPosition(LLCoordScreen *position); - /*virtual*/ BOOL getSize(LLCoordScreen *size); - /*virtual*/ BOOL getSize(LLCoordWindow *size); - /*virtual*/ BOOL setPosition(LLCoordScreen position); - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); - /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); + /*virtual*/ bool getFullscreen(); + /*virtual*/ bool getPosition(LLCoordScreen *position); + /*virtual*/ bool getSize(LLCoordScreen *size); + /*virtual*/ bool getSize(LLCoordWindow *size); + /*virtual*/ bool setPosition(LLCoordScreen position); + /*virtual*/ bool setSizeImpl(LLCoordScreen size); + /*virtual*/ bool setSizeImpl(LLCoordWindow size); + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ bool setCursorPosition(LLCoordWindow position); + /*virtual*/ bool getCursorPosition(LLCoordWindow *position); /*virtual*/ void showCursor(); /*virtual*/ void hideCursor(); /*virtual*/ void showCursorFromMouseMove(); /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ BOOL isCursorHidden(); + /*virtual*/ bool isCursorHidden(); /*virtual*/ void updateCursor(); /*virtual*/ void captureMouse(); /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( BOOL b ); + /*virtual*/ void setMouseClipping( bool b ); /*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - /*virtual*/ BOOL isClipboardTextAvailable(); - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); - /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); + /*virtual*/ bool isClipboardTextAvailable(); + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); + /*virtual*/ bool copyTextToClipboard(const LLWString & src); - /*virtual*/ BOOL isPrimaryTextAvailable(); - /*virtual*/ BOOL pasteTextFromPrimary(LLWString &dst); - /*virtual*/ BOOL copyTextToPrimary(const LLWString & src); + /*virtual*/ bool isPrimaryTextAvailable(); + /*virtual*/ bool pasteTextFromPrimary(LLWString &dst); + /*virtual*/ bool copyTextToPrimary(const LLWString & src); /*virtual*/ void flashIcon(F32 seconds); /*virtual*/ F32 getGamma(); - /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma + /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma /*virtual*/ U32 getFSAASamples(); /*virtual*/ void setFSAASamples(const U32 samples); - /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void processMiscNativeEvents(); /*virtual*/ void gatherInput(); @@ -102,12 +102,12 @@ public: /*virtual*/ void delayInputProcessing() { }; // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); /*virtual*/ F32 getNativeAspectRatio(); @@ -117,7 +117,7 @@ public: /*virtual*/ void beforeDialog(); /*virtual*/ void afterDialog(); - /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); + /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b); /*virtual*/ void *getPlatformWindow(); /*virtual*/ void bringToFront(); @@ -148,11 +148,11 @@ public: protected: LLWindowSDL(LLWindowCallbacks* callbacks, const std::string& title, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, U32 fsaa_samples); + bool fullscreen, bool clearBg, bool disable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples); ~LLWindowSDL(); - /*virtual*/ BOOL isValid(); + /*virtual*/ bool isValid(); /*virtual*/ LLSD getNativeKeyData(); void initCursors(); @@ -160,12 +160,12 @@ protected: void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); + bool setFullscreenResolution(); - BOOL shouldPostQuit() { return mPostQuit; } + bool shouldPostQuit() { return mPostQuit; } protected: // @@ -173,12 +173,12 @@ protected: // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); void fixWindowSize(void); - U32 SDLCheckGrabbyKeys(SDLKey keysym, BOOL gain); - BOOL SDLReallyCaptureInput(BOOL capture); + U32 SDLCheckGrabbyKeys(SDLKey keysym, bool gain); + bool SDLReallyCaptureInput(bool capture); // // Platform specific variables @@ -188,7 +188,7 @@ protected: SDL_Surface * mWindow; std::string mWindowTitle; double mOriginalAspectRatio; - BOOL mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. LLCoordScreen mNeedsResizeSize; F32 mOverrideAspectRatio; F32 mGamma; @@ -204,8 +204,8 @@ protected: private: #if LL_X11 - void x11_set_urgent(BOOL urgent); - BOOL mFlashing; + void x11_set_urgent(bool urgent); + bool mFlashing; LLTimer mFlashTimer; #endif //LL_X11 diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 0dbb5b64c1..35e52a8969 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -92,7 +92,7 @@ const F32 ICON_FLASH_TIME = 0.5f; const UINT WM_DUMMY_(WM_USER + 0x0017); const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); -extern BOOL gDebugWindowProc; +extern bool gDebugWindowProc; static std::thread::id sWindowThreadId; static std::thread::id sMainThreadId; @@ -178,10 +178,10 @@ GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) } //static -BOOL LLWindowWin32::sIsClassRegistered = FALSE; +bool LLWindowWin32::sIsClassRegistered = false; -BOOL LLWindowWin32::sLanguageTextInputAllowed = TRUE; -BOOL LLWindowWin32::sWinIMEOpened = FALSE; +bool LLWindowWin32::sLanguageTextInputAllowed = true; +bool LLWindowWin32::sWinIMEOpened = false; HKL LLWindowWin32::sWinInputLocale = 0; DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; @@ -200,24 +200,24 @@ public: public: // Wrappers for IMM API. - static BOOL isIME(HKL hkl); + static bool isIME(HKL hkl); static HIMC getContext(HWND hwnd); - static BOOL releaseContext(HWND hwnd, HIMC himc); - static BOOL getOpenStatus(HIMC himc); - static BOOL setOpenStatus(HIMC himc, BOOL status); - static BOOL getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); - static BOOL setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); - static BOOL getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static BOOL setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static bool releaseContext(HWND hwnd, HIMC himc); + static bool getOpenStatus(HIMC himc); + static bool setOpenStatus(HIMC himc, bool status); + static bool getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); + static bool setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); + static bool getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static bool setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); - static BOOL setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); - static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); - static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); - static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); + static bool setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); + static bool setCompositionFont(HIMC himc, LPLOGFONTW logfont); + static bool setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); + static bool notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); }; // static -BOOL LLWinImm::isIME(HKL hkl) +bool LLWinImm::isIME(HKL hkl) { return ImmIsIME(hkl); } @@ -229,43 +229,43 @@ HIMC LLWinImm::getContext(HWND hwnd) } //static -BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) +bool LLWinImm::releaseContext(HWND hwnd, HIMC himc) { return ImmReleaseContext(hwnd, himc); } // static -BOOL LLWinImm::getOpenStatus(HIMC himc) +bool LLWinImm::getOpenStatus(HIMC himc) { return ImmGetOpenStatus(himc); } // static -BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) +bool LLWinImm::setOpenStatus(HIMC himc, bool status) { return ImmSetOpenStatus(himc, status); } // static -BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) +bool LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) { return ImmGetConversionStatus(himc, conversion, sentence); } // static -BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) +bool LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) { return ImmSetConversionStatus(himc, conversion, sentence); } // static -BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +bool LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) { return ImmGetCompositionWindow(himc, form); } // static -BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +bool LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) { return ImmSetCompositionWindow(himc, form); } @@ -279,25 +279,25 @@ LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD // static -BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) +bool LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) { return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); } // static -BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) +bool LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) { return ImmSetCompositionFont(himc, pFont); } // static -BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) +bool LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) { return ImmSetCandidateWindow(himc, form); } // static -BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) +bool LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) { return ImmNotifyIME(himc, action, index, value); } @@ -432,9 +432,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, - BOOL fullscreen, BOOL clearBg, - BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, @@ -527,7 +527,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mIconResource = gIconResource; mOverrideAspectRatio = 0.f; mNativeAspectRatio = 0.f; - mInputProcessingPaused = FALSE; + mInputProcessingPaused = false; mPreeditor = NULL; mKeyCharCode = 0; mKeyScanCode = 0; @@ -536,7 +536,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mhRC = NULL; memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); - mCustomGammaSet = FALSE; + mCustomGammaSet = false; mWindowHandle = NULL; mRect = {0, 0, 0, 0}; @@ -544,7 +544,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) { - mMouseVanish = TRUE; + mMouseVanish = true; } // Initialize the keyboard @@ -556,7 +556,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Initialize (boot strap) the Language text input management, // based on the system's (user's) default settings. - allowLanguageTextInput(mPreeditor, FALSE); + allowLanguageTextInput(mPreeditor, false); WNDCLASS wc; RECT window_rect; @@ -674,7 +674,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mCallbacks->translateString("MBError"), OSMB_OK); return; } - sIsClassRegistered = TRUE; + sIsClassRegistered = true; } //----------------------------------------------------------------------- @@ -702,7 +702,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, //----------------------------------------------------------------------- if (mFullscreen) { - BOOL success = FALSE; + bool success = false; DWORD closest_refresh = 0; for (S32 mode_num = 0;; mode_num++) @@ -716,7 +716,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, dev_mode.dmPelsHeight == height && dev_mode.dmBitsPerPel == BITS_PER_PIXEL) { - success = TRUE; + success = true; if ((dev_mode.dmDisplayFrequency - current_refresh) < (closest_refresh - current_refresh)) { @@ -728,11 +728,11 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, if (closest_refresh == 0) { LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - //success = FALSE; + //success = false; if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) { - success = FALSE; + success = false; } else { @@ -741,12 +741,12 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; window_rect.right=width=dev_mode.dmPelsWidth; window_rect.bottom=height=dev_mode.dmPelsHeight; - success = TRUE; + success = true; } else { LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; - success = FALSE; + success = false; } } } @@ -764,7 +764,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // If it failed, we don't want to run fullscreen if (success) { - mFullscreen = TRUE; + mFullscreen = true; mFullscreenWidth = dev_mode.dmPelsWidth; mFullscreenHeight = dev_mode.dmPelsHeight; mFullscreenBits = dev_mode.dmBitsPerPel; @@ -778,7 +778,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, } else { - mFullscreen = FALSE; + mFullscreen = false; mFullscreenWidth = -1; mFullscreenHeight = -1; mFullscreenBits = -1; @@ -859,7 +859,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. - allowLanguageTextInput(NULL, FALSE); + allowLanguageTextInput(NULL, false); } @@ -889,14 +889,14 @@ void LLWindowWin32::show() void LLWindowWin32::hide() { - setMouseClipping(FALSE); + setMouseClipping(false); ShowWindow(mWindowHandle, SW_HIDE); } //virtual void LLWindowWin32::minimize() { - setMouseClipping(FALSE); + setMouseClipping(false); showCursor(); ShowWindow(mWindowHandle, SW_MINIMIZE); } @@ -953,7 +953,7 @@ void LLWindowWin32::close() // Make sure cursor is visible and we haven't mangled the clipping state. showCursor(); - setMouseClipping(FALSE); + setMouseClipping(false); if (gKeyboard) { gKeyboard->resetKeys(); @@ -1029,29 +1029,29 @@ void LLWindowWin32::close() mWindowThread->close(); } -BOOL LLWindowWin32::isValid() +bool LLWindowWin32::isValid() { return (mWindowHandle != NULL); } -BOOL LLWindowWin32::getVisible() +bool LLWindowWin32::getVisible() { return (mWindowHandle && IsWindowVisible(mWindowHandle)); } -BOOL LLWindowWin32::getMinimized() +bool LLWindowWin32::getMinimized() { return (mWindowHandle && IsIconic(mWindowHandle)); } -BOOL LLWindowWin32::getMaximized() +bool LLWindowWin32::getMaximized() { return (mWindowHandle && IsZoomed(mWindowHandle)); } -BOOL LLWindowWin32::maximize() +bool LLWindowWin32::maximize() { - BOOL success = FALSE; + bool success = false; if (!mWindowHandle) return success; mWindowThread->post([=] @@ -1066,56 +1066,56 @@ BOOL LLWindowWin32::maximize() } }); - return TRUE; + return true; } -BOOL LLWindowWin32::getFullscreen() +bool LLWindowWin32::getFullscreen() { return mFullscreen; } -BOOL LLWindowWin32::getPosition(LLCoordScreen *position) +bool LLWindowWin32::getPosition(LLCoordScreen *position) { position->mX = mRect.left; position->mY = mRect.top; - return TRUE; + return true; } -BOOL LLWindowWin32::getSize(LLCoordScreen *size) +bool LLWindowWin32::getSize(LLCoordScreen *size) { size->mX = mRect.right - mRect.left; size->mY = mRect.bottom - mRect.top; - return TRUE; + return true; } -BOOL LLWindowWin32::getSize(LLCoordWindow *size) +bool LLWindowWin32::getSize(LLCoordWindow *size) { size->mX = mClientRect.right - mClientRect.left; size->mY = mClientRect.bottom - mClientRect.top; - return TRUE; + return true; } -BOOL LLWindowWin32::setPosition(const LLCoordScreen position) +bool LLWindowWin32::setPosition(const LLCoordScreen position) { LLCoordScreen size; if (!mWindowHandle) { - return FALSE; + return false; } getSize(&size); moveWindow(position, size); - return TRUE; + return true; } -BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) +bool LLWindowWin32::setSizeImpl(const LLCoordScreen size) { LLCoordScreen position; getPosition(&position); if (!mWindowHandle) { - return FALSE; + return false; } mWindowThread->post([=]() @@ -1131,10 +1131,10 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) }); moveWindow(position, size); - return TRUE; + return true; } -BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) +bool LLWindowWin32::setSizeImpl(const LLCoordWindow size) { RECT window_rect = {0, 0, size.mX, size.mY }; DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; @@ -1146,7 +1146,7 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) } // changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BOOL enable_vsync, const LLCoordScreen* const posp) +bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bool enable_vsync, const LLCoordScreen* const posp) { //called from main thread GLuint pixel_format; @@ -1159,11 +1159,11 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO RECT window_rect = { 0, 0, 0, 0 }; S32 width = size.mX; S32 height = size.mY; - BOOL auto_show = FALSE; + bool auto_show = false; if (mhRC) { - auto_show = TRUE; + auto_show = true; resetDisplayResolution(); } @@ -1196,8 +1196,8 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO if (fullscreen) { - mFullscreen = TRUE; - BOOL success = FALSE; + mFullscreen = true; + bool success = false; DWORD closest_refresh = 0; for (S32 mode_num = 0;; mode_num++) @@ -1211,7 +1211,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO dev_mode.dmPelsHeight == height && dev_mode.dmBitsPerPel == BITS_PER_PIXEL) { - success = TRUE; + success = true; if ((dev_mode.dmDisplayFrequency - current_refresh) < (closest_refresh - current_refresh)) { @@ -1223,7 +1223,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO if (closest_refresh == 0) { LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - return FALSE; + return false; } // If we found a good resolution, use it. @@ -1238,7 +1238,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO if (success) { - mFullscreen = TRUE; + mFullscreen = true; mFullscreenWidth = dev_mode.dmPelsWidth; mFullscreenHeight = dev_mode.dmPelsHeight; mFullscreenBits = dev_mode.dmBitsPerPel; @@ -1264,19 +1264,19 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO // If it failed, we don't want to run fullscreen else { - mFullscreen = FALSE; + mFullscreen = false; mFullscreenWidth = -1; mFullscreenHeight = -1; mFullscreenBits = -1; mFullscreenRefresh = -1; LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; - return FALSE; + return false; } } else { - mFullscreen = FALSE; + mFullscreen = false; window_rect.left = (long)(posp ? posp->mX : 0); window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel window_rect.top = (long)(posp ? posp->mY : 0); @@ -1288,7 +1288,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO // don't post quit messages when destroying old windows - mPostQuit = FALSE; + mPostQuit = false; // create window @@ -1338,7 +1338,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO close(); OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; + return false; } LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; @@ -1352,7 +1352,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } } catch (...) @@ -1361,7 +1361,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; @@ -1373,7 +1373,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash @@ -1412,7 +1412,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } @@ -1421,7 +1421,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } if (!wglMakeCurrent(mhDC, mhRC)) @@ -1429,7 +1429,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; @@ -1521,7 +1521,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO close(); show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); - return FALSE; + return false; } if (!num_formats) @@ -1536,7 +1536,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO { close(); show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); - return FALSE; + return false; } } @@ -1550,7 +1550,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO { close(); show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); - return FALSE; + return false; } if (!num_formats) @@ -1562,7 +1562,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BO { close(); show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); - return FALSE; + return false; } } } @@ -1635,7 +1635,7 @@ const S32 max_format = (S32)num_formats - 1; { OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } if (!SetPixelFormat(mhDC, pixel_format, &pfd)) @@ -1643,7 +1643,7 @@ const S32 max_format = (S32)num_formats - 1; OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) @@ -1680,7 +1680,7 @@ const S32 max_format = (S32)num_formats - 1; { OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) @@ -1694,7 +1694,7 @@ const S32 max_format = (S32)num_formats - 1; mhRC = (HGLRC) createSharedContext(); if (!mhRC) { - return FALSE; + return false; } } @@ -1702,14 +1702,14 @@ const S32 max_format = (S32)num_formats - 1; { OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } if (!gGLManager.initGL()) { OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); close(); - return FALSE; + return false; } // Disable vertical sync for swap @@ -1726,7 +1726,7 @@ const S32 max_format = (S32)num_formats - 1; SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer // ok to post quit messages now - mPostQuit = TRUE; + mPostQuit = true; // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 @@ -1745,7 +1745,7 @@ const S32 max_format = (S32)num_formats - 1; LL_PROFILER_GPU_CONTEXT; - return TRUE; + return true; } void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) @@ -1970,13 +1970,13 @@ void LLWindowWin32::setTitle(const std::string title) }); } -BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) +bool LLWindowWin32::setCursorPosition(const LLCoordWindow position) { ASSERT_MAIN_THREAD(); if (!mWindowHandle) { - return FALSE; + return false; } LLCoordScreen screen_pos(position.convert()); @@ -1996,31 +1996,31 @@ BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) SetCursorPos(screen_pos.mX, screen_pos.mY); }); - return TRUE; + return true; } -BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) +bool LLWindowWin32::getCursorPosition(LLCoordWindow *position) { ASSERT_MAIN_THREAD(); if (!position) { - return FALSE; + return false; } *position = mCursorPosition; - return TRUE; + return true; } -BOOL LLWindowWin32::getCursorDelta(LLCoordCommon* delta) +bool LLWindowWin32::getCursorDelta(LLCoordCommon* delta) { if (delta == nullptr) { - return FALSE; + return false; } *delta = mMouseFrameDelta; - return TRUE; + return true; } void LLWindowWin32::hideCursor() @@ -2035,8 +2035,8 @@ void LLWindowWin32::hideCursor() } }); - mCursorHidden = TRUE; - mHideCursorPermanent = TRUE; + mCursorHidden = true; + mHideCursorPermanent = true; } void LLWindowWin32::showCursor() @@ -2054,8 +2054,8 @@ void LLWindowWin32::showCursor() } }); - mCursorHidden = FALSE; - mHideCursorPermanent = FALSE; + mCursorHidden = false; + mHideCursorPermanent = false; } void LLWindowWin32::showCursorFromMouseMove() @@ -2071,11 +2071,11 @@ void LLWindowWin32::hideCursorUntilMouseMove() if (!mHideCursorPermanent && mMouseVanish) { hideCursor(); - mHideCursorPermanent = FALSE; + mHideCursorPermanent = false; } } -BOOL LLWindowWin32::isCursorHidden() +bool LLWindowWin32::isCursorHidden() { return mCursorHidden; } @@ -2195,7 +2195,7 @@ void LLWindowWin32::releaseMouse() void LLWindowWin32::delayInputProcessing() { - mInputProcessingPaused = TRUE; + mInputProcessingPaused = true; } @@ -2276,7 +2276,7 @@ void LLWindowWin32::gatherInput() } } - mInputProcessingPaused = FALSE; + mInputProcessingPaused = false; updateCursor(); } @@ -2321,7 +2321,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // pass along extended flag in mask MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; - BOOL eat_keystroke = TRUE; + bool eat_keystroke = true; switch (u_msg) { @@ -2343,7 +2343,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - return TRUE; + return true; } break; } @@ -2500,7 +2500,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN"); // allow system keys, such as ALT-F4 to be processed by Windows - eat_keystroke = FALSE; + eat_keystroke = false; // intentional fall-through here } case WM_KEYDOWN: @@ -2521,7 +2521,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; } case WM_SYSKEYUP: - eat_keystroke = FALSE; + eat_keystroke = false; // intentional fall-through here case WM_KEYUP: { @@ -2613,9 +2613,9 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's // by ourselves. It is not that tough. -- Alissa Sabre @ SL - // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, + // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, bool) returned false, // we *did* processed the event, so I believe we should not pass it to DefWindowProc... - window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); + window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(false)); }); return 0; } @@ -2646,7 +2646,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->interruptLanguageTextInput(); } - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); auto gl_coord = window_imp->mCursorPosition.convert(); window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask); @@ -2669,7 +2669,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ sHandleDoubleClick = true; return; } - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); // generate move event to update mouse coordinates window_imp->mCursorPosition = window_coord; @@ -2693,7 +2693,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ sHandleDoubleClick = true; - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); // generate move event to update mouse coordinates window_imp->mCursorPosition = window_coord; window_imp->mCallbacks->handleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); @@ -2714,7 +2714,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ WINDOW_IMP_POST(window_imp->interruptLanguageTextInput()); } - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); // generate move event to update mouse coordinates auto gl_coord = window_imp->mCursorPosition.convert(); window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); @@ -2732,7 +2732,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->postMouseButtonEvent([=]() { - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); window_imp->mCallbacks->handleRightMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); }); } @@ -2752,7 +2752,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->interruptLanguageTextInput(); } - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); window_imp->mCallbacks->handleMiddleMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask); }); } @@ -2766,7 +2766,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); window_imp->postMouseButtonEvent([=]() { - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); window_imp->mCallbacks->handleMiddleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); }); } @@ -2784,7 +2784,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ window_imp->interruptLanguageTextInput(); } - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); }); @@ -2801,7 +2801,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); S32 button = GET_XBUTTON_WPARAM(w_param); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 window_imp->mCallbacks->handleOtherMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); }); @@ -2911,7 +2911,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda"); - MASK mask = gKeyboard->currentMask(TRUE); + MASK mask = gKeyboard->currentMask(true); window_imp->mMouseMask = mask; window_imp->mCursorPosition = window_coord; }); @@ -2948,19 +2948,19 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // means that the window was un-minimized. if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) { - WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, TRUE)); + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true)); } // handle case of window being maximized from fully minimized state if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) { - WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, TRUE)); + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true)); } // Also handle the minimization case if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) { - WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, FALSE)); + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, false)); } // Actually resize all of our views @@ -3039,7 +3039,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0)) { - WINDOW_IMP_POST(window_imp->mMouseVanish = TRUE); + WINDOW_IMP_POST(window_imp->mMouseVanish = true); } } } @@ -3148,7 +3148,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return ret; } -BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) +bool LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) { S32 client_height; RECT client_rect; @@ -3158,17 +3158,17 @@ BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) !GetClientRect(mWindowHandle, &client_rect) || NULL == to) { - return FALSE; + return false; } to->mX = from.mX; client_height = client_rect.bottom - client_rect.top; to->mY = client_height - from.mY - 1; - return TRUE; + return true; } -BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) +bool LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) { S32 client_height; RECT client_rect; @@ -3177,23 +3177,23 @@ BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) !GetClientRect(mWindowHandle, &client_rect) || NULL == to) { - return FALSE; + return false; } to->mX = from.mX; client_height = client_rect.bottom - client_rect.top; to->mY = client_height - from.mY - 1; - return TRUE; + return true; } -BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) +bool LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) { POINT mouse_point; mouse_point.x = from.mX; mouse_point.y = from.mY; - BOOL result = ScreenToClient(mWindowHandle, &mouse_point); + bool result = ScreenToClient(mWindowHandle, &mouse_point); if (result) { @@ -3204,13 +3204,13 @@ BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) return result; } -BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) +bool LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) { POINT mouse_point; mouse_point.x = from.mX; mouse_point.y = from.mY; - BOOL result = ClientToScreen(mWindowHandle, &mouse_point); + bool result = ClientToScreen(mWindowHandle, &mouse_point); if (result) { @@ -3221,44 +3221,44 @@ BOOL LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) return result; } -BOOL LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) +bool LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) { LLCoordWindow window_coord; if (!mWindowHandle || (NULL == to)) { - return FALSE; + return false; } convertCoords(from, &window_coord); convertCoords(window_coord, to); - return TRUE; + return true; } -BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) +bool LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) { LLCoordWindow window_coord; if (!mWindowHandle || (NULL == to)) { - return FALSE; + return false; } convertCoords(from, &window_coord); convertCoords(window_coord, to); - return TRUE; + return true; } -BOOL LLWindowWin32::isClipboardTextAvailable() +bool LLWindowWin32::isClipboardTextAvailable() { return IsClipboardFormatAvailable(CF_UNICODETEXT); } -BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) +bool LLWindowWin32::pasteTextFromClipboard(LLWString &dst) { - BOOL success = FALSE; + bool success = false; if (IsClipboardFormatAvailable(CF_UNICODETEXT)) { @@ -3273,7 +3273,7 @@ BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) dst = utf16str_to_wstring(utf16str); LLWStringUtil::removeWindowsCR(dst); GlobalUnlock(h_data); - success = TRUE; + success = true; } } CloseClipboard(); @@ -3284,9 +3284,9 @@ BOOL LLWindowWin32::pasteTextFromClipboard(LLWString &dst) } -BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) +bool LLWindowWin32::copyTextToClipboard(const LLWString& wstr) { - BOOL success = FALSE; + bool success = false; if (OpenClipboard(mWindowHandle)) { @@ -3310,7 +3310,7 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) { - success = TRUE; + success = true; } } } @@ -3322,13 +3322,13 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) } // Constrains the mouse to the window. -void LLWindowWin32::setMouseClipping( BOOL b ) +void LLWindowWin32::setMouseClipping( bool b ) { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; ASSERT_MAIN_THREAD(); if( b != mIsMouseClipping ) { - BOOL success = FALSE; + bool success = false; if( b ) { @@ -3354,9 +3354,9 @@ void LLWindowWin32::setMouseClipping( BOOL b ) } } -BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) +bool LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) { - BOOL success = FALSE; + bool success = false; RECT client_rect; if (mWindowHandle && GetClientRect(mWindowHandle, &client_rect)) @@ -3377,7 +3377,7 @@ BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) bottom_right.x, bottom_right.y); - success = TRUE; + success = true; } return success; @@ -3403,25 +3403,25 @@ F32 LLWindowWin32::getGamma() return mCurrentGamma; } -BOOL LLWindowWin32::restoreGamma() +bool LLWindowWin32::restoreGamma() { ASSERT_MAIN_THREAD(); - if (mCustomGammaSet != FALSE) + if (mCustomGammaSet != false) { LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; - mCustomGammaSet = FALSE; + mCustomGammaSet = false; return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); } - return TRUE; + return true; } -BOOL LLWindowWin32::setGamma(const F32 gamma) +bool LLWindowWin32::setGamma(const F32 gamma) { ASSERT_MAIN_THREAD(); mCurrentGamma = gamma; //Get the previous gamma ramp to restore later. - if (mCustomGammaSet == FALSE) + if (mCustomGammaSet == false) { if (!gGLManager.mIsIntel) // skip for Intel GPUs (see SL-11341) { @@ -3429,10 +3429,10 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) if(GetDeviceGammaRamp(mhDC, mPrevGammaRamp) == FALSE) { LL_WARNS("Window") << "Failed to get the previous gamma ramp" << LL_ENDL; - return FALSE; + return false; } } - mCustomGammaSet = TRUE; + mCustomGammaSet = true; } LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; @@ -3487,13 +3487,13 @@ LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_re dev_mode.dmPelsWidth >= 800 && dev_mode.dmPelsHeight >= 600) { - BOOL resolution_exists = FALSE; + bool resolution_exists = false; for(S32 i = 0; i < mNumSupportedResolutions; i++) { if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) { - resolution_exists = TRUE; + resolution_exists = true; } } if (!resolution_exists) @@ -3546,12 +3546,12 @@ F32 LLWindowWin32::getPixelAspectRatio() // Change display resolution. Returns true if successful. // protected -BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) +bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) { DEVMODE dev_mode; ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); dev_mode.dmSize = sizeof(DEVMODE); - BOOL success = FALSE; + bool success = false; // Don't change anything if we don't have to if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) @@ -3562,7 +3562,7 @@ BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re dev_mode.dmDisplayFrequency == refresh ) { // ...display mode identical, do nothing - return TRUE; + return true; } } @@ -3589,7 +3589,7 @@ BOOL LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 re } // protected -BOOL LLWindowWin32::setFullscreenResolution() +bool LLWindowWin32::setFullscreenResolution() { if (mFullscreen) { @@ -3597,18 +3597,18 @@ BOOL LLWindowWin32::setFullscreenResolution() } else { - return FALSE; + return false; } } // protected -BOOL LLWindowWin32::resetDisplayResolution() +bool LLWindowWin32::resetDisplayResolution() { LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; LONG cds_result = ChangeDisplaySettings(NULL, 0); - BOOL success = (DISP_CHANGE_SUCCESSFUL == cds_result); + bool success = (DISP_CHANGE_SUCCESSFUL == cds_result); if (!success) { @@ -3815,9 +3815,9 @@ LLSD LLWindowWin32::getNativeKeyData() return result; } -BOOL LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) +bool LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) { - BOOL retval = FALSE; + bool retval = false; static CHOOSECOLOR cc; static COLORREF crCustColors[16]; @@ -3870,7 +3870,7 @@ void LLWindowWin32::focusClient() }); } -void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) +void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, bool b) { if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) { @@ -3880,7 +3880,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) if (preeditor != mPreeditor && !b) { // This condition may occur with a call to - // setEnabled(BOOL) from LLTextEditor or LLLineEditor + // setEnabled(bool) from LLTextEditor or LLLineEditor // when the control is not focused. // We need to silently ignore the case so that // the language input status of the focused control @@ -3910,7 +3910,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) { HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setOpenStatus(himc, TRUE); + LLWinImm::setOpenStatus(himc, true); LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); LLWinImm::releaseContext(mWindowHandle, himc); } @@ -3936,7 +3936,7 @@ void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's // keyboard hooking, because Some IME reacts only on the former and some other on the latter... LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); - LLWinImm::setOpenStatus(himc, FALSE); + LLWinImm::setOpenStatus(himc, false); } LLWinImm::releaseContext(mWindowHandle, himc); } @@ -4142,7 +4142,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) { return; } - BOOL needs_update = FALSE; + bool needs_update = false; LLWString result_string; LLWString preedit_string; S32 preedit_string_utf16_length = 0; @@ -4165,7 +4165,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); } delete[] data; - needs_update = TRUE; + needs_update = true; } } @@ -4182,7 +4182,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); } delete[] data; - needs_update = TRUE; + needs_update = true; } } @@ -4218,13 +4218,13 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); if (size == preedit_string_utf16_length) { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + preedit_standouts.assign(preedit_segment_lengths.size(), false); S32 offset = 0; for (U32 i = 0; i < preedit_segment_lengths.size(); i++) { if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) { - preedit_standouts[i] = TRUE; + preedit_standouts[i] = true; } offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); } @@ -4248,7 +4248,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) // I'm not sure this condition really happens, but // Windows SDK document says it is an indication // of "reset everything." - needs_update = TRUE; + needs_update = true; } LLWinImm::releaseContext(mWindowHandle, himc); @@ -4283,7 +4283,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) } if (preedit_standouts.size() == 0) { - preedit_standouts.assign(preedit_segment_lengths.size(), FALSE); + preedit_standouts.assign(preedit_segment_lengths.size(), false); } } mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); @@ -4330,11 +4330,11 @@ LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( cons } // Handle WM_IME_REQUEST message. -// If it handled the message, returns TRUE. Otherwise, FALSE. +// If it handled the message, returns true. Otherwise, false. // When it handled the message, the value to be returned from // the Window Procedure is set to *result. -BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result) +bool LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result) { if ( mPreeditor ) { @@ -4352,7 +4352,7 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res form->dwIndex = dwIndex; *result = 1; - return TRUE; + return true; } case IMR_QUERYCHARPOSITION: { @@ -4372,20 +4372,20 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) { LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; - return FALSE; + return false; } fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); *result = 1; - return TRUE; + return true; } case IMR_COMPOSITIONFONT: { fillCompositionLogfont((LOGFONT *)param); *result = 1; - return TRUE; + return true; } case IMR_RECONVERTSTRING: { @@ -4406,7 +4406,7 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res // Let the IME to decide the reconversion range, and // adjust the reconvert_string structure accordingly. HIMC himc = LLWinImm::getContext(mWindowHandle); - const BOOL adjusted = LLWinImm::setCompositionString(himc, + const bool adjusted = LLWinImm::setCompositionString(himc, SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); LLWinImm::releaseContext(mWindowHandle, himc); if (adjusted) @@ -4423,12 +4423,12 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res } *result = size; - return TRUE; + return true; } case IMR_CONFIRMRECONVERTSTRING: { - *result = FALSE; - return TRUE; + *result = 0; + return true; } case IMR_DOCUMENTFEED: { @@ -4450,14 +4450,14 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; *result = fillReconvertString(context, preedit, 0, reconvert_string); - return TRUE; + return true; } default: - return FALSE; + return false; } } - return FALSE; + return false; } //static diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index c8ce507c8b..8b82ad92d5 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -48,47 +48,47 @@ public: /*virtual*/ void show(); /*virtual*/ void hide(); /*virtual*/ void close(); - /*virtual*/ BOOL getVisible(); - /*virtual*/ BOOL getMinimized(); - /*virtual*/ BOOL getMaximized(); - /*virtual*/ BOOL maximize(); + /*virtual*/ bool getVisible(); + /*virtual*/ bool getMinimized(); + /*virtual*/ bool getMaximized(); + /*virtual*/ bool maximize(); /*virtual*/ void minimize(); /*virtual*/ void restore(); - /*virtual*/ BOOL getFullscreen(); - /*virtual*/ BOOL getPosition(LLCoordScreen *position); - /*virtual*/ BOOL getSize(LLCoordScreen *size); - /*virtual*/ BOOL getSize(LLCoordWindow *size); - /*virtual*/ BOOL setPosition(LLCoordScreen position); - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); - /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ bool getFullscreen(); + /*virtual*/ bool getPosition(LLCoordScreen *position); + /*virtual*/ bool getSize(LLCoordScreen *size); + /*virtual*/ bool getSize(LLCoordWindow *size); + /*virtual*/ bool setPosition(LLCoordScreen position); + /*virtual*/ bool setSizeImpl(LLCoordScreen size); + /*virtual*/ bool setSizeImpl(LLCoordWindow size); + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL); /*virtual*/ void setTitle(const std::string title); void* createSharedContext() override; void makeContextCurrent(void* context) override; void destroySharedContext(void* context) override; /*virtual*/ void toggleVSync(bool enable_vsync); - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); - /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta); + /*virtual*/ bool setCursorPosition(LLCoordWindow position); + /*virtual*/ bool getCursorPosition(LLCoordWindow *position); + /*virtual*/ bool getCursorDelta(LLCoordCommon* delta); /*virtual*/ void showCursor(); /*virtual*/ void hideCursor(); /*virtual*/ void showCursorFromMouseMove(); /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ BOOL isCursorHidden(); + /*virtual*/ bool isCursorHidden(); /*virtual*/ void updateCursor(); /*virtual*/ ECursorType getCursor() const; /*virtual*/ void captureMouse(); /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( BOOL b ); - /*virtual*/ BOOL isClipboardTextAvailable(); - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); - /*virtual*/ BOOL copyTextToClipboard(const LLWString &src); + /*virtual*/ void setMouseClipping( bool b ); + /*virtual*/ bool isClipboardTextAvailable(); + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); + /*virtual*/ bool copyTextToClipboard(const LLWString &src); /*virtual*/ void flashIcon(F32 seconds); /*virtual*/ F32 getGamma(); - /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma + /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma /*virtual*/ void setFSAASamples(const U32 fsaa_samples); /*virtual*/ U32 getFSAASamples(); - /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } /*virtual*/ void gatherInput(); /*virtual*/ void delayInputProcessing(); @@ -96,12 +96,12 @@ public: /*virtual*/ void restoreGLContext() {}; // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); /*virtual*/ F32 getNativeAspectRatio(); @@ -111,13 +111,13 @@ public: U32 getAvailableVRAMMegabytes() override; /*virtual*/ void setMaxVRAMMegabytes(U32 max_vram) override; - /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b ); + /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ); /*virtual*/ void *getPlatformWindow(); /*virtual*/ void bringToFront(); /*virtual*/ void focusClient(); - /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); + /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, bool b); /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); /*virtual*/ void updateLanguageTextInputArea(); /*virtual*/ void interruptLanguageTextInput(); @@ -139,27 +139,27 @@ public: protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, - BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); + bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); ~LLWindowWin32(); void initCursors(); void initInputDevices(); HCURSOR loadColorCursor(LPCTSTR name); - BOOL isValid(); + bool isValid(); void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); virtual LLSD getNativeKeyData(); // Changes display resolution. Returns true if successful - BOOL setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); // Go back to last fullscreen display resolution. - BOOL setFullscreenResolution(); + bool setFullscreenResolution(); // Restore the display resolution to its value before we ran the app. - BOOL resetDisplayResolution(); + bool resetDisplayResolution(); - BOOL shouldPostQuit() { return mPostQuit; } + bool shouldPostQuit() { return mPostQuit; } void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); @@ -168,18 +168,18 @@ protected: U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); void handleStartCompositionMessage(); void handleCompositionMessage(U32 indexes); - BOOL handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); + bool handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); protected: // // Platform specific methods // - BOOL getClientRectInScreenSpace(RECT* rectp); + bool getClientRectInScreenSpace(RECT* rectp); void updateJoystick( ); static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); - static BOOL CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); + static bool CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); // @@ -207,7 +207,7 @@ protected: MASK mMouseMask; - static BOOL sIsClassRegistered; // has the window class been registered? + static bool sIsClassRegistered; // has the window class been registered? F32 mCurrentGamma; U32 mFSAASamples; @@ -215,16 +215,16 @@ protected: F32 mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6) WORD mPrevGammaRamp[3][256]; WORD mCurrentGammaRamp[3][256]; - BOOL mCustomGammaSet; + bool mCustomGammaSet; LPWSTR mIconResource; - BOOL mInputProcessingPaused; + bool mInputProcessingPaused; // The following variables are for Language Text Input control. // They are all static, since one context is shared by all LLWindowWin32 // instances. - static BOOL sLanguageTextInputAllowed; - static BOOL sWinIMEOpened; + static bool sLanguageTextInputAllowed; + static bool sWinIMEOpened; static HKL sWinInputLocale; static DWORD sWinIMEConversionMode; static DWORD sWinIMESentenceMode; @@ -243,7 +243,7 @@ protected: U32 mRawWParam; U32 mRawLParam; - BOOL mMouseVanish; + bool mMouseVanish; // Cached values of GetWindowRect and GetClientRect to be used by app thread void updateWindowRect(); -- cgit v1.2.3 From 238d0b27375c5293702925142f55f8575f630ae0 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sun, 18 Feb 2024 13:03:24 +0100 Subject: Fixed incorrect return value and missing fallthrough annotations LLWindowWin32 --- indra/llwindow/llwindowwin32.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 35e52a8969..7ca825ee65 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -2343,7 +2343,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ { WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - return true; + return 1; } break; } @@ -2502,6 +2502,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ // allow system keys, such as ALT-F4 to be processed by Windows eat_keystroke = false; // intentional fall-through here + [[fallthrough]]; } case WM_KEYDOWN: { @@ -2523,6 +2524,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ case WM_SYSKEYUP: eat_keystroke = false; // intentional fall-through here + [[fallthrough]]; case WM_KEYUP: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP"); @@ -3029,8 +3031,6 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ }); }; return 0; - - break; } case WM_SETTINGCHANGE: { @@ -3115,6 +3115,7 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ } } } + break; //list of messages we get often that we don't care to log about case WM_NCHITTEST: -- cgit v1.2.3 From 2817d6c67d65bee9cae8f0d77e229ccf8eaa286f Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Sun, 18 Feb 2024 15:53:54 +0200 Subject: viewer#831 Xcode buildfix --- indra/llwindow/llwindowmacosx-objc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 77024d3a9c..f9a7a098cb 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -37,7 +37,7 @@ typedef std::vector > segment_t; typedef std::vector segment_lengths; -typedef std::vector segment_standouts; +typedef std::vector segment_standouts; struct attributedStringInfo { segment_lengths seg_lengths; -- cgit v1.2.3 From 5486d87b566aabb43fa585de3ee86e5bc77391c9 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 19 Feb 2024 15:44:40 +0100 Subject: Change LLPreeditor::standouts_t to std::deque since std::vector since it's a specialization that does not necessarily behave like standard STL containers --- indra/llwindow/llpreeditor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llpreeditor.h b/indra/llwindow/llpreeditor.h index 2be1290c02..7f1daefdac 100644 --- a/indra/llwindow/llpreeditor.h +++ b/indra/llwindow/llpreeditor.h @@ -34,7 +34,7 @@ class LLPreeditor public: typedef std::vector segment_lengths_t; - typedef std::vector standouts_t; + typedef std::deque standouts_t; // We don't delete against LLPreeditor, but compilers complain without this... -- cgit v1.2.3 From 88f168f33bcf2bea7ea4769233793cf67d2cf37e Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 19 Feb 2024 18:41:18 +0200 Subject: viewer#836 Xcode buildfix --- indra/llwindow/llwindowmacosx-objc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index f9a7a098cb..e406f7dd19 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -30,6 +30,7 @@ #include #include +#include //fir CGSize #include @@ -37,7 +38,7 @@ typedef std::vector > segment_t; typedef std::vector segment_lengths; -typedef std::vector segment_standouts; +typedef std::deque segment_standouts; struct attributedStringInfo { segment_lengths seg_lengths; -- cgit v1.2.3 From ea268fcd48550f98baceef0294fd977ff12d2b35 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 6 May 2024 22:48:24 +0300 Subject: viewer#799 getAvailableVRAMMegabytes cleanup --- indra/llwindow/llwindow.h | 2 - indra/llwindow/llwindowheadless.h | 1 - indra/llwindow/llwindowmacosx.cpp | 16 ------- indra/llwindow/llwindowmacosx.h | 5 +- indra/llwindow/llwindowwin32.cpp | 97 +-------------------------------------- indra/llwindow/llwindowwin32.h | 1 - 6 files changed, 2 insertions(+), 120 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 1c41c1f627..396daec527 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -164,8 +164,6 @@ public: virtual F32 getPixelAspectRatio() = 0; virtual void setNativeAspectRatio(F32 aspect) = 0; - // query VRAM usage - virtual U32 getAvailableVRAMMegabytes() = 0; virtual void setMaxVRAMMegabytes(U32 max_vram) = 0; virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 06e6b2783d..f422152ab2 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -101,7 +101,6 @@ public: /*virtual*/ F32 getPixelAspectRatio() override { return 1.0f; } /*virtual*/ void setNativeAspectRatio(F32 ratio) override {} - U32 getAvailableVRAMMegabytes() override { return 4096; } void setMaxVRAMMegabytes(U32 max_vram) override {} /*virtual*/ void *getPlatformWindow() override { return 0; } diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index bfa893fff8..73230805b4 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -118,7 +118,6 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, U32 fsaa_samples, U32 max_vram) : LLWindow(NULL, fullscreen, flags) - , mMaxVRAM(max_vram) { // *HACK: During window construction we get lots of OS events for window // reshape, activate, etc. that the viewer isn't ready to handle. @@ -1255,21 +1254,6 @@ F32 LLWindowMacOSX::getPixelAspectRatio() return 1.f; } -U32 LLWindowMacOSX::getAvailableVRAMMegabytes() { - // MTL (and MoltenVK) has some additional gpu data, such as recommendedMaxWorkingSetSize and currentAllocatedSize. - // But these are not available for OpenGL and/or our current mimimum OS version. - // So we will estimate. - static const U32 mb = 1024*1024; - // We're asked for total available gpu memory, but we only have allocation info on texture usage. So estimate by doubling that. - static const U32 total_factor = 2; // estimated total/textures - U32 total_vram = gGLManager.mVRAM; - if (mMaxVRAM) - { - total_vram = llmin(mMaxVRAM, total_vram); - } - return total_vram - (LLImageGL::getTextureBytesAllocated() * total_factor/mb); -} - //static SInt32 oldWindowLevel; // MBW -- XXX -- There's got to be a better way than this. Find it, please... diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 7b0695bc79..0d675671a9 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -100,9 +100,7 @@ public: F32 getPixelAspectRatio() override; void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - // query VRAM usage - /*virtual*/ U32 getAvailableVRAMMegabytes() override; - virtual void setMaxVRAMMegabytes(U32 max_vram) override { mMaxVRAM = max_vram; } + virtual void setMaxVRAMMegabytes(U32 max_vram) override {} void beforeDialog() override; void afterDialog() override; @@ -226,7 +224,6 @@ protected: bool mMinimized; U32 mFSAASamples; bool mForceRebuild; - U32 mMaxVRAM; S32 mDragOverrideCursor; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 1ed801a85a..24a7b5709b 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -370,14 +370,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool //clean up DXGI/D3D resources void cleanupDX(); - // call periodically to update available VRAM - void updateVRAMUsage(); - - U32 getAvailableVRAMMegabytes() - { - return mAvailableVRAM; - } - /// called by main thread to post work to this window thread template void post(CALLABLE&& func) @@ -425,8 +417,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; - // best guess at available video memory in MB - std::atomic mAvailableVRAM; U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) @@ -4556,11 +4546,6 @@ std::vector LLWindowWin32::getDynamicFallbackFontList() return std::vector(); } -U32 LLWindowWin32::getAvailableVRAMMegabytes() -{ - return mWindowThread ? mWindowThread->getAvailableVRAMMegabytes() : 0; -} - void LLWindowWin32::setMaxVRAMMegabytes(U32 max_vram) { if (mWindowThread) @@ -4787,79 +4772,6 @@ void LLWindowWin32::LLWindowWin32Thread::cleanupDX() } } -void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() -{ - LL_PROFILE_ZONE_SCOPED; - if (!mGLReady) { return; } - - if (mDXGIAdapter != nullptr) - { - // NOTE: what lies below is hand wavy math based on compatibility testing and observation against a variety of hardware - // It doesn't make sense, but please don't refactor it to make sense. -- davep - - DXGI_QUERY_VIDEO_MEMORY_INFO info; - mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info); -#if 0 // debug 0 budget and 0 CU - info.Budget = 0; - info.CurrentUsage = 0; -#endif - - U32 budget_mb = info.Budget / 1024 / 1024; - gGLManager.mVRAM = llmax(gGLManager.mVRAM, (S32) budget_mb); - - U32 afr_mb = info.AvailableForReservation / 1024 / 1024; - // correct for systems that misreport budget - if (budget_mb == 0) - { - // fall back to available for reservation clamped between 512MB and 2GB - budget_mb = llclamp(afr_mb, (U32) 512, (U32) 2048); - } - - if ( mMaxVRAM != 0) - { - budget_mb = llmin(budget_mb, mMaxVRAM); - } - - U32 cu_mb = info.CurrentUsage / 1024 / 1024; - - // get an estimated usage based on texture bytes allocated - U32 eu_mb = LLImageGL::getTextureBytesAllocated() * 2 / 1024 / 1024; - - if (cu_mb == 0) - { // current usage is sometimes unreliable on Intel GPUs, fall back to estimated usage - cu_mb = llmax((U32)1, eu_mb); - } - U32 target_mb = budget_mb; - - if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free - { - target_mb -= 2048; - } - else // if less than 4GB are installed, try not to use more than half of it - { - target_mb /= 2; - } - - mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0; - -#if 0 - - F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb; - LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024 - << "\nBudget: " << info.Budget / 1024 / 1024 - << "\nCR: " << info.CurrentReservation / 1024 / 1024 - << "\nCU: " << info.CurrentUsage / 1024 / 1024 - << "\nEU: " << eu_mb << llformat(" (%.2f)", eu_error) - << "\nTU: " << target_mb - << "\nAM: " << mAvailableVRAM << LL_ENDL; -#endif - } - else if (mD3DDevice != NULL) - { // fallback to D3D9 - mAvailableVRAM = mD3DDevice->GetAvailableTextureMem() / 1024 / 1024; - } -} - void LLWindowWin32::LLWindowWin32Thread::run() { sWindowThreadId = std::this_thread::get_id(); @@ -4917,14 +4829,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() //process any pending functions getQueue().runPending(); } - - // update available vram once every 3 seconds - static LLFrameTimer vramTimer; - if (vramTimer.getElapsedTimeF32() > 3.f) - { - updateVRAMUsage(); - vramTimer.reset(); - } + #if 0 { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep"); diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 8b82ad92d5..7e320053a6 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -108,7 +108,6 @@ public: /*virtual*/ F32 getPixelAspectRatio(); /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } - U32 getAvailableVRAMMegabytes() override; /*virtual*/ void setMaxVRAMMegabytes(U32 max_vram) override; /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ); -- cgit v1.2.3 From f9473e8afcb624cc1b101195bf15943ec372b56f Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Mon, 6 May 2024 16:52:34 +0200 Subject: secondlife/viewer#1333 BOOL to bool conversion leftovers: ternaries --- indra/llwindow/llwindow.cpp | 2 +- indra/llwindow/llwindowwin32.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index d951f7f676..f1e6114f85 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -336,7 +336,7 @@ void LLWindow::handleUnicodeUTF16(U16 utf16, MASK mask) // static bool LLSplashScreen::isVisible() { - return gSplashScreenp ? true: false; + return gSplashScreenp; } // static diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 24a7b5709b..eb9ece6ea9 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3368,7 +3368,7 @@ F32 LLWindowWin32::getGamma() bool LLWindowWin32::restoreGamma() { ASSERT_MAIN_THREAD(); - if (mCustomGammaSet != false) + if (mCustomGammaSet) { LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; mCustomGammaSet = false; @@ -3383,12 +3383,12 @@ bool LLWindowWin32::setGamma(const F32 gamma) mCurrentGamma = gamma; //Get the previous gamma ramp to restore later. - if (mCustomGammaSet == false) + if (!mCustomGammaSet) { if (!gGLManager.mIsIntel) // skip for Intel GPUs (see SL-11341) { LL_DEBUGS("Window") << "Getting the previous gamma ramp to restore later" << LL_ENDL; - if(GetDeviceGammaRamp(mhDC, mPrevGammaRamp) == FALSE) + if (!GetDeviceGammaRamp(mhDC, mPrevGammaRamp)) { LL_WARNS("Window") << "Failed to get the previous gamma ramp" << LL_ENDL; return false; -- cgit v1.2.3 From e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 22 May 2024 21:25:21 +0200 Subject: Fix line endlings --- indra/llwindow/lldragdropwin32.cpp | 722 +-- indra/llwindow/lldxhardware.cpp | 2238 +++---- indra/llwindow/lldxhardware.h | 252 +- indra/llwindow/llkeyboard.cpp | 1086 ++-- indra/llwindow/llkeyboard.h | 288 +- indra/llwindow/llkeyboardheadless.cpp | 160 +- indra/llwindow/llkeyboardheadless.h | 96 +- indra/llwindow/llkeyboardmacosx.cpp | 634 +- indra/llwindow/llkeyboardmacosx.h | 128 +- indra/llwindow/llkeyboardsdl.cpp | 648 +- indra/llwindow/llkeyboardsdl.h | 110 +- indra/llwindow/llkeyboardwin32.cpp | 648 +- indra/llwindow/llkeyboardwin32.h | 116 +- indra/llwindow/llmousehandler.cpp | 132 +- indra/llwindow/llmousehandler.h | 146 +- indra/llwindow/llpreeditor.h | 202 +- indra/llwindow/llwindow.cpp | 1020 +-- indra/llwindow/llwindow.h | 668 +- indra/llwindow/llwindowcallbacks.cpp | 454 +- indra/llwindow/llwindowcallbacks.h | 200 +- indra/llwindow/llwindowheadless.cpp | 106 +- indra/llwindow/llwindowheadless.h | 266 +- indra/llwindow/llwindowmacosx-objc.h | 372 +- indra/llwindow/llwindowmacosx.cpp | 5324 ++++++++-------- indra/llwindow/llwindowmacosx.h | 530 +- indra/llwindow/llwindowmesaheadless.cpp | 156 +- indra/llwindow/llwindowmesaheadless.h | 246 +- indra/llwindow/llwindowsdl.cpp | 5394 ++++++++-------- indra/llwindow/llwindowsdl.h | 462 +- indra/llwindow/llwindowwin32.cpp | 10000 +++++++++++++++--------------- indra/llwindow/llwindowwin32.h | 590 +- 31 files changed, 16697 insertions(+), 16697 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/lldragdropwin32.cpp b/indra/llwindow/lldragdropwin32.cpp index e08a2c2fc6..15490ef953 100644 --- a/indra/llwindow/lldragdropwin32.cpp +++ b/indra/llwindow/lldragdropwin32.cpp @@ -1,361 +1,361 @@ -/** - * @file lldragdrop32.cpp - * @brief Handler for Windows specific drag and drop (OS to client) code - * - * $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$ - */ - -#if LL_WINDOWS - -#if LL_OS_DRAGDROP_ENABLED - -#include "linden_common.h" - -#include "llwindowwin32.h" -#include "llkeyboardwin32.h" -#include "llwindowcallbacks.h" -#include "lldragdropwin32.h" - -class LLDragDropWin32Target: - public IDropTarget -{ - public: - //////////////////////////////////////////////////////////////////////////////// - // - LLDragDropWin32Target( HWND hWnd ) : - mRefCount( 1 ), - mAppWindowHandle( hWnd ), - mAllowDrop(false), - mIsSlurl(false) - { - }; - - virtual ~LLDragDropWin32Target() - { - }; - - //////////////////////////////////////////////////////////////////////////////// - // - ULONG __stdcall AddRef( void ) - { - return InterlockedIncrement( &mRefCount ); - }; - - //////////////////////////////////////////////////////////////////////////////// - // - ULONG __stdcall Release( void ) - { - LONG count = InterlockedDecrement( &mRefCount ); - - if ( count == 0 ) - { - delete this; - return 0; - } - else - { - return count; - }; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - HRESULT __stdcall QueryInterface( REFIID iid, void** ppvObject ) - { - if ( iid == IID_IUnknown || iid == IID_IDropTarget ) - { - AddRef(); - *ppvObject = this; - return S_OK; - } - else - { - *ppvObject = 0; - return E_NOINTERFACE; - }; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) - { - FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; - - // support CF_TEXT using a HGLOBAL? - if ( S_OK == pDataObject->QueryGetData( &fmtetc ) ) - { - mAllowDrop = true; - mDropUrl = std::string(); - mIsSlurl = false; - - STGMEDIUM stgmed; - if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) ) - { - PVOID data = GlobalLock( stgmed.hGlobal ); - mDropUrl = std::string( (char*)data ); - // XXX MAJOR MAJOR HACK! - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); - if (NULL != window_imp) - { - LLCoordGL gl_coord( 0, 0 ); - - POINT pt2; - pt2.x = pt.x; - pt2.y = pt.y; - ScreenToClient( mAppWindowHandle, &pt2 ); - - LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); - MASK mask = gKeyboard->currentMask(true); - - LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask, - LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl ); - - switch (result) - { - case LLWindowCallbacks::DND_COPY: - *pdwEffect = DROPEFFECT_COPY; - break; - case LLWindowCallbacks::DND_LINK: - *pdwEffect = DROPEFFECT_LINK; - break; - case LLWindowCallbacks::DND_MOVE: - *pdwEffect = DROPEFFECT_MOVE; - break; - case LLWindowCallbacks::DND_NONE: - default: - *pdwEffect = DROPEFFECT_NONE; - break; - } - }; - - GlobalUnlock( stgmed.hGlobal ); - ReleaseStgMedium( &stgmed ); - }; - SetFocus( mAppWindowHandle ); - } - else - { - mAllowDrop = false; - *pdwEffect = DROPEFFECT_NONE; - }; - - return S_OK; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) - { - if ( mAllowDrop ) - { - // XXX MAJOR MAJOR HACK! - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); - if (NULL != window_imp) - { - LLCoordGL gl_coord( 0, 0 ); - - POINT pt2; - pt2.x = pt.x; - pt2.y = pt.y; - ScreenToClient( mAppWindowHandle, &pt2 ); - - LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); - MASK mask = gKeyboard->currentMask(true); - - LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask, - LLWindowCallbacks::DNDA_TRACK, mDropUrl ); - - switch (result) - { - case LLWindowCallbacks::DND_COPY: - *pdwEffect = DROPEFFECT_COPY; - break; - case LLWindowCallbacks::DND_LINK: - *pdwEffect = DROPEFFECT_LINK; - break; - case LLWindowCallbacks::DND_MOVE: - *pdwEffect = DROPEFFECT_MOVE; - break; - case LLWindowCallbacks::DND_NONE: - default: - *pdwEffect = DROPEFFECT_NONE; - break; - } - }; - } - else - { - *pdwEffect = DROPEFFECT_NONE; - }; - - return S_OK; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - HRESULT __stdcall DragLeave( void ) - { - // XXX MAJOR MAJOR HACK! - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); - if (NULL != window_imp) - { - LLCoordGL gl_coord( 0, 0 ); - MASK mask = gKeyboard->currentMask(true); - window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_STOP_TRACKING, mDropUrl ); - }; - return S_OK; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) - { - if ( mAllowDrop ) - { - // window impl stored in Window data (neat!) - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); - if ( NULL != window_imp ) - { - POINT pt_client; - pt_client.x = pt.x; - pt_client.y = pt.y; - ScreenToClient( mAppWindowHandle, &pt_client ); - - LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); - LLCoordGL gl_coord(cursor_coord_window.convert()); - LL_INFOS() << "### (Drop) URL is: " << mDropUrl << LL_ENDL; - LL_INFOS() << "### raw coords are: " << pt.x << " x " << pt.y << LL_ENDL; - LL_INFOS() << "### client coords are: " << pt_client.x << " x " << pt_client.y << LL_ENDL; - LL_INFOS() << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << LL_ENDL; - LL_INFOS() << LL_ENDL; - - // no keyboard modifier option yet but we could one day - MASK mask = gKeyboard->currentMask( true ); - - // actually do the drop - LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, - LLWindowCallbacks::DNDA_DROPPED, mDropUrl ); - - switch (result) - { - case LLWindowCallbacks::DND_COPY: - *pdwEffect = DROPEFFECT_COPY; - break; - case LLWindowCallbacks::DND_LINK: - *pdwEffect = DROPEFFECT_LINK; - break; - case LLWindowCallbacks::DND_MOVE: - *pdwEffect = DROPEFFECT_MOVE; - break; - case LLWindowCallbacks::DND_NONE: - default: - *pdwEffect = DROPEFFECT_NONE; - break; - } - }; - } - else - { - *pdwEffect = DROPEFFECT_NONE; - }; - - return S_OK; - }; - - //////////////////////////////////////////////////////////////////////////////// - // - private: - LONG mRefCount; - HWND mAppWindowHandle; - bool mAllowDrop; - std::string mDropUrl; - bool mIsSlurl; - friend class LLWindowWin32; -}; - -//////////////////////////////////////////////////////////////////////////////// -// -LLDragDropWin32::LLDragDropWin32() : - mDropTarget( NULL ), - mDropWindowHandle( NULL ) - -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -LLDragDropWin32::~LLDragDropWin32() -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// -bool LLDragDropWin32::init( HWND hWnd ) -{ - if ( NOERROR != OleInitialize( NULL ) ) - return false; - - mDropTarget = new LLDragDropWin32Target( hWnd ); - if ( mDropTarget ) - { - HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE ); - if ( S_OK == result ) - { - result = RegisterDragDrop( hWnd, mDropTarget ); - if ( S_OK != result ) - { - // RegisterDragDrop failed - return false; - }; - - // all ok - mDropWindowHandle = hWnd; - } - else - { - // Unable to lock OLE object - return false; - }; - }; - - // success - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// -void LLDragDropWin32::reset() -{ - if ( mDropTarget ) - { - RevokeDragDrop( mDropWindowHandle ); - CoLockObjectExternal( mDropTarget, FALSE, TRUE ); - mDropTarget->Release(); - }; - - OleUninitialize(); -} - -#endif // LL_OS_DRAGDROP_ENABLED - -#endif // LL_WINDOWS - +/** + * @file lldragdrop32.cpp + * @brief Handler for Windows specific drag and drop (OS to client) code + * + * $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$ + */ + +#if LL_WINDOWS + +#if LL_OS_DRAGDROP_ENABLED + +#include "linden_common.h" + +#include "llwindowwin32.h" +#include "llkeyboardwin32.h" +#include "llwindowcallbacks.h" +#include "lldragdropwin32.h" + +class LLDragDropWin32Target: + public IDropTarget +{ + public: + //////////////////////////////////////////////////////////////////////////////// + // + LLDragDropWin32Target( HWND hWnd ) : + mRefCount( 1 ), + mAppWindowHandle( hWnd ), + mAllowDrop(false), + mIsSlurl(false) + { + }; + + virtual ~LLDragDropWin32Target() + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + ULONG __stdcall AddRef( void ) + { + return InterlockedIncrement( &mRefCount ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + ULONG __stdcall Release( void ) + { + LONG count = InterlockedDecrement( &mRefCount ); + + if ( count == 0 ) + { + delete this; + return 0; + } + else + { + return count; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall QueryInterface( REFIID iid, void** ppvObject ) + { + if ( iid == IID_IUnknown || iid == IID_IDropTarget ) + { + AddRef(); + *ppvObject = this; + return S_OK; + } + else + { + *ppvObject = 0; + return E_NOINTERFACE; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall DragEnter( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) + { + FORMATETC fmtetc = { CF_TEXT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; + + // support CF_TEXT using a HGLOBAL? + if ( S_OK == pDataObject->QueryGetData( &fmtetc ) ) + { + mAllowDrop = true; + mDropUrl = std::string(); + mIsSlurl = false; + + STGMEDIUM stgmed; + if( S_OK == pDataObject->GetData( &fmtetc, &stgmed ) ) + { + PVOID data = GlobalLock( stgmed.hGlobal ); + mDropUrl = std::string( (char*)data ); + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt2 ); + + LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); + MASK mask = gKeyboard->currentMask(true); + + LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask, + LLWindowCallbacks::DNDA_START_TRACKING, mDropUrl ); + + switch (result) + { + case LLWindowCallbacks::DND_COPY: + *pdwEffect = DROPEFFECT_COPY; + break; + case LLWindowCallbacks::DND_LINK: + *pdwEffect = DROPEFFECT_LINK; + break; + case LLWindowCallbacks::DND_MOVE: + *pdwEffect = DROPEFFECT_MOVE; + break; + case LLWindowCallbacks::DND_NONE: + default: + *pdwEffect = DROPEFFECT_NONE; + break; + } + }; + + GlobalUnlock( stgmed.hGlobal ); + ReleaseStgMedium( &stgmed ); + }; + SetFocus( mAppWindowHandle ); + } + else + { + mAllowDrop = false; + *pdwEffect = DROPEFFECT_NONE; + }; + + return S_OK; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall DragOver( DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) + { + if ( mAllowDrop ) + { + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + + POINT pt2; + pt2.x = pt.x; + pt2.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt2 ); + + LLCoordWindow cursor_coord_window( pt2.x, pt2.y ); + MASK mask = gKeyboard->currentMask(true); + + LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( cursor_coord_window.convert(), mask, + LLWindowCallbacks::DNDA_TRACK, mDropUrl ); + + switch (result) + { + case LLWindowCallbacks::DND_COPY: + *pdwEffect = DROPEFFECT_COPY; + break; + case LLWindowCallbacks::DND_LINK: + *pdwEffect = DROPEFFECT_LINK; + break; + case LLWindowCallbacks::DND_MOVE: + *pdwEffect = DROPEFFECT_MOVE; + break; + case LLWindowCallbacks::DND_NONE: + default: + *pdwEffect = DROPEFFECT_NONE; + break; + } + }; + } + else + { + *pdwEffect = DROPEFFECT_NONE; + }; + + return S_OK; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall DragLeave( void ) + { + // XXX MAJOR MAJOR HACK! + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); + if (NULL != window_imp) + { + LLCoordGL gl_coord( 0, 0 ); + MASK mask = gKeyboard->currentMask(true); + window_imp->completeDragNDropRequest( gl_coord, mask, LLWindowCallbacks::DNDA_STOP_TRACKING, mDropUrl ); + }; + return S_OK; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + HRESULT __stdcall Drop( IDataObject* pDataObject, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect ) + { + if ( mAllowDrop ) + { + // window impl stored in Window data (neat!) + LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( mAppWindowHandle, GWLP_USERDATA ); + if ( NULL != window_imp ) + { + POINT pt_client; + pt_client.x = pt.x; + pt_client.y = pt.y; + ScreenToClient( mAppWindowHandle, &pt_client ); + + LLCoordWindow cursor_coord_window( pt_client.x, pt_client.y ); + LLCoordGL gl_coord(cursor_coord_window.convert()); + LL_INFOS() << "### (Drop) URL is: " << mDropUrl << LL_ENDL; + LL_INFOS() << "### raw coords are: " << pt.x << " x " << pt.y << LL_ENDL; + LL_INFOS() << "### client coords are: " << pt_client.x << " x " << pt_client.y << LL_ENDL; + LL_INFOS() << "### GL coords are: " << gl_coord.mX << " x " << gl_coord.mY << LL_ENDL; + LL_INFOS() << LL_ENDL; + + // no keyboard modifier option yet but we could one day + MASK mask = gKeyboard->currentMask( true ); + + // actually do the drop + LLWindowCallbacks::DragNDropResult result = window_imp->completeDragNDropRequest( gl_coord, mask, + LLWindowCallbacks::DNDA_DROPPED, mDropUrl ); + + switch (result) + { + case LLWindowCallbacks::DND_COPY: + *pdwEffect = DROPEFFECT_COPY; + break; + case LLWindowCallbacks::DND_LINK: + *pdwEffect = DROPEFFECT_LINK; + break; + case LLWindowCallbacks::DND_MOVE: + *pdwEffect = DROPEFFECT_MOVE; + break; + case LLWindowCallbacks::DND_NONE: + default: + *pdwEffect = DROPEFFECT_NONE; + break; + } + }; + } + else + { + *pdwEffect = DROPEFFECT_NONE; + }; + + return S_OK; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + private: + LONG mRefCount; + HWND mAppWindowHandle; + bool mAllowDrop; + std::string mDropUrl; + bool mIsSlurl; + friend class LLWindowWin32; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +LLDragDropWin32::LLDragDropWin32() : + mDropTarget( NULL ), + mDropWindowHandle( NULL ) + +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLDragDropWin32::~LLDragDropWin32() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLDragDropWin32::init( HWND hWnd ) +{ + if ( NOERROR != OleInitialize( NULL ) ) + return false; + + mDropTarget = new LLDragDropWin32Target( hWnd ); + if ( mDropTarget ) + { + HRESULT result = CoLockObjectExternal( mDropTarget, TRUE, FALSE ); + if ( S_OK == result ) + { + result = RegisterDragDrop( hWnd, mDropTarget ); + if ( S_OK != result ) + { + // RegisterDragDrop failed + return false; + }; + + // all ok + mDropWindowHandle = hWnd; + } + else + { + // Unable to lock OLE object + return false; + }; + }; + + // success + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLDragDropWin32::reset() +{ + if ( mDropTarget ) + { + RevokeDragDrop( mDropWindowHandle ); + CoLockObjectExternal( mDropTarget, FALSE, TRUE ); + mDropTarget->Release(); + }; + + OleUninitialize(); +} + +#endif // LL_OS_DRAGDROP_ENABLED + +#endif // LL_WINDOWS + diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index 5d0e15d9f4..0830dc9528 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -1,1119 +1,1119 @@ -/** - * @file lldxhardware.cpp - * @brief LLDXHardware implementation - * - * $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$ - */ - -#ifdef LL_WINDOWS - -// Culled from some Microsoft sample code - -#include "linden_common.h" - -#define INITGUID -#include -#undef INITGUID - -#include -#include - -#include - -#include "lldxhardware.h" - -#include "llerror.h" - -#include "llstring.h" -#include "llstl.h" -#include "lltimer.h" - -void (*gWriteDebug)(const char* msg) = NULL; -LLDXHardware gDXHardware; - -//----------------------------------------------------------------------------- -// Defines, and constants -//----------------------------------------------------------------------------- -#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } -#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } -#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } - -typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, - OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, - RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities ); - -HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) -{ - HRESULT hr; - bool bGotMemory = false; - IWbemLocator* pIWbemLocator = nullptr; - IWbemServices* pIWbemServices = nullptr; - BSTR pNamespace = nullptr; - - *pdwAdapterRam = 0; - CoInitializeEx(0, COINIT_APARTMENTTHREADED); - - hr = CoCreateInstance( CLSID_WbemLocator, - nullptr, - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, - ( LPVOID* )&pIWbemLocator ); -#ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) wprintf( L"WMI: CoCreateInstance failed: 0x%0.8x\n", hr ); -#endif - - if( SUCCEEDED( hr ) && pIWbemLocator ) - { - // Using the locator, connect to WMI in the given namespace. - pNamespace = SysAllocString( L"\\\\.\\root\\cimv2" ); - - hr = pIWbemLocator->ConnectServer( pNamespace, nullptr, nullptr, 0L, - 0L, nullptr, nullptr, &pIWbemServices ); -#ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) wprintf( L"WMI: pIWbemLocator->ConnectServer failed: 0x%0.8x\n", hr ); -#endif - if( SUCCEEDED( hr ) && pIWbemServices != 0 ) - { - HINSTANCE hinstOle32 = nullptr; - - hinstOle32 = LoadLibraryW( L"ole32.dll" ); - if( hinstOle32 ) - { - PfnCoSetProxyBlanket pfnCoSetProxyBlanket = nullptr; - - pfnCoSetProxyBlanket = ( PfnCoSetProxyBlanket )GetProcAddress( hinstOle32, "CoSetProxyBlanket" ); - if( pfnCoSetProxyBlanket != 0 ) - { - // Switch security level to IMPERSONATE. - pfnCoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, - RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0 ); - } - - FreeLibrary( hinstOle32 ); - } - - IEnumWbemClassObject* pEnumVideoControllers = nullptr; - BSTR pClassName = nullptr; - - pClassName = SysAllocString( L"Win32_VideoController" ); - - hr = pIWbemServices->CreateInstanceEnum( pClassName, 0, - nullptr, &pEnumVideoControllers ); -#ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) wprintf( L"WMI: pIWbemServices->CreateInstanceEnum failed: 0x%0.8x\n", hr ); -#endif - - if( SUCCEEDED( hr ) && pEnumVideoControllers ) - { - IWbemClassObject* pVideoControllers[10] = {0}; - DWORD uReturned = 0; - BSTR pPropName = nullptr; - - // Get the first one in the list - pEnumVideoControllers->Reset(); - hr = pEnumVideoControllers->Next( 5000, // timeout in 5 seconds - 10, // return the first 10 - pVideoControllers, - &uReturned ); -#ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) wprintf( L"WMI: pEnumVideoControllers->Next failed: 0x%0.8x\n", hr ); - if( uReturned == 0 ) wprintf( L"WMI: pEnumVideoControllers uReturned == 0\n" ); -#endif - - VARIANT var; - if( SUCCEEDED( hr ) ) - { - bool bFound = false; - for( UINT iController = 0; iController < uReturned; iController++ ) - { - if ( !pVideoControllers[iController] ) - continue; - - // if strInputDeviceID is set find this specific device and return memory or specific device - // if strInputDeviceID is not set return the best device - if (strInputDeviceID) - { - pPropName = SysAllocString( L"PNPDeviceID" ); - hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); -#ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) - wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); -#endif - if( SUCCEEDED( hr ) && strInputDeviceID) - { - if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) - bFound = true; - } - VariantClear( &var ); - if( pPropName ) SysFreeString( pPropName ); - } - - if( bFound || !strInputDeviceID ) - { - pPropName = SysAllocString( L"AdapterRAM" ); - hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); -#ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) - wprintf( L"WMI: pVideoControllers[iController]->Get AdapterRAM failed: 0x%0.8x\n", - hr ); -#endif - if( SUCCEEDED( hr ) ) - { - bGotMemory = true; - *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam); - } - VariantClear( &var ); - if( pPropName ) SysFreeString( pPropName ); - } - - SAFE_RELEASE( pVideoControllers[iController] ); - - if (bFound) - { - break; - } - } - } - } - - if( pClassName ) - SysFreeString( pClassName ); - SAFE_RELEASE( pEnumVideoControllers ); - } - - if( pNamespace ) - SysFreeString( pNamespace ); - SAFE_RELEASE( pIWbemServices ); - } - - SAFE_RELEASE( pIWbemLocator ); - - CoUninitialize(); - - if( bGotMemory ) - return S_OK; - else - return E_FAIL; -} - -//static -S32 LLDXHardware::getMBVideoMemoryViaWMI() -{ - DWORD vram = 0; - if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram))) - { - return vram / (1024 * 1024);; - } - return 0; -} - -//Getting the version of graphics controller driver via WMI -std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) -{ - std::string mDriverVersion; - HRESULT hres; - CoInitializeEx(0, COINIT_APARTMENTTHREADED); - IWbemLocator *pLoc = NULL; - - hres = CoCreateInstance( - CLSID_WbemLocator, - 0, - CLSCTX_INPROC_SERVER, - IID_IWbemLocator, (LPVOID *)&pLoc); - - if (FAILED(hres)) - { - LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hres << LL_ENDL; - return std::string(); // Program has failed. - } - - IWbemServices *pSvc = NULL; - - // Connect to the root\cimv2 namespace with - // the current user and obtain pointer pSvc - // to make IWbemServices calls. - hres = pLoc->ConnectServer( - _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace - NULL, // User name. NULL = current user - NULL, // User password. NULL = current - 0, // Locale. NULL indicates current - NULL, // Security flags. - 0, // Authority (e.g. Kerberos) - 0, // Context object - &pSvc // pointer to IWbemServices proxy - ); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << hres << LL_ENDL; - pLoc->Release(); - CoUninitialize(); - return std::string(); // Program has failed. - } - - LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL; - - // Set security levels on the proxy ------------------------- - hres = CoSetProxyBlanket( - pSvc, // Indicates the proxy to set - RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx - RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx - NULL, // Server principal name - RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx - RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx - NULL, // client identity - EOAC_NONE // proxy capabilities - ); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hres << LL_ENDL; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return std::string(); // Program has failed. - } - IEnumWbemClassObject* pEnumerator = NULL; - - // Get the data from the query - ULONG uReturn = 0; - hres = pSvc->ExecQuery( - bstr_t("WQL"), - bstr_t("SELECT * FROM Win32_VideoController"), //Consider using Availability to filter out disabled controllers - WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, - NULL, - &pEnumerator); - - if (FAILED(hres)) - { - LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hres << LL_ENDL; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return std::string(); // Program has failed. - } - - while (pEnumerator) - { - IWbemClassObject *pclsObj = NULL; - HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, - &pclsObj, &uReturn); - - if (0 == uReturn) - { - break; // If quantity less then 1. - } - - if (vendor != GPU_ANY) - { - VARIANT vtCaptionProp; - // Might be preferable to check "AdapterCompatibility" here instead of caption. - hr = pclsObj->Get(L"Caption", 0, &vtCaptionProp, 0, 0); - - if (FAILED(hr)) - { - LL_WARNS("AppInit") << "Query for Caption property failed." << " Error code = 0x" << hr << LL_ENDL; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return std::string(); // Program has failed. - } - - // use characters in the returned driver version - BSTR caption(vtCaptionProp.bstrVal); - - //convert BSTR to std::string - std::wstring ws(caption, SysStringLen(caption)); - std::string caption_str(ws.begin(), ws.end()); - LLStringUtil::toLower(caption_str); - - bool found = false; - switch (vendor) - { - case GPU_INTEL: - found = caption_str.find("intel") != std::string::npos; - break; - case GPU_NVIDIA: - found = caption_str.find("nvidia") != std::string::npos; - break; - case GPU_AMD: - found = caption_str.find("amd") != std::string::npos - || caption_str.find("ati ") != std::string::npos - || caption_str.find("radeon") != std::string::npos; - break; - default: - break; - } - - if (found) - { - VariantClear(&vtCaptionProp); - } - else - { - VariantClear(&vtCaptionProp); - pclsObj->Release(); - continue; - } - } - - VARIANT vtVersionProp; - - // Get the value of the DriverVersion property - hr = pclsObj->Get(L"DriverVersion", 0, &vtVersionProp, 0, 0); - - if (FAILED(hr)) - { - LL_WARNS("AppInit") << "Query for DriverVersion property failed." << " Error code = 0x" << hr << LL_ENDL; - pSvc->Release(); - pLoc->Release(); - CoUninitialize(); - return std::string(); // Program has failed. - } - - // use characters in the returned driver version - BSTR driverVersion(vtVersionProp.bstrVal); - - //convert BSTR to std::string - std::wstring ws(driverVersion, SysStringLen(driverVersion)); - std::string str(ws.begin(), ws.end()); - LL_INFOS("AppInit") << " DriverVersion : " << str << LL_ENDL; - - if (mDriverVersion.empty()) - { - mDriverVersion = str; - } - else if (mDriverVersion != str) - { - if (vendor == GPU_ANY) - { - // Expected from systems with gpus from different vendors - LL_INFOS("DriverVersion") << "Multiple video drivers detected. Version of second driver: " << str << LL_ENDL; - } - else - { - // Not Expected! - LL_WARNS("DriverVersion") << "Multiple video drivers detected from same vendor. Version of second driver : " << str << LL_ENDL; - } - } - - VariantClear(&vtVersionProp); - pclsObj->Release(); - } - - // Cleanup - // ======== - if (pSvc) - { - pSvc->Release(); - } - if (pLoc) - { - pLoc->Release(); - } - if (pEnumerator) - { - pEnumerator->Release(); - } - - // supposed to always call CoUninitialize even if init returned false - CoUninitialize(); - - return mDriverVersion; -} - -void get_wstring(IDxDiagContainer* containerp, WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize) -{ - HRESULT hr; - VARIANT var; - - VariantInit( &var ); - hr = containerp->GetProp(wszPropName, &var ); - if( SUCCEEDED(hr) ) - { - // Switch off the type. There's 4 different types: - switch( var.vt ) - { - case VT_UI4: - swprintf( wszPropValue, L"%d", var.ulVal ); /* Flawfinder: ignore */ - break; - case VT_I4: - swprintf( wszPropValue, L"%d", var.lVal ); /* Flawfinder: ignore */ - break; - case VT_BOOL: - wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); /* Flawfinder: ignore */ - break; - case VT_BSTR: - wcsncpy( wszPropValue, var.bstrVal, outputSize-1 ); /* Flawfinder: ignore */ - wszPropValue[outputSize-1] = 0; - break; - } - } - // Clear the variant (this is needed to free BSTR memory) - VariantClear( &var ); -} - -std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName) -{ - WCHAR wszPropValue[256]; - get_wstring(containerp, wszPropName, wszPropValue, 256); - - return utf16str_to_utf8str(wszPropValue); -} - - -LLVersion::LLVersion() -{ - mValid = false; - S32 i; - for (i = 0; i < 4; i++) - { - mFields[i] = 0; - } -} - -bool LLVersion::set(const std::string &version_string) -{ - S32 i; - for (i = 0; i < 4; i++) - { - mFields[i] = 0; - } - // Split the version string. - std::string str(version_string); - typedef boost::tokenizer > tokenizer; - boost::char_separator sep(".", "", boost::keep_empty_tokens); - tokenizer tokens(str, sep); - - tokenizer::iterator iter = tokens.begin(); - S32 count = 0; - for (;(iter != tokens.end()) && (count < 4);++iter) - { - mFields[count] = atoi(iter->c_str()); - count++; - } - if (count < 4) - { - //LL_WARNS() << "Potentially bogus version string!" << version_string << LL_ENDL; - for (i = 0; i < 4; i++) - { - mFields[i] = 0; - } - mValid = false; - } - else - { - mValid = true; - } - return mValid; -} - -S32 LLVersion::getField(const S32 field_num) -{ - if (!mValid) - { - return -1; - } - else - { - return mFields[field_num]; - } -} - -std::string LLDXDriverFile::dump() -{ - if (gWriteDebug) - { - gWriteDebug("Filename:"); - gWriteDebug(mName.c_str()); - gWriteDebug("\n"); - gWriteDebug("Ver:"); - gWriteDebug(mVersionString.c_str()); - gWriteDebug("\n"); - gWriteDebug("Date:"); - gWriteDebug(mDateString.c_str()); - gWriteDebug("\n"); - } - LL_INFOS() << mFilepath << LL_ENDL; - LL_INFOS() << mName << LL_ENDL; - LL_INFOS() << mVersionString << LL_ENDL; - LL_INFOS() << mDateString << LL_ENDL; - - return ""; -} - -LLDXDevice::~LLDXDevice() -{ - for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer()); - mDriverFiles.clear(); -} - -std::string LLDXDevice::dump() -{ - if (gWriteDebug) - { - gWriteDebug("StartDevice\n"); - gWriteDebug("DeviceName:"); - gWriteDebug(mName.c_str()); - gWriteDebug("\n"); - gWriteDebug("PCIString:"); - gWriteDebug(mPCIString.c_str()); - gWriteDebug("\n"); - } - LL_INFOS() << LL_ENDL; - LL_INFOS() << "DeviceName:" << mName << LL_ENDL; - LL_INFOS() << "PCIString:" << mPCIString << LL_ENDL; - LL_INFOS() << "Drivers" << LL_ENDL; - LL_INFOS() << "-------" << LL_ENDL; - for (driver_file_map_t::iterator iter = mDriverFiles.begin(), - end = mDriverFiles.end(); - iter != end; iter++) - { - LLDXDriverFile *filep = iter->second; - filep->dump(); - } - if (gWriteDebug) - { - gWriteDebug("EndDevice\n"); - } - - return ""; -} - -LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver) -{ - for (driver_file_map_t::iterator iter = mDriverFiles.begin(), - end = mDriverFiles.end(); - iter != end; iter++) - { - LLDXDriverFile *filep = iter->second; - if (!utf8str_compare_insensitive(filep->mName,driver)) - { - return filep; - } - } - - return NULL; -} - -LLDXHardware::LLDXHardware() -{ - mVRAM = 0; - gWriteDebug = NULL; -} - -void LLDXHardware::cleanup() -{ - // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer()); - // mDevices.clear(); -} - -/* -std::string LLDXHardware::dumpDevices() -{ - if (gWriteDebug) - { - gWriteDebug("\n"); - gWriteDebug("StartAllDevices\n"); - } - for (device_map_t::iterator iter = mDevices.begin(), - end = mDevices.end(); - iter != end; iter++) - { - LLDXDevice *devicep = iter->second; - devicep->dump(); - } - if (gWriteDebug) - { - gWriteDebug("EndAllDevices\n\n"); - } - return ""; -} - -LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices) -{ - // Iterate through different devices tokenized in devices string - std::string str(devices); - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(str, sep); - - tokenizer::iterator iter = tokens.begin(); - for (;iter != tokens.end();++iter) - { - std::string dev_str = *iter; - for (device_map_t::iterator iter = mDevices.begin(), - end = mDevices.end(); - iter != end; iter++) - { - LLDXDevice *devicep = iter->second; - if ((devicep->mVendorID == vendor) - && (devicep->mDeviceID == dev_str)) - { - return devicep; - } - } - } - - return NULL; -} -*/ - -bool LLDXHardware::getInfo(bool vram_only) -{ - LLTimer hw_timer; - bool ok = false; - HRESULT hr; - - // CLSID_DxDiagProvider does not work with Multithreaded? - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - - IDxDiagProvider *dx_diag_providerp = NULL; - IDxDiagContainer *dx_diag_rootp = NULL; - IDxDiagContainer *devices_containerp = NULL; - // IDxDiagContainer *system_device_containerp= NULL; - IDxDiagContainer *device_containerp = NULL; - IDxDiagContainer *file_containerp = NULL; - IDxDiagContainer *driver_containerp = NULL; - DWORD dw_device_count; - - mVRAM = 0; - - // CoCreate a IDxDiagProvider* - LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; - hr = CoCreateInstance(CLSID_DxDiagProvider, - NULL, - CLSCTX_INPROC_SERVER, - IID_IDxDiagProvider, - (LPVOID*) &dx_diag_providerp); - - if (FAILED(hr)) - { - LL_WARNS("AppInit") << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL; - gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); - goto LCleanup; - } - if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed - { - // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize - // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are - // digital signed as logo'd by WHQL which may connect via internet to update - // WHQL certificates. - DXDIAG_INIT_PARAMS dx_diag_init_params; - ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); - - dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); - dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; - dx_diag_init_params.bAllowWHQLChecks = TRUE; - dx_diag_init_params.pReserved = NULL; - - LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL; - hr = dx_diag_providerp->Initialize(&dx_diag_init_params); - if(FAILED(hr)) - { - goto LCleanup; - } - - LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL; - hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); - if(FAILED(hr) || !dx_diag_rootp) - { - goto LCleanup; - } - - HRESULT hr; - - // Get display driver information - LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL; - hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); - if(FAILED(hr) || !devices_containerp) - { - // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp - devices_containerp = NULL; - goto LCleanup; - } - - // make sure there is something inside - hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); - if (FAILED(hr) || dw_device_count == 0) - { - goto LCleanup; - } - - // Get device 0 - // By default 0 device is the primary one, howhever in case of various hybrid graphics - // like itegrated AMD and PCI AMD GPUs system might switch. - LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; - hr = devices_containerp->GetChildContainer(L"0", &device_containerp); - if(FAILED(hr) || !device_containerp) - { - goto LCleanup; - } - - DWORD vram = 0; - - WCHAR deviceID[512]; - - get_wstring(device_containerp, L"szDeviceID", deviceID, 512); - // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06) - // doesn't seem to work on some systems since format is unrecognizable - // but in such case keyDeviceID works - if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) - { - mVRAM = vram/(1024*1024); - } - else - { - get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512); - LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL; - // '+9' to avoid ENUM\\PCI\\ prefix - // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS... - // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient - if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram))) - { - mVRAM = vram / (1024 * 1024); - } - } - - if (mVRAM == 0) - { // Get the English VRAM string - std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); - - // We don't need the device any more - SAFE_RELEASE(device_containerp); - - // Dump the string as an int into the structure - char *stopstring; - mVRAM = strtol(ram_str.c_str(), &stopstring, 10); - LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL; - } - - if (vram_only) - { - ok = true; - goto LCleanup; - } - - - /* for now, we ONLY do vram_only the rest of this - is commented out, to ensure no-one is tempted - to use it - - // Now let's get device and driver information - // Get the IDxDiagContainer object called "DxDiag_SystemDevices". - // This call may take some time while dxdiag gathers the info. - DWORD num_devices = 0; - WCHAR wszContainer[256]; - LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL; - hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp); - if (FAILED(hr)) - { - goto LCleanup; - } - - hr = system_device_containerp->GetNumberOfChildContainers(&num_devices); - if (FAILED(hr)) - { - goto LCleanup; - } - - LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL; - S32 device_num = 0; - for (device_num = 0; device_num < (S32)num_devices; device_num++) - { - hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256); - if (FAILED(hr)) - { - goto LCleanup; - } - - hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp); - if (FAILED(hr) || device_containerp == NULL) - { - goto LCleanup; - } - - std::string device_name = get_string(device_containerp, L"szDescription"); - - std::string device_id = get_string(device_containerp, L"szDeviceID"); - - LLDXDevice *dxdevicep = new LLDXDevice; - dxdevicep->mName = device_name; - dxdevicep->mPCIString = device_id; - mDevices[dxdevicep->mPCIString] = dxdevicep; - - // Split the PCI string based on vendor, device, subsys, rev. - std::string str(device_id); - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("&\\", "", boost::keep_empty_tokens); - tokenizer tokens(str, sep); - - tokenizer::iterator iter = tokens.begin(); - S32 count = 0; - bool valid = true; - for (;(iter != tokens.end()) && (count < 3);++iter) - { - switch (count) - { - case 0: - if (strcmp(iter->c_str(), "PCI")) - { - valid = false; - } - break; - case 1: - dxdevicep->mVendorID = iter->c_str(); - break; - case 2: - dxdevicep->mDeviceID = iter->c_str(); - break; - default: - // Ignore it - break; - } - count++; - } - - - - - // Now, iterate through the related drivers - hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp); - if (FAILED(hr) || !driver_containerp) - { - goto LCleanup; - } - - DWORD num_files = 0; - hr = driver_containerp->GetNumberOfChildContainers(&num_files); - if (FAILED(hr)) - { - goto LCleanup; - } - - S32 file_num = 0; - for (file_num = 0; file_num < (S32)num_files; file_num++ ) - { - - hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256); - if (FAILED(hr)) - { - goto LCleanup; - } - - hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp); - if (FAILED(hr) || file_containerp == NULL) - { - goto LCleanup; - } - - std::string driver_path = get_string(file_containerp, L"szPath"); - std::string driver_name = get_string(file_containerp, L"szName"); - std::string driver_version = get_string(file_containerp, L"szVersion"); - std::string driver_date = get_string(file_containerp, L"szDatestampEnglish"); - - LLDXDriverFile *dxdriverfilep = new LLDXDriverFile; - dxdriverfilep->mName = driver_name; - dxdriverfilep->mFilepath= driver_path; - dxdriverfilep->mVersionString = driver_version; - dxdriverfilep->mVersion.set(driver_version); - dxdriverfilep->mDateString = driver_date; - - dxdevicep->mDriverFiles[driver_name] = dxdriverfilep; - - SAFE_RELEASE(file_containerp); - } - SAFE_RELEASE(device_containerp); - } - */ - } - - // dumpDevices(); - ok = true; - -LCleanup: - if (!ok) - { - LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL; - gWriteDebug("DX9 probe failed\n"); - } - - SAFE_RELEASE(file_containerp); - SAFE_RELEASE(driver_containerp); - SAFE_RELEASE(device_containerp); - SAFE_RELEASE(devices_containerp); - SAFE_RELEASE(dx_diag_rootp); - SAFE_RELEASE(dx_diag_providerp); - - CoUninitialize(); - - return ok; - } - -LLSD LLDXHardware::getDisplayInfo() -{ - LLTimer hw_timer; - HRESULT hr; - LLSD ret; - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - - IDxDiagProvider *dx_diag_providerp = NULL; - IDxDiagContainer *dx_diag_rootp = NULL; - IDxDiagContainer *devices_containerp = NULL; - IDxDiagContainer *device_containerp = NULL; - IDxDiagContainer *file_containerp = NULL; - IDxDiagContainer *driver_containerp = NULL; - DWORD dw_device_count; - - // CoCreate a IDxDiagProvider* - LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; - hr = CoCreateInstance(CLSID_DxDiagProvider, - NULL, - CLSCTX_INPROC_SERVER, - IID_IDxDiagProvider, - (LPVOID*) &dx_diag_providerp); - - if (FAILED(hr)) - { - LL_WARNS() << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL; - gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); - goto LCleanup; - } - if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed - { - // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize - // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are - // digital signed as logo'd by WHQL which may connect via internet to update - // WHQL certificates. - DXDIAG_INIT_PARAMS dx_diag_init_params; - ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); - - dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); - dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; - dx_diag_init_params.bAllowWHQLChecks = TRUE; - dx_diag_init_params.pReserved = NULL; - - LL_INFOS() << "dx_diag_providerp->Initialize" << LL_ENDL; - hr = dx_diag_providerp->Initialize(&dx_diag_init_params); - if(FAILED(hr)) - { - goto LCleanup; - } - - LL_INFOS() << "dx_diag_providerp->GetRootContainer" << LL_ENDL; - hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); - if(FAILED(hr) || !dx_diag_rootp) - { - goto LCleanup; - } - - HRESULT hr; - - // Get display driver information - LL_INFOS() << "dx_diag_rootp->GetChildContainer" << LL_ENDL; - hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); - if(FAILED(hr) || !devices_containerp) - { - // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp - devices_containerp = NULL; - goto LCleanup; - } - - // make sure there is something inside - hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); - if (FAILED(hr) || dw_device_count == 0) - { - goto LCleanup; - } - - // Get device 0 - LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL; - hr = devices_containerp->GetChildContainer(L"0", &device_containerp); - if(FAILED(hr) || !device_containerp) - { - goto LCleanup; - } - - // Get the English VRAM string - std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); - - - // Dump the string as an int into the structure - char *stopstring; - ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10); - std::string device_name = get_string(device_containerp, L"szDescription"); - ret["DeviceName"] = device_name; - std::string device_driver= get_string(device_containerp, L"szDriverVersion"); - ret["DriverVersion"] = device_driver; - - // ATI has a slightly different version string - if(device_name.length() >= 4 && device_name.substr(0,4) == "ATI ") - { - // get the key - HKEY hKey; - const DWORD RV_SIZE = 100; - WCHAR release_version[RV_SIZE]; - - // Hard coded registry entry. Using this since it's simpler for now. - // And using EnumDisplayDevices to get a registry key also requires - // a hard coded Query value. - if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\ATI Technologies\\CBT"), &hKey)) - { - // get the value - DWORD dwType = REG_SZ; - DWORD dwSize = sizeof(WCHAR) * RV_SIZE; - if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("ReleaseVersion"), - NULL, &dwType, (LPBYTE)release_version, &dwSize)) - { - // print the value - // windows doesn't guarantee to be null terminated - release_version[RV_SIZE - 1] = NULL; - ret["DriverVersion"] = utf16str_to_utf8str(release_version); - - } - RegCloseKey(hKey); - } - } - } - -LCleanup: - if (!ret.isMap() || (ret.size() == 0)) - { - LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL; - } - SAFE_RELEASE(file_containerp); - SAFE_RELEASE(driver_containerp); - SAFE_RELEASE(device_containerp); - SAFE_RELEASE(devices_containerp); - SAFE_RELEASE(dx_diag_rootp); - SAFE_RELEASE(dx_diag_providerp); - - CoUninitialize(); - return ret; -} - -void LLDXHardware::setWriteDebugFunc(void (*func)(const char*)) -{ - gWriteDebug = func; -} - -#endif +/** + * @file lldxhardware.cpp + * @brief LLDXHardware implementation + * + * $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$ + */ + +#ifdef LL_WINDOWS + +// Culled from some Microsoft sample code + +#include "linden_common.h" + +#define INITGUID +#include +#undef INITGUID + +#include +#include + +#include + +#include "lldxhardware.h" + +#include "llerror.h" + +#include "llstring.h" +#include "llstl.h" +#include "lltimer.h" + +void (*gWriteDebug)(const char* msg) = NULL; +LLDXHardware gDXHardware; + +//----------------------------------------------------------------------------- +// Defines, and constants +//----------------------------------------------------------------------------- +#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } +#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } } +#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } + +typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, + OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, + RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities ); + +HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) +{ + HRESULT hr; + bool bGotMemory = false; + IWbemLocator* pIWbemLocator = nullptr; + IWbemServices* pIWbemServices = nullptr; + BSTR pNamespace = nullptr; + + *pdwAdapterRam = 0; + CoInitializeEx(0, COINIT_APARTMENTTHREADED); + + hr = CoCreateInstance( CLSID_WbemLocator, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, + ( LPVOID* )&pIWbemLocator ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: CoCreateInstance failed: 0x%0.8x\n", hr ); +#endif + + if( SUCCEEDED( hr ) && pIWbemLocator ) + { + // Using the locator, connect to WMI in the given namespace. + pNamespace = SysAllocString( L"\\\\.\\root\\cimv2" ); + + hr = pIWbemLocator->ConnectServer( pNamespace, nullptr, nullptr, 0L, + 0L, nullptr, nullptr, &pIWbemServices ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: pIWbemLocator->ConnectServer failed: 0x%0.8x\n", hr ); +#endif + if( SUCCEEDED( hr ) && pIWbemServices != 0 ) + { + HINSTANCE hinstOle32 = nullptr; + + hinstOle32 = LoadLibraryW( L"ole32.dll" ); + if( hinstOle32 ) + { + PfnCoSetProxyBlanket pfnCoSetProxyBlanket = nullptr; + + pfnCoSetProxyBlanket = ( PfnCoSetProxyBlanket )GetProcAddress( hinstOle32, "CoSetProxyBlanket" ); + if( pfnCoSetProxyBlanket != 0 ) + { + // Switch security level to IMPERSONATE. + pfnCoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, + RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, 0 ); + } + + FreeLibrary( hinstOle32 ); + } + + IEnumWbemClassObject* pEnumVideoControllers = nullptr; + BSTR pClassName = nullptr; + + pClassName = SysAllocString( L"Win32_VideoController" ); + + hr = pIWbemServices->CreateInstanceEnum( pClassName, 0, + nullptr, &pEnumVideoControllers ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: pIWbemServices->CreateInstanceEnum failed: 0x%0.8x\n", hr ); +#endif + + if( SUCCEEDED( hr ) && pEnumVideoControllers ) + { + IWbemClassObject* pVideoControllers[10] = {0}; + DWORD uReturned = 0; + BSTR pPropName = nullptr; + + // Get the first one in the list + pEnumVideoControllers->Reset(); + hr = pEnumVideoControllers->Next( 5000, // timeout in 5 seconds + 10, // return the first 10 + pVideoControllers, + &uReturned ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) wprintf( L"WMI: pEnumVideoControllers->Next failed: 0x%0.8x\n", hr ); + if( uReturned == 0 ) wprintf( L"WMI: pEnumVideoControllers uReturned == 0\n" ); +#endif + + VARIANT var; + if( SUCCEEDED( hr ) ) + { + bool bFound = false; + for( UINT iController = 0; iController < uReturned; iController++ ) + { + if ( !pVideoControllers[iController] ) + continue; + + // if strInputDeviceID is set find this specific device and return memory or specific device + // if strInputDeviceID is not set return the best device + if (strInputDeviceID) + { + pPropName = SysAllocString( L"PNPDeviceID" ); + hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) + wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); +#endif + if( SUCCEEDED( hr ) && strInputDeviceID) + { + if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) + bFound = true; + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); + } + + if( bFound || !strInputDeviceID ) + { + pPropName = SysAllocString( L"AdapterRAM" ); + hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); +#ifdef PRINTF_DEBUGGING + if( FAILED( hr ) ) + wprintf( L"WMI: pVideoControllers[iController]->Get AdapterRAM failed: 0x%0.8x\n", + hr ); +#endif + if( SUCCEEDED( hr ) ) + { + bGotMemory = true; + *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam); + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); + } + + SAFE_RELEASE( pVideoControllers[iController] ); + + if (bFound) + { + break; + } + } + } + } + + if( pClassName ) + SysFreeString( pClassName ); + SAFE_RELEASE( pEnumVideoControllers ); + } + + if( pNamespace ) + SysFreeString( pNamespace ); + SAFE_RELEASE( pIWbemServices ); + } + + SAFE_RELEASE( pIWbemLocator ); + + CoUninitialize(); + + if( bGotMemory ) + return S_OK; + else + return E_FAIL; +} + +//static +S32 LLDXHardware::getMBVideoMemoryViaWMI() +{ + DWORD vram = 0; + if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram))) + { + return vram / (1024 * 1024);; + } + return 0; +} + +//Getting the version of graphics controller driver via WMI +std::string LLDXHardware::getDriverVersionWMI(EGPUVendor vendor) +{ + std::string mDriverVersion; + HRESULT hres; + CoInitializeEx(0, COINIT_APARTMENTTHREADED); + IWbemLocator *pLoc = NULL; + + hres = CoCreateInstance( + CLSID_WbemLocator, + 0, + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, (LPVOID *)&pLoc); + + if (FAILED(hres)) + { + LL_DEBUGS("AppInit") << "Failed to initialize COM library. Error code = 0x" << hres << LL_ENDL; + return std::string(); // Program has failed. + } + + IWbemServices *pSvc = NULL; + + // Connect to the root\cimv2 namespace with + // the current user and obtain pointer pSvc + // to make IWbemServices calls. + hres = pLoc->ConnectServer( + _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace + NULL, // User name. NULL = current user + NULL, // User password. NULL = current + 0, // Locale. NULL indicates current + NULL, // Security flags. + 0, // Authority (e.g. Kerberos) + 0, // Context object + &pSvc // pointer to IWbemServices proxy + ); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Could not connect. Error code = 0x" << hres << LL_ENDL; + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + LL_DEBUGS("AppInit") << "Connected to ROOT\\CIMV2 WMI namespace" << LL_ENDL; + + // Set security levels on the proxy ------------------------- + hres = CoSetProxyBlanket( + pSvc, // Indicates the proxy to set + RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx + RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx + NULL, // Server principal name + RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx + RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx + NULL, // client identity + EOAC_NONE // proxy capabilities + ); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Could not set proxy blanket. Error code = 0x" << hres << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + IEnumWbemClassObject* pEnumerator = NULL; + + // Get the data from the query + ULONG uReturn = 0; + hres = pSvc->ExecQuery( + bstr_t("WQL"), + bstr_t("SELECT * FROM Win32_VideoController"), //Consider using Availability to filter out disabled controllers + WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, + NULL, + &pEnumerator); + + if (FAILED(hres)) + { + LL_WARNS("AppInit") << "Query for operating system name failed." << " Error code = 0x" << hres << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + while (pEnumerator) + { + IWbemClassObject *pclsObj = NULL; + HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, + &pclsObj, &uReturn); + + if (0 == uReturn) + { + break; // If quantity less then 1. + } + + if (vendor != GPU_ANY) + { + VARIANT vtCaptionProp; + // Might be preferable to check "AdapterCompatibility" here instead of caption. + hr = pclsObj->Get(L"Caption", 0, &vtCaptionProp, 0, 0); + + if (FAILED(hr)) + { + LL_WARNS("AppInit") << "Query for Caption property failed." << " Error code = 0x" << hr << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + // use characters in the returned driver version + BSTR caption(vtCaptionProp.bstrVal); + + //convert BSTR to std::string + std::wstring ws(caption, SysStringLen(caption)); + std::string caption_str(ws.begin(), ws.end()); + LLStringUtil::toLower(caption_str); + + bool found = false; + switch (vendor) + { + case GPU_INTEL: + found = caption_str.find("intel") != std::string::npos; + break; + case GPU_NVIDIA: + found = caption_str.find("nvidia") != std::string::npos; + break; + case GPU_AMD: + found = caption_str.find("amd") != std::string::npos + || caption_str.find("ati ") != std::string::npos + || caption_str.find("radeon") != std::string::npos; + break; + default: + break; + } + + if (found) + { + VariantClear(&vtCaptionProp); + } + else + { + VariantClear(&vtCaptionProp); + pclsObj->Release(); + continue; + } + } + + VARIANT vtVersionProp; + + // Get the value of the DriverVersion property + hr = pclsObj->Get(L"DriverVersion", 0, &vtVersionProp, 0, 0); + + if (FAILED(hr)) + { + LL_WARNS("AppInit") << "Query for DriverVersion property failed." << " Error code = 0x" << hr << LL_ENDL; + pSvc->Release(); + pLoc->Release(); + CoUninitialize(); + return std::string(); // Program has failed. + } + + // use characters in the returned driver version + BSTR driverVersion(vtVersionProp.bstrVal); + + //convert BSTR to std::string + std::wstring ws(driverVersion, SysStringLen(driverVersion)); + std::string str(ws.begin(), ws.end()); + LL_INFOS("AppInit") << " DriverVersion : " << str << LL_ENDL; + + if (mDriverVersion.empty()) + { + mDriverVersion = str; + } + else if (mDriverVersion != str) + { + if (vendor == GPU_ANY) + { + // Expected from systems with gpus from different vendors + LL_INFOS("DriverVersion") << "Multiple video drivers detected. Version of second driver: " << str << LL_ENDL; + } + else + { + // Not Expected! + LL_WARNS("DriverVersion") << "Multiple video drivers detected from same vendor. Version of second driver : " << str << LL_ENDL; + } + } + + VariantClear(&vtVersionProp); + pclsObj->Release(); + } + + // Cleanup + // ======== + if (pSvc) + { + pSvc->Release(); + } + if (pLoc) + { + pLoc->Release(); + } + if (pEnumerator) + { + pEnumerator->Release(); + } + + // supposed to always call CoUninitialize even if init returned false + CoUninitialize(); + + return mDriverVersion; +} + +void get_wstring(IDxDiagContainer* containerp, WCHAR* wszPropName, WCHAR* wszPropValue, int outputSize) +{ + HRESULT hr; + VARIANT var; + + VariantInit( &var ); + hr = containerp->GetProp(wszPropName, &var ); + if( SUCCEEDED(hr) ) + { + // Switch off the type. There's 4 different types: + switch( var.vt ) + { + case VT_UI4: + swprintf( wszPropValue, L"%d", var.ulVal ); /* Flawfinder: ignore */ + break; + case VT_I4: + swprintf( wszPropValue, L"%d", var.lVal ); /* Flawfinder: ignore */ + break; + case VT_BOOL: + wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); /* Flawfinder: ignore */ + break; + case VT_BSTR: + wcsncpy( wszPropValue, var.bstrVal, outputSize-1 ); /* Flawfinder: ignore */ + wszPropValue[outputSize-1] = 0; + break; + } + } + // Clear the variant (this is needed to free BSTR memory) + VariantClear( &var ); +} + +std::string get_string(IDxDiagContainer *containerp, WCHAR *wszPropName) +{ + WCHAR wszPropValue[256]; + get_wstring(containerp, wszPropName, wszPropValue, 256); + + return utf16str_to_utf8str(wszPropValue); +} + + +LLVersion::LLVersion() +{ + mValid = false; + S32 i; + for (i = 0; i < 4; i++) + { + mFields[i] = 0; + } +} + +bool LLVersion::set(const std::string &version_string) +{ + S32 i; + for (i = 0; i < 4; i++) + { + mFields[i] = 0; + } + // Split the version string. + std::string str(version_string); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep(".", "", boost::keep_empty_tokens); + tokenizer tokens(str, sep); + + tokenizer::iterator iter = tokens.begin(); + S32 count = 0; + for (;(iter != tokens.end()) && (count < 4);++iter) + { + mFields[count] = atoi(iter->c_str()); + count++; + } + if (count < 4) + { + //LL_WARNS() << "Potentially bogus version string!" << version_string << LL_ENDL; + for (i = 0; i < 4; i++) + { + mFields[i] = 0; + } + mValid = false; + } + else + { + mValid = true; + } + return mValid; +} + +S32 LLVersion::getField(const S32 field_num) +{ + if (!mValid) + { + return -1; + } + else + { + return mFields[field_num]; + } +} + +std::string LLDXDriverFile::dump() +{ + if (gWriteDebug) + { + gWriteDebug("Filename:"); + gWriteDebug(mName.c_str()); + gWriteDebug("\n"); + gWriteDebug("Ver:"); + gWriteDebug(mVersionString.c_str()); + gWriteDebug("\n"); + gWriteDebug("Date:"); + gWriteDebug(mDateString.c_str()); + gWriteDebug("\n"); + } + LL_INFOS() << mFilepath << LL_ENDL; + LL_INFOS() << mName << LL_ENDL; + LL_INFOS() << mVersionString << LL_ENDL; + LL_INFOS() << mDateString << LL_ENDL; + + return ""; +} + +LLDXDevice::~LLDXDevice() +{ + for_each(mDriverFiles.begin(), mDriverFiles.end(), DeletePairedPointer()); + mDriverFiles.clear(); +} + +std::string LLDXDevice::dump() +{ + if (gWriteDebug) + { + gWriteDebug("StartDevice\n"); + gWriteDebug("DeviceName:"); + gWriteDebug(mName.c_str()); + gWriteDebug("\n"); + gWriteDebug("PCIString:"); + gWriteDebug(mPCIString.c_str()); + gWriteDebug("\n"); + } + LL_INFOS() << LL_ENDL; + LL_INFOS() << "DeviceName:" << mName << LL_ENDL; + LL_INFOS() << "PCIString:" << mPCIString << LL_ENDL; + LL_INFOS() << "Drivers" << LL_ENDL; + LL_INFOS() << "-------" << LL_ENDL; + for (driver_file_map_t::iterator iter = mDriverFiles.begin(), + end = mDriverFiles.end(); + iter != end; iter++) + { + LLDXDriverFile *filep = iter->second; + filep->dump(); + } + if (gWriteDebug) + { + gWriteDebug("EndDevice\n"); + } + + return ""; +} + +LLDXDriverFile *LLDXDevice::findDriver(const std::string &driver) +{ + for (driver_file_map_t::iterator iter = mDriverFiles.begin(), + end = mDriverFiles.end(); + iter != end; iter++) + { + LLDXDriverFile *filep = iter->second; + if (!utf8str_compare_insensitive(filep->mName,driver)) + { + return filep; + } + } + + return NULL; +} + +LLDXHardware::LLDXHardware() +{ + mVRAM = 0; + gWriteDebug = NULL; +} + +void LLDXHardware::cleanup() +{ + // for_each(mDevices.begin(), mDevices.end(), DeletePairedPointer()); + // mDevices.clear(); +} + +/* +std::string LLDXHardware::dumpDevices() +{ + if (gWriteDebug) + { + gWriteDebug("\n"); + gWriteDebug("StartAllDevices\n"); + } + for (device_map_t::iterator iter = mDevices.begin(), + end = mDevices.end(); + iter != end; iter++) + { + LLDXDevice *devicep = iter->second; + devicep->dump(); + } + if (gWriteDebug) + { + gWriteDebug("EndAllDevices\n\n"); + } + return ""; +} + +LLDXDevice *LLDXHardware::findDevice(const std::string &vendor, const std::string &devices) +{ + // Iterate through different devices tokenized in devices string + std::string str(devices); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("|", "", boost::keep_empty_tokens); + tokenizer tokens(str, sep); + + tokenizer::iterator iter = tokens.begin(); + for (;iter != tokens.end();++iter) + { + std::string dev_str = *iter; + for (device_map_t::iterator iter = mDevices.begin(), + end = mDevices.end(); + iter != end; iter++) + { + LLDXDevice *devicep = iter->second; + if ((devicep->mVendorID == vendor) + && (devicep->mDeviceID == dev_str)) + { + return devicep; + } + } + } + + return NULL; +} +*/ + +bool LLDXHardware::getInfo(bool vram_only) +{ + LLTimer hw_timer; + bool ok = false; + HRESULT hr; + + // CLSID_DxDiagProvider does not work with Multithreaded? + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + IDxDiagProvider *dx_diag_providerp = NULL; + IDxDiagContainer *dx_diag_rootp = NULL; + IDxDiagContainer *devices_containerp = NULL; + // IDxDiagContainer *system_device_containerp= NULL; + IDxDiagContainer *device_containerp = NULL; + IDxDiagContainer *file_containerp = NULL; + IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; + + mVRAM = 0; + + // CoCreate a IDxDiagProvider* + LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; + hr = CoCreateInstance(CLSID_DxDiagProvider, + NULL, + CLSCTX_INPROC_SERVER, + IID_IDxDiagProvider, + (LPVOID*) &dx_diag_providerp); + + if (FAILED(hr)) + { + LL_WARNS("AppInit") << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL; + gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); + goto LCleanup; + } + if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed + { + // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize + // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are + // digital signed as logo'd by WHQL which may connect via internet to update + // WHQL certificates. + DXDIAG_INIT_PARAMS dx_diag_init_params; + ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); + + dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); + dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; + dx_diag_init_params.bAllowWHQLChecks = TRUE; + dx_diag_init_params.pReserved = NULL; + + LL_DEBUGS("AppInit") << "dx_diag_providerp->Initialize" << LL_ENDL; + hr = dx_diag_providerp->Initialize(&dx_diag_init_params); + if(FAILED(hr)) + { + goto LCleanup; + } + + LL_DEBUGS("AppInit") << "dx_diag_providerp->GetRootContainer" << LL_ENDL; + hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); + if(FAILED(hr) || !dx_diag_rootp) + { + goto LCleanup; + } + + HRESULT hr; + + // Get display driver information + LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer" << LL_ENDL; + hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); + if(FAILED(hr) || !devices_containerp) + { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; + goto LCleanup; + } + + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + + // Get device 0 + // By default 0 device is the primary one, howhever in case of various hybrid graphics + // like itegrated AMD and PCI AMD GPUs system might switch. + LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; + hr = devices_containerp->GetChildContainer(L"0", &device_containerp); + if(FAILED(hr) || !device_containerp) + { + goto LCleanup; + } + + DWORD vram = 0; + + WCHAR deviceID[512]; + + get_wstring(device_containerp, L"szDeviceID", deviceID, 512); + // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06) + // doesn't seem to work on some systems since format is unrecognizable + // but in such case keyDeviceID works + if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) + { + mVRAM = vram/(1024*1024); + } + else + { + get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512); + LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL; + // '+9' to avoid ENUM\\PCI\\ prefix + // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS... + // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient + if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram))) + { + mVRAM = vram / (1024 * 1024); + } + } + + if (mVRAM == 0) + { // Get the English VRAM string + std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); + + // We don't need the device any more + SAFE_RELEASE(device_containerp); + + // Dump the string as an int into the structure + char *stopstring; + mVRAM = strtol(ram_str.c_str(), &stopstring, 10); + LL_INFOS("AppInit") << "VRAM Detected: " << mVRAM << " DX9 string: " << ram_str << LL_ENDL; + } + + if (vram_only) + { + ok = true; + goto LCleanup; + } + + + /* for now, we ONLY do vram_only the rest of this + is commented out, to ensure no-one is tempted + to use it + + // Now let's get device and driver information + // Get the IDxDiagContainer object called "DxDiag_SystemDevices". + // This call may take some time while dxdiag gathers the info. + DWORD num_devices = 0; + WCHAR wszContainer[256]; + LL_DEBUGS("AppInit") << "dx_diag_rootp->GetChildContainer DxDiag_SystemDevices" << LL_ENDL; + hr = dx_diag_rootp->GetChildContainer(L"DxDiag_SystemDevices", &system_device_containerp); + if (FAILED(hr)) + { + goto LCleanup; + } + + hr = system_device_containerp->GetNumberOfChildContainers(&num_devices); + if (FAILED(hr)) + { + goto LCleanup; + } + + LL_DEBUGS("AppInit") << "DX9 iterating over devices" << LL_ENDL; + S32 device_num = 0; + for (device_num = 0; device_num < (S32)num_devices; device_num++) + { + hr = system_device_containerp->EnumChildContainerNames(device_num, wszContainer, 256); + if (FAILED(hr)) + { + goto LCleanup; + } + + hr = system_device_containerp->GetChildContainer(wszContainer, &device_containerp); + if (FAILED(hr) || device_containerp == NULL) + { + goto LCleanup; + } + + std::string device_name = get_string(device_containerp, L"szDescription"); + + std::string device_id = get_string(device_containerp, L"szDeviceID"); + + LLDXDevice *dxdevicep = new LLDXDevice; + dxdevicep->mName = device_name; + dxdevicep->mPCIString = device_id; + mDevices[dxdevicep->mPCIString] = dxdevicep; + + // Split the PCI string based on vendor, device, subsys, rev. + std::string str(device_id); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("&\\", "", boost::keep_empty_tokens); + tokenizer tokens(str, sep); + + tokenizer::iterator iter = tokens.begin(); + S32 count = 0; + bool valid = true; + for (;(iter != tokens.end()) && (count < 3);++iter) + { + switch (count) + { + case 0: + if (strcmp(iter->c_str(), "PCI")) + { + valid = false; + } + break; + case 1: + dxdevicep->mVendorID = iter->c_str(); + break; + case 2: + dxdevicep->mDeviceID = iter->c_str(); + break; + default: + // Ignore it + break; + } + count++; + } + + + + + // Now, iterate through the related drivers + hr = device_containerp->GetChildContainer(L"Drivers", &driver_containerp); + if (FAILED(hr) || !driver_containerp) + { + goto LCleanup; + } + + DWORD num_files = 0; + hr = driver_containerp->GetNumberOfChildContainers(&num_files); + if (FAILED(hr)) + { + goto LCleanup; + } + + S32 file_num = 0; + for (file_num = 0; file_num < (S32)num_files; file_num++ ) + { + + hr = driver_containerp->EnumChildContainerNames(file_num, wszContainer, 256); + if (FAILED(hr)) + { + goto LCleanup; + } + + hr = driver_containerp->GetChildContainer(wszContainer, &file_containerp); + if (FAILED(hr) || file_containerp == NULL) + { + goto LCleanup; + } + + std::string driver_path = get_string(file_containerp, L"szPath"); + std::string driver_name = get_string(file_containerp, L"szName"); + std::string driver_version = get_string(file_containerp, L"szVersion"); + std::string driver_date = get_string(file_containerp, L"szDatestampEnglish"); + + LLDXDriverFile *dxdriverfilep = new LLDXDriverFile; + dxdriverfilep->mName = driver_name; + dxdriverfilep->mFilepath= driver_path; + dxdriverfilep->mVersionString = driver_version; + dxdriverfilep->mVersion.set(driver_version); + dxdriverfilep->mDateString = driver_date; + + dxdevicep->mDriverFiles[driver_name] = dxdriverfilep; + + SAFE_RELEASE(file_containerp); + } + SAFE_RELEASE(device_containerp); + } + */ + } + + // dumpDevices(); + ok = true; + +LCleanup: + if (!ok) + { + LL_WARNS("AppInit") << "DX9 probe failed" << LL_ENDL; + gWriteDebug("DX9 probe failed\n"); + } + + SAFE_RELEASE(file_containerp); + SAFE_RELEASE(driver_containerp); + SAFE_RELEASE(device_containerp); + SAFE_RELEASE(devices_containerp); + SAFE_RELEASE(dx_diag_rootp); + SAFE_RELEASE(dx_diag_providerp); + + CoUninitialize(); + + return ok; + } + +LLSD LLDXHardware::getDisplayInfo() +{ + LLTimer hw_timer; + HRESULT hr; + LLSD ret; + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + IDxDiagProvider *dx_diag_providerp = NULL; + IDxDiagContainer *dx_diag_rootp = NULL; + IDxDiagContainer *devices_containerp = NULL; + IDxDiagContainer *device_containerp = NULL; + IDxDiagContainer *file_containerp = NULL; + IDxDiagContainer *driver_containerp = NULL; + DWORD dw_device_count; + + // CoCreate a IDxDiagProvider* + LL_INFOS() << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; + hr = CoCreateInstance(CLSID_DxDiagProvider, + NULL, + CLSCTX_INPROC_SERVER, + IID_IDxDiagProvider, + (LPVOID*) &dx_diag_providerp); + + if (FAILED(hr)) + { + LL_WARNS() << "No DXDiag provider found! DirectX 9 not installed!" << LL_ENDL; + gWriteDebug("No DXDiag provider found! DirectX 9 not installed!\n"); + goto LCleanup; + } + if (SUCCEEDED(hr)) // if FAILED(hr) then dx9 is not installed + { + // Fill out a DXDIAG_INIT_PARAMS struct and pass it to IDxDiagContainer::Initialize + // Passing in TRUE for bAllowWHQLChecks, allows dxdiag to check if drivers are + // digital signed as logo'd by WHQL which may connect via internet to update + // WHQL certificates. + DXDIAG_INIT_PARAMS dx_diag_init_params; + ZeroMemory(&dx_diag_init_params, sizeof(DXDIAG_INIT_PARAMS)); + + dx_diag_init_params.dwSize = sizeof(DXDIAG_INIT_PARAMS); + dx_diag_init_params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; + dx_diag_init_params.bAllowWHQLChecks = TRUE; + dx_diag_init_params.pReserved = NULL; + + LL_INFOS() << "dx_diag_providerp->Initialize" << LL_ENDL; + hr = dx_diag_providerp->Initialize(&dx_diag_init_params); + if(FAILED(hr)) + { + goto LCleanup; + } + + LL_INFOS() << "dx_diag_providerp->GetRootContainer" << LL_ENDL; + hr = dx_diag_providerp->GetRootContainer( &dx_diag_rootp ); + if(FAILED(hr) || !dx_diag_rootp) + { + goto LCleanup; + } + + HRESULT hr; + + // Get display driver information + LL_INFOS() << "dx_diag_rootp->GetChildContainer" << LL_ENDL; + hr = dx_diag_rootp->GetChildContainer(L"DxDiag_DisplayDevices", &devices_containerp); + if(FAILED(hr) || !devices_containerp) + { + // do not release 'dirty' devices_containerp at this stage, only dx_diag_rootp + devices_containerp = NULL; + goto LCleanup; + } + + // make sure there is something inside + hr = devices_containerp->GetNumberOfChildContainers(&dw_device_count); + if (FAILED(hr) || dw_device_count == 0) + { + goto LCleanup; + } + + // Get device 0 + LL_INFOS() << "devices_containerp->GetChildContainer" << LL_ENDL; + hr = devices_containerp->GetChildContainer(L"0", &device_containerp); + if(FAILED(hr) || !device_containerp) + { + goto LCleanup; + } + + // Get the English VRAM string + std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); + + + // Dump the string as an int into the structure + char *stopstring; + ret["VRAM"] = strtol(ram_str.c_str(), &stopstring, 10); + std::string device_name = get_string(device_containerp, L"szDescription"); + ret["DeviceName"] = device_name; + std::string device_driver= get_string(device_containerp, L"szDriverVersion"); + ret["DriverVersion"] = device_driver; + + // ATI has a slightly different version string + if(device_name.length() >= 4 && device_name.substr(0,4) == "ATI ") + { + // get the key + HKEY hKey; + const DWORD RV_SIZE = 100; + WCHAR release_version[RV_SIZE]; + + // Hard coded registry entry. Using this since it's simpler for now. + // And using EnumDisplayDevices to get a registry key also requires + // a hard coded Query value. + if(ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\ATI Technologies\\CBT"), &hKey)) + { + // get the value + DWORD dwType = REG_SZ; + DWORD dwSize = sizeof(WCHAR) * RV_SIZE; + if(ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("ReleaseVersion"), + NULL, &dwType, (LPBYTE)release_version, &dwSize)) + { + // print the value + // windows doesn't guarantee to be null terminated + release_version[RV_SIZE - 1] = NULL; + ret["DriverVersion"] = utf16str_to_utf8str(release_version); + + } + RegCloseKey(hKey); + } + } + } + +LCleanup: + if (!ret.isMap() || (ret.size() == 0)) + { + LL_INFOS() << "Failed to get data, cleaning up" << LL_ENDL; + } + SAFE_RELEASE(file_containerp); + SAFE_RELEASE(driver_containerp); + SAFE_RELEASE(device_containerp); + SAFE_RELEASE(devices_containerp); + SAFE_RELEASE(dx_diag_rootp); + SAFE_RELEASE(dx_diag_providerp); + + CoUninitialize(); + return ret; +} + +void LLDXHardware::setWriteDebugFunc(void (*func)(const char*)) +{ + gWriteDebug = func; +} + +#endif diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index 54447a87b3..aaefc6ae8c 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -1,126 +1,126 @@ -/** - * @file lldxhardware.h - * @brief LLDXHardware definition - * - * $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$ - */ - -#ifndef LL_LLDXHARDWARE_H -#define LL_LLDXHARDWARE_H - -#include - -#include "stdtypes.h" -#include "llstring.h" -#include "llsd.h" - -class LLVersion -{ -public: - LLVersion(); - bool set(const std::string &version_string); - S32 getField(const S32 field_num); -protected: - std::string mVersionString; - S32 mFields[4]; - bool mValid; -}; - -class LLDXDriverFile -{ -public: - std::string dump(); - -public: - std::string mFilepath; - std::string mName; - std::string mVersionString; - LLVersion mVersion; - std::string mDateString; -}; - -class LLDXDevice -{ -public: - ~LLDXDevice(); - std::string dump(); - - LLDXDriverFile *findDriver(const std::string &driver); -public: - std::string mName; - std::string mPCIString; - std::string mVendorID; - std::string mDeviceID; - - typedef std::map driver_file_map_t; - driver_file_map_t mDriverFiles; -}; - - -class LLDXHardware -{ -public: - LLDXHardware(); - - void setWriteDebugFunc(void (*func)(const char*)); - void cleanup(); - - // Returns true on success. - // vram_only true does a "light" probe. - bool getInfo(bool vram_only); - - // WMI can return multiple GPU drivers - // specify which one to output - typedef enum { - GPU_INTEL, - GPU_NVIDIA, - GPU_AMD, - GPU_ANY - } EGPUVendor; - std::string getDriverVersionWMI(EGPUVendor vendor); - - S32 getVRAM() const { return mVRAM; } - - LLSD getDisplayInfo(); - - // Will get memory of best GPU in MB, return memory on sucsess, 0 on failure - // Note: WMI is not accurate in some cases - static S32 getMBVideoMemoryViaWMI(); - - // Find a particular device that matches the following specs. - // Empty strings indicate that you don't care. - // You can separate multiple devices with '|' chars to indicate you want - // ANY of them to match and return. - // LLDXDevice *findDevice(const std::string &vendor, const std::string &devices); - - // std::string dumpDevices(); -public: - typedef std::map device_map_t; - // device_map_t mDevices; -protected: - S32 mVRAM; -}; - -extern void (*gWriteDebug)(const char* msg); -extern LLDXHardware gDXHardware; - -#endif // LL_LLDXHARDWARE_H +/** + * @file lldxhardware.h + * @brief LLDXHardware definition + * + * $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$ + */ + +#ifndef LL_LLDXHARDWARE_H +#define LL_LLDXHARDWARE_H + +#include + +#include "stdtypes.h" +#include "llstring.h" +#include "llsd.h" + +class LLVersion +{ +public: + LLVersion(); + bool set(const std::string &version_string); + S32 getField(const S32 field_num); +protected: + std::string mVersionString; + S32 mFields[4]; + bool mValid; +}; + +class LLDXDriverFile +{ +public: + std::string dump(); + +public: + std::string mFilepath; + std::string mName; + std::string mVersionString; + LLVersion mVersion; + std::string mDateString; +}; + +class LLDXDevice +{ +public: + ~LLDXDevice(); + std::string dump(); + + LLDXDriverFile *findDriver(const std::string &driver); +public: + std::string mName; + std::string mPCIString; + std::string mVendorID; + std::string mDeviceID; + + typedef std::map driver_file_map_t; + driver_file_map_t mDriverFiles; +}; + + +class LLDXHardware +{ +public: + LLDXHardware(); + + void setWriteDebugFunc(void (*func)(const char*)); + void cleanup(); + + // Returns true on success. + // vram_only true does a "light" probe. + bool getInfo(bool vram_only); + + // WMI can return multiple GPU drivers + // specify which one to output + typedef enum { + GPU_INTEL, + GPU_NVIDIA, + GPU_AMD, + GPU_ANY + } EGPUVendor; + std::string getDriverVersionWMI(EGPUVendor vendor); + + S32 getVRAM() const { return mVRAM; } + + LLSD getDisplayInfo(); + + // Will get memory of best GPU in MB, return memory on sucsess, 0 on failure + // Note: WMI is not accurate in some cases + static S32 getMBVideoMemoryViaWMI(); + + // Find a particular device that matches the following specs. + // Empty strings indicate that you don't care. + // You can separate multiple devices with '|' chars to indicate you want + // ANY of them to match and return. + // LLDXDevice *findDevice(const std::string &vendor, const std::string &devices); + + // std::string dumpDevices(); +public: + typedef std::map device_map_t; + // device_map_t mDevices; +protected: + S32 mVRAM; +}; + +extern void (*gWriteDebug)(const char* msg); +extern LLDXHardware gDXHardware; + +#endif // LL_LLDXHARDWARE_H diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index 361666d1c5..4f29fb0b0a 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -1,543 +1,543 @@ -/** - * @file llkeyboard.cpp - * @brief Handler for assignable key bindings - * - * $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 "indra_constants.h" -#include "llkeyboard.h" - -#include "llwindowcallbacks.h" - -// -// Globals -// - -LLKeyboard *gKeyboard = NULL; - -//static -std::map LLKeyboard::sKeysToNames; -std::map LLKeyboard::sNamesToKeys; -LLKeyStringTranslatorFunc* LLKeyboard::mStringTranslator = NULL; // Used for l10n + PC/Mac/Linux accelerator labeling - - -// -// Class Implementation -// - -LLKeyboard::LLKeyboard() : mCallbacks(NULL) -{ - S32 i; - - // Constructor for LLTimer inits each timer. We want them to - // be constructed without being initialized, so we shut them down here. - for (i = 0; i < KEY_COUNT; i++) - { - mKeyLevelFrameCount[i] = 0; - mKeyLevel[i] = false; - mKeyUp[i] = false; - mKeyDown[i] = false; - mKeyRepeated[i] = false; - } - - mInsertMode = LL_KIM_INSERT; - mCurTranslatedKey = KEY_NONE; - mCurScanKey = KEY_NONE; - - addKeyName(' ', "Space" ); - addKeyName(KEY_RETURN, "Enter" ); - addKeyName(KEY_LEFT, "Left" ); - addKeyName(KEY_RIGHT, "Right" ); - addKeyName(KEY_UP, "Up" ); - addKeyName(KEY_DOWN, "Down" ); - addKeyName(KEY_ESCAPE, "Esc" ); - addKeyName(KEY_HOME, "Home" ); - addKeyName(KEY_END, "End" ); - addKeyName(KEY_PAGE_UP, "PgUp" ); - addKeyName(KEY_PAGE_DOWN, "PgDn" ); - addKeyName(KEY_F1, "F1" ); - addKeyName(KEY_F2, "F2" ); - addKeyName(KEY_F3, "F3" ); - addKeyName(KEY_F4, "F4" ); - addKeyName(KEY_F5, "F5" ); - addKeyName(KEY_F6, "F6" ); - addKeyName(KEY_F7, "F7" ); - addKeyName(KEY_F8, "F8" ); - addKeyName(KEY_F9, "F9" ); - addKeyName(KEY_F10, "F10" ); - addKeyName(KEY_F11, "F11" ); - addKeyName(KEY_F12, "F12" ); - addKeyName(KEY_TAB, "Tab" ); - addKeyName(KEY_ADD, "Add" ); - addKeyName(KEY_SUBTRACT, "Subtract" ); - addKeyName(KEY_MULTIPLY, "Multiply" ); - addKeyName(KEY_DIVIDE, "Divide" ); - addKeyName(KEY_PAD_DIVIDE, "PAD_DIVIDE" ); - addKeyName(KEY_PAD_LEFT, "PAD_LEFT" ); - addKeyName(KEY_PAD_RIGHT, "PAD_RIGHT" ); - addKeyName(KEY_PAD_DOWN, "PAD_DOWN" ); - addKeyName(KEY_PAD_UP, "PAD_UP" ); - addKeyName(KEY_PAD_HOME, "PAD_HOME" ); - addKeyName(KEY_PAD_END, "PAD_END" ); - addKeyName(KEY_PAD_PGUP, "PAD_PGUP" ); - addKeyName(KEY_PAD_PGDN, "PAD_PGDN" ); - addKeyName(KEY_PAD_CENTER, "PAD_CENTER" ); - addKeyName(KEY_PAD_INS, "PAD_INS" ); - addKeyName(KEY_PAD_DEL, "PAD_DEL" ); - addKeyName(KEY_PAD_RETURN, "PAD_Enter" ); - addKeyName(KEY_BUTTON0, "PAD_BUTTON0" ); - addKeyName(KEY_BUTTON1, "PAD_BUTTON1" ); - addKeyName(KEY_BUTTON2, "PAD_BUTTON2" ); - addKeyName(KEY_BUTTON3, "PAD_BUTTON3" ); - addKeyName(KEY_BUTTON4, "PAD_BUTTON4" ); - addKeyName(KEY_BUTTON5, "PAD_BUTTON5" ); - addKeyName(KEY_BUTTON6, "PAD_BUTTON6" ); - addKeyName(KEY_BUTTON7, "PAD_BUTTON7" ); - addKeyName(KEY_BUTTON8, "PAD_BUTTON8" ); - addKeyName(KEY_BUTTON9, "PAD_BUTTON9" ); - addKeyName(KEY_BUTTON10, "PAD_BUTTON10" ); - addKeyName(KEY_BUTTON11, "PAD_BUTTON11" ); - addKeyName(KEY_BUTTON12, "PAD_BUTTON12" ); - addKeyName(KEY_BUTTON13, "PAD_BUTTON13" ); - addKeyName(KEY_BUTTON14, "PAD_BUTTON14" ); - addKeyName(KEY_BUTTON15, "PAD_BUTTON15" ); - - addKeyName(KEY_BACKSPACE, "Backsp" ); - addKeyName(KEY_DELETE, "Del" ); - addKeyName(KEY_SHIFT, "Shift" ); - addKeyName(KEY_CONTROL, "Ctrl" ); - addKeyName(KEY_ALT, "Alt" ); - addKeyName(KEY_HYPHEN, "-" ); - addKeyName(KEY_EQUALS, "=" ); - addKeyName(KEY_INSERT, "Ins" ); - addKeyName(KEY_CAPSLOCK, "CapsLock" ); -} - - -LLKeyboard::~LLKeyboard() -{ - // nothing -} - -void LLKeyboard::addKeyName(KEY key, const std::string& name) -{ - sKeysToNames[key] = name; - std::string nameuc = name; - LLStringUtil::toUpper(nameuc); - sNamesToKeys[nameuc] = key; -} - -void LLKeyboard::resetKeyDownAndHandle() -{ - MASK mask = currentMask(false); - for (S32 i = 0; i < KEY_COUNT; i++) - { - if (mKeyLevel[i]) - { - mKeyDown[i] = false; - mKeyLevel[i] = false; - mKeyUp[i] = true; - mCurTranslatedKey = (KEY)i; - mCallbacks->handleTranslatedKeyUp(i, mask); - } - } -} - -// BUG this has to be called when an OS dialog is shown, otherwise modifier key state -// is wrong because the keyup event is never received by the main window. JC -void LLKeyboard::resetKeys() -{ - S32 i; - - for (i = 0; i < KEY_COUNT; i++) - { - if( mKeyLevel[i] ) - { - mKeyLevel[i] = false; - } - } - - for (i = 0; i < KEY_COUNT; i++) - { - mKeyUp[i] = false; - } - - for (i = 0; i < KEY_COUNT; i++) - { - mKeyDown[i] = false; - } - - for (i = 0; i < KEY_COUNT; i++) - { - mKeyRepeated[i] = false; - } -} - - -bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) -{ - std::map::iterator iter; - - // Only translate keys in the map, ignore all other keys for now - iter = mTranslateKeyMap.find(os_key); - if (iter == mTranslateKeyMap.end()) - { - //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; - *out_key = 0; - return false; - } - else - { - *out_key = iter->second; - return true; - } -} - - -U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) -{ - std::map::iterator iter; - iter = mInvTranslateKeyMap.find(translated_key); - if (iter == mInvTranslateKeyMap.end()) - { - return 0; - } - else - { - return iter->second; - } -} - - -bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) -{ - bool handled = false; - bool repeated = false; - - // is this the first time the key went down? - // if so, generate "character" message - if( !mKeyLevel[translated_key] ) - { - mKeyLevel[translated_key] = true; - mKeyLevelTimer[translated_key].reset(); - mKeyLevelFrameCount[translated_key] = 0; - mKeyRepeated[translated_key] = false; - } - else - { - // Level is already down, assume it's repeated. - repeated = true; - mKeyRepeated[translated_key] = true; - } - - mKeyDown[translated_key] = true; - mCurTranslatedKey = (KEY)translated_key; - handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated); - return handled; -} - - -bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) -{ - bool handled = false; - if( mKeyLevel[translated_key] ) - { - mKeyLevel[translated_key] = false; - - // Only generate key up events if the key is thought to - // be down. This allows you to call resetKeys() in the - // middle of a frame and ignore subsequent KEY_UP - // messages in the same frame. This was causing the - // sequence W in chat to move agents forward. JC - mKeyUp[translated_key] = true; - handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask); - } - - LL_DEBUGS("UserInput") << "keyup -" << translated_key << "-" << LL_ENDL; - - return handled; -} - - -void LLKeyboard::toggleInsertMode() -{ - if (LL_KIM_INSERT == mInsertMode) - { - mInsertMode = LL_KIM_OVERWRITE; - } - else - { - mInsertMode = LL_KIM_INSERT; - } -} - - -// Returns time in seconds since key was pressed. -F32 LLKeyboard::getKeyElapsedTime(KEY key) -{ - return mKeyLevelTimer[key].getElapsedTimeF32(); -} - -// Returns time in frames since key was pressed. -S32 LLKeyboard::getKeyElapsedFrameCount(KEY key) -{ - return mKeyLevelFrameCount[key]; -} - -// static -bool LLKeyboard::keyFromString(const std::string& str, KEY *key) -{ - std::string instring(str); - size_t length = instring.size(); - - if (length < 1) - { - return false; - } - if (length == 1) - { - char ch = toupper(instring[0]); - if (('0' <= ch && ch <= '9') || - ('A' <= ch && ch <= 'Z') || - ('!' <= ch && ch <= '/') || // !"#$%&'()*+,-./ - (':' <= ch && ch <= '@') || // :;<=>?@ - ('[' <= ch && ch <= '`') || // [\]^_` - ('{' <= ch && ch <= '~')) // {|}~ - { - *key = ch; - return true; - } - } - - LLStringUtil::toUpper(instring); - KEY res = get_if_there(sNamesToKeys, instring, (KEY)0); - if (res != 0) - { - *key = res; - return true; - } - LL_WARNS() << "keyFromString failed: " << str << LL_ENDL; - return false; -} - - -// static -std::string LLKeyboard::stringFromKey(KEY key, bool translate) -{ - std::string res = get_if_there(sKeysToNames, key, std::string()); - if (res.empty()) - { - char buffer[2]; /* Flawfinder: ignore */ - buffer[0] = key; - buffer[1] = '\0'; - res = std::string(buffer); - } - - if (translate) - { - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - if (trans != NULL) - { - res = trans(res.c_str()); - } - } - - return res; -} - -//static -std::string LLKeyboard::stringFromMouse(EMouseClickType click, bool translate) -{ - std::string res; - switch (click) - { - case CLICK_LEFT: - res = "LMB"; - break; - case CLICK_MIDDLE: - res = "MMB"; - break; - case CLICK_RIGHT: - res = "RMB"; - break; - case CLICK_BUTTON4: - res = "MB4"; - break; - case CLICK_BUTTON5: - res = "MB5"; - break; - case CLICK_DOUBLELEFT: - res = "Double LMB"; - break; - default: - break; - } - - if (translate && !res.empty()) - { - LLKeyStringTranslatorFunc* trans = gKeyboard->mStringTranslator; - if (trans != NULL) - { - res = trans(res.c_str()); - } - } - return res; -} - -//static -std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) -{ - std::string res; - - LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; - - if (trans == NULL) - { - LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; - return res; - } - - // Append any masks -#ifdef LL_DARWIN - // Standard Mac names for modifier keys in menu equivalents - // We could use the symbol characters, but they only exist in certain fonts. - if (accel_mask & MASK_CONTROL) - { - if (accel_mask & MASK_MAC_CONTROL) - { - res.append(trans("accel-mac-control")); - } - else - { - res.append(trans("accel-mac-command")); // Symbol would be "\xE2\x8C\x98" - } - } - if (accel_mask & MASK_ALT) - res.append(trans("accel-mac-option")); // Symbol would be "\xE2\x8C\xA5" - if (accel_mask & MASK_SHIFT) - res.append(trans("accel-mac-shift")); // Symbol would be "\xE2\x8C\xA7" -#else - if (accel_mask & MASK_CONTROL) - res.append(trans("accel-win-control")); - if (accel_mask & MASK_ALT) - res.append(trans("accel-win-alt")); - if (accel_mask & MASK_SHIFT) - res.append(trans("accel-win-shift")); -#endif - return res; -} -//static -std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) -{ - std::string res; - - // break early if this is a silly thing to do. - if( KEY_NONE == key ) - { - return res; - } - - res.append(stringFromAccelerator(accel_mask)); - std::string key_string = LLKeyboard::stringFromKey(key); - if ((accel_mask & MASK_NORMALKEYS) && - (key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+')) - { - res.append( " " ); - } - - std::string keystr = stringFromKey( key ); - res.append( keystr ); - - return res; -} - -//static -std::string LLKeyboard::stringFromAccelerator(MASK accel_mask, EMouseClickType click) -{ - std::string res; - if (CLICK_NONE == click) - { - return res; - } - res.append(stringFromAccelerator(accel_mask)); - res.append(stringFromMouse(click)); - return res; -} - -//static -bool LLKeyboard::maskFromString(const std::string& str, MASK *mask) -{ - std::string instring(str); - if (instring == "NONE") - { - *mask = MASK_NONE; - return true; - } - else if (instring == "SHIFT") - { - *mask = MASK_SHIFT; - return true; - } - else if (instring == "CTL") - { - *mask = MASK_CONTROL; - return true; - } - else if (instring == "ALT") - { - *mask = MASK_ALT; - return true; - } - else if (instring == "CTL_SHIFT") - { - *mask = MASK_CONTROL | MASK_SHIFT; - return true; - } - else if (instring == "ALT_SHIFT") - { - *mask = MASK_ALT | MASK_SHIFT; - return true; - } - else if (instring == "CTL_ALT") - { - *mask = MASK_CONTROL | MASK_ALT; - return true; - } - else if (instring == "CTL_ALT_SHIFT") - { - *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT; - return true; - } - else - { - return false; - } -} - - -//static -void LLKeyboard::setStringTranslatorFunc( LLKeyStringTranslatorFunc *trans_func ) -{ - mStringTranslator = trans_func; -} +/** + * @file llkeyboard.cpp + * @brief Handler for assignable key bindings + * + * $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 "indra_constants.h" +#include "llkeyboard.h" + +#include "llwindowcallbacks.h" + +// +// Globals +// + +LLKeyboard *gKeyboard = NULL; + +//static +std::map LLKeyboard::sKeysToNames; +std::map LLKeyboard::sNamesToKeys; +LLKeyStringTranslatorFunc* LLKeyboard::mStringTranslator = NULL; // Used for l10n + PC/Mac/Linux accelerator labeling + + +// +// Class Implementation +// + +LLKeyboard::LLKeyboard() : mCallbacks(NULL) +{ + S32 i; + + // Constructor for LLTimer inits each timer. We want them to + // be constructed without being initialized, so we shut them down here. + for (i = 0; i < KEY_COUNT; i++) + { + mKeyLevelFrameCount[i] = 0; + mKeyLevel[i] = false; + mKeyUp[i] = false; + mKeyDown[i] = false; + mKeyRepeated[i] = false; + } + + mInsertMode = LL_KIM_INSERT; + mCurTranslatedKey = KEY_NONE; + mCurScanKey = KEY_NONE; + + addKeyName(' ', "Space" ); + addKeyName(KEY_RETURN, "Enter" ); + addKeyName(KEY_LEFT, "Left" ); + addKeyName(KEY_RIGHT, "Right" ); + addKeyName(KEY_UP, "Up" ); + addKeyName(KEY_DOWN, "Down" ); + addKeyName(KEY_ESCAPE, "Esc" ); + addKeyName(KEY_HOME, "Home" ); + addKeyName(KEY_END, "End" ); + addKeyName(KEY_PAGE_UP, "PgUp" ); + addKeyName(KEY_PAGE_DOWN, "PgDn" ); + addKeyName(KEY_F1, "F1" ); + addKeyName(KEY_F2, "F2" ); + addKeyName(KEY_F3, "F3" ); + addKeyName(KEY_F4, "F4" ); + addKeyName(KEY_F5, "F5" ); + addKeyName(KEY_F6, "F6" ); + addKeyName(KEY_F7, "F7" ); + addKeyName(KEY_F8, "F8" ); + addKeyName(KEY_F9, "F9" ); + addKeyName(KEY_F10, "F10" ); + addKeyName(KEY_F11, "F11" ); + addKeyName(KEY_F12, "F12" ); + addKeyName(KEY_TAB, "Tab" ); + addKeyName(KEY_ADD, "Add" ); + addKeyName(KEY_SUBTRACT, "Subtract" ); + addKeyName(KEY_MULTIPLY, "Multiply" ); + addKeyName(KEY_DIVIDE, "Divide" ); + addKeyName(KEY_PAD_DIVIDE, "PAD_DIVIDE" ); + addKeyName(KEY_PAD_LEFT, "PAD_LEFT" ); + addKeyName(KEY_PAD_RIGHT, "PAD_RIGHT" ); + addKeyName(KEY_PAD_DOWN, "PAD_DOWN" ); + addKeyName(KEY_PAD_UP, "PAD_UP" ); + addKeyName(KEY_PAD_HOME, "PAD_HOME" ); + addKeyName(KEY_PAD_END, "PAD_END" ); + addKeyName(KEY_PAD_PGUP, "PAD_PGUP" ); + addKeyName(KEY_PAD_PGDN, "PAD_PGDN" ); + addKeyName(KEY_PAD_CENTER, "PAD_CENTER" ); + addKeyName(KEY_PAD_INS, "PAD_INS" ); + addKeyName(KEY_PAD_DEL, "PAD_DEL" ); + addKeyName(KEY_PAD_RETURN, "PAD_Enter" ); + addKeyName(KEY_BUTTON0, "PAD_BUTTON0" ); + addKeyName(KEY_BUTTON1, "PAD_BUTTON1" ); + addKeyName(KEY_BUTTON2, "PAD_BUTTON2" ); + addKeyName(KEY_BUTTON3, "PAD_BUTTON3" ); + addKeyName(KEY_BUTTON4, "PAD_BUTTON4" ); + addKeyName(KEY_BUTTON5, "PAD_BUTTON5" ); + addKeyName(KEY_BUTTON6, "PAD_BUTTON6" ); + addKeyName(KEY_BUTTON7, "PAD_BUTTON7" ); + addKeyName(KEY_BUTTON8, "PAD_BUTTON8" ); + addKeyName(KEY_BUTTON9, "PAD_BUTTON9" ); + addKeyName(KEY_BUTTON10, "PAD_BUTTON10" ); + addKeyName(KEY_BUTTON11, "PAD_BUTTON11" ); + addKeyName(KEY_BUTTON12, "PAD_BUTTON12" ); + addKeyName(KEY_BUTTON13, "PAD_BUTTON13" ); + addKeyName(KEY_BUTTON14, "PAD_BUTTON14" ); + addKeyName(KEY_BUTTON15, "PAD_BUTTON15" ); + + addKeyName(KEY_BACKSPACE, "Backsp" ); + addKeyName(KEY_DELETE, "Del" ); + addKeyName(KEY_SHIFT, "Shift" ); + addKeyName(KEY_CONTROL, "Ctrl" ); + addKeyName(KEY_ALT, "Alt" ); + addKeyName(KEY_HYPHEN, "-" ); + addKeyName(KEY_EQUALS, "=" ); + addKeyName(KEY_INSERT, "Ins" ); + addKeyName(KEY_CAPSLOCK, "CapsLock" ); +} + + +LLKeyboard::~LLKeyboard() +{ + // nothing +} + +void LLKeyboard::addKeyName(KEY key, const std::string& name) +{ + sKeysToNames[key] = name; + std::string nameuc = name; + LLStringUtil::toUpper(nameuc); + sNamesToKeys[nameuc] = key; +} + +void LLKeyboard::resetKeyDownAndHandle() +{ + MASK mask = currentMask(false); + for (S32 i = 0; i < KEY_COUNT; i++) + { + if (mKeyLevel[i]) + { + mKeyDown[i] = false; + mKeyLevel[i] = false; + mKeyUp[i] = true; + mCurTranslatedKey = (KEY)i; + mCallbacks->handleTranslatedKeyUp(i, mask); + } + } +} + +// BUG this has to be called when an OS dialog is shown, otherwise modifier key state +// is wrong because the keyup event is never received by the main window. JC +void LLKeyboard::resetKeys() +{ + S32 i; + + for (i = 0; i < KEY_COUNT; i++) + { + if( mKeyLevel[i] ) + { + mKeyLevel[i] = false; + } + } + + for (i = 0; i < KEY_COUNT; i++) + { + mKeyUp[i] = false; + } + + for (i = 0; i < KEY_COUNT; i++) + { + mKeyDown[i] = false; + } + + for (i = 0; i < KEY_COUNT; i++) + { + mKeyRepeated[i] = false; + } +} + + +bool LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +{ + std::map::iterator iter; + + // Only translate keys in the map, ignore all other keys for now + iter = mTranslateKeyMap.find(os_key); + if (iter == mTranslateKeyMap.end()) + { + //LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; + *out_key = 0; + return false; + } + else + { + *out_key = iter->second; + return true; + } +} + + +U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +{ + std::map::iterator iter; + iter = mInvTranslateKeyMap.find(translated_key); + if (iter == mInvTranslateKeyMap.end()) + { + return 0; + } + else + { + return iter->second; + } +} + + +bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask) +{ + bool handled = false; + bool repeated = false; + + // is this the first time the key went down? + // if so, generate "character" message + if( !mKeyLevel[translated_key] ) + { + mKeyLevel[translated_key] = true; + mKeyLevelTimer[translated_key].reset(); + mKeyLevelFrameCount[translated_key] = 0; + mKeyRepeated[translated_key] = false; + } + else + { + // Level is already down, assume it's repeated. + repeated = true; + mKeyRepeated[translated_key] = true; + } + + mKeyDown[translated_key] = true; + mCurTranslatedKey = (KEY)translated_key; + handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated); + return handled; +} + + +bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask) +{ + bool handled = false; + if( mKeyLevel[translated_key] ) + { + mKeyLevel[translated_key] = false; + + // Only generate key up events if the key is thought to + // be down. This allows you to call resetKeys() in the + // middle of a frame and ignore subsequent KEY_UP + // messages in the same frame. This was causing the + // sequence W in chat to move agents forward. JC + mKeyUp[translated_key] = true; + handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask); + } + + LL_DEBUGS("UserInput") << "keyup -" << translated_key << "-" << LL_ENDL; + + return handled; +} + + +void LLKeyboard::toggleInsertMode() +{ + if (LL_KIM_INSERT == mInsertMode) + { + mInsertMode = LL_KIM_OVERWRITE; + } + else + { + mInsertMode = LL_KIM_INSERT; + } +} + + +// Returns time in seconds since key was pressed. +F32 LLKeyboard::getKeyElapsedTime(KEY key) +{ + return mKeyLevelTimer[key].getElapsedTimeF32(); +} + +// Returns time in frames since key was pressed. +S32 LLKeyboard::getKeyElapsedFrameCount(KEY key) +{ + return mKeyLevelFrameCount[key]; +} + +// static +bool LLKeyboard::keyFromString(const std::string& str, KEY *key) +{ + std::string instring(str); + size_t length = instring.size(); + + if (length < 1) + { + return false; + } + if (length == 1) + { + char ch = toupper(instring[0]); + if (('0' <= ch && ch <= '9') || + ('A' <= ch && ch <= 'Z') || + ('!' <= ch && ch <= '/') || // !"#$%&'()*+,-./ + (':' <= ch && ch <= '@') || // :;<=>?@ + ('[' <= ch && ch <= '`') || // [\]^_` + ('{' <= ch && ch <= '~')) // {|}~ + { + *key = ch; + return true; + } + } + + LLStringUtil::toUpper(instring); + KEY res = get_if_there(sNamesToKeys, instring, (KEY)0); + if (res != 0) + { + *key = res; + return true; + } + LL_WARNS() << "keyFromString failed: " << str << LL_ENDL; + return false; +} + + +// static +std::string LLKeyboard::stringFromKey(KEY key, bool translate) +{ + std::string res = get_if_there(sKeysToNames, key, std::string()); + if (res.empty()) + { + char buffer[2]; /* Flawfinder: ignore */ + buffer[0] = key; + buffer[1] = '\0'; + res = std::string(buffer); + } + + if (translate) + { + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + if (trans != NULL) + { + res = trans(res.c_str()); + } + } + + return res; +} + +//static +std::string LLKeyboard::stringFromMouse(EMouseClickType click, bool translate) +{ + std::string res; + switch (click) + { + case CLICK_LEFT: + res = "LMB"; + break; + case CLICK_MIDDLE: + res = "MMB"; + break; + case CLICK_RIGHT: + res = "RMB"; + break; + case CLICK_BUTTON4: + res = "MB4"; + break; + case CLICK_BUTTON5: + res = "MB5"; + break; + case CLICK_DOUBLELEFT: + res = "Double LMB"; + break; + default: + break; + } + + if (translate && !res.empty()) + { + LLKeyStringTranslatorFunc* trans = gKeyboard->mStringTranslator; + if (trans != NULL) + { + res = trans(res.c_str()); + } + } + return res; +} + +//static +std::string LLKeyboard::stringFromAccelerator(MASK accel_mask) +{ + std::string res; + + LLKeyStringTranslatorFunc *trans = gKeyboard->mStringTranslator; + + if (trans == NULL) + { + LL_ERRS() << "No mKeyStringTranslator" << LL_ENDL; + return res; + } + + // Append any masks +#ifdef LL_DARWIN + // Standard Mac names for modifier keys in menu equivalents + // We could use the symbol characters, but they only exist in certain fonts. + if (accel_mask & MASK_CONTROL) + { + if (accel_mask & MASK_MAC_CONTROL) + { + res.append(trans("accel-mac-control")); + } + else + { + res.append(trans("accel-mac-command")); // Symbol would be "\xE2\x8C\x98" + } + } + if (accel_mask & MASK_ALT) + res.append(trans("accel-mac-option")); // Symbol would be "\xE2\x8C\xA5" + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-mac-shift")); // Symbol would be "\xE2\x8C\xA7" +#else + if (accel_mask & MASK_CONTROL) + res.append(trans("accel-win-control")); + if (accel_mask & MASK_ALT) + res.append(trans("accel-win-alt")); + if (accel_mask & MASK_SHIFT) + res.append(trans("accel-win-shift")); +#endif + return res; +} +//static +std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key ) +{ + std::string res; + + // break early if this is a silly thing to do. + if( KEY_NONE == key ) + { + return res; + } + + res.append(stringFromAccelerator(accel_mask)); + std::string key_string = LLKeyboard::stringFromKey(key); + if ((accel_mask & MASK_NORMALKEYS) && + (key_string[0] == '-' || key_string[0] == '=' || key_string[0] == '+')) + { + res.append( " " ); + } + + std::string keystr = stringFromKey( key ); + res.append( keystr ); + + return res; +} + +//static +std::string LLKeyboard::stringFromAccelerator(MASK accel_mask, EMouseClickType click) +{ + std::string res; + if (CLICK_NONE == click) + { + return res; + } + res.append(stringFromAccelerator(accel_mask)); + res.append(stringFromMouse(click)); + return res; +} + +//static +bool LLKeyboard::maskFromString(const std::string& str, MASK *mask) +{ + std::string instring(str); + if (instring == "NONE") + { + *mask = MASK_NONE; + return true; + } + else if (instring == "SHIFT") + { + *mask = MASK_SHIFT; + return true; + } + else if (instring == "CTL") + { + *mask = MASK_CONTROL; + return true; + } + else if (instring == "ALT") + { + *mask = MASK_ALT; + return true; + } + else if (instring == "CTL_SHIFT") + { + *mask = MASK_CONTROL | MASK_SHIFT; + return true; + } + else if (instring == "ALT_SHIFT") + { + *mask = MASK_ALT | MASK_SHIFT; + return true; + } + else if (instring == "CTL_ALT") + { + *mask = MASK_CONTROL | MASK_ALT; + return true; + } + else if (instring == "CTL_ALT_SHIFT") + { + *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT; + return true; + } + else + { + return false; + } +} + + +//static +void LLKeyboard::setStringTranslatorFunc( LLKeyStringTranslatorFunc *trans_func ) +{ + mStringTranslator = trans_func; +} diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index 4278ffb12f..7f8d0af155 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -1,144 +1,144 @@ -/** - * @file llkeyboard.h - * @brief Handler for assignable key bindings - * - * $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$ - */ - -#ifndef LL_LLKEYBOARD_H -#define LL_LLKEYBOARD_H - -#include -#include - -#include "llstringtable.h" -#include "lltimer.h" -#include "indra_constants.h" - -enum EKeystate -{ - KEYSTATE_DOWN, - KEYSTATE_LEVEL, - KEYSTATE_UP -}; - -typedef boost::function LLKeyFunc; -typedef std::string (LLKeyStringTranslatorFunc)(const char *label); - -enum EKeyboardInsertMode -{ - LL_KIM_INSERT, - LL_KIM_OVERWRITE -}; - -class LLWindowCallbacks; - -class LLKeyboard -{ -public: - LLKeyboard(); - virtual ~LLKeyboard(); - - void resetKeyDownAndHandle(); - void resetKeys(); - - - F32 getCurKeyElapsedTime() { return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; } - F32 getCurKeyElapsedFrameCount() { return getKeyDown(mCurScanKey) ? (F32)getKeyElapsedFrameCount( mCurScanKey ) : 0.f; } - bool getKeyDown(const KEY key) { return mKeyLevel[key]; } - bool getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } - - bool translateKey(const U16 os_key, KEY *translated_key); - U16 inverseTranslateKey(const KEY translated_key); - bool handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - bool handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes - - - virtual bool handleKeyUp(const U16 key, MASK mask) = 0; - virtual bool handleKeyDown(const U16 key, MASK mask) = 0; - -#ifdef LL_DARWIN - // We only actually use this for macOS. - virtual void handleModifier(MASK mask) = 0; -#endif // LL_DARWIN - - // Asynchronously poll the control, alt, and shift keys and set the - // appropriate internal key masks. - virtual void resetMaskKeys() = 0; - virtual void scanKeyboard() = 0; // scans keyboard, calls functions as necessary - // Mac must differentiate between Command = Control for keyboard events - // and Command != Control for mouse events. - virtual MASK currentMask(bool for_mouse_event) = 0; - virtual KEY currentKey() { return mCurTranslatedKey; } - - EKeyboardInsertMode getInsertMode() { return mInsertMode; } - void toggleInsertMode(); - - static bool maskFromString(const std::string& str, MASK *mask); // False on failure - static bool keyFromString(const std::string& str, KEY *key); // False on failure - static std::string stringFromKey(KEY key, bool translate = true); - static std::string stringFromMouse(EMouseClickType click, bool translate = true); - static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... - static std::string stringFromAccelerator( MASK accel_mask, KEY key ); - static std::string stringFromAccelerator(MASK accel_mask, EMouseClickType click); - - void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } - F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed. - S32 getKeyElapsedFrameCount( KEY key ); // Returns time in frames since key was pressed. - - static void setStringTranslatorFunc( LLKeyStringTranslatorFunc *trans_func ); - -protected: - void addKeyName(KEY key, const std::string& name); - -protected: - std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs - std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys - LLWindowCallbacks *mCallbacks; - - LLTimer mKeyLevelTimer[KEY_COUNT]; // Time since level was set - S32 mKeyLevelFrameCount[KEY_COUNT]; // Frames since level was set - bool mKeyLevel[KEY_COUNT]; // Levels - bool mKeyRepeated[KEY_COUNT]; // Key was repeated - bool mKeyUp[KEY_COUNT]; // Up edge - bool mKeyDown[KEY_COUNT]; // Down edge - KEY mCurTranslatedKey; - KEY mCurScanKey; // Used during the scanKeyboard() - - static LLKeyStringTranslatorFunc* mStringTranslator; // Used for l10n + PC/Mac/Linux accelerator labeling - - EKeyboardInsertMode mInsertMode; - - static std::map sKeysToNames; - static std::map sNamesToKeys; -}; - -// Interface to get key from assigned command -class LLKeyBindingToStringHandler -{ -public: - virtual std::string getKeyBindingAsString(const std::string& mode, const std::string& control) const = 0; -}; - -extern LLKeyboard *gKeyboard; - -#endif +/** + * @file llkeyboard.h + * @brief Handler for assignable key bindings + * + * $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$ + */ + +#ifndef LL_LLKEYBOARD_H +#define LL_LLKEYBOARD_H + +#include +#include + +#include "llstringtable.h" +#include "lltimer.h" +#include "indra_constants.h" + +enum EKeystate +{ + KEYSTATE_DOWN, + KEYSTATE_LEVEL, + KEYSTATE_UP +}; + +typedef boost::function LLKeyFunc; +typedef std::string (LLKeyStringTranslatorFunc)(const char *label); + +enum EKeyboardInsertMode +{ + LL_KIM_INSERT, + LL_KIM_OVERWRITE +}; + +class LLWindowCallbacks; + +class LLKeyboard +{ +public: + LLKeyboard(); + virtual ~LLKeyboard(); + + void resetKeyDownAndHandle(); + void resetKeys(); + + + F32 getCurKeyElapsedTime() { return getKeyDown(mCurScanKey) ? getKeyElapsedTime( mCurScanKey ) : 0.f; } + F32 getCurKeyElapsedFrameCount() { return getKeyDown(mCurScanKey) ? (F32)getKeyElapsedFrameCount( mCurScanKey ) : 0.f; } + bool getKeyDown(const KEY key) { return mKeyLevel[key]; } + bool getKeyRepeated(const KEY key) { return mKeyRepeated[key]; } + + bool translateKey(const U16 os_key, KEY *translated_key); + U16 inverseTranslateKey(const KEY translated_key); + bool handleTranslatedKeyUp(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes + bool handleTranslatedKeyDown(KEY translated_key, U32 translated_mask); // Translated into "Linden" keycodes + + + virtual bool handleKeyUp(const U16 key, MASK mask) = 0; + virtual bool handleKeyDown(const U16 key, MASK mask) = 0; + +#ifdef LL_DARWIN + // We only actually use this for macOS. + virtual void handleModifier(MASK mask) = 0; +#endif // LL_DARWIN + + // Asynchronously poll the control, alt, and shift keys and set the + // appropriate internal key masks. + virtual void resetMaskKeys() = 0; + virtual void scanKeyboard() = 0; // scans keyboard, calls functions as necessary + // Mac must differentiate between Command = Control for keyboard events + // and Command != Control for mouse events. + virtual MASK currentMask(bool for_mouse_event) = 0; + virtual KEY currentKey() { return mCurTranslatedKey; } + + EKeyboardInsertMode getInsertMode() { return mInsertMode; } + void toggleInsertMode(); + + static bool maskFromString(const std::string& str, MASK *mask); // False on failure + static bool keyFromString(const std::string& str, KEY *key); // False on failure + static std::string stringFromKey(KEY key, bool translate = true); + static std::string stringFromMouse(EMouseClickType click, bool translate = true); + static std::string stringFromAccelerator( MASK accel_mask ); // separated for convinience, returns with "+": "Shift+" or "Shift+Alt+"... + static std::string stringFromAccelerator( MASK accel_mask, KEY key ); + static std::string stringFromAccelerator(MASK accel_mask, EMouseClickType click); + + void setCallbacks(LLWindowCallbacks *cbs) { mCallbacks = cbs; } + F32 getKeyElapsedTime( KEY key ); // Returns time in seconds since key was pressed. + S32 getKeyElapsedFrameCount( KEY key ); // Returns time in frames since key was pressed. + + static void setStringTranslatorFunc( LLKeyStringTranslatorFunc *trans_func ); + +protected: + void addKeyName(KEY key, const std::string& name); + +protected: + std::map mTranslateKeyMap; // Map of translations from OS keys to Linden KEYs + std::map mInvTranslateKeyMap; // Map of translations from Linden KEYs to OS keys + LLWindowCallbacks *mCallbacks; + + LLTimer mKeyLevelTimer[KEY_COUNT]; // Time since level was set + S32 mKeyLevelFrameCount[KEY_COUNT]; // Frames since level was set + bool mKeyLevel[KEY_COUNT]; // Levels + bool mKeyRepeated[KEY_COUNT]; // Key was repeated + bool mKeyUp[KEY_COUNT]; // Up edge + bool mKeyDown[KEY_COUNT]; // Down edge + KEY mCurTranslatedKey; + KEY mCurScanKey; // Used during the scanKeyboard() + + static LLKeyStringTranslatorFunc* mStringTranslator; // Used for l10n + PC/Mac/Linux accelerator labeling + + EKeyboardInsertMode mInsertMode; + + static std::map sKeysToNames; + static std::map sNamesToKeys; +}; + +// Interface to get key from assigned command +class LLKeyBindingToStringHandler +{ +public: + virtual std::string getKeyBindingAsString(const std::string& mode, const std::string& control) const = 0; +}; + +extern LLKeyboard *gKeyboard; + +#endif diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index 098d9b62c7..8669a5b41a 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -1,80 +1,80 @@ -/** - * @file llkeyboardheadless.cpp - * @brief Handler for assignable key bindings - * - * $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 "llkeyboardheadless.h" -#include "llwindowcallbacks.h" - -LLKeyboardHeadless::LLKeyboardHeadless() -{ } - -void LLKeyboardHeadless::resetMaskKeys() -{ } - - -bool LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) -{ return false; } - - -bool LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) -{ return false; } - -MASK LLKeyboardHeadless::currentMask(bool for_mouse_event) -{ return MASK_NONE; } - -#ifdef LL_DARWIN -void LLKeyboardHeadless::handleModifier(MASK mask) -{ - -} -#endif - -void LLKeyboardHeadless::scanKeyboard() -{ - for (S32 key = 0; key < KEY_COUNT; key++) - { - // Generate callback if any event has occurred on this key this frame. - // Can't just test mKeyLevel, because this could be a slow frame and - // key might have gone down then up. JC - if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) - { - mCurScanKey = key; - mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); - } - } - - // Reset edges for next frame - for (S32 key = 0; key < KEY_COUNT; key++) - { - mKeyUp[key] = false; - mKeyDown[key] = false; - if (mKeyLevel[key]) - { - mKeyLevelFrameCount[key]++; - } - } -} - +/** + * @file llkeyboardheadless.cpp + * @brief Handler for assignable key bindings + * + * $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 "llkeyboardheadless.h" +#include "llwindowcallbacks.h" + +LLKeyboardHeadless::LLKeyboardHeadless() +{ } + +void LLKeyboardHeadless::resetMaskKeys() +{ } + + +bool LLKeyboardHeadless::handleKeyDown(const U16 key, const U32 mask) +{ return false; } + + +bool LLKeyboardHeadless::handleKeyUp(const U16 key, const U32 mask) +{ return false; } + +MASK LLKeyboardHeadless::currentMask(bool for_mouse_event) +{ return MASK_NONE; } + +#ifdef LL_DARWIN +void LLKeyboardHeadless::handleModifier(MASK mask) +{ + +} +#endif + +void LLKeyboardHeadless::scanKeyboard() +{ + for (S32 key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (S32 key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = false; + mKeyDown[key] = false; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} + diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index df7b015e8d..2528f0e3f1 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -1,48 +1,48 @@ -/** - * @file llkeyboardheadless.h - * @brief Handler for assignable key bindings - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#ifndef LL_LLKEYBOARDHEADLESS_H -#define LL_LLKEYBOARDHEADLESS_H - -#include "llkeyboard.h" - -class LLKeyboardHeadless : public LLKeyboard -{ -public: - LLKeyboardHeadless(); - /*virtual*/ ~LLKeyboardHeadless() {}; - - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); -#ifdef LL_DARWIN - /*virtual*/ void handleModifier(MASK mask); -#endif -}; - -#endif +/** + * @file llkeyboardheadless.h + * @brief Handler for assignable key bindings + * + * $LicenseInfo:firstyear=2004&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$ + */ + +#ifndef LL_LLKEYBOARDHEADLESS_H +#define LL_LLKEYBOARDHEADLESS_H + +#include "llkeyboard.h" + +class LLKeyboardHeadless : public LLKeyboard +{ +public: + LLKeyboardHeadless(); + /*virtual*/ ~LLKeyboardHeadless() {}; + + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); + /*virtual*/ void resetMaskKeys(); + /*virtual*/ MASK currentMask(bool for_mouse_event); + /*virtual*/ void scanKeyboard(); +#ifdef LL_DARWIN + /*virtual*/ void handleModifier(MASK mask); +#endif +}; + +#endif diff --git a/indra/llwindow/llkeyboardmacosx.cpp b/indra/llwindow/llkeyboardmacosx.cpp index 4a415a2f54..89ff7c6d3f 100644 --- a/indra/llwindow/llkeyboardmacosx.cpp +++ b/indra/llwindow/llkeyboardmacosx.cpp @@ -1,317 +1,317 @@ -/** - * @file llkeyboardmacosx.cpp - * @brief Handler for assignable key bindings - * - * $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$ - */ - -#if LL_DARWIN - -#include "linden_common.h" -#include "llkeyboardmacosx.h" -#include "llwindowcallbacks.h" - -#include "llwindowmacosx-objc.h" - -LLKeyboardMacOSX::LLKeyboardMacOSX() -{ - // Virtual keycode mapping table. Yes, this was as annoying to generate as it looks. - mTranslateKeyMap[0x00] = 'A'; - mTranslateKeyMap[0x01] = 'S'; - mTranslateKeyMap[0x02] = 'D'; - mTranslateKeyMap[0x03] = 'F'; - mTranslateKeyMap[0x04] = 'H'; - mTranslateKeyMap[0x05] = 'G'; - mTranslateKeyMap[0x06] = 'Z'; - mTranslateKeyMap[0x07] = 'X'; - mTranslateKeyMap[0x08] = 'C'; - mTranslateKeyMap[0x09] = 'V'; - mTranslateKeyMap[0x0b] = 'B'; - mTranslateKeyMap[0x0c] = 'Q'; - mTranslateKeyMap[0x0d] = 'W'; - mTranslateKeyMap[0x0e] = 'E'; - mTranslateKeyMap[0x0f] = 'R'; - mTranslateKeyMap[0x10] = 'Y'; - mTranslateKeyMap[0x11] = 'T'; - mTranslateKeyMap[0x12] = '1'; - mTranslateKeyMap[0x13] = '2'; - mTranslateKeyMap[0x14] = '3'; - mTranslateKeyMap[0x15] = '4'; - mTranslateKeyMap[0x16] = '6'; - mTranslateKeyMap[0x17] = '5'; - mTranslateKeyMap[0x18] = '='; // KEY_EQUALS - mTranslateKeyMap[0x19] = '9'; - mTranslateKeyMap[0x1a] = '7'; - mTranslateKeyMap[0x1b] = '-'; // KEY_HYPHEN - mTranslateKeyMap[0x1c] = '8'; - mTranslateKeyMap[0x1d] = '0'; - mTranslateKeyMap[0x1e] = ']'; - mTranslateKeyMap[0x1f] = 'O'; - mTranslateKeyMap[0x20] = 'U'; - mTranslateKeyMap[0x21] = '['; - mTranslateKeyMap[0x22] = 'I'; - mTranslateKeyMap[0x23] = 'P'; - mTranslateKeyMap[0x24] = KEY_RETURN, - mTranslateKeyMap[0x25] = 'L'; - mTranslateKeyMap[0x26] = 'J'; - mTranslateKeyMap[0x27] = '\''; - mTranslateKeyMap[0x28] = 'K'; - mTranslateKeyMap[0x29] = ';'; - mTranslateKeyMap[0x2a] = '\\'; - mTranslateKeyMap[0x2b] = ','; - mTranslateKeyMap[0x2c] = KEY_DIVIDE; - mTranslateKeyMap[0x2d] = 'N'; - mTranslateKeyMap[0x2e] = 'M'; - mTranslateKeyMap[0x2f] = '.'; - mTranslateKeyMap[0x30] = KEY_TAB; - mTranslateKeyMap[0x31] = ' '; // space! - mTranslateKeyMap[0x32] = '`'; - mTranslateKeyMap[0x33] = KEY_BACKSPACE; - mTranslateKeyMap[0x35] = KEY_ESCAPE; - //mTranslateKeyMap[0x37] = 0; // Command key. (not used yet) - mTranslateKeyMap[0x38] = KEY_SHIFT; - mTranslateKeyMap[0x39] = KEY_CAPSLOCK; - mTranslateKeyMap[0x3a] = KEY_ALT; - mTranslateKeyMap[0x3b] = KEY_CONTROL; - mTranslateKeyMap[0x41] = '.'; // keypad - mTranslateKeyMap[0x43] = '*'; // keypad - mTranslateKeyMap[0x45] = '+'; // keypad - mTranslateKeyMap[0x4b] = KEY_PAD_DIVIDE; // keypad - mTranslateKeyMap[0x4c] = KEY_RETURN; // keypad enter - mTranslateKeyMap[0x4e] = '-'; // keypad - mTranslateKeyMap[0x51] = '='; // keypad - mTranslateKeyMap[0x52] = '0'; // keypad - mTranslateKeyMap[0x53] = '1'; // keypad - mTranslateKeyMap[0x54] = '2'; // keypad - mTranslateKeyMap[0x55] = '3'; // keypad - mTranslateKeyMap[0x56] = '4'; // keypad - mTranslateKeyMap[0x57] = '5'; // keypad - mTranslateKeyMap[0x58] = '6'; // keypad - mTranslateKeyMap[0x59] = '7'; // keypad - mTranslateKeyMap[0x5b] = '8'; // keypad - mTranslateKeyMap[0x5c] = '9'; // keypad - mTranslateKeyMap[0x60] = KEY_F5; - mTranslateKeyMap[0x61] = KEY_F6; - mTranslateKeyMap[0x62] = KEY_F7; - mTranslateKeyMap[0x63] = KEY_F3; - mTranslateKeyMap[0x64] = KEY_F8; - mTranslateKeyMap[0x65] = KEY_F9; - mTranslateKeyMap[0x67] = KEY_F11; - mTranslateKeyMap[0x6d] = KEY_F10; - mTranslateKeyMap[0x6f] = KEY_F12; - mTranslateKeyMap[0x72] = KEY_INSERT; - mTranslateKeyMap[0x73] = KEY_HOME; - mTranslateKeyMap[0x74] = KEY_PAGE_UP; - mTranslateKeyMap[0x75] = KEY_DELETE; - mTranslateKeyMap[0x76] = KEY_F4; - mTranslateKeyMap[0x77] = KEY_END; - mTranslateKeyMap[0x78] = KEY_F2; - mTranslateKeyMap[0x79] = KEY_PAGE_DOWN; - mTranslateKeyMap[0x7a] = KEY_F1; - mTranslateKeyMap[0x7b] = KEY_LEFT; - mTranslateKeyMap[0x7c] = KEY_RIGHT; - mTranslateKeyMap[0x7d] = KEY_DOWN; - mTranslateKeyMap[0x7e] = KEY_UP; - - // Build inverse map - std::map::iterator iter; - for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) - { - mInvTranslateKeyMap[iter->second] = iter->first; - } - - // build numpad maps - mTranslateNumpadMap[0x52] = KEY_PAD_INS; // keypad 0 - mTranslateNumpadMap[0x53] = KEY_PAD_END; // keypad 1 - mTranslateNumpadMap[0x54] = KEY_PAD_DOWN; // keypad 2 - mTranslateNumpadMap[0x55] = KEY_PAD_PGDN; // keypad 3 - mTranslateNumpadMap[0x56] = KEY_PAD_LEFT; // keypad 4 - mTranslateNumpadMap[0x57] = KEY_PAD_CENTER; // keypad 5 - mTranslateNumpadMap[0x58] = KEY_PAD_RIGHT; // keypad 6 - mTranslateNumpadMap[0x59] = KEY_PAD_HOME; // keypad 7 - mTranslateNumpadMap[0x5b] = KEY_PAD_UP; // keypad 8 - mTranslateNumpadMap[0x5c] = KEY_PAD_PGUP; // keypad 9 - mTranslateNumpadMap[0x41] = KEY_PAD_DEL; // keypad . - mTranslateNumpadMap[0x4c] = KEY_PAD_RETURN; // keypad enter - - // Build inverse numpad map - for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) - { - mInvTranslateNumpadMap[iter->second] = iter->first; - } -} - -void LLKeyboardMacOSX::resetMaskKeys() -{ - U32 mask = getModifiers(); - - // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). - // It looks a bit suspicious, as it won't correct for keys that have been released. - // Is this the way it's supposed to work? - - // We apply the modifier masks directly within getModifiers. So check to see which masks we've applied. - - if(mask & MAC_SHIFT_KEY) - { - mKeyLevel[KEY_SHIFT] = true; - } - - if(mask & MAC_CTRL_KEY) - { - mKeyLevel[KEY_CONTROL] = true; - } - - if(mask & MAC_ALT_KEY) - { - mKeyLevel[KEY_ALT] = true; - } -} - -/* -static bool translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) -{ - // Translate the virtual keycode into the keycodes the keyboard system expects. - U16 virtualKey = (mask >> 24) & 0x0000007F; - outKey = macKeyTransArray[virtualKey]; - - - return(outKey != 0); -} -*/ - -void LLKeyboardMacOSX::handleModifier(MASK mask) -{ - updateModifiers(mask); -} - -MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) -{ - // translate the mask - MASK out_mask = 0; - - if(mask & MAC_SHIFT_KEY) - { - out_mask |= MASK_SHIFT; - } - - if(mask & (MAC_CTRL_KEY | MAC_CMD_KEY)) - { - out_mask |= MASK_CONTROL; - } - - if(mask & MAC_ALT_KEY) - { - out_mask |= MASK_ALT; - } - - return out_mask; -} - -bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) -{ - KEY translated_key = 0; - U32 translated_mask = 0; - bool handled = false; - - translated_mask = updateModifiers(mask); - - if(translateNumpadKey(key, &translated_key)) - { - handled = handleTranslatedKeyDown(translated_key, translated_mask); - } - - return handled; -} - - -bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) -{ - KEY translated_key = 0; - U32 translated_mask = 0; - bool handled = false; - - translated_mask = updateModifiers(mask); - - if(translateNumpadKey(key, &translated_key)) - { - handled = handleTranslatedKeyUp(translated_key, translated_mask); - } - - return handled; -} - -MASK LLKeyboardMacOSX::currentMask(bool for_mouse_event) -{ - MASK result = MASK_NONE; - U32 mask = getModifiers(); - - if (mask & MAC_SHIFT_KEY) result |= MASK_SHIFT; - if (mask & MAC_CTRL_KEY) result |= MASK_CONTROL; - if (mask & MAC_ALT_KEY) result |= MASK_ALT; - - // For keyboard events, consider Command equivalent to Control - if (!for_mouse_event) - { - if (mask & MAC_CMD_KEY) result |= MASK_CONTROL; - } - - return result; -} - -void LLKeyboardMacOSX::scanKeyboard() -{ - S32 key; - for (key = 0; key < KEY_COUNT; key++) - { - // Generate callback if any event has occurred on this key this frame. - // Can't just test mKeyLevel, because this could be a slow frame and - // key might have gone down then up. JC - if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) - { - mCurScanKey = key; - mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); - } - } - - // Reset edges for next frame - for (key = 0; key < KEY_COUNT; key++) - { - mKeyUp[key] = false; - mKeyDown[key] = false; - if (mKeyLevel[key]) - { - mKeyLevelFrameCount[key]++; - } - } -} - -bool LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key ) -{ - return translateKey(os_key, translated_key); -} - -U16 LLKeyboardMacOSX::inverseTranslateNumpadKey(const KEY translated_key) -{ - return inverseTranslateKey(translated_key); -} - -#endif // LL_DARWIN +/** + * @file llkeyboardmacosx.cpp + * @brief Handler for assignable key bindings + * + * $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$ + */ + +#if LL_DARWIN + +#include "linden_common.h" +#include "llkeyboardmacosx.h" +#include "llwindowcallbacks.h" + +#include "llwindowmacosx-objc.h" + +LLKeyboardMacOSX::LLKeyboardMacOSX() +{ + // Virtual keycode mapping table. Yes, this was as annoying to generate as it looks. + mTranslateKeyMap[0x00] = 'A'; + mTranslateKeyMap[0x01] = 'S'; + mTranslateKeyMap[0x02] = 'D'; + mTranslateKeyMap[0x03] = 'F'; + mTranslateKeyMap[0x04] = 'H'; + mTranslateKeyMap[0x05] = 'G'; + mTranslateKeyMap[0x06] = 'Z'; + mTranslateKeyMap[0x07] = 'X'; + mTranslateKeyMap[0x08] = 'C'; + mTranslateKeyMap[0x09] = 'V'; + mTranslateKeyMap[0x0b] = 'B'; + mTranslateKeyMap[0x0c] = 'Q'; + mTranslateKeyMap[0x0d] = 'W'; + mTranslateKeyMap[0x0e] = 'E'; + mTranslateKeyMap[0x0f] = 'R'; + mTranslateKeyMap[0x10] = 'Y'; + mTranslateKeyMap[0x11] = 'T'; + mTranslateKeyMap[0x12] = '1'; + mTranslateKeyMap[0x13] = '2'; + mTranslateKeyMap[0x14] = '3'; + mTranslateKeyMap[0x15] = '4'; + mTranslateKeyMap[0x16] = '6'; + mTranslateKeyMap[0x17] = '5'; + mTranslateKeyMap[0x18] = '='; // KEY_EQUALS + mTranslateKeyMap[0x19] = '9'; + mTranslateKeyMap[0x1a] = '7'; + mTranslateKeyMap[0x1b] = '-'; // KEY_HYPHEN + mTranslateKeyMap[0x1c] = '8'; + mTranslateKeyMap[0x1d] = '0'; + mTranslateKeyMap[0x1e] = ']'; + mTranslateKeyMap[0x1f] = 'O'; + mTranslateKeyMap[0x20] = 'U'; + mTranslateKeyMap[0x21] = '['; + mTranslateKeyMap[0x22] = 'I'; + mTranslateKeyMap[0x23] = 'P'; + mTranslateKeyMap[0x24] = KEY_RETURN, + mTranslateKeyMap[0x25] = 'L'; + mTranslateKeyMap[0x26] = 'J'; + mTranslateKeyMap[0x27] = '\''; + mTranslateKeyMap[0x28] = 'K'; + mTranslateKeyMap[0x29] = ';'; + mTranslateKeyMap[0x2a] = '\\'; + mTranslateKeyMap[0x2b] = ','; + mTranslateKeyMap[0x2c] = KEY_DIVIDE; + mTranslateKeyMap[0x2d] = 'N'; + mTranslateKeyMap[0x2e] = 'M'; + mTranslateKeyMap[0x2f] = '.'; + mTranslateKeyMap[0x30] = KEY_TAB; + mTranslateKeyMap[0x31] = ' '; // space! + mTranslateKeyMap[0x32] = '`'; + mTranslateKeyMap[0x33] = KEY_BACKSPACE; + mTranslateKeyMap[0x35] = KEY_ESCAPE; + //mTranslateKeyMap[0x37] = 0; // Command key. (not used yet) + mTranslateKeyMap[0x38] = KEY_SHIFT; + mTranslateKeyMap[0x39] = KEY_CAPSLOCK; + mTranslateKeyMap[0x3a] = KEY_ALT; + mTranslateKeyMap[0x3b] = KEY_CONTROL; + mTranslateKeyMap[0x41] = '.'; // keypad + mTranslateKeyMap[0x43] = '*'; // keypad + mTranslateKeyMap[0x45] = '+'; // keypad + mTranslateKeyMap[0x4b] = KEY_PAD_DIVIDE; // keypad + mTranslateKeyMap[0x4c] = KEY_RETURN; // keypad enter + mTranslateKeyMap[0x4e] = '-'; // keypad + mTranslateKeyMap[0x51] = '='; // keypad + mTranslateKeyMap[0x52] = '0'; // keypad + mTranslateKeyMap[0x53] = '1'; // keypad + mTranslateKeyMap[0x54] = '2'; // keypad + mTranslateKeyMap[0x55] = '3'; // keypad + mTranslateKeyMap[0x56] = '4'; // keypad + mTranslateKeyMap[0x57] = '5'; // keypad + mTranslateKeyMap[0x58] = '6'; // keypad + mTranslateKeyMap[0x59] = '7'; // keypad + mTranslateKeyMap[0x5b] = '8'; // keypad + mTranslateKeyMap[0x5c] = '9'; // keypad + mTranslateKeyMap[0x60] = KEY_F5; + mTranslateKeyMap[0x61] = KEY_F6; + mTranslateKeyMap[0x62] = KEY_F7; + mTranslateKeyMap[0x63] = KEY_F3; + mTranslateKeyMap[0x64] = KEY_F8; + mTranslateKeyMap[0x65] = KEY_F9; + mTranslateKeyMap[0x67] = KEY_F11; + mTranslateKeyMap[0x6d] = KEY_F10; + mTranslateKeyMap[0x6f] = KEY_F12; + mTranslateKeyMap[0x72] = KEY_INSERT; + mTranslateKeyMap[0x73] = KEY_HOME; + mTranslateKeyMap[0x74] = KEY_PAGE_UP; + mTranslateKeyMap[0x75] = KEY_DELETE; + mTranslateKeyMap[0x76] = KEY_F4; + mTranslateKeyMap[0x77] = KEY_END; + mTranslateKeyMap[0x78] = KEY_F2; + mTranslateKeyMap[0x79] = KEY_PAGE_DOWN; + mTranslateKeyMap[0x7a] = KEY_F1; + mTranslateKeyMap[0x7b] = KEY_LEFT; + mTranslateKeyMap[0x7c] = KEY_RIGHT; + mTranslateKeyMap[0x7d] = KEY_DOWN; + mTranslateKeyMap[0x7e] = KEY_UP; + + // Build inverse map + std::map::iterator iter; + for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + { + mInvTranslateKeyMap[iter->second] = iter->first; + } + + // build numpad maps + mTranslateNumpadMap[0x52] = KEY_PAD_INS; // keypad 0 + mTranslateNumpadMap[0x53] = KEY_PAD_END; // keypad 1 + mTranslateNumpadMap[0x54] = KEY_PAD_DOWN; // keypad 2 + mTranslateNumpadMap[0x55] = KEY_PAD_PGDN; // keypad 3 + mTranslateNumpadMap[0x56] = KEY_PAD_LEFT; // keypad 4 + mTranslateNumpadMap[0x57] = KEY_PAD_CENTER; // keypad 5 + mTranslateNumpadMap[0x58] = KEY_PAD_RIGHT; // keypad 6 + mTranslateNumpadMap[0x59] = KEY_PAD_HOME; // keypad 7 + mTranslateNumpadMap[0x5b] = KEY_PAD_UP; // keypad 8 + mTranslateNumpadMap[0x5c] = KEY_PAD_PGUP; // keypad 9 + mTranslateNumpadMap[0x41] = KEY_PAD_DEL; // keypad . + mTranslateNumpadMap[0x4c] = KEY_PAD_RETURN; // keypad enter + + // Build inverse numpad map + for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) + { + mInvTranslateNumpadMap[iter->second] = iter->first; + } +} + +void LLKeyboardMacOSX::resetMaskKeys() +{ + U32 mask = getModifiers(); + + // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). + // It looks a bit suspicious, as it won't correct for keys that have been released. + // Is this the way it's supposed to work? + + // We apply the modifier masks directly within getModifiers. So check to see which masks we've applied. + + if(mask & MAC_SHIFT_KEY) + { + mKeyLevel[KEY_SHIFT] = true; + } + + if(mask & MAC_CTRL_KEY) + { + mKeyLevel[KEY_CONTROL] = true; + } + + if(mask & MAC_ALT_KEY) + { + mKeyLevel[KEY_ALT] = true; + } +} + +/* +static bool translateKeyMac(const U16 key, const U32 mask, KEY &outKey, U32 &outMask) +{ + // Translate the virtual keycode into the keycodes the keyboard system expects. + U16 virtualKey = (mask >> 24) & 0x0000007F; + outKey = macKeyTransArray[virtualKey]; + + + return(outKey != 0); +} +*/ + +void LLKeyboardMacOSX::handleModifier(MASK mask) +{ + updateModifiers(mask); +} + +MASK LLKeyboardMacOSX::updateModifiers(const U32 mask) +{ + // translate the mask + MASK out_mask = 0; + + if(mask & MAC_SHIFT_KEY) + { + out_mask |= MASK_SHIFT; + } + + if(mask & (MAC_CTRL_KEY | MAC_CMD_KEY)) + { + out_mask |= MASK_CONTROL; + } + + if(mask & MAC_ALT_KEY) + { + out_mask |= MASK_ALT; + } + + return out_mask; +} + +bool LLKeyboardMacOSX::handleKeyDown(const U16 key, const U32 mask) +{ + KEY translated_key = 0; + U32 translated_mask = 0; + bool handled = false; + + translated_mask = updateModifiers(mask); + + if(translateNumpadKey(key, &translated_key)) + { + handled = handleTranslatedKeyDown(translated_key, translated_mask); + } + + return handled; +} + + +bool LLKeyboardMacOSX::handleKeyUp(const U16 key, const U32 mask) +{ + KEY translated_key = 0; + U32 translated_mask = 0; + bool handled = false; + + translated_mask = updateModifiers(mask); + + if(translateNumpadKey(key, &translated_key)) + { + handled = handleTranslatedKeyUp(translated_key, translated_mask); + } + + return handled; +} + +MASK LLKeyboardMacOSX::currentMask(bool for_mouse_event) +{ + MASK result = MASK_NONE; + U32 mask = getModifiers(); + + if (mask & MAC_SHIFT_KEY) result |= MASK_SHIFT; + if (mask & MAC_CTRL_KEY) result |= MASK_CONTROL; + if (mask & MAC_ALT_KEY) result |= MASK_ALT; + + // For keyboard events, consider Command equivalent to Control + if (!for_mouse_event) + { + if (mask & MAC_CMD_KEY) result |= MASK_CONTROL; + } + + return result; +} + +void LLKeyboardMacOSX::scanKeyboard() +{ + S32 key; + for (key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = false; + mKeyDown[key] = false; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} + +bool LLKeyboardMacOSX::translateNumpadKey( const U16 os_key, KEY *translated_key ) +{ + return translateKey(os_key, translated_key); +} + +U16 LLKeyboardMacOSX::inverseTranslateNumpadKey(const KEY translated_key) +{ + return inverseTranslateKey(translated_key); +} + +#endif // LL_DARWIN diff --git a/indra/llwindow/llkeyboardmacosx.h b/indra/llwindow/llkeyboardmacosx.h index 5c5328a156..92ab5c9a85 100644 --- a/indra/llwindow/llkeyboardmacosx.h +++ b/indra/llwindow/llkeyboardmacosx.h @@ -1,64 +1,64 @@ -/** - * @file llkeyboardmacosx.h - * @brief Handler for assignable key bindings - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#ifndef LL_LLKEYBOARDMACOSX_H -#define LL_LLKEYBOARDMACOSX_H - -#include "llkeyboard.h" - -// These more or less mirror their equivalents in NSEvent.h. -enum EMacEventKeys { - MAC_SHIFT_KEY = 1 << 17, - MAC_CTRL_KEY = 1 << 18, - MAC_ALT_KEY = 1 << 19, - MAC_CMD_KEY = 1 << 20, - MAC_FN_KEY = 1 << 23 -}; - -class LLKeyboardMacOSX : public LLKeyboard -{ -public: - LLKeyboardMacOSX(); - /*virtual*/ ~LLKeyboardMacOSX() {}; - - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - /*virtual*/ void handleModifier(MASK mask); - -protected: - MASK updateModifiers(const U32 mask); - void setModifierKeyLevel( KEY key, bool new_state ); - bool translateNumpadKey( const U16 os_key, KEY *translated_key ); - U16 inverseTranslateNumpadKey(const KEY translated_key); -private: - std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys - std::map mInvTranslateNumpadMap; // inverse of the above -}; - -#endif +/** + * @file llkeyboardmacosx.h + * @brief Handler for assignable key bindings + * + * $LicenseInfo:firstyear=2004&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$ + */ + +#ifndef LL_LLKEYBOARDMACOSX_H +#define LL_LLKEYBOARDMACOSX_H + +#include "llkeyboard.h" + +// These more or less mirror their equivalents in NSEvent.h. +enum EMacEventKeys { + MAC_SHIFT_KEY = 1 << 17, + MAC_CTRL_KEY = 1 << 18, + MAC_ALT_KEY = 1 << 19, + MAC_CMD_KEY = 1 << 20, + MAC_FN_KEY = 1 << 23 +}; + +class LLKeyboardMacOSX : public LLKeyboard +{ +public: + LLKeyboardMacOSX(); + /*virtual*/ ~LLKeyboardMacOSX() {}; + + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); + /*virtual*/ void resetMaskKeys(); + /*virtual*/ MASK currentMask(bool for_mouse_event); + /*virtual*/ void scanKeyboard(); + /*virtual*/ void handleModifier(MASK mask); + +protected: + MASK updateModifiers(const U32 mask); + void setModifierKeyLevel( KEY key, bool new_state ); + bool translateNumpadKey( const U16 os_key, KEY *translated_key ); + U16 inverseTranslateNumpadKey(const KEY translated_key); +private: + std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys + std::map mInvTranslateNumpadMap; // inverse of the above +}; + +#endif diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index eaf577108a..97198f0cc0 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -1,324 +1,324 @@ -/** - * @file llkeyboardsdl.cpp - * @brief Handler for assignable key bindings - * - * $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$ - */ - -#if LL_SDL - -#include "linden_common.h" -#include "llkeyboardsdl.h" -#include "llwindowcallbacks.h" -#include "SDL/SDL.h" - -LLKeyboardSDL::LLKeyboardSDL() -{ - // Set up key mapping for SDL - eventually can read this from a file? - // Anything not in the key map gets dropped - // Add default A-Z - - // Virtual key mappings from SDL_keysym.h ... - - // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... - U16 cur_char; - for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) - { - mTranslateKeyMap[cur_char] = cur_char; - } - for (cur_char = 'a'; cur_char <= 'z'; cur_char++) - { - mTranslateKeyMap[cur_char] = (cur_char - 'a') + 'A'; - } - - for (cur_char = '0'; cur_char <= '9'; cur_char++) - { - mTranslateKeyMap[cur_char] = cur_char; - } - - // These ones are translated manually upon keydown/keyup because - // SDL doesn't handle their numlock transition. - //mTranslateKeyMap[SDLK_KP4] = KEY_PAD_LEFT; - //mTranslateKeyMap[SDLK_KP6] = KEY_PAD_RIGHT; - //mTranslateKeyMap[SDLK_KP8] = KEY_PAD_UP; - //mTranslateKeyMap[SDLK_KP2] = KEY_PAD_DOWN; - //mTranslateKeyMap[SDLK_KP_PERIOD] = KEY_DELETE; - //mTranslateKeyMap[SDLK_KP7] = KEY_HOME; - //mTranslateKeyMap[SDLK_KP1] = KEY_END; - //mTranslateKeyMap[SDLK_KP9] = KEY_PAGE_UP; - //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; - //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; - - mTranslateKeyMap[SDLK_SPACE] = ' '; - mTranslateKeyMap[SDLK_RETURN] = KEY_RETURN; - mTranslateKeyMap[SDLK_LEFT] = KEY_LEFT; - mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; - mTranslateKeyMap[SDLK_UP] = KEY_UP; - mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; - mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; - mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN; - mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; - mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; - mTranslateKeyMap[SDLK_DELETE] = KEY_DELETE; - mTranslateKeyMap[SDLK_LSHIFT] = KEY_SHIFT; - mTranslateKeyMap[SDLK_RSHIFT] = KEY_SHIFT; - mTranslateKeyMap[SDLK_LCTRL] = KEY_CONTROL; - mTranslateKeyMap[SDLK_RCTRL] = KEY_CONTROL; - mTranslateKeyMap[SDLK_LALT] = KEY_ALT; - mTranslateKeyMap[SDLK_RALT] = KEY_ALT; - mTranslateKeyMap[SDLK_HOME] = KEY_HOME; - mTranslateKeyMap[SDLK_END] = KEY_END; - mTranslateKeyMap[SDLK_PAGEUP] = KEY_PAGE_UP; - mTranslateKeyMap[SDLK_PAGEDOWN] = KEY_PAGE_DOWN; - mTranslateKeyMap[SDLK_MINUS] = KEY_HYPHEN; - mTranslateKeyMap[SDLK_EQUALS] = KEY_EQUALS; - mTranslateKeyMap[SDLK_KP_EQUALS] = KEY_EQUALS; - mTranslateKeyMap[SDLK_INSERT] = KEY_INSERT; - mTranslateKeyMap[SDLK_CAPSLOCK] = KEY_CAPSLOCK; - mTranslateKeyMap[SDLK_TAB] = KEY_TAB; - mTranslateKeyMap[SDLK_KP_PLUS] = KEY_ADD; - mTranslateKeyMap[SDLK_KP_MINUS] = KEY_SUBTRACT; - mTranslateKeyMap[SDLK_KP_MULTIPLY] = KEY_MULTIPLY; - mTranslateKeyMap[SDLK_KP_DIVIDE] = KEY_PAD_DIVIDE; - mTranslateKeyMap[SDLK_F1] = KEY_F1; - mTranslateKeyMap[SDLK_F2] = KEY_F2; - mTranslateKeyMap[SDLK_F3] = KEY_F3; - mTranslateKeyMap[SDLK_F4] = KEY_F4; - mTranslateKeyMap[SDLK_F5] = KEY_F5; - mTranslateKeyMap[SDLK_F6] = KEY_F6; - mTranslateKeyMap[SDLK_F7] = KEY_F7; - mTranslateKeyMap[SDLK_F8] = KEY_F8; - mTranslateKeyMap[SDLK_F9] = KEY_F9; - mTranslateKeyMap[SDLK_F10] = KEY_F10; - mTranslateKeyMap[SDLK_F11] = KEY_F11; - mTranslateKeyMap[SDLK_F12] = KEY_F12; - mTranslateKeyMap[SDLK_PLUS] = '='; - mTranslateKeyMap[SDLK_COMMA] = ','; - mTranslateKeyMap[SDLK_MINUS] = '-'; - mTranslateKeyMap[SDLK_PERIOD] = '.'; - mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; - mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; - mTranslateKeyMap[SDLK_SEMICOLON] = ';'; - mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; - mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; - mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; - mTranslateKeyMap[SDLK_QUOTE] = '\''; - - // Build inverse map - std::map::iterator iter; - for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) - { - mInvTranslateKeyMap[iter->second] = iter->first; - } - - // numpad map - mTranslateNumpadMap[SDLK_KP0] = KEY_PAD_INS; - mTranslateNumpadMap[SDLK_KP1] = KEY_PAD_END; - mTranslateNumpadMap[SDLK_KP2] = KEY_PAD_DOWN; - mTranslateNumpadMap[SDLK_KP3] = KEY_PAD_PGDN; - mTranslateNumpadMap[SDLK_KP4] = KEY_PAD_LEFT; - mTranslateNumpadMap[SDLK_KP5] = KEY_PAD_CENTER; - mTranslateNumpadMap[SDLK_KP6] = KEY_PAD_RIGHT; - mTranslateNumpadMap[SDLK_KP7] = KEY_PAD_HOME; - mTranslateNumpadMap[SDLK_KP8] = KEY_PAD_UP; - mTranslateNumpadMap[SDLK_KP9] = KEY_PAD_PGUP; - mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL; - - // build inverse numpad map - for (iter = mTranslateNumpadMap.begin(); - iter != mTranslateNumpadMap.end(); - iter++) - { - mInvTranslateNumpadMap[iter->second] = iter->first; - } -} - -void LLKeyboardSDL::resetMaskKeys() -{ - SDLMod mask = SDL_GetModState(); - - // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). - // It looks a bit suspicious, as it won't correct for keys that have been released. - // Is this the way it's supposed to work? - - if(mask & KMOD_SHIFT) - { - mKeyLevel[KEY_SHIFT] = true; - } - - if(mask & KMOD_CTRL) - { - mKeyLevel[KEY_CONTROL] = true; - } - - if(mask & KMOD_ALT) - { - mKeyLevel[KEY_ALT] = true; - } -} - - -MASK LLKeyboardSDL::updateModifiers(const U32 mask) -{ - // translate the mask - MASK out_mask = MASK_NONE; - - if(mask & KMOD_SHIFT) - { - out_mask |= MASK_SHIFT; - } - - if(mask & KMOD_CTRL) - { - out_mask |= MASK_CONTROL; - } - - if(mask & KMOD_ALT) - { - out_mask |= MASK_ALT; - } - - return out_mask; -} - - -static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) -{ - // SDL doesn't automatically adjust the keysym according to - // whether NUMLOCK is engaged, so we massage the keysym manually. - U16 rtn = key; - if (!(mask & KMOD_NUM)) - { - switch (key) - { - case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; - case SDLK_KP0: rtn = SDLK_INSERT; break; - case SDLK_KP1: rtn = SDLK_END; break; - case SDLK_KP2: rtn = SDLK_DOWN; break; - case SDLK_KP3: rtn = SDLK_PAGEDOWN; break; - case SDLK_KP4: rtn = SDLK_LEFT; break; - case SDLK_KP6: rtn = SDLK_RIGHT; break; - case SDLK_KP7: rtn = SDLK_HOME; break; - case SDLK_KP8: rtn = SDLK_UP; break; - case SDLK_KP9: rtn = SDLK_PAGEUP; break; - } - } - return rtn; -} - - -bool LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) -{ - U16 adjusted_nativekey; - KEY translated_key = 0; - U32 translated_mask = MASK_NONE; - bool handled = false; - - adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); - - translated_mask = updateModifiers(mask); - - if(translateNumpadKey(adjusted_nativekey, &translated_key)) - { - handled = handleTranslatedKeyDown(translated_key, translated_mask); - } - - return handled; -} - - -bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) -{ - U16 adjusted_nativekey; - KEY translated_key = 0; - U32 translated_mask = MASK_NONE; - bool handled = false; - - adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); - - translated_mask = updateModifiers(mask); - - if(translateNumpadKey(adjusted_nativekey, &translated_key)) - { - handled = handleTranslatedKeyUp(translated_key, translated_mask); - } - - return handled; -} - -MASK LLKeyboardSDL::currentMask(bool for_mouse_event) -{ - MASK result = MASK_NONE; - SDLMod mask = SDL_GetModState(); - - if (mask & KMOD_SHIFT) result |= MASK_SHIFT; - if (mask & KMOD_CTRL) result |= MASK_CONTROL; - if (mask & KMOD_ALT) result |= MASK_ALT; - - // For keyboard events, consider Meta keys equivalent to Control - if (!for_mouse_event) - { - if (mask & KMOD_META) result |= MASK_CONTROL; - } - - return result; -} - -void LLKeyboardSDL::scanKeyboard() -{ - for (S32 key = 0; key < KEY_COUNT; key++) - { - // Generate callback if any event has occurred on this key this frame. - // Can't just test mKeyLevel, because this could be a slow frame and - // key might have gone down then up. JC - if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) - { - mCurScanKey = key; - mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); - } - } - - // Reset edges for next frame - for (S32 key = 0; key < KEY_COUNT; key++) - { - mKeyUp[key] = false; - mKeyDown[key] = false; - if (mKeyLevel[key]) - { - mKeyLevelFrameCount[key]++; - } - } -} - - -bool LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) -{ - return translateKey(os_key, translated_key); -} - -U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) -{ - return inverseTranslateKey(translated_key); -} - -#endif - +/** + * @file llkeyboardsdl.cpp + * @brief Handler for assignable key bindings + * + * $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$ + */ + +#if LL_SDL + +#include "linden_common.h" +#include "llkeyboardsdl.h" +#include "llwindowcallbacks.h" +#include "SDL/SDL.h" + +LLKeyboardSDL::LLKeyboardSDL() +{ + // Set up key mapping for SDL - eventually can read this from a file? + // Anything not in the key map gets dropped + // Add default A-Z + + // Virtual key mappings from SDL_keysym.h ... + + // SDL maps the letter keys to the ASCII you'd expect, but it's lowercase... + U16 cur_char; + for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) + { + mTranslateKeyMap[cur_char] = cur_char; + } + for (cur_char = 'a'; cur_char <= 'z'; cur_char++) + { + mTranslateKeyMap[cur_char] = (cur_char - 'a') + 'A'; + } + + for (cur_char = '0'; cur_char <= '9'; cur_char++) + { + mTranslateKeyMap[cur_char] = cur_char; + } + + // These ones are translated manually upon keydown/keyup because + // SDL doesn't handle their numlock transition. + //mTranslateKeyMap[SDLK_KP4] = KEY_PAD_LEFT; + //mTranslateKeyMap[SDLK_KP6] = KEY_PAD_RIGHT; + //mTranslateKeyMap[SDLK_KP8] = KEY_PAD_UP; + //mTranslateKeyMap[SDLK_KP2] = KEY_PAD_DOWN; + //mTranslateKeyMap[SDLK_KP_PERIOD] = KEY_DELETE; + //mTranslateKeyMap[SDLK_KP7] = KEY_HOME; + //mTranslateKeyMap[SDLK_KP1] = KEY_END; + //mTranslateKeyMap[SDLK_KP9] = KEY_PAGE_UP; + //mTranslateKeyMap[SDLK_KP3] = KEY_PAGE_DOWN; + //mTranslateKeyMap[SDLK_KP0] = KEY_INSERT; + + mTranslateKeyMap[SDLK_SPACE] = ' '; + mTranslateKeyMap[SDLK_RETURN] = KEY_RETURN; + mTranslateKeyMap[SDLK_LEFT] = KEY_LEFT; + mTranslateKeyMap[SDLK_RIGHT] = KEY_RIGHT; + mTranslateKeyMap[SDLK_UP] = KEY_UP; + mTranslateKeyMap[SDLK_DOWN] = KEY_DOWN; + mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; + mTranslateKeyMap[SDLK_KP_ENTER] = KEY_RETURN; + mTranslateKeyMap[SDLK_ESCAPE] = KEY_ESCAPE; + mTranslateKeyMap[SDLK_BACKSPACE] = KEY_BACKSPACE; + mTranslateKeyMap[SDLK_DELETE] = KEY_DELETE; + mTranslateKeyMap[SDLK_LSHIFT] = KEY_SHIFT; + mTranslateKeyMap[SDLK_RSHIFT] = KEY_SHIFT; + mTranslateKeyMap[SDLK_LCTRL] = KEY_CONTROL; + mTranslateKeyMap[SDLK_RCTRL] = KEY_CONTROL; + mTranslateKeyMap[SDLK_LALT] = KEY_ALT; + mTranslateKeyMap[SDLK_RALT] = KEY_ALT; + mTranslateKeyMap[SDLK_HOME] = KEY_HOME; + mTranslateKeyMap[SDLK_END] = KEY_END; + mTranslateKeyMap[SDLK_PAGEUP] = KEY_PAGE_UP; + mTranslateKeyMap[SDLK_PAGEDOWN] = KEY_PAGE_DOWN; + mTranslateKeyMap[SDLK_MINUS] = KEY_HYPHEN; + mTranslateKeyMap[SDLK_EQUALS] = KEY_EQUALS; + mTranslateKeyMap[SDLK_KP_EQUALS] = KEY_EQUALS; + mTranslateKeyMap[SDLK_INSERT] = KEY_INSERT; + mTranslateKeyMap[SDLK_CAPSLOCK] = KEY_CAPSLOCK; + mTranslateKeyMap[SDLK_TAB] = KEY_TAB; + mTranslateKeyMap[SDLK_KP_PLUS] = KEY_ADD; + mTranslateKeyMap[SDLK_KP_MINUS] = KEY_SUBTRACT; + mTranslateKeyMap[SDLK_KP_MULTIPLY] = KEY_MULTIPLY; + mTranslateKeyMap[SDLK_KP_DIVIDE] = KEY_PAD_DIVIDE; + mTranslateKeyMap[SDLK_F1] = KEY_F1; + mTranslateKeyMap[SDLK_F2] = KEY_F2; + mTranslateKeyMap[SDLK_F3] = KEY_F3; + mTranslateKeyMap[SDLK_F4] = KEY_F4; + mTranslateKeyMap[SDLK_F5] = KEY_F5; + mTranslateKeyMap[SDLK_F6] = KEY_F6; + mTranslateKeyMap[SDLK_F7] = KEY_F7; + mTranslateKeyMap[SDLK_F8] = KEY_F8; + mTranslateKeyMap[SDLK_F9] = KEY_F9; + mTranslateKeyMap[SDLK_F10] = KEY_F10; + mTranslateKeyMap[SDLK_F11] = KEY_F11; + mTranslateKeyMap[SDLK_F12] = KEY_F12; + mTranslateKeyMap[SDLK_PLUS] = '='; + mTranslateKeyMap[SDLK_COMMA] = ','; + mTranslateKeyMap[SDLK_MINUS] = '-'; + mTranslateKeyMap[SDLK_PERIOD] = '.'; + mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; + mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; + mTranslateKeyMap[SDLK_SEMICOLON] = ';'; + mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; + mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; + mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; + mTranslateKeyMap[SDLK_QUOTE] = '\''; + + // Build inverse map + std::map::iterator iter; + for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + { + mInvTranslateKeyMap[iter->second] = iter->first; + } + + // numpad map + mTranslateNumpadMap[SDLK_KP0] = KEY_PAD_INS; + mTranslateNumpadMap[SDLK_KP1] = KEY_PAD_END; + mTranslateNumpadMap[SDLK_KP2] = KEY_PAD_DOWN; + mTranslateNumpadMap[SDLK_KP3] = KEY_PAD_PGDN; + mTranslateNumpadMap[SDLK_KP4] = KEY_PAD_LEFT; + mTranslateNumpadMap[SDLK_KP5] = KEY_PAD_CENTER; + mTranslateNumpadMap[SDLK_KP6] = KEY_PAD_RIGHT; + mTranslateNumpadMap[SDLK_KP7] = KEY_PAD_HOME; + mTranslateNumpadMap[SDLK_KP8] = KEY_PAD_UP; + mTranslateNumpadMap[SDLK_KP9] = KEY_PAD_PGUP; + mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL; + + // build inverse numpad map + for (iter = mTranslateNumpadMap.begin(); + iter != mTranslateNumpadMap.end(); + iter++) + { + mInvTranslateNumpadMap[iter->second] = iter->first; + } +} + +void LLKeyboardSDL::resetMaskKeys() +{ + SDLMod mask = SDL_GetModState(); + + // MBW -- XXX -- This mirrors the operation of the Windows version of resetMaskKeys(). + // It looks a bit suspicious, as it won't correct for keys that have been released. + // Is this the way it's supposed to work? + + if(mask & KMOD_SHIFT) + { + mKeyLevel[KEY_SHIFT] = true; + } + + if(mask & KMOD_CTRL) + { + mKeyLevel[KEY_CONTROL] = true; + } + + if(mask & KMOD_ALT) + { + mKeyLevel[KEY_ALT] = true; + } +} + + +MASK LLKeyboardSDL::updateModifiers(const U32 mask) +{ + // translate the mask + MASK out_mask = MASK_NONE; + + if(mask & KMOD_SHIFT) + { + out_mask |= MASK_SHIFT; + } + + if(mask & KMOD_CTRL) + { + out_mask |= MASK_CONTROL; + } + + if(mask & KMOD_ALT) + { + out_mask |= MASK_ALT; + } + + return out_mask; +} + + +static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) +{ + // SDL doesn't automatically adjust the keysym according to + // whether NUMLOCK is engaged, so we massage the keysym manually. + U16 rtn = key; + if (!(mask & KMOD_NUM)) + { + switch (key) + { + case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; + case SDLK_KP0: rtn = SDLK_INSERT; break; + case SDLK_KP1: rtn = SDLK_END; break; + case SDLK_KP2: rtn = SDLK_DOWN; break; + case SDLK_KP3: rtn = SDLK_PAGEDOWN; break; + case SDLK_KP4: rtn = SDLK_LEFT; break; + case SDLK_KP6: rtn = SDLK_RIGHT; break; + case SDLK_KP7: rtn = SDLK_HOME; break; + case SDLK_KP8: rtn = SDLK_UP; break; + case SDLK_KP9: rtn = SDLK_PAGEUP; break; + } + } + return rtn; +} + + +bool LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) +{ + U16 adjusted_nativekey; + KEY translated_key = 0; + U32 translated_mask = MASK_NONE; + bool handled = false; + + adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); + + translated_mask = updateModifiers(mask); + + if(translateNumpadKey(adjusted_nativekey, &translated_key)) + { + handled = handleTranslatedKeyDown(translated_key, translated_mask); + } + + return handled; +} + + +bool LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +{ + U16 adjusted_nativekey; + KEY translated_key = 0; + U32 translated_mask = MASK_NONE; + bool handled = false; + + adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); + + translated_mask = updateModifiers(mask); + + if(translateNumpadKey(adjusted_nativekey, &translated_key)) + { + handled = handleTranslatedKeyUp(translated_key, translated_mask); + } + + return handled; +} + +MASK LLKeyboardSDL::currentMask(bool for_mouse_event) +{ + MASK result = MASK_NONE; + SDLMod mask = SDL_GetModState(); + + if (mask & KMOD_SHIFT) result |= MASK_SHIFT; + if (mask & KMOD_CTRL) result |= MASK_CONTROL; + if (mask & KMOD_ALT) result |= MASK_ALT; + + // For keyboard events, consider Meta keys equivalent to Control + if (!for_mouse_event) + { + if (mask & KMOD_META) result |= MASK_CONTROL; + } + + return result; +} + +void LLKeyboardSDL::scanKeyboard() +{ + for (S32 key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (S32 key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = false; + mKeyDown[key] = false; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} + + +bool LLKeyboardSDL::translateNumpadKey( const U16 os_key, KEY *translated_key) +{ + return translateKey(os_key, translated_key); +} + +U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key) +{ + return inverseTranslateKey(translated_key); +} + +#endif + diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index f1c069c242..fd348b28f2 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -1,55 +1,55 @@ -/** - * @file llkeyboardsdl.h - * @brief Handler for assignable key bindings - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#ifndef LL_LLKEYBOARDSDL_H -#define LL_LLKEYBOARDSDL_H - -#include "llkeyboard.h" -#include "SDL/SDL.h" - -class LLKeyboardSDL : public LLKeyboard -{ -public: - LLKeyboardSDL(); - /*virtual*/ ~LLKeyboardSDL() {}; - - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - -protected: - MASK updateModifiers(const U32 mask); - void setModifierKeyLevel( KEY key, bool new_state ); - bool translateNumpadKey( const U16 os_key, KEY *translated_key ); - U16 inverseTranslateNumpadKey(const KEY translated_key); -private: - std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys - std::map mInvTranslateNumpadMap; // inverse of the above -}; - -#endif +/** + * @file llkeyboardsdl.h + * @brief Handler for assignable key bindings + * + * $LicenseInfo:firstyear=2004&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$ + */ + +#ifndef LL_LLKEYBOARDSDL_H +#define LL_LLKEYBOARDSDL_H + +#include "llkeyboard.h" +#include "SDL/SDL.h" + +class LLKeyboardSDL : public LLKeyboard +{ +public: + LLKeyboardSDL(); + /*virtual*/ ~LLKeyboardSDL() {}; + + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); + /*virtual*/ void resetMaskKeys(); + /*virtual*/ MASK currentMask(bool for_mouse_event); + /*virtual*/ void scanKeyboard(); + +protected: + MASK updateModifiers(const U32 mask); + void setModifierKeyLevel( KEY key, bool new_state ); + bool translateNumpadKey( const U16 os_key, KEY *translated_key ); + U16 inverseTranslateNumpadKey(const KEY translated_key); +private: + std::map mTranslateNumpadMap; // special map for translating OS keys to numpad keys + std::map mInvTranslateNumpadMap; // inverse of the above +}; + +#endif diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index 510d680941..ec0055fe60 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -1,324 +1,324 @@ -/** - * @file llkeyboardwin32.cpp - * @brief Handler for assignable key bindings - * - * $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$ - */ - -#if LL_WINDOWS - -#include "linden_common.h" - -#include "llwin32headerslean.h" -#include "llkeyboardwin32.h" - -#include "llwindowcallbacks.h" - - - -LLKeyboardWin32::LLKeyboardWin32() -{ - // Set up key mapping for windows - eventually can read this from a file? - // Anything not in the key map gets dropped - // Add default A-Z - - // Virtual key mappings from WinUser.h - - KEY cur_char; - for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) - { - mTranslateKeyMap[cur_char] = (KEY)cur_char; - } - - for (cur_char = '0'; cur_char <= '9'; cur_char++) - { - mTranslateKeyMap[cur_char] = (KEY)cur_char; - } - // numpad number keys - for (cur_char = 0x60; cur_char <= 0x69; cur_char++) - { - mTranslateKeyMap[cur_char] = (KEY)('0' + (cur_char - 0x60)); - } - - - mTranslateKeyMap[VK_SPACE] = ' '; - mTranslateKeyMap[VK_OEM_1] = ';'; - // When the user hits, for example, Ctrl-= as a keyboard shortcut, - // Windows generates VK_OEM_PLUS. This is true on both QWERTY and DVORAK - // keyboards in the US. Numeric keypad '+' generates VK_ADD below. - // Thus we translate it as '='. - // Potential bug: This may not be true on international keyboards. JC - mTranslateKeyMap[VK_OEM_PLUS] = '='; - mTranslateKeyMap[VK_OEM_COMMA] = ','; - mTranslateKeyMap[VK_OEM_MINUS] = '-'; - mTranslateKeyMap[VK_OEM_PERIOD] = '.'; - mTranslateKeyMap[VK_OEM_2] = '/';//This used to be KEY_PAD_DIVIDE, but that breaks typing into text fields in media prims - mTranslateKeyMap[VK_OEM_3] = '`'; - mTranslateKeyMap[VK_OEM_4] = '['; - mTranslateKeyMap[VK_OEM_5] = '\\'; - mTranslateKeyMap[VK_OEM_6] = ']'; - mTranslateKeyMap[VK_OEM_7] = '\''; - mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE; - mTranslateKeyMap[VK_RETURN] = KEY_RETURN; - mTranslateKeyMap[VK_LEFT] = KEY_LEFT; - mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT; - mTranslateKeyMap[VK_UP] = KEY_UP; - mTranslateKeyMap[VK_DOWN] = KEY_DOWN; - mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE; - mTranslateKeyMap[VK_INSERT] = KEY_INSERT; - mTranslateKeyMap[VK_DELETE] = KEY_DELETE; - mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT; - mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL; - mTranslateKeyMap[VK_MENU] = KEY_ALT; - mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK; - mTranslateKeyMap[VK_HOME] = KEY_HOME; - mTranslateKeyMap[VK_END] = KEY_END; - mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP; - mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN; - mTranslateKeyMap[VK_TAB] = KEY_TAB; - mTranslateKeyMap[VK_ADD] = KEY_ADD; - mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT; - mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY; - mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE; - mTranslateKeyMap[VK_F1] = KEY_F1; - mTranslateKeyMap[VK_F2] = KEY_F2; - mTranslateKeyMap[VK_F3] = KEY_F3; - mTranslateKeyMap[VK_F4] = KEY_F4; - mTranslateKeyMap[VK_F5] = KEY_F5; - mTranslateKeyMap[VK_F6] = KEY_F6; - mTranslateKeyMap[VK_F7] = KEY_F7; - mTranslateKeyMap[VK_F8] = KEY_F8; - mTranslateKeyMap[VK_F9] = KEY_F9; - mTranslateKeyMap[VK_F10] = KEY_F10; - mTranslateKeyMap[VK_F11] = KEY_F11; - mTranslateKeyMap[VK_F12] = KEY_F12; - mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER; - - // Build inverse map - std::map::iterator iter; - for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) - { - mInvTranslateKeyMap[iter->second] = iter->first; - } - - // numpad map - mTranslateNumpadMap[0x60] = KEY_PAD_INS; // keypad 0 - mTranslateNumpadMap[0x61] = KEY_PAD_END; // keypad 1 - mTranslateNumpadMap[0x62] = KEY_PAD_DOWN; // keypad 2 - mTranslateNumpadMap[0x63] = KEY_PAD_PGDN; // keypad 3 - mTranslateNumpadMap[0x64] = KEY_PAD_LEFT; // keypad 4 - mTranslateNumpadMap[0x65] = KEY_PAD_CENTER; // keypad 5 - mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT; // keypad 6 - mTranslateNumpadMap[0x67] = KEY_PAD_HOME; // keypad 7 - mTranslateNumpadMap[0x68] = KEY_PAD_UP; // keypad 8 - mTranslateNumpadMap[0x69] = KEY_PAD_PGUP; // keypad 9 - mTranslateNumpadMap[0x6A] = KEY_PAD_MULTIPLY; // keypad * - mTranslateNumpadMap[0x6B] = KEY_PAD_ADD; // keypad + - mTranslateNumpadMap[0x6D] = KEY_PAD_SUBTRACT; // keypad - - mTranslateNumpadMap[0x6E] = KEY_PAD_DEL; // keypad . - mTranslateNumpadMap[0x6F] = KEY_PAD_DIVIDE; // keypad / - - for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) - { - mInvTranslateNumpadMap[iter->second] = iter->first; - } -} - -// Asynchronously poll the control, alt and shift keys and set the -// appropriate states. -// Note: this does not generate edges. -void LLKeyboardWin32::resetMaskKeys() -{ - // GetAsyncKeyState returns a short and uses the most significant - // bit to indicate that the key is down. - if (GetAsyncKeyState(VK_SHIFT) & 0x8000) - { - mKeyLevel[KEY_SHIFT] = true; - } - - if (GetAsyncKeyState(VK_CONTROL) & 0x8000) - { - mKeyLevel[KEY_CONTROL] = true; - } - - if (GetAsyncKeyState(VK_MENU) & 0x8000) - { - mKeyLevel[KEY_ALT] = true; - } -} - - -//void LLKeyboardWin32::setModifierKeyLevel( KEY key, bool new_state ) -//{ -// if( mKeyLevel[key] != new_state ) -// { -// mKeyLevelFrameCount[key] = 0; -// -// if( new_state ) -// { -// mKeyLevelTimer[key].reset(); -// } -// mKeyLevel[key] = new_state; -// } -//} - - -MASK LLKeyboardWin32::updateModifiers() -{ - //RN: this seems redundant, as we should have already received the appropriate - // messages for the modifier keys - - // Scan the modifier keys as of the last Windows key message - // (keydown encoded in high order bit of short) - mKeyLevel[KEY_CAPSLOCK] = (GetKeyState(VK_CAPITAL) & 0x0001) != 0; // Low order bit carries the toggle state. - // Get mask for keyboard events - MASK mask = currentMask(false); - return mask; -} - - -// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) -{ - KEY translated_key; - U32 translated_mask; - bool handled = false; - - translated_mask = updateModifiers(); - - if (translateExtendedKey(key, mask, &translated_key)) - { - handled = handleTranslatedKeyDown(translated_key, translated_mask); - } - - return handled; -} - -// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags -bool LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) -{ - KEY translated_key; - U32 translated_mask; - bool handled = false; - - translated_mask = updateModifiers(); - - if (translateExtendedKey(key, mask, &translated_key)) - { - handled = handleTranslatedKeyUp(translated_key, translated_mask); - } - - return handled; -} - - -MASK LLKeyboardWin32::currentMask(bool) -{ - MASK mask = MASK_NONE; - - if (mKeyLevel[KEY_SHIFT]) mask |= MASK_SHIFT; - if (mKeyLevel[KEY_CONTROL]) mask |= MASK_CONTROL; - if (mKeyLevel[KEY_ALT]) mask |= MASK_ALT; - - return mask; -} - - -void LLKeyboardWin32::scanKeyboard() -{ - S32 key; - MSG msg; - PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD); - for (key = 0; key < KEY_COUNT; key++) - { - // Generate callback if any event has occurred on this key this frame. - // Can't just test mKeyLevel, because this could be a slow frame and - // key might have gone down then up. JC - if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) - { - mCurScanKey = key; - mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); - } - } - - // Reset edges for next frame - for (key = 0; key < KEY_COUNT; key++) - { - mKeyUp[key] = false; - mKeyDown[key] = false; - if (mKeyLevel[key]) - { - mKeyLevelFrameCount[key]++; - } - } -} - -bool LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) -{ - return translateKey(os_key, translated_key); -} - -U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key) -{ - // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number - if(GetKeyState(VK_NUMLOCK) & 1) - { - std::map::iterator iter = mInvTranslateNumpadMap.find(translated_key); - if (iter != mInvTranslateNumpadMap.end()) - { - return iter->second; - } - } - - // if numlock is off or we're not converting numbers to arrows, we map our keypad arrows - // to regular arrows since Windows doesn't distinguish between them - KEY converted_key = translated_key; - switch (converted_key) - { - case KEY_PAD_LEFT: - converted_key = KEY_LEFT; break; - case KEY_PAD_RIGHT: - converted_key = KEY_RIGHT; break; - case KEY_PAD_UP: - converted_key = KEY_UP; break; - case KEY_PAD_DOWN: - converted_key = KEY_DOWN; break; - case KEY_PAD_HOME: - converted_key = KEY_HOME; break; - case KEY_PAD_END: - converted_key = KEY_END; break; - case KEY_PAD_PGUP: - converted_key = KEY_PAGE_UP; break; - case KEY_PAD_PGDN: - converted_key = KEY_PAGE_DOWN; break; - case KEY_PAD_INS: - converted_key = KEY_INSERT; break; - case KEY_PAD_DEL: - converted_key = KEY_DELETE; break; - case KEY_PAD_RETURN: - converted_key = KEY_RETURN; break; - } - // convert our virtual keys to OS keys - return inverseTranslateKey(converted_key); -} - -#endif +/** + * @file llkeyboardwin32.cpp + * @brief Handler for assignable key bindings + * + * $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$ + */ + +#if LL_WINDOWS + +#include "linden_common.h" + +#include "llwin32headerslean.h" +#include "llkeyboardwin32.h" + +#include "llwindowcallbacks.h" + + + +LLKeyboardWin32::LLKeyboardWin32() +{ + // Set up key mapping for windows - eventually can read this from a file? + // Anything not in the key map gets dropped + // Add default A-Z + + // Virtual key mappings from WinUser.h + + KEY cur_char; + for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) + { + mTranslateKeyMap[cur_char] = (KEY)cur_char; + } + + for (cur_char = '0'; cur_char <= '9'; cur_char++) + { + mTranslateKeyMap[cur_char] = (KEY)cur_char; + } + // numpad number keys + for (cur_char = 0x60; cur_char <= 0x69; cur_char++) + { + mTranslateKeyMap[cur_char] = (KEY)('0' + (cur_char - 0x60)); + } + + + mTranslateKeyMap[VK_SPACE] = ' '; + mTranslateKeyMap[VK_OEM_1] = ';'; + // When the user hits, for example, Ctrl-= as a keyboard shortcut, + // Windows generates VK_OEM_PLUS. This is true on both QWERTY and DVORAK + // keyboards in the US. Numeric keypad '+' generates VK_ADD below. + // Thus we translate it as '='. + // Potential bug: This may not be true on international keyboards. JC + mTranslateKeyMap[VK_OEM_PLUS] = '='; + mTranslateKeyMap[VK_OEM_COMMA] = ','; + mTranslateKeyMap[VK_OEM_MINUS] = '-'; + mTranslateKeyMap[VK_OEM_PERIOD] = '.'; + mTranslateKeyMap[VK_OEM_2] = '/';//This used to be KEY_PAD_DIVIDE, but that breaks typing into text fields in media prims + mTranslateKeyMap[VK_OEM_3] = '`'; + mTranslateKeyMap[VK_OEM_4] = '['; + mTranslateKeyMap[VK_OEM_5] = '\\'; + mTranslateKeyMap[VK_OEM_6] = ']'; + mTranslateKeyMap[VK_OEM_7] = '\''; + mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE; + mTranslateKeyMap[VK_RETURN] = KEY_RETURN; + mTranslateKeyMap[VK_LEFT] = KEY_LEFT; + mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT; + mTranslateKeyMap[VK_UP] = KEY_UP; + mTranslateKeyMap[VK_DOWN] = KEY_DOWN; + mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE; + mTranslateKeyMap[VK_INSERT] = KEY_INSERT; + mTranslateKeyMap[VK_DELETE] = KEY_DELETE; + mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT; + mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL; + mTranslateKeyMap[VK_MENU] = KEY_ALT; + mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK; + mTranslateKeyMap[VK_HOME] = KEY_HOME; + mTranslateKeyMap[VK_END] = KEY_END; + mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP; + mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN; + mTranslateKeyMap[VK_TAB] = KEY_TAB; + mTranslateKeyMap[VK_ADD] = KEY_ADD; + mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT; + mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY; + mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE; + mTranslateKeyMap[VK_F1] = KEY_F1; + mTranslateKeyMap[VK_F2] = KEY_F2; + mTranslateKeyMap[VK_F3] = KEY_F3; + mTranslateKeyMap[VK_F4] = KEY_F4; + mTranslateKeyMap[VK_F5] = KEY_F5; + mTranslateKeyMap[VK_F6] = KEY_F6; + mTranslateKeyMap[VK_F7] = KEY_F7; + mTranslateKeyMap[VK_F8] = KEY_F8; + mTranslateKeyMap[VK_F9] = KEY_F9; + mTranslateKeyMap[VK_F10] = KEY_F10; + mTranslateKeyMap[VK_F11] = KEY_F11; + mTranslateKeyMap[VK_F12] = KEY_F12; + mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER; + + // Build inverse map + std::map::iterator iter; + for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + { + mInvTranslateKeyMap[iter->second] = iter->first; + } + + // numpad map + mTranslateNumpadMap[0x60] = KEY_PAD_INS; // keypad 0 + mTranslateNumpadMap[0x61] = KEY_PAD_END; // keypad 1 + mTranslateNumpadMap[0x62] = KEY_PAD_DOWN; // keypad 2 + mTranslateNumpadMap[0x63] = KEY_PAD_PGDN; // keypad 3 + mTranslateNumpadMap[0x64] = KEY_PAD_LEFT; // keypad 4 + mTranslateNumpadMap[0x65] = KEY_PAD_CENTER; // keypad 5 + mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT; // keypad 6 + mTranslateNumpadMap[0x67] = KEY_PAD_HOME; // keypad 7 + mTranslateNumpadMap[0x68] = KEY_PAD_UP; // keypad 8 + mTranslateNumpadMap[0x69] = KEY_PAD_PGUP; // keypad 9 + mTranslateNumpadMap[0x6A] = KEY_PAD_MULTIPLY; // keypad * + mTranslateNumpadMap[0x6B] = KEY_PAD_ADD; // keypad + + mTranslateNumpadMap[0x6D] = KEY_PAD_SUBTRACT; // keypad - + mTranslateNumpadMap[0x6E] = KEY_PAD_DEL; // keypad . + mTranslateNumpadMap[0x6F] = KEY_PAD_DIVIDE; // keypad / + + for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) + { + mInvTranslateNumpadMap[iter->second] = iter->first; + } +} + +// Asynchronously poll the control, alt and shift keys and set the +// appropriate states. +// Note: this does not generate edges. +void LLKeyboardWin32::resetMaskKeys() +{ + // GetAsyncKeyState returns a short and uses the most significant + // bit to indicate that the key is down. + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + { + mKeyLevel[KEY_SHIFT] = true; + } + + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + mKeyLevel[KEY_CONTROL] = true; + } + + if (GetAsyncKeyState(VK_MENU) & 0x8000) + { + mKeyLevel[KEY_ALT] = true; + } +} + + +//void LLKeyboardWin32::setModifierKeyLevel( KEY key, bool new_state ) +//{ +// if( mKeyLevel[key] != new_state ) +// { +// mKeyLevelFrameCount[key] = 0; +// +// if( new_state ) +// { +// mKeyLevelTimer[key].reset(); +// } +// mKeyLevel[key] = new_state; +// } +//} + + +MASK LLKeyboardWin32::updateModifiers() +{ + //RN: this seems redundant, as we should have already received the appropriate + // messages for the modifier keys + + // Scan the modifier keys as of the last Windows key message + // (keydown encoded in high order bit of short) + mKeyLevel[KEY_CAPSLOCK] = (GetKeyState(VK_CAPITAL) & 0x0001) != 0; // Low order bit carries the toggle state. + // Get mask for keyboard events + MASK mask = currentMask(false); + return mask; +} + + +// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags +bool LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) +{ + KEY translated_key; + U32 translated_mask; + bool handled = false; + + translated_mask = updateModifiers(); + + if (translateExtendedKey(key, mask, &translated_key)) + { + handled = handleTranslatedKeyDown(translated_key, translated_mask); + } + + return handled; +} + +// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags +bool LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) +{ + KEY translated_key; + U32 translated_mask; + bool handled = false; + + translated_mask = updateModifiers(); + + if (translateExtendedKey(key, mask, &translated_key)) + { + handled = handleTranslatedKeyUp(translated_key, translated_mask); + } + + return handled; +} + + +MASK LLKeyboardWin32::currentMask(bool) +{ + MASK mask = MASK_NONE; + + if (mKeyLevel[KEY_SHIFT]) mask |= MASK_SHIFT; + if (mKeyLevel[KEY_CONTROL]) mask |= MASK_CONTROL; + if (mKeyLevel[KEY_ALT]) mask |= MASK_ALT; + + return mask; +} + + +void LLKeyboardWin32::scanKeyboard() +{ + S32 key; + MSG msg; + PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD); + for (key = 0; key < KEY_COUNT; key++) + { + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = false; + mKeyDown[key] = false; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} + +bool LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) +{ + return translateKey(os_key, translated_key); +} + +U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key) +{ + // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number + if(GetKeyState(VK_NUMLOCK) & 1) + { + std::map::iterator iter = mInvTranslateNumpadMap.find(translated_key); + if (iter != mInvTranslateNumpadMap.end()) + { + return iter->second; + } + } + + // if numlock is off or we're not converting numbers to arrows, we map our keypad arrows + // to regular arrows since Windows doesn't distinguish between them + KEY converted_key = translated_key; + switch (converted_key) + { + case KEY_PAD_LEFT: + converted_key = KEY_LEFT; break; + case KEY_PAD_RIGHT: + converted_key = KEY_RIGHT; break; + case KEY_PAD_UP: + converted_key = KEY_UP; break; + case KEY_PAD_DOWN: + converted_key = KEY_DOWN; break; + case KEY_PAD_HOME: + converted_key = KEY_HOME; break; + case KEY_PAD_END: + converted_key = KEY_END; break; + case KEY_PAD_PGUP: + converted_key = KEY_PAGE_UP; break; + case KEY_PAD_PGDN: + converted_key = KEY_PAGE_DOWN; break; + case KEY_PAD_INS: + converted_key = KEY_INSERT; break; + case KEY_PAD_DEL: + converted_key = KEY_DELETE; break; + case KEY_PAD_RETURN: + converted_key = KEY_RETURN; break; + } + // convert our virtual keys to OS keys + return inverseTranslateKey(converted_key); +} + +#endif diff --git a/indra/llwindow/llkeyboardwin32.h b/indra/llwindow/llkeyboardwin32.h index 7788af8011..d0dfc5cfdd 100644 --- a/indra/llwindow/llkeyboardwin32.h +++ b/indra/llwindow/llkeyboardwin32.h @@ -1,58 +1,58 @@ -/** - * @file llkeyboardwin32.h - * @brief Handler for assignable key bindings - * - * $LicenseInfo:firstyear=2004&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$ - */ - -#ifndef LL_LLKEYBOARDWIN32_H -#define LL_LLKEYBOARDWIN32_H - -#include "llkeyboard.h" - -// this mask distinguishes extended keys, which include non-numpad arrow keys -// (and, curiously, the num lock and numpad '/') -const MASK MASK_EXTENDED = 0x0100; - -class LLKeyboardWin32 : public LLKeyboard -{ -public: - LLKeyboardWin32(); - /*virtual*/ ~LLKeyboardWin32() {}; - - /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); - /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); - /*virtual*/ void resetMaskKeys(); - /*virtual*/ MASK currentMask(bool for_mouse_event); - /*virtual*/ void scanKeyboard(); - bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); - U16 inverseTranslateExtendedKey(const KEY translated_key); - -protected: - MASK updateModifiers(); - //void setModifierKeyLevel( KEY key, bool new_state ); -private: - std::map mTranslateNumpadMap; - std::map mInvTranslateNumpadMap; -}; - -#endif +/** + * @file llkeyboardwin32.h + * @brief Handler for assignable key bindings + * + * $LicenseInfo:firstyear=2004&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$ + */ + +#ifndef LL_LLKEYBOARDWIN32_H +#define LL_LLKEYBOARDWIN32_H + +#include "llkeyboard.h" + +// this mask distinguishes extended keys, which include non-numpad arrow keys +// (and, curiously, the num lock and numpad '/') +const MASK MASK_EXTENDED = 0x0100; + +class LLKeyboardWin32 : public LLKeyboard +{ +public: + LLKeyboardWin32(); + /*virtual*/ ~LLKeyboardWin32() {}; + + /*virtual*/ bool handleKeyUp(const U16 key, MASK mask); + /*virtual*/ bool handleKeyDown(const U16 key, MASK mask); + /*virtual*/ void resetMaskKeys(); + /*virtual*/ MASK currentMask(bool for_mouse_event); + /*virtual*/ void scanKeyboard(); + bool translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key); + U16 inverseTranslateExtendedKey(const KEY translated_key); + +protected: + MASK updateModifiers(); + //void setModifierKeyLevel( KEY key, bool new_state ); +private: + std::map mTranslateNumpadMap; + std::map mInvTranslateNumpadMap; +}; + +#endif diff --git a/indra/llwindow/llmousehandler.cpp b/indra/llwindow/llmousehandler.cpp index 6498d42642..eeceab502a 100644 --- a/indra/llwindow/llmousehandler.cpp +++ b/indra/llwindow/llmousehandler.cpp @@ -1,66 +1,66 @@ -/** - * @file llmousehandler.cpp - * @brief LLMouseHandler class implementation - * - * $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 "llmousehandler.h" - -//virtual -bool LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down) -{ - bool handled = false; - if (down) - { - switch (clicktype) - { - case CLICK_LEFT: handled = handleMouseDown(x, y, mask); break; - case CLICK_RIGHT: handled = handleRightMouseDown(x, y, mask); break; - case CLICK_MIDDLE: handled = handleMiddleMouseDown(x, y, mask); break; - case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; - case CLICK_BUTTON4: - case CLICK_BUTTON5: - LL_INFOS() << "Handle mouse button " << clicktype + 1 << " down." << LL_ENDL; - break; - default: - LL_WARNS() << "Unhandled enum." << LL_ENDL; - } - } - else - { - switch (clicktype) - { - case CLICK_LEFT: handled = handleMouseUp(x, y, mask); break; - case CLICK_RIGHT: handled = handleRightMouseUp(x, y, mask); break; - case CLICK_MIDDLE: handled = handleMiddleMouseUp(x, y, mask); break; - case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; - case CLICK_BUTTON4: - case CLICK_BUTTON5: - LL_INFOS() << "Handle mouse button " << clicktype + 1 << " up." << LL_ENDL; - break; - default: - LL_WARNS() << "Unhandled enum." << LL_ENDL; - } - } - return handled; -} +/** + * @file llmousehandler.cpp + * @brief LLMouseHandler class implementation + * + * $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 "llmousehandler.h" + +//virtual +bool LLMouseHandler::handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down) +{ + bool handled = false; + if (down) + { + switch (clicktype) + { + case CLICK_LEFT: handled = handleMouseDown(x, y, mask); break; + case CLICK_RIGHT: handled = handleRightMouseDown(x, y, mask); break; + case CLICK_MIDDLE: handled = handleMiddleMouseDown(x, y, mask); break; + case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + case CLICK_BUTTON4: + case CLICK_BUTTON5: + LL_INFOS() << "Handle mouse button " << clicktype + 1 << " down." << LL_ENDL; + break; + default: + LL_WARNS() << "Unhandled enum." << LL_ENDL; + } + } + else + { + switch (clicktype) + { + case CLICK_LEFT: handled = handleMouseUp(x, y, mask); break; + case CLICK_RIGHT: handled = handleRightMouseUp(x, y, mask); break; + case CLICK_MIDDLE: handled = handleMiddleMouseUp(x, y, mask); break; + case CLICK_DOUBLELEFT: handled = handleDoubleClick(x, y, mask); break; + case CLICK_BUTTON4: + case CLICK_BUTTON5: + LL_INFOS() << "Handle mouse button " << clicktype + 1 << " up." << LL_ENDL; + break; + default: + LL_WARNS() << "Unhandled enum." << LL_ENDL; + } + } + return handled; +} diff --git a/indra/llwindow/llmousehandler.h b/indra/llwindow/llmousehandler.h index fea750fa91..565d7bed70 100644 --- a/indra/llwindow/llmousehandler.h +++ b/indra/llwindow/llmousehandler.h @@ -1,73 +1,73 @@ -/** - * @file llmousehandler.h - * @brief LLMouseHandler class definition - * - * $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$ - */ - -#ifndef LL_MOUSEHANDLER_H -#define LL_MOUSEHANDLER_H - -#include "linden_common.h" -#include "llrect.h" -#include "indra_constants.h" - -// Mostly-abstract interface. -// Intended for use via multiple inheritance. -// A class may have as many interfaces as it likes, but never needs to inherit one more than once. - -class LLMouseHandler -{ -public: - LLMouseHandler() {} - virtual ~LLMouseHandler() {} - - typedef enum { - SHOW_NEVER, - SHOW_IF_NOT_BLOCKED, - SHOW_ALWAYS, - } EShowToolTip; - - virtual bool handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down); - virtual bool handleMouseDown(S32 x, S32 y, MASK mask) = 0; - virtual bool handleMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual bool handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; - virtual bool handleMiddleMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask) = 0; - virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask) = 0; - virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) = 0; - - virtual bool handleHover(S32 x, S32 y, MASK mask) = 0; - virtual bool handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; - virtual bool handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; - virtual bool handleToolTip(S32 x, S32 y, MASK mask) = 0; - virtual const std::string& getName() const = 0; - - virtual void onMouseCaptureLost() = 0; - - virtual void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const = 0; - virtual void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const = 0; - - virtual bool hasMouseCapture() = 0; -}; - -#endif +/** + * @file llmousehandler.h + * @brief LLMouseHandler class definition + * + * $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$ + */ + +#ifndef LL_MOUSEHANDLER_H +#define LL_MOUSEHANDLER_H + +#include "linden_common.h" +#include "llrect.h" +#include "indra_constants.h" + +// Mostly-abstract interface. +// Intended for use via multiple inheritance. +// A class may have as many interfaces as it likes, but never needs to inherit one more than once. + +class LLMouseHandler +{ +public: + LLMouseHandler() {} + virtual ~LLMouseHandler() {} + + typedef enum { + SHOW_NEVER, + SHOW_IF_NOT_BLOCKED, + SHOW_ALWAYS, + } EShowToolTip; + + virtual bool handleAnyMouseClick(S32 x, S32 y, MASK mask, EMouseClickType clicktype, bool down); + virtual bool handleMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual bool handleMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual bool handleMiddleMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual bool handleMiddleMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual bool handleRightMouseDown(S32 x, S32 y, MASK mask) = 0; + virtual bool handleRightMouseUp(S32 x, S32 y, MASK mask) = 0; + virtual bool handleDoubleClick(S32 x, S32 y, MASK mask) = 0; + + virtual bool handleHover(S32 x, S32 y, MASK mask) = 0; + virtual bool handleScrollWheel(S32 x, S32 y, S32 clicks) = 0; + virtual bool handleScrollHWheel(S32 x, S32 y, S32 clicks) = 0; + virtual bool handleToolTip(S32 x, S32 y, MASK mask) = 0; + virtual const std::string& getName() const = 0; + + virtual void onMouseCaptureLost() = 0; + + virtual void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const = 0; + virtual void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const = 0; + + virtual bool hasMouseCapture() = 0; +}; + +#endif diff --git a/indra/llwindow/llpreeditor.h b/indra/llwindow/llpreeditor.h index 915957e63a..492a3e9e88 100644 --- a/indra/llwindow/llpreeditor.h +++ b/indra/llwindow/llpreeditor.h @@ -1,101 +1,101 @@ -/** - * @file llpreeditor.h - * @brief I believe this is used for languages like Japanese that require - * an "input method editor" to type Kanji. - * @author Open source patch, incorporated by Dave Simmons - * - * $LicenseInfo:firstyear=2007&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$ - */ - -#ifndef LL_PREEDITOR -#define LL_PREEDITOR - -class LLPreeditor -{ -public: - - typedef std::vector segment_lengths_t; - typedef std::deque standouts_t; - - // We don't delete against LLPreeditor, but compilers complain without this... - - virtual ~LLPreeditor() {}; - - // Discard any preedit info. on this preeditor. - - virtual void resetPreedit() = 0; - - // Update the preedit feedback using specified details. - // Existing preedit is discarded and replaced with the new one. (I.e., updatePreedit is not cumulative.) - // All arguments are IN. - // preedit_count is the number of elements in arrays preedit_list and preedit_standouts. - // preedit list is an array of preedit texts (clauses.) - // preedit_standouts indicates whether each preedit text should be shown as standout clause. - // caret_position is the preedit-local position of text editing caret, in # of llwchar. - - virtual void updatePreedit(const LLWString &preedit_string, - const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) = 0; - - // Turn the specified sub-contents into an active preedit. - // Both position and length are IN and count with UTF-32 (llwchar) characters. - // This method primarily facilitates reconversion. - - virtual void markAsPreedit(S32 position, S32 length) = 0; - - // Get the position and the length of the active preedit in the contents. - // Both position and length are OUT and count with UTF-32 (llwchar) characters. - // When this preeditor has no active preedit, position receives - // the caret position, and length receives 0. - - virtual void getPreeditRange(S32 *position, S32 *length) const = 0; - - // Get the position and the length of the current selection in the contents. - // Both position and length are OUT and count with UTF-32 (llwchar) characters. - // When this preeditor has no selection, position receives - // the caret position, and length receives 0. - - virtual void getSelectionRange(S32 *position, S32 *length) const = 0; - - // Get the locations where the preedit and related UI elements are displayed. - // Locations are relative to the app window and measured in GL coordinate space (before scaling.) - // query_position is IN argument, and other three are OUT. - - virtual bool getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const = 0; - - // Get the size (height) of the current font used in this preeditor. - - virtual S32 getPreeditFontSize() const = 0; - - // Get the contents of this preeditor as a LLWString. If there is an active preedit, - // the returned LLWString contains it. - - virtual LLWString getPreeditString() const = 0; - - // Handle a UTF-32 char on this preeditor, i.e., add the character - // to the contents. - // This is a back door of the method of same name of LLWindowCallback. - // called_from_parent should be set to false if calling through LLPreeditor. - - virtual bool handleUnicodeCharHere(llwchar uni_char) = 0; -}; - -#endif +/** + * @file llpreeditor.h + * @brief I believe this is used for languages like Japanese that require + * an "input method editor" to type Kanji. + * @author Open source patch, incorporated by Dave Simmons + * + * $LicenseInfo:firstyear=2007&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$ + */ + +#ifndef LL_PREEDITOR +#define LL_PREEDITOR + +class LLPreeditor +{ +public: + + typedef std::vector segment_lengths_t; + typedef std::deque standouts_t; + + // We don't delete against LLPreeditor, but compilers complain without this... + + virtual ~LLPreeditor() {}; + + // Discard any preedit info. on this preeditor. + + virtual void resetPreedit() = 0; + + // Update the preedit feedback using specified details. + // Existing preedit is discarded and replaced with the new one. (I.e., updatePreedit is not cumulative.) + // All arguments are IN. + // preedit_count is the number of elements in arrays preedit_list and preedit_standouts. + // preedit list is an array of preedit texts (clauses.) + // preedit_standouts indicates whether each preedit text should be shown as standout clause. + // caret_position is the preedit-local position of text editing caret, in # of llwchar. + + virtual void updatePreedit(const LLWString &preedit_string, + const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) = 0; + + // Turn the specified sub-contents into an active preedit. + // Both position and length are IN and count with UTF-32 (llwchar) characters. + // This method primarily facilitates reconversion. + + virtual void markAsPreedit(S32 position, S32 length) = 0; + + // Get the position and the length of the active preedit in the contents. + // Both position and length are OUT and count with UTF-32 (llwchar) characters. + // When this preeditor has no active preedit, position receives + // the caret position, and length receives 0. + + virtual void getPreeditRange(S32 *position, S32 *length) const = 0; + + // Get the position and the length of the current selection in the contents. + // Both position and length are OUT and count with UTF-32 (llwchar) characters. + // When this preeditor has no selection, position receives + // the caret position, and length receives 0. + + virtual void getSelectionRange(S32 *position, S32 *length) const = 0; + + // Get the locations where the preedit and related UI elements are displayed. + // Locations are relative to the app window and measured in GL coordinate space (before scaling.) + // query_position is IN argument, and other three are OUT. + + virtual bool getPreeditLocation(S32 query_position, LLCoordGL *coord, LLRect *bounds, LLRect *control) const = 0; + + // Get the size (height) of the current font used in this preeditor. + + virtual S32 getPreeditFontSize() const = 0; + + // Get the contents of this preeditor as a LLWString. If there is an active preedit, + // the returned LLWString contains it. + + virtual LLWString getPreeditString() const = 0; + + // Handle a UTF-32 char on this preeditor, i.e., add the character + // to the contents. + // This is a back door of the method of same name of LLWindowCallback. + // called_from_parent should be set to false if calling through LLPreeditor. + + virtual bool handleUnicodeCharHere(llwchar uni_char) = 0; +}; + +#endif diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index e8c1301230..964b173e74 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -1,510 +1,510 @@ -/** - * @file llwindow.cpp - * @brief Basic graphical window class - * - * $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 "llwindowheadless.h" - -#if LL_MESA_HEADLESS -#include "llwindowmesaheadless.h" -#elif LL_SDL -#include "llwindowsdl.h" -#elif LL_WINDOWS -#include "llwindowwin32.h" -#elif LL_DARWIN -#include "llwindowmacosx.h" -#endif - -#include "llerror.h" -#include "llkeyboard.h" -#include "llwindowcallbacks.h" - - -// -// Globals -// -LLSplashScreen *gSplashScreenp = NULL; -bool gDebugClicks = false; -bool gDebugWindowProc = false; - -const S32 gURLProtocolWhitelistCount = 5; -const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" }; - -// CP: added a handler list - this is what's used to open the protocol and is based on registry entry -// only meaningful difference currently is that file: protocols are opened using http: -// since no protocol handler exists in registry for file: -// Important - these lists should match - protocol to handler -// Maestro: This list isn't referenced anywhere that I could find -//const std::string gURLProtocolWhitelistHandler[] = { "http", "http", "https" }; - - -S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) -{ - // Properly hide the splash screen when displaying the message box - bool was_visible = false; - if (LLSplashScreen::isVisible()) - { - was_visible = true; - LLSplashScreen::hide(); - } - - S32 result = 0; -#if LL_MESA_HEADLESS // !!! *FIX: (?) - LL_WARNS() << "OSMessageBox: " << text << LL_ENDL; - return OSBTN_OK; -#elif LL_WINDOWS - result = OSMessageBoxWin32(text, caption, type); -#elif LL_DARWIN - result = OSMessageBoxMacOSX(text, caption, type); -#elif LL_SDL - result = OSMessageBoxSDL(text, caption, type); -#else -#error("OSMessageBox not implemented for this platform!") -#endif - - if (was_visible) - { - LLSplashScreen::show(); - } - - return result; -} - - -// -// LLWindow -// - -LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags) - : mCallbacks(callbacks), - mPostQuit(true), - mFullscreen(fullscreen), - mFullscreenWidth(0), - mFullscreenHeight(0), - mFullscreenBits(0), - mFullscreenRefresh(0), - mSupportedResolutions(NULL), - mNumSupportedResolutions(0), - mCurrentCursor(UI_CURSOR_ARROW), - mNextCursor(UI_CURSOR_ARROW), - mCursorHidden(false), - mBusyCount(0), - mIsMouseClipping(false), - mMinWindowWidth(0), - mMinWindowHeight(0), - mSwapMethod(SWAP_METHOD_UNDEFINED), - mHideCursorPermanent(false), - mFlags(flags), - mHighSurrogate(0), - mRefreshRate(0) -{ -} - -LLWindow::~LLWindow() -{ -} - -//virtual -bool LLWindow::isValid() -{ - return true; -} - -//virtual -bool LLWindow::canDelete() -{ - return true; -} - -//virtual -void LLWindow::setTitle(const std::string title) -{ - // the action happens in the platform specific impl -} - -// virtual -void LLWindow::incBusyCount() -{ - ++mBusyCount; -} - -// virtual -void LLWindow::decBusyCount() -{ - if (mBusyCount > 0) - { - --mBusyCount; - } -} - -//virtual -void LLWindow::resetBusyCount() -{ - mBusyCount = 0; -} - -//virtual -S32 LLWindow::getBusyCount() const -{ - return mBusyCount; -} - -//virtual -ECursorType LLWindow::getCursor() const -{ - return mCurrentCursor; -} - -//virtual -bool LLWindow::dialogColorPicker(F32 *r, F32 *g, F32 *b) -{ - return false; -} - -void *LLWindow::getMediaWindow() -{ - // Default to returning the platform window. - return getPlatformWindow(); -} - -bool LLWindow::setSize(LLCoordScreen size) -{ - if (!getMaximized()) - { - size.mX = llmax(size.mX, mMinWindowWidth); - size.mY = llmax(size.mY, mMinWindowHeight); - } - return setSizeImpl(size); -} - -bool LLWindow::setSize(LLCoordWindow size) -{ - //HACK: we are inconsistently using minimum window dimensions - // in this case, we are constraining the inner "client" rect and other times - // we constrain the outer "window" rect - // There doesn't seem to be a good way to do this consistently without a bunch of platform - // specific code - if (!getMaximized()) - { - size.mX = llmax(size.mX, mMinWindowWidth); - size.mY = llmax(size.mY, mMinWindowHeight); - } - return setSizeImpl(size); -} - - -// virtual -void LLWindow::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately) -{ - mMinWindowWidth = min_width; - mMinWindowHeight = min_height; - - if (enforce_immediately) - { - LLCoordScreen cur_size; - if (!getMaximized() && getSize(&cur_size)) - { - if (cur_size.mX < mMinWindowWidth || cur_size.mY < mMinWindowHeight) - { - setSizeImpl(LLCoordScreen(llmin(cur_size.mX, mMinWindowWidth), llmin(cur_size.mY, mMinWindowHeight))); - } - } - } -} - -//virtual -void LLWindow::processMiscNativeEvents() -{ - // do nothing unless subclassed -} - -//virtual -bool LLWindow::isPrimaryTextAvailable() -{ - return false; // no -} -//virtual -bool LLWindow::pasteTextFromPrimary(LLWString &dst) -{ - return false; // fail -} -// virtual -bool LLWindow::copyTextToPrimary(const LLWString &src) -{ - return false; // fail -} - -// static -std::vector LLWindow::getDynamicFallbackFontList() -{ -#if LL_WINDOWS - return LLWindowWin32::getDynamicFallbackFontList(); -#elif LL_DARWIN - return LLWindowMacOSX::getDynamicFallbackFontList(); -#elif LL_SDL - return LLWindowSDL::getDynamicFallbackFontList(); -#else - return std::vector(); -#endif -} - -// static -std::vector LLWindow::getDisplaysResolutionList() -{ -#if LL_WINDOWS - return LLWindowWin32::getDisplaysResolutionList(); -#elif LL_DARWIN - return LLWindowMacOSX::getDisplaysResolutionList(); -#else - return std::vector(); -#endif -} - -#define UTF16_IS_HIGH_SURROGATE(U) ((U16)((U) - 0xD800) < 0x0400) -#define UTF16_IS_LOW_SURROGATE(U) ((U16)((U) - 0xDC00) < 0x0400) -#define UTF16_SURROGATE_PAIR_TO_UTF32(H,L) (((H) << 10) + (L) - (0xD800 << 10) - 0xDC00 + 0x00010000) - -void LLWindow::handleUnicodeUTF16(U16 utf16, MASK mask) -{ - // Note that we could discard unpaired surrogates, but I'm - // following the Unicode Consortium's recommendation here; - // that is, to preserve those unpaired surrogates in UTF-32 - // values. _To_preserve_ means to pass to the callback in our - // context. - - if (mHighSurrogate == 0) - { - if (UTF16_IS_HIGH_SURROGATE(utf16)) - { - mHighSurrogate = utf16; - } - else - { - mCallbacks->handleUnicodeChar(utf16, mask); - } - } - else - { - if (UTF16_IS_LOW_SURROGATE(utf16)) - { - /* A legal surrogate pair. */ - mCallbacks->handleUnicodeChar(UTF16_SURROGATE_PAIR_TO_UTF32(mHighSurrogate, utf16), mask); - mHighSurrogate = 0; - } - else if (UTF16_IS_HIGH_SURROGATE(utf16)) - { - /* Two consecutive high surrogates. */ - mCallbacks->handleUnicodeChar(mHighSurrogate, mask); - mHighSurrogate = utf16; - } - else - { - /* A non-low-surrogate preceeded by a high surrogate. */ - mCallbacks->handleUnicodeChar(mHighSurrogate, mask); - mHighSurrogate = 0; - mCallbacks->handleUnicodeChar(utf16, mask); - } - } -} - -// -// LLSplashScreen -// - -// static -bool LLSplashScreen::isVisible() -{ - return gSplashScreenp; -} - -// static -LLSplashScreen *LLSplashScreen::create() -{ -#if LL_MESA_HEADLESS || LL_SDL // !!! *FIX: (?) - return 0; -#elif LL_WINDOWS - return new LLSplashScreenWin32; -#elif LL_DARWIN - return new LLSplashScreenMacOSX; -#else -#error("LLSplashScreen not implemented on this platform!") -#endif -} - - -//static -void LLSplashScreen::show() -{ - if (!gSplashScreenp) - { -#if LL_WINDOWS && !LL_MESA_HEADLESS - gSplashScreenp = new LLSplashScreenWin32; -#elif LL_DARWIN - gSplashScreenp = new LLSplashScreenMacOSX; -#endif - if (gSplashScreenp) - { - gSplashScreenp->showImpl(); - } - } -} - -//static -void LLSplashScreen::update(const std::string& str) -{ - LLSplashScreen::show(); - if (gSplashScreenp) - { - gSplashScreenp->updateImpl(str); - } -} - -//static -void LLSplashScreen::hide() -{ - if (gSplashScreenp) - { - gSplashScreenp->hideImpl(); - } - delete gSplashScreenp; - gSplashScreenp = NULL; -} - -// -// LLWindowManager -// - -// TODO: replace with std::set -static std::set sWindowList; - -LLWindow* LLWindowManager::createWindow( - LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, - bool fullscreen, - bool clearBg, - bool enable_vsync, - bool use_gl, - bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_cores, - U32 max_vram, - F32 max_gl_version) -{ - LLWindow* new_window; - - if (use_gl) - { -#if LL_MESA_HEADLESS - new_window = new LLWindowMesaHeadless(callbacks, - title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); -#elif LL_SDL - new_window = new LLWindowSDL(callbacks, - title, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); -#elif LL_WINDOWS - new_window = new LLWindowWin32(callbacks, - title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_vram, max_gl_version); -#elif LL_DARWIN - new_window = new LLWindowMacOSX(callbacks, - title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_vram); -#endif - } - else - { - new_window = new LLWindowHeadless(callbacks, - title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); - } - - if (false == new_window->isValid()) - { - delete new_window; - LL_WARNS() << "LLWindowManager::create() : Error creating window." << LL_ENDL; - return NULL; - } - sWindowList.insert(new_window); - return new_window; -} - -bool LLWindowManager::destroyWindow(LLWindow* window) -{ - if (sWindowList.find(window) == sWindowList.end()) - { - LL_ERRS() << "LLWindowManager::destroyWindow() : Window pointer not valid, this window doesn't exist!" - << LL_ENDL; - return false; - } - - window->close(); - - sWindowList.erase(window); - - delete window; - - return true; -} - -bool LLWindowManager::isWindowValid(LLWindow *window) -{ - return sWindowList.find(window) != sWindowList.end(); -} - -//coordinate conversion utility funcs that forward to llwindow -LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const -{ - const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); - - LLCoordGL out; - LLWindow::instance_snapshot().begin()->convertCoords(self, &out); - return out.convert(); -} - -void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from) -{ - LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); - - LLCoordGL from_gl(from); - LLWindow::instance_snapshot().begin()->convertCoords(from_gl, &self); -} - -LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const -{ - const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); - - LLCoordGL out; - LLWindow::instance_snapshot().begin()->convertCoords(self, &out); - return out.convert(); -} - -void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from) -{ - LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); - - LLCoordGL from_gl(from); - LLWindow::instance_snapshot().begin()->convertCoords(from_gl, &self); -} +/** + * @file llwindow.cpp + * @brief Basic graphical window class + * + * $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 "llwindowheadless.h" + +#if LL_MESA_HEADLESS +#include "llwindowmesaheadless.h" +#elif LL_SDL +#include "llwindowsdl.h" +#elif LL_WINDOWS +#include "llwindowwin32.h" +#elif LL_DARWIN +#include "llwindowmacosx.h" +#endif + +#include "llerror.h" +#include "llkeyboard.h" +#include "llwindowcallbacks.h" + + +// +// Globals +// +LLSplashScreen *gSplashScreenp = NULL; +bool gDebugClicks = false; +bool gDebugWindowProc = false; + +const S32 gURLProtocolWhitelistCount = 5; +const std::string gURLProtocolWhitelist[] = { "secondlife:", "http:", "https:", "data:", "mailto:" }; + +// CP: added a handler list - this is what's used to open the protocol and is based on registry entry +// only meaningful difference currently is that file: protocols are opened using http: +// since no protocol handler exists in registry for file: +// Important - these lists should match - protocol to handler +// Maestro: This list isn't referenced anywhere that I could find +//const std::string gURLProtocolWhitelistHandler[] = { "http", "http", "https" }; + + +S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type) +{ + // Properly hide the splash screen when displaying the message box + bool was_visible = false; + if (LLSplashScreen::isVisible()) + { + was_visible = true; + LLSplashScreen::hide(); + } + + S32 result = 0; +#if LL_MESA_HEADLESS // !!! *FIX: (?) + LL_WARNS() << "OSMessageBox: " << text << LL_ENDL; + return OSBTN_OK; +#elif LL_WINDOWS + result = OSMessageBoxWin32(text, caption, type); +#elif LL_DARWIN + result = OSMessageBoxMacOSX(text, caption, type); +#elif LL_SDL + result = OSMessageBoxSDL(text, caption, type); +#else +#error("OSMessageBox not implemented for this platform!") +#endif + + if (was_visible) + { + LLSplashScreen::show(); + } + + return result; +} + + +// +// LLWindow +// + +LLWindow::LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags) + : mCallbacks(callbacks), + mPostQuit(true), + mFullscreen(fullscreen), + mFullscreenWidth(0), + mFullscreenHeight(0), + mFullscreenBits(0), + mFullscreenRefresh(0), + mSupportedResolutions(NULL), + mNumSupportedResolutions(0), + mCurrentCursor(UI_CURSOR_ARROW), + mNextCursor(UI_CURSOR_ARROW), + mCursorHidden(false), + mBusyCount(0), + mIsMouseClipping(false), + mMinWindowWidth(0), + mMinWindowHeight(0), + mSwapMethod(SWAP_METHOD_UNDEFINED), + mHideCursorPermanent(false), + mFlags(flags), + mHighSurrogate(0), + mRefreshRate(0) +{ +} + +LLWindow::~LLWindow() +{ +} + +//virtual +bool LLWindow::isValid() +{ + return true; +} + +//virtual +bool LLWindow::canDelete() +{ + return true; +} + +//virtual +void LLWindow::setTitle(const std::string title) +{ + // the action happens in the platform specific impl +} + +// virtual +void LLWindow::incBusyCount() +{ + ++mBusyCount; +} + +// virtual +void LLWindow::decBusyCount() +{ + if (mBusyCount > 0) + { + --mBusyCount; + } +} + +//virtual +void LLWindow::resetBusyCount() +{ + mBusyCount = 0; +} + +//virtual +S32 LLWindow::getBusyCount() const +{ + return mBusyCount; +} + +//virtual +ECursorType LLWindow::getCursor() const +{ + return mCurrentCursor; +} + +//virtual +bool LLWindow::dialogColorPicker(F32 *r, F32 *g, F32 *b) +{ + return false; +} + +void *LLWindow::getMediaWindow() +{ + // Default to returning the platform window. + return getPlatformWindow(); +} + +bool LLWindow::setSize(LLCoordScreen size) +{ + if (!getMaximized()) + { + size.mX = llmax(size.mX, mMinWindowWidth); + size.mY = llmax(size.mY, mMinWindowHeight); + } + return setSizeImpl(size); +} + +bool LLWindow::setSize(LLCoordWindow size) +{ + //HACK: we are inconsistently using minimum window dimensions + // in this case, we are constraining the inner "client" rect and other times + // we constrain the outer "window" rect + // There doesn't seem to be a good way to do this consistently without a bunch of platform + // specific code + if (!getMaximized()) + { + size.mX = llmax(size.mX, mMinWindowWidth); + size.mY = llmax(size.mY, mMinWindowHeight); + } + return setSizeImpl(size); +} + + +// virtual +void LLWindow::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately) +{ + mMinWindowWidth = min_width; + mMinWindowHeight = min_height; + + if (enforce_immediately) + { + LLCoordScreen cur_size; + if (!getMaximized() && getSize(&cur_size)) + { + if (cur_size.mX < mMinWindowWidth || cur_size.mY < mMinWindowHeight) + { + setSizeImpl(LLCoordScreen(llmin(cur_size.mX, mMinWindowWidth), llmin(cur_size.mY, mMinWindowHeight))); + } + } + } +} + +//virtual +void LLWindow::processMiscNativeEvents() +{ + // do nothing unless subclassed +} + +//virtual +bool LLWindow::isPrimaryTextAvailable() +{ + return false; // no +} +//virtual +bool LLWindow::pasteTextFromPrimary(LLWString &dst) +{ + return false; // fail +} +// virtual +bool LLWindow::copyTextToPrimary(const LLWString &src) +{ + return false; // fail +} + +// static +std::vector LLWindow::getDynamicFallbackFontList() +{ +#if LL_WINDOWS + return LLWindowWin32::getDynamicFallbackFontList(); +#elif LL_DARWIN + return LLWindowMacOSX::getDynamicFallbackFontList(); +#elif LL_SDL + return LLWindowSDL::getDynamicFallbackFontList(); +#else + return std::vector(); +#endif +} + +// static +std::vector LLWindow::getDisplaysResolutionList() +{ +#if LL_WINDOWS + return LLWindowWin32::getDisplaysResolutionList(); +#elif LL_DARWIN + return LLWindowMacOSX::getDisplaysResolutionList(); +#else + return std::vector(); +#endif +} + +#define UTF16_IS_HIGH_SURROGATE(U) ((U16)((U) - 0xD800) < 0x0400) +#define UTF16_IS_LOW_SURROGATE(U) ((U16)((U) - 0xDC00) < 0x0400) +#define UTF16_SURROGATE_PAIR_TO_UTF32(H,L) (((H) << 10) + (L) - (0xD800 << 10) - 0xDC00 + 0x00010000) + +void LLWindow::handleUnicodeUTF16(U16 utf16, MASK mask) +{ + // Note that we could discard unpaired surrogates, but I'm + // following the Unicode Consortium's recommendation here; + // that is, to preserve those unpaired surrogates in UTF-32 + // values. _To_preserve_ means to pass to the callback in our + // context. + + if (mHighSurrogate == 0) + { + if (UTF16_IS_HIGH_SURROGATE(utf16)) + { + mHighSurrogate = utf16; + } + else + { + mCallbacks->handleUnicodeChar(utf16, mask); + } + } + else + { + if (UTF16_IS_LOW_SURROGATE(utf16)) + { + /* A legal surrogate pair. */ + mCallbacks->handleUnicodeChar(UTF16_SURROGATE_PAIR_TO_UTF32(mHighSurrogate, utf16), mask); + mHighSurrogate = 0; + } + else if (UTF16_IS_HIGH_SURROGATE(utf16)) + { + /* Two consecutive high surrogates. */ + mCallbacks->handleUnicodeChar(mHighSurrogate, mask); + mHighSurrogate = utf16; + } + else + { + /* A non-low-surrogate preceeded by a high surrogate. */ + mCallbacks->handleUnicodeChar(mHighSurrogate, mask); + mHighSurrogate = 0; + mCallbacks->handleUnicodeChar(utf16, mask); + } + } +} + +// +// LLSplashScreen +// + +// static +bool LLSplashScreen::isVisible() +{ + return gSplashScreenp; +} + +// static +LLSplashScreen *LLSplashScreen::create() +{ +#if LL_MESA_HEADLESS || LL_SDL // !!! *FIX: (?) + return 0; +#elif LL_WINDOWS + return new LLSplashScreenWin32; +#elif LL_DARWIN + return new LLSplashScreenMacOSX; +#else +#error("LLSplashScreen not implemented on this platform!") +#endif +} + + +//static +void LLSplashScreen::show() +{ + if (!gSplashScreenp) + { +#if LL_WINDOWS && !LL_MESA_HEADLESS + gSplashScreenp = new LLSplashScreenWin32; +#elif LL_DARWIN + gSplashScreenp = new LLSplashScreenMacOSX; +#endif + if (gSplashScreenp) + { + gSplashScreenp->showImpl(); + } + } +} + +//static +void LLSplashScreen::update(const std::string& str) +{ + LLSplashScreen::show(); + if (gSplashScreenp) + { + gSplashScreenp->updateImpl(str); + } +} + +//static +void LLSplashScreen::hide() +{ + if (gSplashScreenp) + { + gSplashScreenp->hideImpl(); + } + delete gSplashScreenp; + gSplashScreenp = NULL; +} + +// +// LLWindowManager +// + +// TODO: replace with std::set +static std::set sWindowList; + +LLWindow* LLWindowManager::createWindow( + LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, + bool fullscreen, + bool clearBg, + bool enable_vsync, + bool use_gl, + bool ignore_pixel_depth, + U32 fsaa_samples, + U32 max_cores, + U32 max_vram, + F32 max_gl_version) +{ + LLWindow* new_window; + + if (use_gl) + { +#if LL_MESA_HEADLESS + new_window = new LLWindowMesaHeadless(callbacks, + title, name, x, y, width, height, flags, + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); +#elif LL_SDL + new_window = new LLWindowSDL(callbacks, + title, x, y, width, height, flags, + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); +#elif LL_WINDOWS + new_window = new LLWindowWin32(callbacks, + title, name, x, y, width, height, flags, + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_vram, max_gl_version); +#elif LL_DARWIN + new_window = new LLWindowMacOSX(callbacks, + title, name, x, y, width, height, flags, + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_vram); +#endif + } + else + { + new_window = new LLWindowHeadless(callbacks, + title, name, x, y, width, height, flags, + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); + } + + if (false == new_window->isValid()) + { + delete new_window; + LL_WARNS() << "LLWindowManager::create() : Error creating window." << LL_ENDL; + return NULL; + } + sWindowList.insert(new_window); + return new_window; +} + +bool LLWindowManager::destroyWindow(LLWindow* window) +{ + if (sWindowList.find(window) == sWindowList.end()) + { + LL_ERRS() << "LLWindowManager::destroyWindow() : Window pointer not valid, this window doesn't exist!" + << LL_ENDL; + return false; + } + + window->close(); + + sWindowList.erase(window); + + delete window; + + return true; +} + +bool LLWindowManager::isWindowValid(LLWindow *window) +{ + return sWindowList.find(window) != sWindowList.end(); +} + +//coordinate conversion utility funcs that forward to llwindow +LLCoordCommon LL_COORD_TYPE_WINDOW::convertToCommon() const +{ + const LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); + + LLCoordGL out; + LLWindow::instance_snapshot().begin()->convertCoords(self, &out); + return out.convert(); +} + +void LL_COORD_TYPE_WINDOW::convertFromCommon(const LLCoordCommon& from) +{ + LLCoordWindow& self = LLCoordWindow::getTypedCoords(*this); + + LLCoordGL from_gl(from); + LLWindow::instance_snapshot().begin()->convertCoords(from_gl, &self); +} + +LLCoordCommon LL_COORD_TYPE_SCREEN::convertToCommon() const +{ + const LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); + + LLCoordGL out; + LLWindow::instance_snapshot().begin()->convertCoords(self, &out); + return out.convert(); +} + +void LL_COORD_TYPE_SCREEN::convertFromCommon(const LLCoordCommon& from) +{ + LLCoordScreen& self = LLCoordScreen::getTypedCoords(*this); + + LLCoordGL from_gl(from); + LLWindow::instance_snapshot().begin()->convertCoords(from_gl, &self); +} diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 5eca3e8939..b7bb426654 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -1,334 +1,334 @@ -/** - * @file llwindow.h - * @brief Basic graphical window class - * - * $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$ - */ - -#ifndef LL_LLWINDOW_H -#define LL_LLWINDOW_H - -#include "llrect.h" -#include "llcoord.h" -#include "llstring.h" -#include "llcursortypes.h" -#include "llinstancetracker.h" -#include "llsd.h" - -class LLSplashScreen; -class LLPreeditor; -class LLWindowCallbacks; - -// Refer to llwindow_test in test/common/llwindow for usage example - -class LLWindow : public LLInstanceTracker -{ -public: - - struct LLWindowResolution - { - S32 mWidth; - S32 mHeight; - }; - enum ESwapMethod - { - SWAP_METHOD_UNDEFINED, - SWAP_METHOD_EXCHANGE, - SWAP_METHOD_COPY - }; - enum EFlags - { - // currently unused - }; -public: - virtual void show() = 0; - virtual void hide() = 0; - virtual void close() = 0; - virtual bool getVisible() = 0; - virtual bool getMinimized() = 0; - virtual bool getMaximized() = 0; - virtual bool maximize() = 0; - virtual void minimize() = 0; - virtual void restore() = 0; - bool getFullscreen() { return mFullscreen; }; - virtual bool getPosition(LLCoordScreen *position) = 0; - virtual bool getSize(LLCoordScreen *size) = 0; - virtual bool getSize(LLCoordWindow *size) = 0; - virtual bool setPosition(LLCoordScreen position) = 0; - bool setSize(LLCoordScreen size); - bool setSize(LLCoordWindow size); - virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) = 0; - - //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread - // returns a pointer to be handed back to destroySharedConext/makeContextCurrent - virtual void* createSharedContext() = 0; - //make the given context current on the current thread - virtual void makeContextCurrent(void* context) = 0; - //destroy the given context that was retrieved by createSharedContext() - //Must be called on the same thread that called createSharedContext() - virtual void destroySharedContext(void* context) = 0; - - virtual void toggleVSync(bool enable_vsync) = 0; - - virtual bool setCursorPosition(LLCoordWindow position) = 0; - virtual bool getCursorPosition(LLCoordWindow *position) = 0; -#if LL_WINDOWS - virtual bool getCursorDelta(LLCoordCommon* delta) = 0; -#endif - virtual void showCursor() = 0; - virtual void hideCursor() = 0; - virtual bool isCursorHidden() = 0; - virtual void showCursorFromMouseMove() = 0; - virtual void hideCursorUntilMouseMove() = 0; - - // Provide a way to set the Viewer window title after the - // windows has been created. The initial use case for this - // is described in SL-16102 (update window title with agent - // name, location etc. for non-interactive viewer) but it - // may also be useful in other cases. - virtual void setTitle(const std::string title); - - // These two functions create a way to make a busy cursor instead - // of an arrow when someone's busy doing something. Draw an - // arrow/hour if busycount > 0. - virtual void incBusyCount(); - virtual void decBusyCount(); - virtual void resetBusyCount(); - virtual S32 getBusyCount() const; - - // Sets cursor, may set to arrow+hourglass - virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; }; - virtual ECursorType getCursor() const; - virtual ECursorType getNextCursor() const { return mNextCursor; }; - virtual void updateCursor() = 0; - - virtual void captureMouse() = 0; - virtual void releaseMouse() = 0; - virtual void setMouseClipping( bool b ) = 0; - - virtual bool isClipboardTextAvailable() = 0; - virtual bool pasteTextFromClipboard(LLWString &dst) = 0; - virtual bool copyTextToClipboard(const LLWString &src) = 0; - - virtual bool isPrimaryTextAvailable(); - virtual bool pasteTextFromPrimary(LLWString &dst); - virtual bool copyTextToPrimary(const LLWString &src); - - virtual void flashIcon(F32 seconds) = 0; - virtual F32 getGamma() = 0; - virtual bool setGamma(const F32 gamma) = 0; // Set the gamma - virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples - virtual U32 getFSAASamples() = 0; - virtual bool restoreGamma() = 0; // Restore original gamma table (before updating gamma) - virtual ESwapMethod getSwapMethod() { return mSwapMethod; } - virtual void processMiscNativeEvents(); - virtual void gatherInput() = 0; - virtual void delayInputProcessing() = 0; - virtual void swapBuffers() = 0; - virtual void bringToFront() = 0; - virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract - virtual void setOldResize(bool oldresize) { }; - // handy coordinate space conversion routines - // NB: screen to window and vice verse won't work on width/height coordinate pairs, - // as the conversion must take into account left AND right border widths, etc. - virtual bool convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; - virtual bool convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; - virtual bool convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; - virtual bool convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; - virtual bool convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; - virtual bool convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; - - // query supported resolutions - virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; - virtual F32 getNativeAspectRatio() = 0; - virtual F32 getPixelAspectRatio() = 0; - virtual void setNativeAspectRatio(F32 aspect) = 0; - - virtual void setMaxVRAMMegabytes(U32 max_vram) = 0; - - virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) - virtual void afterDialog() {}; // undo whatever was done in beforeDialog() - - // opens system default color picker, modally - // Returns true if valid color selected - virtual bool dialogColorPicker(F32 *r, F32 *g, F32 *b); - -// return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getPlatformWindow() = 0; - -// return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) - virtual void *getMediaWindow(); - - // control platform's Language Text Input mechanisms. - virtual void allowLanguageTextInput(LLPreeditor *preeditor, bool b) {} - virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; - virtual void updateLanguageTextInputArea() {} - virtual void interruptLanguageTextInput() {} - virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; - - static std::vector getDynamicFallbackFontList(); - - // Provide native key event data - virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } - - // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) - virtual F32 getSystemUISize() { return 1.0; } - - static std::vector getDisplaysResolutionList(); - - // windows only DirectInput8 for joysticks - virtual void* getDirectInput8() { return NULL; }; - virtual bool getInputDevices(U32 device_type_filter, - std::function osx_callback, - void* win_callback, - void* userdata) - { - return false; - }; - - virtual S32 getRefreshRate() { return mRefreshRate; } -protected: - LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags); - virtual ~LLWindow(); - // Defaults to true - virtual bool isValid(); - // Defaults to true - virtual bool canDelete(); - - virtual bool setSizeImpl(LLCoordScreen size) = 0; - virtual bool setSizeImpl(LLCoordWindow size) = 0; - -protected: - LLWindowCallbacks* mCallbacks; - - bool mPostQuit; // should this window post a quit message when destroyed? - bool mFullscreen; - S32 mFullscreenWidth; - S32 mFullscreenHeight; - S32 mFullscreenBits; - S32 mFullscreenRefresh; - LLWindowResolution* mSupportedResolutions; - S32 mNumSupportedResolutions; - ECursorType mCurrentCursor; - ECursorType mNextCursor; - bool mCursorHidden; - S32 mBusyCount; // how deep is the "cursor busy" stack? - bool mIsMouseClipping; // Is this window currently clipping the mouse - ESwapMethod mSwapMethod; - bool mHideCursorPermanent; - U32 mFlags; - U16 mHighSurrogate; - S32 mMinWindowWidth; - S32 mMinWindowHeight; - S32 mRefreshRate; - - // Handle a UTF-16 encoding unit received from keyboard. - // Converting the series of UTF-16 encoding units to UTF-32 data, - // this method passes the resulting UTF-32 data to mCallback's - // handleUnicodeChar. The mask should be that to be passed to the - // callback. This method uses mHighSurrogate as a dedicated work - // variable. - void handleUnicodeUTF16(U16 utf16, MASK mask); - - friend class LLWindowManager; -}; - - -// LLSplashScreen -// A simple, OS-specific splash screen that we can display -// while initializing the application and before creating a GL -// window - - -class LLSplashScreen -{ -public: - LLSplashScreen() { }; - virtual ~LLSplashScreen() { }; - - - // Call to display the window. - static LLSplashScreen * create(); - static void show(); - static void hide(); - static void update(const std::string& string); - - static bool isVisible(); -protected: - // These are overridden by the platform implementation - virtual void showImpl() = 0; - virtual void updateImpl(const std::string& string) = 0; - virtual void hideImpl() = 0; - - static bool sVisible; - -}; - -// Platform-neutral for accessing the platform specific message box -S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type); -const U32 OSMB_OK = 0; -const U32 OSMB_OKCANCEL = 1; -const U32 OSMB_YESNO = 2; - -const S32 OSBTN_YES = 0; -const S32 OSBTN_NO = 1; -const S32 OSBTN_OK = 2; -const S32 OSBTN_CANCEL = 3; - -// -// LLWindowManager -// Manages window creation and error checking - -class LLWindowManager -{ -public: - static LLWindow *createWindow( - LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - U32 flags = 0, - bool fullscreen = false, - bool clearBg = false, - bool enable_vsync = false, - bool use_gl = true, - bool ignore_pixel_depth = false, - U32 fsaa_samples = 0, - U32 max_cores = 0, - U32 max_vram = 0, - F32 max_gl_version = 4.6f); - static bool destroyWindow(LLWindow* window); - static bool isWindowValid(LLWindow *window); -}; - -// -// helper funcs -// -extern bool gDebugWindowProc; - -// Protocols, like "http" and "https" we support in URLs -extern const S32 gURLProtocolWhitelistCount; -extern const std::string gURLProtocolWhitelist[]; -//extern const std::string gURLProtocolWhitelistHandler[]; - -void simpleEscapeString ( std::string& stringIn ); - -#endif // _LL_window_h_ +/** + * @file llwindow.h + * @brief Basic graphical window class + * + * $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$ + */ + +#ifndef LL_LLWINDOW_H +#define LL_LLWINDOW_H + +#include "llrect.h" +#include "llcoord.h" +#include "llstring.h" +#include "llcursortypes.h" +#include "llinstancetracker.h" +#include "llsd.h" + +class LLSplashScreen; +class LLPreeditor; +class LLWindowCallbacks; + +// Refer to llwindow_test in test/common/llwindow for usage example + +class LLWindow : public LLInstanceTracker +{ +public: + + struct LLWindowResolution + { + S32 mWidth; + S32 mHeight; + }; + enum ESwapMethod + { + SWAP_METHOD_UNDEFINED, + SWAP_METHOD_EXCHANGE, + SWAP_METHOD_COPY + }; + enum EFlags + { + // currently unused + }; +public: + virtual void show() = 0; + virtual void hide() = 0; + virtual void close() = 0; + virtual bool getVisible() = 0; + virtual bool getMinimized() = 0; + virtual bool getMaximized() = 0; + virtual bool maximize() = 0; + virtual void minimize() = 0; + virtual void restore() = 0; + bool getFullscreen() { return mFullscreen; }; + virtual bool getPosition(LLCoordScreen *position) = 0; + virtual bool getSize(LLCoordScreen *size) = 0; + virtual bool getSize(LLCoordWindow *size) = 0; + virtual bool setPosition(LLCoordScreen position) = 0; + bool setSize(LLCoordScreen size); + bool setSize(LLCoordWindow size); + virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); + virtual bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) = 0; + + //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread + // returns a pointer to be handed back to destroySharedConext/makeContextCurrent + virtual void* createSharedContext() = 0; + //make the given context current on the current thread + virtual void makeContextCurrent(void* context) = 0; + //destroy the given context that was retrieved by createSharedContext() + //Must be called on the same thread that called createSharedContext() + virtual void destroySharedContext(void* context) = 0; + + virtual void toggleVSync(bool enable_vsync) = 0; + + virtual bool setCursorPosition(LLCoordWindow position) = 0; + virtual bool getCursorPosition(LLCoordWindow *position) = 0; +#if LL_WINDOWS + virtual bool getCursorDelta(LLCoordCommon* delta) = 0; +#endif + virtual void showCursor() = 0; + virtual void hideCursor() = 0; + virtual bool isCursorHidden() = 0; + virtual void showCursorFromMouseMove() = 0; + virtual void hideCursorUntilMouseMove() = 0; + + // Provide a way to set the Viewer window title after the + // windows has been created. The initial use case for this + // is described in SL-16102 (update window title with agent + // name, location etc. for non-interactive viewer) but it + // may also be useful in other cases. + virtual void setTitle(const std::string title); + + // These two functions create a way to make a busy cursor instead + // of an arrow when someone's busy doing something. Draw an + // arrow/hour if busycount > 0. + virtual void incBusyCount(); + virtual void decBusyCount(); + virtual void resetBusyCount(); + virtual S32 getBusyCount() const; + + // Sets cursor, may set to arrow+hourglass + virtual void setCursor(ECursorType cursor) { mNextCursor = cursor; }; + virtual ECursorType getCursor() const; + virtual ECursorType getNextCursor() const { return mNextCursor; }; + virtual void updateCursor() = 0; + + virtual void captureMouse() = 0; + virtual void releaseMouse() = 0; + virtual void setMouseClipping( bool b ) = 0; + + virtual bool isClipboardTextAvailable() = 0; + virtual bool pasteTextFromClipboard(LLWString &dst) = 0; + virtual bool copyTextToClipboard(const LLWString &src) = 0; + + virtual bool isPrimaryTextAvailable(); + virtual bool pasteTextFromPrimary(LLWString &dst); + virtual bool copyTextToPrimary(const LLWString &src); + + virtual void flashIcon(F32 seconds) = 0; + virtual F32 getGamma() = 0; + virtual bool setGamma(const F32 gamma) = 0; // Set the gamma + virtual void setFSAASamples(const U32 fsaa_samples) = 0; //set number of FSAA samples + virtual U32 getFSAASamples() = 0; + virtual bool restoreGamma() = 0; // Restore original gamma table (before updating gamma) + virtual ESwapMethod getSwapMethod() { return mSwapMethod; } + virtual void processMiscNativeEvents(); + virtual void gatherInput() = 0; + virtual void delayInputProcessing() = 0; + virtual void swapBuffers() = 0; + virtual void bringToFront() = 0; + virtual void focusClient() { }; // this may not have meaning or be required on other platforms, therefore, it's not abstract + virtual void setOldResize(bool oldresize) { }; + // handy coordinate space conversion routines + // NB: screen to window and vice verse won't work on width/height coordinate pairs, + // as the conversion must take into account left AND right border widths, etc. + virtual bool convertCoords( LLCoordScreen from, LLCoordWindow *to) = 0; + virtual bool convertCoords( LLCoordWindow from, LLCoordScreen *to) = 0; + virtual bool convertCoords( LLCoordWindow from, LLCoordGL *to) = 0; + virtual bool convertCoords( LLCoordGL from, LLCoordWindow *to) = 0; + virtual bool convertCoords( LLCoordScreen from, LLCoordGL *to) = 0; + virtual bool convertCoords( LLCoordGL from, LLCoordScreen *to) = 0; + + // query supported resolutions + virtual LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) = 0; + virtual F32 getNativeAspectRatio() = 0; + virtual F32 getPixelAspectRatio() = 0; + virtual void setNativeAspectRatio(F32 aspect) = 0; + + virtual void setMaxVRAMMegabytes(U32 max_vram) = 0; + + virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) + virtual void afterDialog() {}; // undo whatever was done in beforeDialog() + + // opens system default color picker, modally + // Returns true if valid color selected + virtual bool dialogColorPicker(F32 *r, F32 *g, F32 *b); + +// return a platform-specific window reference (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) + virtual void *getPlatformWindow() = 0; + +// return the platform-specific window reference we use to initialize llmozlib (HWND on Windows, WindowRef on the Mac, Gtk window on Linux) + virtual void *getMediaWindow(); + + // control platform's Language Text Input mechanisms. + virtual void allowLanguageTextInput(LLPreeditor *preeditor, bool b) {} + virtual void setLanguageTextInput( const LLCoordGL & pos ) {}; + virtual void updateLanguageTextInputArea() {} + virtual void interruptLanguageTextInput() {} + virtual void spawnWebBrowser(const std::string& escaped_url, bool async) {}; + + static std::vector getDynamicFallbackFontList(); + + // Provide native key event data + virtual LLSD getNativeKeyData() { return LLSD::emptyMap(); } + + // Get system UI size based on DPI (for 96 DPI UI size should be 1.0) + virtual F32 getSystemUISize() { return 1.0; } + + static std::vector getDisplaysResolutionList(); + + // windows only DirectInput8 for joysticks + virtual void* getDirectInput8() { return NULL; }; + virtual bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) + { + return false; + }; + + virtual S32 getRefreshRate() { return mRefreshRate; } +protected: + LLWindow(LLWindowCallbacks* callbacks, bool fullscreen, U32 flags); + virtual ~LLWindow(); + // Defaults to true + virtual bool isValid(); + // Defaults to true + virtual bool canDelete(); + + virtual bool setSizeImpl(LLCoordScreen size) = 0; + virtual bool setSizeImpl(LLCoordWindow size) = 0; + +protected: + LLWindowCallbacks* mCallbacks; + + bool mPostQuit; // should this window post a quit message when destroyed? + bool mFullscreen; + S32 mFullscreenWidth; + S32 mFullscreenHeight; + S32 mFullscreenBits; + S32 mFullscreenRefresh; + LLWindowResolution* mSupportedResolutions; + S32 mNumSupportedResolutions; + ECursorType mCurrentCursor; + ECursorType mNextCursor; + bool mCursorHidden; + S32 mBusyCount; // how deep is the "cursor busy" stack? + bool mIsMouseClipping; // Is this window currently clipping the mouse + ESwapMethod mSwapMethod; + bool mHideCursorPermanent; + U32 mFlags; + U16 mHighSurrogate; + S32 mMinWindowWidth; + S32 mMinWindowHeight; + S32 mRefreshRate; + + // Handle a UTF-16 encoding unit received from keyboard. + // Converting the series of UTF-16 encoding units to UTF-32 data, + // this method passes the resulting UTF-32 data to mCallback's + // handleUnicodeChar. The mask should be that to be passed to the + // callback. This method uses mHighSurrogate as a dedicated work + // variable. + void handleUnicodeUTF16(U16 utf16, MASK mask); + + friend class LLWindowManager; +}; + + +// LLSplashScreen +// A simple, OS-specific splash screen that we can display +// while initializing the application and before creating a GL +// window + + +class LLSplashScreen +{ +public: + LLSplashScreen() { }; + virtual ~LLSplashScreen() { }; + + + // Call to display the window. + static LLSplashScreen * create(); + static void show(); + static void hide(); + static void update(const std::string& string); + + static bool isVisible(); +protected: + // These are overridden by the platform implementation + virtual void showImpl() = 0; + virtual void updateImpl(const std::string& string) = 0; + virtual void hideImpl() = 0; + + static bool sVisible; + +}; + +// Platform-neutral for accessing the platform specific message box +S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type); +const U32 OSMB_OK = 0; +const U32 OSMB_OKCANCEL = 1; +const U32 OSMB_YESNO = 2; + +const S32 OSBTN_YES = 0; +const S32 OSBTN_NO = 1; +const S32 OSBTN_OK = 2; +const S32 OSBTN_CANCEL = 3; + +// +// LLWindowManager +// Manages window creation and error checking + +class LLWindowManager +{ +public: + static LLWindow *createWindow( + LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, + U32 flags = 0, + bool fullscreen = false, + bool clearBg = false, + bool enable_vsync = false, + bool use_gl = true, + bool ignore_pixel_depth = false, + U32 fsaa_samples = 0, + U32 max_cores = 0, + U32 max_vram = 0, + F32 max_gl_version = 4.6f); + static bool destroyWindow(LLWindow* window); + static bool isWindowValid(LLWindow *window); +}; + +// +// helper funcs +// +extern bool gDebugWindowProc; + +// Protocols, like "http" and "https" we support in URLs +extern const S32 gURLProtocolWhitelistCount; +extern const std::string gURLProtocolWhitelist[]; +//extern const std::string gURLProtocolWhitelistHandler[]; + +void simpleEscapeString ( std::string& stringIn ); + +#endif // _LL_window_h_ diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 0c328c9140..c160382c17 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -1,227 +1,227 @@ -/** - * @file llwindowcallbacks.cpp - * @brief OS event callback class - * - * $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 "llwindowcallbacks.h" - -// -// LLWindowCallbacks -// - -bool LLWindowCallbacks::handleTranslatedKeyDown(const KEY key, const MASK mask, bool repeated) -{ - return false; -} - - -bool LLWindowCallbacks::handleTranslatedKeyUp(const KEY key, const MASK mask) -{ - return false; -} - -void LLWindowCallbacks::handleScanKey(KEY key, bool key_down, bool key_up, bool key_level) -{ -} - -bool LLWindowCallbacks::handleUnicodeChar(llwchar uni_char, MASK mask) -{ - return false; -} - - -bool LLWindowCallbacks::handleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -bool LLWindowCallbacks::handleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -void LLWindowCallbacks::handleMouseLeave(LLWindow *window) -{ - return; -} - -bool LLWindowCallbacks::handleCloseRequest(LLWindow *window) -{ - //allow the window to close - return true; -} - -void LLWindowCallbacks::handleQuit(LLWindow *window) -{ -} - -bool LLWindowCallbacks::handleRightMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -bool LLWindowCallbacks::handleRightMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -bool LLWindowCallbacks::handleMiddleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -bool LLWindowCallbacks::handleMiddleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -bool LLWindowCallbacks::handleOtherMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) -{ - return false; -} - -bool LLWindowCallbacks::handleOtherMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) -{ - return false; -} - -bool LLWindowCallbacks::handleActivate(LLWindow *window, bool activated) -{ - return false; -} - -bool LLWindowCallbacks::handleActivateApp(LLWindow *window, bool activating) -{ - return false; -} - -void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, MASK mask) -{ -} - -void LLWindowCallbacks::handleMouseDragged(LLWindow *window, const LLCoordGL pos, MASK mask) -{ -} - -void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) -{ -} - -void LLWindowCallbacks::handleScrollHWheel(LLWindow *window, S32 clicks) -{ -} - -void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height) -{ -} - -void LLWindowCallbacks::handleFocus(LLWindow *window) -{ - LL_WARNS("COCOA") << "Called handleFocus proto" << LL_ENDL; -} - -void LLWindowCallbacks::handleFocusLost(LLWindow *window) -{ -} - -void LLWindowCallbacks::handleMenuSelect(LLWindow *window, const S32 menu_item) -{ -} - -bool LLWindowCallbacks::handlePaint(LLWindow *window, const S32 x, const S32 y, - const S32 width, const S32 height) -{ - return false; -} - -bool LLWindowCallbacks::handleDoubleClick(LLWindow *window, const LLCoordGL pos, MASK mask) -{ - return false; -} - -void LLWindowCallbacks::handleWindowBlock(LLWindow *window) -{ -} - -void LLWindowCallbacks::handleWindowUnblock(LLWindow *window) -{ -} - -void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *data) -{ -} - -LLWindowCallbacks::DragNDropResult LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data ) -{ - return LLWindowCallbacks::DND_NONE; -} - -bool LLWindowCallbacks::handleTimerEvent(LLWindow *window) -{ - return false; -} - -bool LLWindowCallbacks::handleDeviceChange(LLWindow *window) -{ - return false; -} - -bool LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) -{ - return false; -} - -bool LLWindowCallbacks::handleWindowDidChangeScreen(LLWindow *window) -{ - return false; -} - -void LLWindowCallbacks::handlePingWatchdog(LLWindow *window, const char * msg) -{ - -} - -void LLWindowCallbacks::handlePauseWatchdog(LLWindow *window) -{ - -} - -void LLWindowCallbacks::handleResumeWatchdog(LLWindow *window) -{ - -} - -std::string LLWindowCallbacks::translateString(const char* tag) -{ - return std::string(); -} - -//virtual -std::string LLWindowCallbacks::translateString(const char* tag, - const std::map& args) -{ - return std::string(); -} +/** + * @file llwindowcallbacks.cpp + * @brief OS event callback class + * + * $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 "llwindowcallbacks.h" + +// +// LLWindowCallbacks +// + +bool LLWindowCallbacks::handleTranslatedKeyDown(const KEY key, const MASK mask, bool repeated) +{ + return false; +} + + +bool LLWindowCallbacks::handleTranslatedKeyUp(const KEY key, const MASK mask) +{ + return false; +} + +void LLWindowCallbacks::handleScanKey(KEY key, bool key_down, bool key_up, bool key_level) +{ +} + +bool LLWindowCallbacks::handleUnicodeChar(llwchar uni_char, MASK mask) +{ + return false; +} + + +bool LLWindowCallbacks::handleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +bool LLWindowCallbacks::handleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +void LLWindowCallbacks::handleMouseLeave(LLWindow *window) +{ + return; +} + +bool LLWindowCallbacks::handleCloseRequest(LLWindow *window) +{ + //allow the window to close + return true; +} + +void LLWindowCallbacks::handleQuit(LLWindow *window) +{ +} + +bool LLWindowCallbacks::handleRightMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +bool LLWindowCallbacks::handleRightMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +bool LLWindowCallbacks::handleMiddleMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +bool LLWindowCallbacks::handleMiddleMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +bool LLWindowCallbacks::handleOtherMouseDown(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +{ + return false; +} + +bool LLWindowCallbacks::handleOtherMouseUp(LLWindow *window, const LLCoordGL pos, MASK mask, S32 button) +{ + return false; +} + +bool LLWindowCallbacks::handleActivate(LLWindow *window, bool activated) +{ + return false; +} + +bool LLWindowCallbacks::handleActivateApp(LLWindow *window, bool activating) +{ + return false; +} + +void LLWindowCallbacks::handleMouseMove(LLWindow *window, const LLCoordGL pos, MASK mask) +{ +} + +void LLWindowCallbacks::handleMouseDragged(LLWindow *window, const LLCoordGL pos, MASK mask) +{ +} + +void LLWindowCallbacks::handleScrollWheel(LLWindow *window, S32 clicks) +{ +} + +void LLWindowCallbacks::handleScrollHWheel(LLWindow *window, S32 clicks) +{ +} + +void LLWindowCallbacks::handleResize(LLWindow *window, const S32 width, const S32 height) +{ +} + +void LLWindowCallbacks::handleFocus(LLWindow *window) +{ + LL_WARNS("COCOA") << "Called handleFocus proto" << LL_ENDL; +} + +void LLWindowCallbacks::handleFocusLost(LLWindow *window) +{ +} + +void LLWindowCallbacks::handleMenuSelect(LLWindow *window, const S32 menu_item) +{ +} + +bool LLWindowCallbacks::handlePaint(LLWindow *window, const S32 x, const S32 y, + const S32 width, const S32 height) +{ + return false; +} + +bool LLWindowCallbacks::handleDoubleClick(LLWindow *window, const LLCoordGL pos, MASK mask) +{ + return false; +} + +void LLWindowCallbacks::handleWindowBlock(LLWindow *window) +{ +} + +void LLWindowCallbacks::handleWindowUnblock(LLWindow *window) +{ +} + +void LLWindowCallbacks::handleDataCopy(LLWindow *window, S32 data_type, void *data) +{ +} + +LLWindowCallbacks::DragNDropResult LLWindowCallbacks::handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data ) +{ + return LLWindowCallbacks::DND_NONE; +} + +bool LLWindowCallbacks::handleTimerEvent(LLWindow *window) +{ + return false; +} + +bool LLWindowCallbacks::handleDeviceChange(LLWindow *window) +{ + return false; +} + +bool LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) +{ + return false; +} + +bool LLWindowCallbacks::handleWindowDidChangeScreen(LLWindow *window) +{ + return false; +} + +void LLWindowCallbacks::handlePingWatchdog(LLWindow *window, const char * msg) +{ + +} + +void LLWindowCallbacks::handlePauseWatchdog(LLWindow *window) +{ + +} + +void LLWindowCallbacks::handleResumeWatchdog(LLWindow *window) +{ + +} + +std::string LLWindowCallbacks::translateString(const char* tag) +{ + return std::string(); +} + +//virtual +std::string LLWindowCallbacks::translateString(const char* tag, + const std::map& args) +{ + return std::string(); +} diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index c38d34c206..63b585231f 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -1,100 +1,100 @@ -/** - * @file llwindowcallbacks.h - * @brief OS event callback class - * - * $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$ - */ -#ifndef LLWINDOWCALLBACKS_H -#define LLWINDOWCALLBACKS_H - -#include "llcoord.h" -class LLWindow; - -class LLWindowCallbacks -{ -public: - virtual ~LLWindowCallbacks() {} - virtual bool handleTranslatedKeyDown(KEY key, MASK mask, bool repeated); - virtual bool handleTranslatedKeyUp(KEY key, MASK mask); - virtual void handleScanKey(KEY key, bool key_down, bool key_up, bool key_level); - virtual bool handleUnicodeChar(llwchar uni_char, MASK mask); - - virtual bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - virtual bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - virtual void handleMouseLeave(LLWindow *window); - // return true to allow window to close, which will then cause handleQuit to be called - virtual bool handleCloseRequest(LLWindow *window); - // window is about to be destroyed, clean up your business - virtual void handleQuit(LLWindow *window); - virtual bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - virtual bool handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - virtual bool handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); - virtual bool handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); - virtual bool handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); - virtual bool handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); - virtual bool handleActivate(LLWindow *window, bool activated); - virtual bool handleActivateApp(LLWindow *window, bool activating); - virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); - virtual void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); - virtual void handleScrollWheel(LLWindow *window, S32 clicks); - virtual void handleScrollHWheel(LLWindow *window, S32 clicks); - virtual void handleResize(LLWindow *window, S32 width, S32 height); - virtual void handleFocus(LLWindow *window); - virtual void handleFocusLost(LLWindow *window); - virtual void handleMenuSelect(LLWindow *window, S32 menu_item); - virtual bool handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); - virtual bool handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); // double-click of left mouse button - virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while - virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while - virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); - virtual bool handleTimerEvent(LLWindow *window); - virtual bool handleDeviceChange(LLWindow *window); - virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); - virtual bool handleWindowDidChangeScreen(LLWindow *window); - - enum DragNDropAction { - DNDA_START_TRACKING = 0,// Start tracking an incoming drag - DNDA_TRACK, // User is dragging an incoming drag around the window - DNDA_STOP_TRACKING, // User is no longer dragging an incoming drag around the window (may have either cancelled or dropped on the window) - DNDA_DROPPED // User dropped an incoming drag on the window (this is the "commit" event) - }; - - enum DragNDropResult { - DND_NONE = 0, // No drop allowed - DND_MOVE, // Drop accepted would result in a "move" operation - DND_COPY, // Drop accepted would result in a "copy" operation - DND_LINK // Drop accepted would result in a "link" operation - }; - virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data); - - virtual void handlePingWatchdog(LLWindow *window, const char * msg); - virtual void handlePauseWatchdog(LLWindow *window); - virtual void handleResumeWatchdog(LLWindow *window); - - // Look up a localized string, usually for an error message - virtual std::string translateString(const char* tag); - virtual std::string translateString(const char* tag, - const std::map& args); -}; - - -#endif +/** + * @file llwindowcallbacks.h + * @brief OS event callback class + * + * $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$ + */ +#ifndef LLWINDOWCALLBACKS_H +#define LLWINDOWCALLBACKS_H + +#include "llcoord.h" +class LLWindow; + +class LLWindowCallbacks +{ +public: + virtual ~LLWindowCallbacks() {} + virtual bool handleTranslatedKeyDown(KEY key, MASK mask, bool repeated); + virtual bool handleTranslatedKeyUp(KEY key, MASK mask); + virtual void handleScanKey(KEY key, bool key_down, bool key_up, bool key_level); + virtual bool handleUnicodeChar(llwchar uni_char, MASK mask); + + virtual bool handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual void handleMouseLeave(LLWindow *window); + // return true to allow window to close, which will then cause handleQuit to be called + virtual bool handleCloseRequest(LLWindow *window); + // window is about to be destroyed, clean up your business + virtual void handleQuit(LLWindow *window); + virtual bool handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask); + virtual bool handleOtherMouseDown(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + virtual bool handleOtherMouseUp(LLWindow *window, LLCoordGL pos, MASK mask, S32 button); + virtual bool handleActivate(LLWindow *window, bool activated); + virtual bool handleActivateApp(LLWindow *window, bool activating); + virtual void handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask); + virtual void handleMouseDragged(LLWindow *window, LLCoordGL pos, MASK mask); + virtual void handleScrollWheel(LLWindow *window, S32 clicks); + virtual void handleScrollHWheel(LLWindow *window, S32 clicks); + virtual void handleResize(LLWindow *window, S32 width, S32 height); + virtual void handleFocus(LLWindow *window); + virtual void handleFocusLost(LLWindow *window); + virtual void handleMenuSelect(LLWindow *window, S32 menu_item); + virtual bool handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height); + virtual bool handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask); // double-click of left mouse button + virtual void handleWindowBlock(LLWindow *window); // window is taking over CPU for a while + virtual void handleWindowUnblock(LLWindow *window); // window coming back after taking over CPU for a while + virtual void handleDataCopy(LLWindow *window, S32 data_type, void *data); + virtual bool handleTimerEvent(LLWindow *window); + virtual bool handleDeviceChange(LLWindow *window); + virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); + virtual bool handleWindowDidChangeScreen(LLWindow *window); + + enum DragNDropAction { + DNDA_START_TRACKING = 0,// Start tracking an incoming drag + DNDA_TRACK, // User is dragging an incoming drag around the window + DNDA_STOP_TRACKING, // User is no longer dragging an incoming drag around the window (may have either cancelled or dropped on the window) + DNDA_DROPPED // User dropped an incoming drag on the window (this is the "commit" event) + }; + + enum DragNDropResult { + DND_NONE = 0, // No drop allowed + DND_MOVE, // Drop accepted would result in a "move" operation + DND_COPY, // Drop accepted would result in a "copy" operation + DND_LINK // Drop accepted would result in a "link" operation + }; + virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data); + + virtual void handlePingWatchdog(LLWindow *window, const char * msg); + virtual void handlePauseWatchdog(LLWindow *window); + virtual void handleResumeWatchdog(LLWindow *window); + + // Look up a localized string, usually for an error message + virtual std::string translateString(const char* tag); + virtual std::string translateString(const char* tag, + const std::map& args); +}; + + +#endif diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index fdcd6ca8a9..55e5cfd51e 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -1,53 +1,53 @@ -/** - * @file llwindowheadless.cpp - * @brief Headless implementation of LLWindow class - * - * $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 "indra_constants.h" - -#include "llwindowheadless.h" -#include "llkeyboardheadless.h" - -// -// LLWindowHeadless -// -LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, - U32 flags, bool fullscreen, bool clear_background, - bool enable_vsync, bool use_gl, bool ignore_pixel_depth) - : LLWindow(callbacks, fullscreen, flags) -{ - // Initialize a headless keyboard. - gKeyboard = new LLKeyboardHeadless(); - gKeyboard->setCallbacks(callbacks); -} - - -LLWindowHeadless::~LLWindowHeadless() -{ -} - -void LLWindowHeadless::swapBuffers() -{ -} +/** + * @file llwindowheadless.cpp + * @brief Headless implementation of LLWindow class + * + * $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 "indra_constants.h" + +#include "llwindowheadless.h" +#include "llkeyboardheadless.h" + +// +// LLWindowHeadless +// +LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, + U32 flags, bool fullscreen, bool clear_background, + bool enable_vsync, bool use_gl, bool ignore_pixel_depth) + : LLWindow(callbacks, fullscreen, flags) +{ + // Initialize a headless keyboard. + gKeyboard = new LLKeyboardHeadless(); + gKeyboard->setCallbacks(callbacks); +} + + +LLWindowHeadless::~LLWindowHeadless() +{ +} + +void LLWindowHeadless::swapBuffers() +{ +} diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 1a2363c13a..32c12b0d47 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -1,133 +1,133 @@ -/** - * @file llwindowheadless.h - * @brief Headless definition of LLWindow class - * - * $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$ - */ - -#ifndef LL_LLWINDOWHEADLESS_H -#define LL_LLWINDOWHEADLESS_H - -#include "llwindow.h" - -class LLWindowHeadless : public LLWindow -{ -public: - /*virtual*/ void show() override {} - /*virtual*/ void hide() override {} - /*virtual*/ void close() override {} - /*virtual*/ bool getVisible() override {return false;} - /*virtual*/ bool getMinimized() override {return false;} - /*virtual*/ bool getMaximized() override {return false;} - /*virtual*/ bool maximize() override {return false;} - /*virtual*/ void minimize() override {} - /*virtual*/ void restore() override {} - // TODO: LLWindow::getFullscreen() is (intentionally?) NOT virtual. - // Apparently the coder of LLWindowHeadless didn't realize that. Is it a - // mistake to shadow the base-class method with an LLWindowHeadless - // override when called on the subclass, yet call the base-class method - // when indirecting through a polymorphic pointer or reference? - bool getFullscreen() {return false;} - /*virtual*/ bool getPosition(LLCoordScreen *position) override {return false;} - /*virtual*/ bool getSize(LLCoordScreen *size) override {return false;} - /*virtual*/ bool getSize(LLCoordWindow *size) override {return false;} - /*virtual*/ bool setPosition(LLCoordScreen position) override {return false;} - /*virtual*/ bool setSizeImpl(LLCoordScreen size) override {return false;} - /*virtual*/ bool setSizeImpl(LLCoordWindow size) override {return false;} - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override {return false;} - void* createSharedContext() override { return nullptr; } - void makeContextCurrent(void*) override {} - void destroySharedContext(void*) override {} - /*virtual*/ void toggleVSync(bool enable_vsync) override { } - /*virtual*/ bool setCursorPosition(LLCoordWindow position) override {return false;} - /*virtual*/ bool getCursorPosition(LLCoordWindow *position) override {return false;} -#if LL_WINDOWS - /*virtual*/ bool getCursorDelta(LLCoordCommon* delta) override { return false; } -#endif - /*virtual*/ void showCursor() override {} - /*virtual*/ void hideCursor() override {} - /*virtual*/ void showCursorFromMouseMove() override {} - /*virtual*/ void hideCursorUntilMouseMove() override {} - /*virtual*/ bool isCursorHidden() override {return false;} - /*virtual*/ void updateCursor() override {} - //virtual ECursorType getCursor() override { return mCurrentCursor; } - /*virtual*/ void captureMouse() override {} - /*virtual*/ void releaseMouse() override {} - /*virtual*/ void setMouseClipping( bool b ) override {} - /*virtual*/ bool isClipboardTextAvailable() override {return false; } - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) override {return false; } - /*virtual*/ bool copyTextToClipboard(const LLWString &src) override {return false; } - /*virtual*/ void flashIcon(F32 seconds) override {} - /*virtual*/ F32 getGamma() override {return 1.0f; } - /*virtual*/ bool setGamma(const F32 gamma) override {return false; } // Set the gamma - /*virtual*/ void setFSAASamples(const U32 fsaa_samples) override { } - /*virtual*/ U32 getFSAASamples() override { return 0; } - /*virtual*/ bool restoreGamma() override {return false; } // Restore original gamma table (before updating gamma) - //virtual ESwapMethod getSwapMethod() override { return mSwapMethod; } - /*virtual*/ void gatherInput() override {} - /*virtual*/ void delayInputProcessing() override {} - /*virtual*/ void swapBuffers() override; - - - // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return false; } - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return false; } - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) override { return false; } - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) override { return false; } - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) override { return false; } - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) override { return false; } - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override { return NULL; } - /*virtual*/ F32 getNativeAspectRatio() override { return 1.0f; } - /*virtual*/ F32 getPixelAspectRatio() override { return 1.0f; } - /*virtual*/ void setNativeAspectRatio(F32 ratio) override {} - - void setMaxVRAMMegabytes(U32 max_vram) override {} - - /*virtual*/ void *getPlatformWindow() override { return 0; } - /*virtual*/ void bringToFront() override {} - - LLWindowHeadless(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, - S32 x, S32 y, - S32 width, S32 height, - U32 flags, bool fullscreen, bool clear_background, - bool enable_vsync, bool use_gl, bool ignore_pixel_depth); - virtual ~LLWindowHeadless(); - -private: -}; - -class LLSplashScreenHeadless : public LLSplashScreen -{ -public: - LLSplashScreenHeadless() {} - virtual ~LLSplashScreenHeadless() {} - - /*virtual*/ void showImpl() override {} - /*virtual*/ void updateImpl(const std::string& mesg) override {} - /*virtual*/ void hideImpl() override {} - -}; - -#endif //LL_LLWINDOWHEADLESS_H - +/** + * @file llwindowheadless.h + * @brief Headless definition of LLWindow class + * + * $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$ + */ + +#ifndef LL_LLWINDOWHEADLESS_H +#define LL_LLWINDOWHEADLESS_H + +#include "llwindow.h" + +class LLWindowHeadless : public LLWindow +{ +public: + /*virtual*/ void show() override {} + /*virtual*/ void hide() override {} + /*virtual*/ void close() override {} + /*virtual*/ bool getVisible() override {return false;} + /*virtual*/ bool getMinimized() override {return false;} + /*virtual*/ bool getMaximized() override {return false;} + /*virtual*/ bool maximize() override {return false;} + /*virtual*/ void minimize() override {} + /*virtual*/ void restore() override {} + // TODO: LLWindow::getFullscreen() is (intentionally?) NOT virtual. + // Apparently the coder of LLWindowHeadless didn't realize that. Is it a + // mistake to shadow the base-class method with an LLWindowHeadless + // override when called on the subclass, yet call the base-class method + // when indirecting through a polymorphic pointer or reference? + bool getFullscreen() {return false;} + /*virtual*/ bool getPosition(LLCoordScreen *position) override {return false;} + /*virtual*/ bool getSize(LLCoordScreen *size) override {return false;} + /*virtual*/ bool getSize(LLCoordWindow *size) override {return false;} + /*virtual*/ bool setPosition(LLCoordScreen position) override {return false;} + /*virtual*/ bool setSizeImpl(LLCoordScreen size) override {return false;} + /*virtual*/ bool setSizeImpl(LLCoordWindow size) override {return false;} + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override {return false;} + void* createSharedContext() override { return nullptr; } + void makeContextCurrent(void*) override {} + void destroySharedContext(void*) override {} + /*virtual*/ void toggleVSync(bool enable_vsync) override { } + /*virtual*/ bool setCursorPosition(LLCoordWindow position) override {return false;} + /*virtual*/ bool getCursorPosition(LLCoordWindow *position) override {return false;} +#if LL_WINDOWS + /*virtual*/ bool getCursorDelta(LLCoordCommon* delta) override { return false; } +#endif + /*virtual*/ void showCursor() override {} + /*virtual*/ void hideCursor() override {} + /*virtual*/ void showCursorFromMouseMove() override {} + /*virtual*/ void hideCursorUntilMouseMove() override {} + /*virtual*/ bool isCursorHidden() override {return false;} + /*virtual*/ void updateCursor() override {} + //virtual ECursorType getCursor() override { return mCurrentCursor; } + /*virtual*/ void captureMouse() override {} + /*virtual*/ void releaseMouse() override {} + /*virtual*/ void setMouseClipping( bool b ) override {} + /*virtual*/ bool isClipboardTextAvailable() override {return false; } + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) override {return false; } + /*virtual*/ bool copyTextToClipboard(const LLWString &src) override {return false; } + /*virtual*/ void flashIcon(F32 seconds) override {} + /*virtual*/ F32 getGamma() override {return 1.0f; } + /*virtual*/ bool setGamma(const F32 gamma) override {return false; } // Set the gamma + /*virtual*/ void setFSAASamples(const U32 fsaa_samples) override { } + /*virtual*/ U32 getFSAASamples() override { return 0; } + /*virtual*/ bool restoreGamma() override {return false; } // Restore original gamma table (before updating gamma) + //virtual ESwapMethod getSwapMethod() override { return mSwapMethod; } + /*virtual*/ void gatherInput() override {} + /*virtual*/ void delayInputProcessing() override {} + /*virtual*/ void swapBuffers() override; + + + // handy coordinate space conversion routines + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) override { return false; } + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) override { return false; } + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override { return NULL; } + /*virtual*/ F32 getNativeAspectRatio() override { return 1.0f; } + /*virtual*/ F32 getPixelAspectRatio() override { return 1.0f; } + /*virtual*/ void setNativeAspectRatio(F32 ratio) override {} + + void setMaxVRAMMegabytes(U32 max_vram) override {} + + /*virtual*/ void *getPlatformWindow() override { return 0; } + /*virtual*/ void bringToFront() override {} + + LLWindowHeadless(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, + S32 x, S32 y, + S32 width, S32 height, + U32 flags, bool fullscreen, bool clear_background, + bool enable_vsync, bool use_gl, bool ignore_pixel_depth); + virtual ~LLWindowHeadless(); + +private: +}; + +class LLSplashScreenHeadless : public LLSplashScreen +{ +public: + LLSplashScreenHeadless() {} + virtual ~LLSplashScreenHeadless() {} + + /*virtual*/ void showImpl() override {} + /*virtual*/ void updateImpl(const std::string& mesg) override {} + /*virtual*/ void hideImpl() override {} + +}; + +#endif //LL_LLWINDOWHEADLESS_H + diff --git a/indra/llwindow/llwindowmacosx-objc.h b/indra/llwindow/llwindowmacosx-objc.h index 609a441d66..d9d8bfce1f 100644 --- a/indra/llwindow/llwindowmacosx-objc.h +++ b/indra/llwindow/llwindowmacosx-objc.h @@ -1,186 +1,186 @@ -/** - * @file llwindowmacosx-objc.h - * @brief Prototypes for functions shared between llwindowmacosx.cpp - * and llwindowmacosx-objc.mm. - * - * $LicenseInfo:firstyear=2006&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$ - */ - -#ifndef LL_LLWINDOWMACOSX_OBJC_H -#define LL_LLWINDOWMACOSX_OBJC_H - -#include -#include -#include - -//fir CGSize -#include - -typedef std::vector > segment_t; - -typedef std::vector segment_lengths; -typedef std::deque segment_standouts; - -struct attributedStringInfo { - segment_lengths seg_lengths; - segment_standouts seg_standouts; -}; - -// This will actually hold an NSCursor*, but that type is only available in objective C. -typedef void *CursorRef; -typedef void *NSWindowRef; -typedef void *GLViewRef; - - -struct NativeKeyEventData { - enum EventType { - KEYUNKNOWN, - KEYUP, - KEYDOWN, - KEYCHAR - }; - - EventType mKeyEvent = KEYUNKNOWN; - uint32_t mEventType = 0; - uint32_t mEventModifiers = 0; - uint32_t mEventKeyCode = 0; - uint32_t mEventChars = 0; - uint32_t mEventUnmodChars = 0; - bool mEventRepeat = false; -}; - -typedef const NativeKeyEventData * NSKeyEventRef; - -// These are defined in llappviewermacosx.cpp. -bool initViewer(); -void handleQuit(); -bool pumpMainLoop(); -void initMainLoop(); -void cleanupViewer(); -void handleUrl(const char* url); -void dispatchUrl(std::string url); - -/* Defined in llwindowmacosx-objc.mm: */ -int createNSApp(int argc, const char **argv); -void setupCocoa(); -bool pasteBoardAvailable(); -bool copyToPBoard(const unsigned short *str, unsigned int len); -unsigned short *copyFromPBoard(); -CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY); -short releaseImageCursor(CursorRef ref); -short setImageCursor(CursorRef ref); -void setArrowCursor(); -void setIBeamCursor(); -void setPointingHandCursor(); -void setCopyCursor(); -void setCrossCursor(); -void setNotAllowedCursor(); -void hideNSCursor(); -void showNSCursor(); -bool isCGCursorVisible(); -void hideNSCursorTillMove(bool hide); -void requestUserAttention(); -long showAlert(std::string title, std::string text, int type); -void setResizeMode(bool oldresize, void* glview); - -NSWindowRef createNSWindow(int x, int y, int width, int height); - -#include - -GLViewRef createOpenGLView(NSWindowRef window, unsigned int samples, bool vsync); -void glSwapBuffers(void* context); -CGLContextObj getCGLContextObj(GLViewRef view); -unsigned long getVramSize(GLViewRef view); -float getDeviceUnitSize(GLViewRef view); -CGPoint getContentViewBoundsPosition(NSWindowRef window); -CGSize getContentViewBoundsSize(NSWindowRef window); -CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view); -void getWindowSize(NSWindowRef window, float* size); -void setWindowSize(NSWindowRef window, int width, int height); -void getCursorPos(NSWindowRef window, float* pos); -void makeWindowOrderFront(NSWindowRef window); -void convertScreenToWindow(NSWindowRef window, float *coord); -void convertWindowToScreen(NSWindowRef window, float *coord); -void convertScreenToView(NSWindowRef window, float *coord); -void convertRectToScreen(NSWindowRef window, float *coord); -void convertRectFromScreen(NSWindowRef window, float *coord); -void setWindowPos(NSWindowRef window, float* pos); -void closeWindow(NSWindowRef window); -void removeGLView(GLViewRef view); -void makeFirstResponder(NSWindowRef window, GLViewRef view); -void setupInputWindow(NSWindowRef window, GLViewRef view); - -// These are all implemented in llwindowmacosx.cpp. -// This is largely for easier interop between Obj-C and C++ (at least in the viewer's case due to the BOOL vs. BOOL conflict) -bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask); -bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character); -void callResetKeys(); -bool callUnicodeCallback(wchar_t character, unsigned int mask); -void callRightMouseDown(float *pos, unsigned int mask); -void callRightMouseUp(float *pos, unsigned int mask); -void callLeftMouseDown(float *pos, unsigned int mask); -void callLeftMouseUp(float *pos, unsigned int mask); -void callDoubleClick(float *pos, unsigned int mask); -void callResize(unsigned int width, unsigned int height); -void callMouseMoved(float *pos, unsigned int mask); -void callMouseDragged(float *pos, unsigned int mask); -void callScrollMoved(float deltaX, float deltaY); -void callMouseExit(); -void callWindowFocus(); -void callWindowUnfocus(); -void callWindowHide(); -void callWindowUnhide(); -void callWindowDidChangeScreen(); -void callDeltaUpdate(float *delta, unsigned int mask); -void callOtherMouseDown(float *pos, unsigned int mask, int button); -void callOtherMouseUp(float *pos, unsigned int mask, int button); -void callFocus(); -void callFocusLost(); -void callModifier(unsigned int mask); -void callQuitHandler(); -void commitCurrentPreedit(GLViewRef glView); - -#include -void callHandleDragEntered(std::string url); -void callHandleDragExited(std::string url); -void callHandleDragUpdated(std::string url); -void callHandleDragDropped(std::string url); - -// LLPreeditor C bindings. -std::basic_string getPreeditString(); -void getPreeditSelectionRange(int *position, int *length); -void getPreeditMarkedRange(int *position, int *length); -bool handleUnicodeCharacter(wchar_t c); -void updatePreeditor(unsigned short *str); -void setPreeditMarkedRange(int position, int length); -void resetPreedit(); -int wstring_length(const std::basic_string & wstr, const int woffset, const int utf16_length, int *unaligned); -void setMarkedText(unsigned short *text, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments); -void getPreeditLocation(float *location, unsigned int length); -void allowDirectMarkedTextInput(bool allow, GLViewRef glView); - -NSWindowRef getMainAppWindow(); -GLViewRef getGLView(); - -unsigned int getModifiers(); - -#endif // LL_LLWINDOWMACOSX_OBJC_H +/** + * @file llwindowmacosx-objc.h + * @brief Prototypes for functions shared between llwindowmacosx.cpp + * and llwindowmacosx-objc.mm. + * + * $LicenseInfo:firstyear=2006&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$ + */ + +#ifndef LL_LLWINDOWMACOSX_OBJC_H +#define LL_LLWINDOWMACOSX_OBJC_H + +#include +#include +#include + +//fir CGSize +#include + +typedef std::vector > segment_t; + +typedef std::vector segment_lengths; +typedef std::deque segment_standouts; + +struct attributedStringInfo { + segment_lengths seg_lengths; + segment_standouts seg_standouts; +}; + +// This will actually hold an NSCursor*, but that type is only available in objective C. +typedef void *CursorRef; +typedef void *NSWindowRef; +typedef void *GLViewRef; + + +struct NativeKeyEventData { + enum EventType { + KEYUNKNOWN, + KEYUP, + KEYDOWN, + KEYCHAR + }; + + EventType mKeyEvent = KEYUNKNOWN; + uint32_t mEventType = 0; + uint32_t mEventModifiers = 0; + uint32_t mEventKeyCode = 0; + uint32_t mEventChars = 0; + uint32_t mEventUnmodChars = 0; + bool mEventRepeat = false; +}; + +typedef const NativeKeyEventData * NSKeyEventRef; + +// These are defined in llappviewermacosx.cpp. +bool initViewer(); +void handleQuit(); +bool pumpMainLoop(); +void initMainLoop(); +void cleanupViewer(); +void handleUrl(const char* url); +void dispatchUrl(std::string url); + +/* Defined in llwindowmacosx-objc.mm: */ +int createNSApp(int argc, const char **argv); +void setupCocoa(); +bool pasteBoardAvailable(); +bool copyToPBoard(const unsigned short *str, unsigned int len); +unsigned short *copyFromPBoard(); +CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY); +short releaseImageCursor(CursorRef ref); +short setImageCursor(CursorRef ref); +void setArrowCursor(); +void setIBeamCursor(); +void setPointingHandCursor(); +void setCopyCursor(); +void setCrossCursor(); +void setNotAllowedCursor(); +void hideNSCursor(); +void showNSCursor(); +bool isCGCursorVisible(); +void hideNSCursorTillMove(bool hide); +void requestUserAttention(); +long showAlert(std::string title, std::string text, int type); +void setResizeMode(bool oldresize, void* glview); + +NSWindowRef createNSWindow(int x, int y, int width, int height); + +#include + +GLViewRef createOpenGLView(NSWindowRef window, unsigned int samples, bool vsync); +void glSwapBuffers(void* context); +CGLContextObj getCGLContextObj(GLViewRef view); +unsigned long getVramSize(GLViewRef view); +float getDeviceUnitSize(GLViewRef view); +CGPoint getContentViewBoundsPosition(NSWindowRef window); +CGSize getContentViewBoundsSize(NSWindowRef window); +CGSize getDeviceContentViewSize(NSWindowRef window, GLViewRef view); +void getWindowSize(NSWindowRef window, float* size); +void setWindowSize(NSWindowRef window, int width, int height); +void getCursorPos(NSWindowRef window, float* pos); +void makeWindowOrderFront(NSWindowRef window); +void convertScreenToWindow(NSWindowRef window, float *coord); +void convertWindowToScreen(NSWindowRef window, float *coord); +void convertScreenToView(NSWindowRef window, float *coord); +void convertRectToScreen(NSWindowRef window, float *coord); +void convertRectFromScreen(NSWindowRef window, float *coord); +void setWindowPos(NSWindowRef window, float* pos); +void closeWindow(NSWindowRef window); +void removeGLView(GLViewRef view); +void makeFirstResponder(NSWindowRef window, GLViewRef view); +void setupInputWindow(NSWindowRef window, GLViewRef view); + +// These are all implemented in llwindowmacosx.cpp. +// This is largely for easier interop between Obj-C and C++ (at least in the viewer's case due to the BOOL vs. BOOL conflict) +bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask); +bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character); +void callResetKeys(); +bool callUnicodeCallback(wchar_t character, unsigned int mask); +void callRightMouseDown(float *pos, unsigned int mask); +void callRightMouseUp(float *pos, unsigned int mask); +void callLeftMouseDown(float *pos, unsigned int mask); +void callLeftMouseUp(float *pos, unsigned int mask); +void callDoubleClick(float *pos, unsigned int mask); +void callResize(unsigned int width, unsigned int height); +void callMouseMoved(float *pos, unsigned int mask); +void callMouseDragged(float *pos, unsigned int mask); +void callScrollMoved(float deltaX, float deltaY); +void callMouseExit(); +void callWindowFocus(); +void callWindowUnfocus(); +void callWindowHide(); +void callWindowUnhide(); +void callWindowDidChangeScreen(); +void callDeltaUpdate(float *delta, unsigned int mask); +void callOtherMouseDown(float *pos, unsigned int mask, int button); +void callOtherMouseUp(float *pos, unsigned int mask, int button); +void callFocus(); +void callFocusLost(); +void callModifier(unsigned int mask); +void callQuitHandler(); +void commitCurrentPreedit(GLViewRef glView); + +#include +void callHandleDragEntered(std::string url); +void callHandleDragExited(std::string url); +void callHandleDragUpdated(std::string url); +void callHandleDragDropped(std::string url); + +// LLPreeditor C bindings. +std::basic_string getPreeditString(); +void getPreeditSelectionRange(int *position, int *length); +void getPreeditMarkedRange(int *position, int *length); +bool handleUnicodeCharacter(wchar_t c); +void updatePreeditor(unsigned short *str); +void setPreeditMarkedRange(int position, int length); +void resetPreedit(); +int wstring_length(const std::basic_string & wstr, const int woffset, const int utf16_length, int *unaligned); +void setMarkedText(unsigned short *text, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments); +void getPreeditLocation(float *location, unsigned int length); +void allowDirectMarkedTextInput(bool allow, GLViewRef glView); + +NSWindowRef getMainAppWindow(); +GLViewRef getGLView(); + +unsigned int getModifiers(); + +#endif // LL_LLWINDOWMACOSX_OBJC_H diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index fee74a9c25..cd00f4d33c 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1,2662 +1,2662 @@ -/** - * @file llwindowmacosx.cpp - * @brief Platform-dependent implementation of llwindow - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llwindowmacosx.h" - -#include "llkeyboardmacosx.h" -#include "llwindowcallbacks.h" -#include "llpreeditor.h" - -#include "llerror.h" -#include "llgl.h" -#include "llstring.h" -#include "lldir.h" -#include "indra_constants.h" - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -extern bool gDebugWindowProc; -bool gHiDPISupport = true; - -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; - -const S32 DEFAULT_REFRESH_RATE = 60; - -namespace -{ - NSKeyEventRef mRawKeyEvent = NULL; -} -// -// LLWindowMacOSX -// - -bool LLWindowMacOSX::sUseMultGL = false; - -// Cross-platform bits: - -bool check_for_card(const char* RENDERER, const char* bad_card) -{ - if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) - { - std::string buffer = llformat( - "Your video card appears to be a %s, which Second Life does not support.\n" - "\n" - "Second Life requires a video card with 32 Mb of memory or more, as well as\n" - "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" - "and ATI Radeon 8500 or better.\n" - "\n" - "If you own a supported card and continue to receive this message, try \n" - "updating to the latest video card drivers. Otherwise look in the\n" - "secondlife.com support section or e-mail technical support\n" - "\n" - "You can try to run Second Life, but it will probably crash or run\n" - "very slowly. Try anyway?", - bad_card); - S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); - if (OSBTN_YES == button) - { - return false; - } - else - { - return true; - } - } - - return false; -} - -// Switch to determine whether we capture all displays, or just the main one. -// We may want to base this on the setting of _DEBUG... - -#define CAPTURE_ALL_DISPLAYS 0 -//static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); -static long getDictLong (CFDictionaryRef refDict, CFStringRef key); - -// MBW -- HACK ALERT -// On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. -// The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these -// require a pointer to the LLWindowMacOSX object. Stash it here and maintain in the constructor and destructor. -// This assumes that there will be only one object of this class at any time. Hopefully this is true. -static LLWindowMacOSX *gWindowImplementation = NULL; - -LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - bool fullscreen, bool clearBg, - bool enable_vsync, bool use_gl, - bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_vram) - : LLWindow(NULL, fullscreen, flags) -{ - // *HACK: During window construction we get lots of OS events for window - // reshape, activate, etc. that the viewer isn't ready to handle. - // Route them to a dummy callback structure until the end of constructor. - LLWindowCallbacks null_callbacks; - mCallbacks = &null_callbacks; - - // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). - setupCocoa(); - - // Initialize the keyboard - gKeyboard = new LLKeyboardMacOSX(); - gKeyboard->setCallbacks(callbacks); - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mContext = NULL; - mPixelFormat = NULL; - mDisplay = CGMainDisplayID(); - mSimulatedRightClick = false; - mLastModifiers = 0; - mHandsOffEvents = false; - mCursorDecoupled = false; - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = false; - mNeedsResize = false; - mOverrideAspectRatio = 0.f; - mMaximized = false; - mMinimized = false; - mLanguageTextInputAllowed = false; - mPreeditor = NULL; - mFSAASamples = fsaa_samples; - mForceRebuild = false; - - // Get the original aspect ratio of the main device. - mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); - - // Stash the window title - mWindowTitle = title; - //mWindowTitle[0] = title.length(); - - mDragOverrideCursor = -1; - - // Set up global event handlers (the fullscreen case needs this) - //InstallStandardEventHandler(GetApplicationEventTarget()); - - // Stash an object pointer for OSMessageBox() - gWindowImplementation = this; - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) - { - if(mWindow != NULL) - { - makeWindowOrderFront(mWindow); - } - - if (!gGLManager.initGL()) - { - setupFailure( - "Second Life is unable to run because your video card drivers\n" - "are out of date or unsupported. Please make sure you have\n" - "the latest video card drivers installed.\n" - "If you continue to receive this message, contact customer service.", - "Error", - OSMB_OK); - return; - } - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - - allowLanguageTextInput(NULL, false); - } - - mCallbacks = callbacks; - stop_glerror(); - - -} - -// These functions are used as wrappers for our internal event handling callbacks. -// It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow. - -bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) -{ - mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyUp(key, mask); - mRawKeyEvent = NULL; - return retVal; -} - -bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) -{ - //if (mask!=MASK_NONE) - { - if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) - { - key = gKeyboard->inverseTranslateKey('Y'); - } - else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) - { - key = gKeyboard->inverseTranslateKey('Z'); - } - } - - mRawKeyEvent = event; - bool retVal = gKeyboard->handleKeyDown(key, mask); - mRawKeyEvent = NULL; - return retVal; -} - -void callResetKeys() -{ - gKeyboard->resetKeys(); -} - -bool callUnicodeCallback(wchar_t character, unsigned int mask) -{ - NativeKeyEventData eventData; - - memset(&eventData, 0, sizeof(NativeKeyEventData)); - - eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; - eventData.mEventType = 0; - eventData.mEventModifiers = mask; - eventData.mEventKeyCode = 0; - eventData.mEventChars = character; - eventData.mEventUnmodChars = character; - eventData.mEventRepeat = false; - - mRawKeyEvent = &eventData; - - bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); - mRawKeyEvent = NULL; - return result; -} - -void callFocus() -{ - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); - } -} - -void callFocusLost() -{ - if (gWindowImplementation) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } -} - -void callRightMouseDown(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callRightMouseUp(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callLeftMouseDown(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callLeftMouseUp(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); - -} - -void callDoubleClick(float *pos, MASK mask) -{ - if (gWindowImplementation->allowsLanguageInput()) - { - gWindowImplementation->interruptLanguageTextInput(); - } - - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callResize(unsigned int width, unsigned int height) -{ - if (gWindowImplementation != NULL) - { - gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); - } -} - -void callMouseMoved(float *pos, MASK mask) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); - //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); -} - -void callMouseDragged(float *pos, MASK mask) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); -} - -void callScrollMoved(float deltaX, float deltaY) -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); - gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); - } -} - -void callMouseExit() -{ - gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); -} - -void callWindowFocus() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); - } - else - { - LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; - } - - -} - -void callWindowUnfocus() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); - } -} - -void callWindowHide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); - } -} - -void callWindowUnhide() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); - } -} - -void callWindowDidChangeScreen() -{ - if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) - { - gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); - } -} - -void callDeltaUpdate(float *delta, MASK mask) -{ - gWindowImplementation->updateMouseDeltas(delta); -} - -void callOtherMouseDown(float *pos, MASK mask, int button) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - - if (button == 2) - { - gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); - } - else - { - gWindowImplementation->getCallbacks()->handleOtherMouseDown(gWindowImplementation, outCoords, mask, button + 1); - } -} - -void callOtherMouseUp(float *pos, MASK mask, int button) -{ - LLCoordGL outCoords; - outCoords.mX = ll_round(pos[0]); - outCoords.mY = ll_round(pos[1]); - float deltas[2]; - gWindowImplementation->getMouseDeltas(deltas); - outCoords.mX += deltas[0]; - outCoords.mY += deltas[1]; - if (button == 2) - { - gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); - } - else - { - gWindowImplementation->getCallbacks()->handleOtherMouseUp(gWindowImplementation, outCoords, mask, button + 1); - } -} - -void callModifier(MASK mask) -{ - gKeyboard->handleModifier(mask); -} - -void callHandleDragEntered(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); -} - -void callHandleDragExited(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); -} - -void callHandleDragUpdated(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); -} - -void callHandleDragDropped(std::string url) -{ - gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); -} - -void callQuitHandler() -{ - if (gWindowImplementation) - { - if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) - { - gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); - } - } -} - -void getPreeditSelectionRange(int *position, int *length) -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getSelectionRange(position, length); - } -} - -void getPreeditMarkedRange(int *position, int *length) -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->getPreeditRange(position, length); - } -} - -void setPreeditMarkedRange(int position, int length) -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->markAsPreedit(position, length); - } -} - -bool handleUnicodeCharacter(wchar_t c) -{ - bool success = false; - if (gWindowImplementation->getPreeditor()) - { - success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); - } - - return success; -} - -void resetPreedit() -{ - if (gWindowImplementation->getPreeditor()) - { - gWindowImplementation->getPreeditor()->resetPreedit(); - } -} - -// For reasons of convenience, handle IME updates here. -// This largely mirrors the old implementation, only sans the carbon parameters. -void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments) -{ - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - preeditor->resetPreedit(); - // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. - if (replacementRange[0] < replacementRange[1]) - { - const LLWString& text = preeditor->getPreeditString(); - const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); - const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); - preeditor->markAsPreedit(location, length); - } - - LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); - - S32 caret_position = fix_str.length(); - - preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); - } -} - -void getPreeditLocation(float *location, unsigned int length) -{ - if (gWindowImplementation->getPreeditor()) - { - LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); - LLCoordGL coord; - LLCoordScreen screen; - LLRect rect; - - preeditor->getPreeditLocation(length, &coord, &rect, NULL); - - float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; - - convertRectToScreen(gWindowImplementation->getWindow(), c); - - location[0] = c[0]; - location[1] = c[1]; - } -} - -void LLWindowMacOSX::updateMouseDeltas(float* deltas) -{ - if (mCursorDecoupled) - { - mCursorLastEventDeltaX = ll_round(deltas[0]); - mCursorLastEventDeltaY = ll_round(-deltas[1]); - - if (mCursorIgnoreNextDelta) - { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - mCursorIgnoreNextDelta = false; - } - } else { - mCursorLastEventDeltaX = 0; - mCursorLastEventDeltaY = 0; - } -} - -void LLWindowMacOSX::getMouseDeltas(float* delta) -{ - delta[0] = mCursorLastEventDeltaX; - delta[1] = mCursorLastEventDeltaY; -} - -bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) -{ - mFullscreen = fullscreen; - - if (mWindow == NULL) - { - mWindow = getMainAppWindow(); - } - - if(mContext == NULL) - { - // Our OpenGL view is already defined within SecondLife.xib. - // Get the view instead. - mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); - mContext = getCGLContextObj(mGLView); - gGLManager.mVRAM = getVramSize(mGLView); - - if(!mPixelFormat) - { - CGLPixelFormatAttribute attribs[] = - { - kCGLPFANoRecovery, - kCGLPFADoubleBuffer, - kCGLPFAClosestPolicy, - kCGLPFAAccelerated, - kCGLPFAMultisample, - kCGLPFASampleBuffers, static_cast((mFSAASamples > 0 ? 1 : 0)), - kCGLPFASamples, static_cast(mFSAASamples), - kCGLPFAStencilSize, static_cast(8), - kCGLPFADepthSize, static_cast(24), - kCGLPFAAlphaSize, static_cast(8), - kCGLPFAColorSize, static_cast(24), - kCGLPFAOpenGLProfile, static_cast(kCGLOGLPVersion_GL4_Core), - static_cast(0) - }; - - GLint numPixelFormats; - CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); - - if(mPixelFormat == NULL) { - CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); - } - } - - } - - // This sets up our view to recieve text from our non-inline text input window. - setupInputWindow(mWindow, mGLView); - - // Hook up the context to a drawable - - if(mContext != NULL) - { - - - U32 err = CGLSetCurrentContext(mContext); - if (err != kCGLNoError) - { - setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); - return false; - } - } - - mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); - if(mRefreshRate == 0) - { - //consider adding more appropriate fallback later - mRefreshRate = DEFAULT_REFRESH_RATE; - } - - // Disable vertical sync for swap - toggleVSync(enable_vsync); - - //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); - - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - makeFirstResponder(mWindow, mGLView); - - return true; -} - - -// We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. -// This makes this method obsolete. -bool LLWindowMacOSX::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) -{ - return false; -} - -void LLWindowMacOSX::destroyContext() -{ - if (!mContext) - { - // We don't have a context - return; - } - // Unhook the GL context from any drawable it may have - if(mContext != NULL) - { - LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; - CGLSetCurrentContext(NULL); - } - - // Clean up remaining GL state before blowing away window - gGLManager.shutdownGL(); - - // Clean up the pixel format - if(mPixelFormat != NULL) - { - CGLDestroyPixelFormat(mPixelFormat); - mPixelFormat = NULL; - } - - // Clean up the GL context - if(mContext != NULL) - { - CGLDestroyContext(mContext); - } - - // Destroy our LLOpenGLView - if(mGLView != NULL) - { - removeGLView(mGLView); - mGLView = NULL; - } - - // Close the window - if(mWindow != NULL) - { - NSWindowRef dead_window = mWindow; - mWindow = NULL; - closeWindow(dead_window); - } - -} - -LLWindowMacOSX::~LLWindowMacOSX() -{ - destroyContext(); - - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } - - gWindowImplementation = NULL; - -} - - -void LLWindowMacOSX::show() -{ -} - -void LLWindowMacOSX::hide() -{ - setMouseClipping(false); -} - -//virtual -void LLWindowMacOSX::minimize() -{ - setMouseClipping(false); - showCursor(); -} - -//virtual -void LLWindowMacOSX::restore() -{ - show(); -} - - -// close() destroys all OS-specific code associated with a window. -// Usually called from LLWindowManager::destroyWindow() -void LLWindowMacOSX::close() -{ - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } - - // Make sure cursor is visible and we haven't mangled the clipping state. - setMouseClipping(false); - showCursor(); - - destroyContext(); -} - -bool LLWindowMacOSX::isValid() -{ - if(mFullscreen) - { - return(true); - } - - return (mWindow != NULL); -} - -bool LLWindowMacOSX::getVisible() -{ - bool result = false; - - if(mFullscreen) - { - result = true; - }if (mWindow) - { - result = true; - } - - return(result); -} - -bool LLWindowMacOSX::getMinimized() -{ - return mMinimized; -} - -bool LLWindowMacOSX::getMaximized() -{ - return mMaximized; -} - -bool LLWindowMacOSX::maximize() -{ - if (mWindow && !mMaximized) - { - } - - return mMaximized; -} - -bool LLWindowMacOSX::getFullscreen() -{ - return mFullscreen; -} - -void LLWindowMacOSX::gatherInput() -{ - updateCursor(); -} - -bool LLWindowMacOSX::getPosition(LLCoordScreen *position) -{ - S32 err = -1; - - if(mFullscreen) - { - position->mX = 0; - position->mY = 0; - err = noErr; - } - else if(mWindow) - { - const CGPoint & pos = getContentViewBoundsPosition(mWindow); - - position->mX = pos.x; - position->mY = pos.y; - - err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); -} - -bool LLWindowMacOSX::getSize(LLCoordScreen *size) -{ - S32 err = -1; - - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - - size->mX = sz.width; - size->mY = sz.height; - err = noErr; - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); -} - -bool LLWindowMacOSX::getSize(LLCoordWindow *size) -{ - S32 err = -1; - - if(mFullscreen) - { - size->mX = mFullscreenWidth; - size->mY = mFullscreenHeight; - err = noErr; - } - else if(mWindow) - { - const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); - - size->mX = sz.width; - size->mY = sz.height; - err = noErr; - - - } - else - { - LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; - } - - return (err == noErr); -} - -bool LLWindowMacOSX::setPosition(const LLCoordScreen position) -{ - if(mWindow) - { - float pos[2] = {float(position.mX), float(position.mY)}; - setWindowPos(mWindow, pos); - } - - return true; -} - -bool LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) -{ - if(mWindow) - { - LLCoordWindow to; - convertCoords(size, &to); - setWindowSize(mWindow, to.mX, to.mY); - return true; - } - - return false; -} - -bool LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) -{ - if (mWindow) - { - const int titlePadding = 22; - setWindowSize(mWindow, size.mX, size.mY + titlePadding); - return true; - } - - return false; -} - -void LLWindowMacOSX::swapBuffers() -{ - CGLFlushDrawable(mContext); -} - -void LLWindowMacOSX::restoreGLContext() -{ - CGLSetCurrentContext(mContext); -} - -F32 LLWindowMacOSX::getGamma() -{ - F32 result = 2.2; // Default to something sane - - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) == noErr) - { - // So many choices... - // Let's just return the green channel gamma for now. - result = greenGamma; - } - - return result; -} - -U32 LLWindowMacOSX::getFSAASamples() -{ - return mFSAASamples; -} - -void LLWindowMacOSX::setFSAASamples(const U32 samples) -{ - mFSAASamples = samples; - mForceRebuild = true; -} - -bool LLWindowMacOSX::restoreGamma() -{ - CGDisplayRestoreColorSyncSettings(); - return true; -} - -bool LLWindowMacOSX::setGamma(const F32 gamma) -{ - CGGammaValue redMin; - CGGammaValue redMax; - CGGammaValue redGamma; - CGGammaValue greenMin; - CGGammaValue greenMax; - CGGammaValue greenGamma; - CGGammaValue blueMin; - CGGammaValue blueMax; - CGGammaValue blueGamma; - - // MBW -- XXX -- Should we allow this in windowed mode? - - if(CGGetDisplayTransferByFormula( - mDisplay, - &redMin, - &redMax, - &redGamma, - &greenMin, - &greenMax, - &greenGamma, - &blueMin, - &blueMax, - &blueGamma) != noErr) - { - return false; - } - - if(CGSetDisplayTransferByFormula( - mDisplay, - redMin, - redMax, - gamma, - greenMin, - greenMax, - gamma, - blueMin, - blueMax, - gamma) != noErr) - { - return false; - } - - - return true; -} - -bool LLWindowMacOSX::isCursorHidden() -{ - return mCursorHidden; -} - - - -// Constrains the mouse to the window. -void LLWindowMacOSX::setMouseClipping( bool b ) -{ - // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. - mIsMouseClipping = b; - - if(b) - { - // LL_INFOS() << "setMouseClipping(true)" << LL_ENDL; - } - else - { - // LL_INFOS() << "setMouseClipping(false)" << LL_ENDL; - } - - adjustCursorDecouple(); -} - -bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) -{ - bool result = false; - LLCoordScreen screen_pos; - - if (!convertCoords(position, &screen_pos)) - { - return false; - } - - CGPoint newPosition; - - // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; - - newPosition.x = screen_pos.mX; - newPosition.y = screen_pos.mY; - - CGSetLocalEventsSuppressionInterval(0.0); - if(CGWarpMouseCursorPosition(newPosition) == noErr) - { - result = true; - } - - // Under certain circumstances, this will trigger us to decouple the cursor. - adjustCursorDecouple(true); - - // trigger mouse move callback - LLCoordGL gl_pos; - convertCoords(position, &gl_pos); - float scale = getSystemUISize(); - gl_pos.mX *= scale; - gl_pos.mY *= scale; - mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); - - return result; -} - -bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) -{ - float cursor_point[2]; - LLCoordScreen screen_pos; - - if(mWindow == NULL) - return false; - - getCursorPos(mWindow, cursor_point); - - if(mCursorDecoupled) - { - // CGMouseDelta x, y; - - // If the cursor's decoupled, we need to read the latest movement delta as well. - // CGGetLastMouseDelta( &x, &y ); - // cursor_point.h += x; - // cursor_point.v += y; - - // CGGetLastMouseDelta may behave strangely when the cursor's first captured. - // Stash in the event handler instead. - cursor_point[0] += mCursorLastEventDeltaX; - cursor_point[1] += mCursorLastEventDeltaY; - } - - float scale = getSystemUISize(); - position->mX = cursor_point[0] * scale; - position->mY = cursor_point[1] * scale; - - return true; -} - -void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) -{ - if(mIsMouseClipping && mCursorHidden) - { - if(warpingMouse) - { - // The cursor should be decoupled. Make sure it is. - if(!mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(false); - mCursorDecoupled = true; - mCursorIgnoreNextDelta = true; - } - } - } - else - { - // The cursor should not be decoupled. Make sure it isn't. - if(mCursorDecoupled) - { - // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; - CGAssociateMouseAndMouseCursorPosition(true); - mCursorDecoupled = false; - } - } -} - -F32 LLWindowMacOSX::getNativeAspectRatio() -{ - if (mFullscreen) - { - return (F32)mFullscreenWidth / (F32)mFullscreenHeight; - } - else - { - // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution - // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. - - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } - - return mOriginalAspectRatio; - } -} - -F32 LLWindowMacOSX::getPixelAspectRatio() -{ - //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode - return 1.f; -} - -//static SInt32 oldWindowLevel; - -// MBW -- XXX -- There's got to be a better way than this. Find it, please... - -// Since we're no longer supporting the "typical" fullscreen mode with CGL or NSOpenGL anymore, these are unnecessary. -Geenz -void LLWindowMacOSX::beforeDialog() -{ -} - -void LLWindowMacOSX::afterDialog() -{ - //For fix problem with Core Flow view on OSX - restoreGLContext(); -} - - -void LLWindowMacOSX::flashIcon(F32 seconds) -{ - // For consistency with macOS conventions, the number of seconds given is ignored and - // left up to the OS (which will actually bounce it for one second). - requestUserAttention(); -} - -bool LLWindowMacOSX::isClipboardTextAvailable() -{ - return pasteBoardAvailable(); -} - -bool LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) -{ - unsigned short* pboard_data = copyFromPBoard(); // must free returned data - llutf16string str(pboard_data); - free(pboard_data); - - dst = utf16str_to_wstring(str); - if (dst != L"") - { - return true; - } else { - return false; - } -} - -bool LLWindowMacOSX::copyTextToClipboard(const LLWString &s) -{ - bool result = false; - llutf16string utf16str = wstring_to_utf16str(s); - - result = copyToPBoard(utf16str.data(), utf16str.length()); - - return result; -} - - -// protected -bool LLWindowMacOSX::resetDisplayResolution() -{ - // This is only called from elsewhere in this class, and it's not used by the Mac implementation. - return true; -} - - -LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) -{ - if (!mSupportedResolutions) - { - CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); - - if(modes != NULL) - { - CFIndex index, cnt; - - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - mNumSupportedResolutions = 0; - - // Examine each mode - cnt = CFArrayGetCount( modes ); - - for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) - { - // Pull the mode dictionary out of the CFArray - CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); - long width = getDictLong(mode, kCGDisplayWidth); - long height = getDictLong(mode, kCGDisplayHeight); - long bits = getDictLong(mode, kCGDisplayBitsPerPixel); - - if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) - { - bool resolution_exists = false; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == width && - mSupportedResolutions[i].mHeight == height) - { - resolution_exists = true; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = width; - mSupportedResolutions[mNumSupportedResolutions].mHeight = height; - mNumSupportedResolutions++; - } - } - } - CFRelease(modes); - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; -} - -bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ - to->mX = from.mX; - to->mY = from.mY; - return true; -} - -bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ - to->mX = from.mX; - to->mY = from.mY; - return true; -} - -bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - if(mWindow) - { - float mouse_point[2]; - - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; - - convertScreenToWindow(mWindow, mouse_point); - - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; - - return true; - } - return false; -} - -bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ - if(mWindow) - { - float mouse_point[2]; - - mouse_point[0] = from.mX; - mouse_point[1] = from.mY; - - convertWindowToScreen(mWindow, mouse_point); - - to->mX = mouse_point[0]; - to->mY = mouse_point[1]; - - return true; - } - return false; -} - -bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - -bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - - - - -void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) -{ - destroyContext(); - - OSMessageBox(text, caption, type); -} - - // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature - // it is handled at a very low-level -const char* cursorIDToName(int id) -{ - switch (id) - { - case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; - case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; - case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; - case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; - case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; - case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; - case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; - case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; - case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; - case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; - case UI_CURSOR_NO: return "UI_CURSOR_NO"; - case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; - case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; - case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; - case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; - case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; - case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; - case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; - case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; - case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; - case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; - case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; - case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; - case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; - case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; - case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; - case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; - case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; - case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; - case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; - case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; - case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; - case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; - case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; - case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; - case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; - case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; - case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; - case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; - case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; - } - - LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; - - return "UI_CURSOR_ARROW"; -} - -static CursorRef gCursors[UI_CURSOR_COUNT]; - - -static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) -{ - // cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif - std::string fullpath = gDirUtilp->add( - gDirUtilp->getAppRODataDir(), - "cursors_mac", - cursorIDToName(cursorid) + std::string(".tif")); - - gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); -} - -void LLWindowMacOSX::updateCursor() -{ - S32 result = 0; - - if (mDragOverrideCursor != -1) - { - // A drag is in progress...remember the requested cursor and we'll - // restore it when it is done - mCurrentCursor = mNextCursor; - return; - } - - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - - if(mCurrentCursor == mNextCursor) - { - if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) - { - hideNSCursor(); - adjustCursorDecouple(); - } - return; - } - - // RN: replace multi-drag cursors with single versions - if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) - { - mNextCursor = UI_CURSOR_ARROWDRAG; - } - else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) - { - mNextCursor = UI_CURSOR_ARROWCOPY; - } - - switch(mNextCursor) - { - default: - case UI_CURSOR_ARROW: - setArrowCursor(); - if(mCursorHidden) - { - // Since InitCursor resets the hide level, correct for it here. - hideNSCursor(); - } - break; - - // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. - // Find out what they look like and replicate them. - - // These are essentially correct - case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; - case UI_CURSOR_IBEAM: setIBeamCursor(); break; - case UI_CURSOR_CROSS: setCrossCursor(); break; - case UI_CURSOR_HAND: setPointingHandCursor(); break; - // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; - case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; - - // Double-check these - case UI_CURSOR_NO: - case UI_CURSOR_SIZEWE: - case UI_CURSOR_SIZENS: - case UI_CURSOR_SIZENWSE: - case UI_CURSOR_SIZENESW: - case UI_CURSOR_WORKING: - case UI_CURSOR_TOOLGRAB: - case UI_CURSOR_TOOLLAND: - case UI_CURSOR_TOOLFOCUS: - case UI_CURSOR_TOOLCREATE: - case UI_CURSOR_ARROWDRAG: - case UI_CURSOR_NOLOCKED: - case UI_CURSOR_ARROWLOCKED: - case UI_CURSOR_GRABLOCKED: - case UI_CURSOR_PIPETTE: - case UI_CURSOR_TOOLTRANSLATE: - case UI_CURSOR_TOOLROTATE: - case UI_CURSOR_TOOLSCALE: - case UI_CURSOR_TOOLCAMERA: - case UI_CURSOR_TOOLPAN: - case UI_CURSOR_TOOLZOOMIN: - case UI_CURSOR_TOOLPICKOBJECT3: - case UI_CURSOR_TOOLPLAY: - case UI_CURSOR_TOOLPAUSE: - case UI_CURSOR_TOOLMEDIAOPEN: - case UI_CURSOR_TOOLSIT: - case UI_CURSOR_TOOLBUY: - case UI_CURSOR_TOOLOPEN: - case UI_CURSOR_TOOLPATHFINDING: - case UI_CURSOR_TOOLPATHFINDING_PATH_START: - case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: - case UI_CURSOR_TOOLPATHFINDING_PATH_END: - case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: - case UI_CURSOR_TOOLNO: - result = setImageCursor(gCursors[mNextCursor]); - break; - - } - - if(result != noErr) - { - setArrowCursor(); - } - - mCurrentCursor = mNextCursor; -} - -ECursorType LLWindowMacOSX::getCursor() const -{ - return mCurrentCursor; -} - -void LLWindowMacOSX::initCursors() -{ - initPixmapCursor(UI_CURSOR_NO, 8, 8); - initPixmapCursor(UI_CURSOR_WORKING, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); - initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); - initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); - initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); - initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); - initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); - initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); - initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); - initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); - initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6); - initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); - initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); - initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); - - initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); - initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); - initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); - initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10); - -} - -void LLWindowMacOSX::captureMouse() -{ - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. -} - -void LLWindowMacOSX::releaseMouse() -{ - // By registering a global CarbonEvent handler for mouse move events, we ensure that - // mouse events are always processed. Thus, capture and release are unnecessary. -} - -void LLWindowMacOSX::hideCursor() -{ - if(!mCursorHidden) - { - // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; - mCursorHidden = true; - mHideCursorPermanent = true; - hideNSCursor(); - } - else - { - // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; - } - - adjustCursorDecouple(); -} - -void LLWindowMacOSX::showCursor() -{ - if(mCursorHidden || !isCGCursorVisible()) - { - // LL_INFOS() << "showCursor: showing" << LL_ENDL; - mCursorHidden = false; - mHideCursorPermanent = false; - showNSCursor(); - } - else - { - // LL_INFOS() << "showCursor: already visible" << LL_ENDL; - } - - adjustCursorDecouple(); -} - -void LLWindowMacOSX::showCursorFromMouseMove() -{ - if (!mHideCursorPermanent) - { - showCursor(); - } -} - -void LLWindowMacOSX::hideCursorUntilMouseMove() -{ - if (!mHideCursorPermanent) - { - hideCursor(); - mHideCursorPermanent = false; - } -} - - - -// -// LLSplashScreenMacOSX -// -LLSplashScreenMacOSX::LLSplashScreenMacOSX() -{ - mWindow = NULL; -} - -LLSplashScreenMacOSX::~LLSplashScreenMacOSX() -{ -} - -void LLSplashScreenMacOSX::showImpl() -{ - // This code _could_ be used to display a spash screen... -} - -void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) -{ - if(mWindow != NULL) - { - CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); - } -} - - -void LLSplashScreenMacOSX::hideImpl() -{ - if(mWindow != NULL) - { - mWindow = NULL; - } -} - -S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) -{ - return showAlert(text, caption, type); -} - -// Open a URL with the user's default web browser. -// Must begin with protocol identifier. -void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) -{ - // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. - - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - S32 result = 0; - CFURLRef urlRef = NULL; - - LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; - - CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); - if (stringRef) - { - // This will succeed if the string is a full URL, including the http:// - // Note that URLs specified this way need to be properly percent-escaped. - urlRef = CFURLCreateWithString(NULL, stringRef, NULL); - - // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs - - CFRelease(stringRef); - } - - if (urlRef) - { - result = LSOpenCFURLRef(urlRef, NULL); - - if (result != noErr) - { - LL_INFOS() << "Error " << result << " on open." << LL_ENDL; - } - - CFRelease(urlRef); - } - else - { - LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; - } -} - -// String should match ndof, so string mapping code was copied as is -static char mapChar( char c ) -{ - unsigned char uc = ( unsigned char ) c; - - switch( uc ) - { - case '/': return '-'; // use dash instead of slash - - case 0x7F: return ' '; - case 0x80: return 'A'; - case 0x81: return 'A'; - case 0x82: return 'C'; - case 0x83: return 'E'; - case 0x84: return 'N'; - case 0x85: return 'O'; - case 0x86: return 'U'; - case 0x87: return 'a'; - case 0x88: return 'a'; - case 0x89: return 'a'; - case 0x8A: return 'a'; - case 0x8B: return 'a'; - case 0x8C: return 'a'; - case 0x8D: return 'c'; - case 0x8E: return 'e'; - case 0x8F: return 'e'; - case 0x90: return ' '; - case 0x91: return ' '; // ? ' - case 0x92: return ' '; // ? ' - case 0x93: return ' '; // ? " - case 0x94: return ' '; // ? " - case 0x95: return ' '; - case 0x96: return ' '; - case 0x97: return ' '; - case 0x98: return ' '; - case 0x99: return ' '; - case 0x9A: return ' '; - case 0x9B: return 0x27; - case 0x9C: return 0x22; - case 0x9D: return ' '; - case 0x9E: return ' '; - case 0x9F: return ' '; - case 0xA0: return ' '; - case 0xA1: return ' '; - case 0xA2: return ' '; - case 0xA3: return ' '; - case 0xA4: return ' '; - case 0xA5: return ' '; - case 0xA6: return ' '; - case 0xA7: return ' '; - case 0xA8: return ' '; - case 0xA9: return ' '; - case 0xAA: return ' '; - case 0xAB: return ' '; - case 0xAC: return ' '; - case 0xAD: return ' '; - case 0xAE: return ' '; - case 0xAF: return ' '; - case 0xB0: return ' '; - case 0xB1: return ' '; - case 0xB2: return ' '; - case 0xB3: return ' '; - case 0xB4: return ' '; - case 0xB5: return ' '; - case 0xB6: return ' '; - case 0xB7: return ' '; - case 0xB8: return ' '; - case 0xB9: return ' '; - case 0xBA: return ' '; - case 0xBB: return ' '; - case 0xBC: return ' '; - case 0xBD: return ' '; - case 0xBE: return ' '; - case 0xBF: return ' '; - case 0xC0: return ' '; - case 0xC1: return ' '; - case 0xC2: return ' '; - case 0xC3: return ' '; - case 0xC4: return ' '; - case 0xC5: return ' '; - case 0xC6: return ' '; - case 0xC7: return ' '; - case 0xC8: return ' '; - case 0xC9: return ' '; - case 0xCA: return ' '; - case 0xCB: return 'A'; - case 0xCC: return 'A'; - case 0xCD: return 'O'; - case 0xCE: return ' '; - case 0xCF: return ' '; - case 0xD0: return '-'; - case 0xD1: return '-'; - case 0xD2: return 0x22; - case 0xD3: return 0x22; - case 0xD4: return 0x27; - case 0xD5: return 0x27; - case 0xD6: return '-'; // use dash instead of slash - case 0xD7: return ' '; - case 0xD8: return 'y'; - case 0xD9: return 'Y'; - case 0xDA: return '-'; // use dash instead of slash - case 0xDB: return ' '; - case 0xDC: return '<'; - case 0xDD: return '>'; - case 0xDE: return ' '; - case 0xDF: return ' '; - case 0xE0: return ' '; - case 0xE1: return ' '; - case 0xE2: return ','; - case 0xE3: return ','; - case 0xE4: return ' '; - case 0xE5: return 'A'; - case 0xE6: return 'E'; - case 0xE7: return 'A'; - case 0xE8: return 'E'; - case 0xE9: return 'E'; - case 0xEA: return 'I'; - case 0xEB: return 'I'; - case 0xEC: return 'I'; - case 0xED: return 'I'; - case 0xEE: return 'O'; - case 0xEF: return 'O'; - case 0xF0: return ' '; - case 0xF1: return 'O'; - case 0xF2: return 'U'; - case 0xF3: return 'U'; - case 0xF4: return 'U'; - case 0xF5: return '|'; - case 0xF6: return ' '; - case 0xF7: return ' '; - case 0xF8: return ' '; - case 0xF9: return ' '; - case 0xFA: return '.'; - case 0xFB: return ' '; - case 0xFC: return ' '; - case 0xFD: return 0x22; - case 0xFE: return ' '; - case 0xFF: return ' '; - } - return c; -} - -// String should match ndof for manufacturer based search to work -static void sanitizeString( char* inCStr ) -{ - char* charIt = inCStr; - while ( *charIt ) - { - *charIt = mapChar( *charIt ); - charIt++; - } -} - -struct HidDevice -{ - long mAxis; - long mLocalID; - char mProduct[256]; - char mManufacturer[256]; - long mUsage; - long mUsagePage; -}; - -static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) -{ - CFMutableDictionaryRef io_properties = nil; - io_registry_entry_t entry1; - io_registry_entry_t entry2; - kern_return_t rc; - - // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also - // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties - // try to get parent1 - rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); - if ( KERN_SUCCESS == rc ) - { - rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); - - IOObjectRelease( entry1 ); - - if ( KERN_SUCCESS == rc ) - { - rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); - // either way, release parent2 - IOObjectRelease( entry2 ); - } - } - if ( KERN_SUCCESS == rc ) - { - // IORegistryEntryCreateCFProperties() succeeded - if ( io_properties != nil ) - { - CFTypeRef dict_element = 0; - // get device info - // try hid dictionary first, if fail then go to usb dictionary - - - dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); - if ( !dict_element ) - { - dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); - } - if ( dict_element ) - { - bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); - sanitizeString(devicep->mProduct); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; - } - } - - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); - if ( !dict_element ) - { - dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); - } - if ( dict_element ) - { - bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); - sanitizeString(devicep->mManufacturer); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; - } - } - - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); - if ( !dict_element ) - { - dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); - } - if ( dict_element ) - { - bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; - } - } - - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); - if ( dict_element ) - { - bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); - if ( !res ) - { - LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; - } - dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); - if ( dict_element ) - { - if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) - { - LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; - } - } - } - - //Add axis, because ndof lib checks sutability by axises as well as other elements - devicep->mAxis = 0; - CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); - if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) - { - long count = CFArrayGetCount( (CFArrayRef) hid_elements ); - for (int i = 0; i < count; ++i) - { - CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); - if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) - { - long type = 0, usage_page = 0, usage = 0; - - CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); - if ( ref_value ) - { - CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); - } - - ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); - if ( ref_value ) - { - CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); - } - - ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); - if ( ref_value ) - { - CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); - } - if ( type != 0 - && type != kIOHIDElementTypeCollection - && usage_page == kHIDPage_GenericDesktop) - { - switch( usage ) - { - case kHIDUsage_GD_X: - case kHIDUsage_GD_Y: - case kHIDUsage_GD_Z: - case kHIDUsage_GD_Rx: - case kHIDUsage_GD_Ry: - case kHIDUsage_GD_Rz: - devicep->mAxis++; - break; - default: - break; - } - } - } - } - } - - CFRelease(io_properties); - } - else - { - LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; - } - } -} - -HidDevice populate_device( io_object_t io_obj ) -{ - void* interfacep = nullptr; - HidDevice device; - memset( &device, 0, sizeof( HidDevice ) ); - CFMutableDictionaryRef device_dic = 0; - kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); - - if ( KERN_SUCCESS == result - && device_dic ) - { - IOReturn io_result = kIOReturnSuccess; - HRESULT query_result = S_OK; - SInt32 the_score = 0; - IOCFPlugInInterface **the_interface = NULL; - - - io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, - kIOCFPlugInInterfaceID, &the_interface, &the_score ); - if ( io_result == kIOReturnSuccess ) - { - query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); - if ( query_result != S_OK ) - { - LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; - } - IODestroyPlugInInterface( the_interface ); - } - else - { - LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; - } - - if ( interfacep ) - { - result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); - - if ( result != kIOReturnSuccess) - { - LL_WARNS("Joystick") << "open failed" << LL_ENDL; - } - } - // extract needed fields - populate_device_info( io_obj, device_dic, &device ); - - // Release interface - if ( interfacep ) - { - ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); - - ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); - - interfacep = NULL; - } - - CFRelease( device_dic ); - } - else - { - LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; - } - - return device; -} - -static void get_devices(std::list &list_of_devices, - io_iterator_t inIODeviceIterator) -{ - IOReturn result = kIOReturnSuccess; // assume success( optimist! ) - io_object_t io_obj = 0; - - while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) - { - HidDevice device = populate_device( io_obj ); - - // Should match ndof - if (device.mAxis >= 3 - || (device.mUsagePage == kHIDPage_GenericDesktop - && (device.mUsage == kHIDUsage_GD_MultiAxisController - || device.mUsage == kHIDUsage_GD_GamePad - || device.mUsage == kHIDUsage_GD_Joystick)) - || (device.mUsagePage == kHIDPage_Game - && device.mUsage == kHIDUsage_Game_3DGameController) - || strstr(device.mManufacturer, "3Dconnexion")) - { - list_of_devices.push_back(device); - } - else - { - LL_DEBUGS("Joystick"); - list_of_devices.push_back(device); - LL_CONT << "Device axes: " << (S32)device.mAxis - << " Device HIDUsepage: " << (S32)device.mUsagePage - << " Device HIDUsage: " << (S32)device.mUsage; - LL_ENDL; - } - - - // release the device object, it is no longer needed - result = IOObjectRelease( io_obj ); - if ( KERN_SUCCESS != result ) - { - LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; - } - } -} - -bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, - std::function osx_callback, - void* win_callback, - void* userdata) -{ - bool return_value = false; - CFMutableDictionaryRef device_dict_ref; - IOReturn result = kIOReturnSuccess; // assume success( optimist! ) - - // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. - - // A dictionary to match devices to? - device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); - - // BUG FIX! one reference is consumed by IOServiceGetMatchingServices - CFRetain( device_dict_ref ); - io_iterator_t io_iter = 0; - - // create an IO object iterator - result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); - if ( kIOReturnSuccess != result ) - { - LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; - } - - if ( io_iter ) - { - // add all existing devices - std::list device_list; - - get_devices(device_list, io_iter); - - std::list::iterator iter; - - for (iter = device_list.begin(); iter != device_list.end(); ++iter) - { - std::string label(iter->mProduct); - LLSD data; - data["manufacturer"] = std::string(iter->mManufacturer); - data["product"] = label; - - if (osx_callback(label, data, userdata)) - { - break; //found device - } - } - return_value = true; - } - - CFRelease( device_dict_ref ); - return return_value; -} - -LLSD LLWindowMacOSX::getNativeKeyData() -{ - LLSD result = LLSD::emptyMap(); - - if(mRawKeyEvent) - { - result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); - result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); - result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); - result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); - result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); - result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); - } - - LL_DEBUGS() << "native key data is: " << result << LL_ENDL; - - return result; -} - -bool LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - bool retval = false; - OSErr error = noErr; - NColorPickerInfo info; - - memset(&info, 0, sizeof(info)); - info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); - info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); - info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); - info.placeWhere = kCenterOnMainScreen; - - error = NPickColor(&info); - - if (error == noErr) - { - retval = info.newColorChosen; - if (info.newColorChosen) - { - *r = ((float) info.theColor.color.rgb.red) / 65535.0; - *g = ((float) info.theColor.color.rgb.green) / 65535.0; - *b = ((float) info.theColor.color.rgb.blue) / 65535.0; - } - } - - return (retval); -} - -void *LLWindowMacOSX::getPlatformWindow() -{ - // NOTE: this will be NULL in fullscreen mode. Plan accordingly. - return (void*)mWindow; -} - -// get a double value from a dictionary -/* -static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) -{ - double double_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it - return -1; // fail - return double_value; // otherwise return the long value -}*/ - -// get a long value from a dictionary -static long getDictLong (CFDictionaryRef refDict, CFStringRef key) -{ - long int_value; - CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); - if (!number_value) // if can't get a number for the dictionary - return -1; // fail - if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it - return -1; // fail - return int_value; // otherwise return the long value -} - -void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, bool b) -{ - if (preeditor != mPreeditor && !b) - { - // This condition may occur by a call to - // setEnabled(bool) against LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - // We need to interrupt before updating mPreeditor, - // so that the fix string from input method goes to - // the old preeditor. - if (mLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - if (b == mLanguageTextInputAllowed) - { - return; - } - mLanguageTextInputAllowed = b; - allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit -} - -class sharedContext -{ -public: - CGLContextObj mContext; -}; - -void* LLWindowMacOSX::createSharedContext() -{ - sharedContext* sc = new sharedContext(); - CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); - - if (sUseMultGL) - { - CGLEnable(mContext, kCGLCEMPEngine); - } - - return (void *)sc; -} - -void LLWindowMacOSX::makeContextCurrent(void* context) -{ - CGLSetCurrentContext(((sharedContext*)context)->mContext); - - //enable multi-threaded OpenGL - if (sUseMultGL) - { - CGLError cgl_err; - CGLContextObj ctx = CGLGetCurrentContext(); - - cgl_err = CGLEnable( ctx, kCGLCEMPEngine); - - if (cgl_err != kCGLNoError ) - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; - } - else - { - LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; - } - } - -} - -void LLWindowMacOSX::destroySharedContext(void* context) -{ - sharedContext* sc = (sharedContext*)context; - - CGLDestroyContext(sc->mContext); - - delete sc; -} - -void LLWindowMacOSX::toggleVSync(bool enable_vsync) -{ - GLint frames_per_swap = 0; - if (!enable_vsync) - { - frames_per_swap = 0; - } - else - { - frames_per_swap = 1; - } - - CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); -} - -void LLWindowMacOSX::interruptLanguageTextInput() -{ - commitCurrentPreedit(mGLView); -} - -std::vector LLWindowMacOSX::getDisplaysResolutionList() -{ - std::vector resolution_list; - - CGDirectDisplayID display_ids[10]; - uint32_t found_displays = 0; - CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); - - if (kCGErrorSuccess != err) - { - LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; - return std::vector(); - } - - for (uint32_t i = 0; i < found_displays; i++) - { - S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); - S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); - - resolution_list.push_back(res); - } - - return resolution_list; -} - -//static -std::vector LLWindowMacOSX::getDynamicFallbackFontList() -{ - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector(); -} - -// static -MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) -{ - MASK mask = 0; - if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } - if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } - if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } - return mask; -} - -F32 LLWindowMacOSX::getSystemUISize() -{ - return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); -} - -#if LL_OS_DRAGDROP_ENABLED -/* -S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, - void * handlerRefCon, DragRef drag) -{ - S16 result = 0; - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - - LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; - - switch(message) - { - case kDragTrackingInWindow: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); - break; - - case kDragTrackingEnterHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); - break; - - case kDragTrackingLeaveHandler: - result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); - break; - - default: - break; - } - - return result; -} -OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, - DragRef drag) -{ - LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; - return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); - -} -*/ -void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) -{ - MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); - - float mouse_point[2]; - // This will return the mouse point in window coords - getCursorPos(mWindow, mouse_point); - LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); - LLCoordGL gl_pos; - convertCoords(window_coords, &gl_pos); - - if(!url.empty()) - { - LLWindowCallbacks::DragNDropResult res = - mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); - - switch (res) { - case LLWindowCallbacks::DND_NONE: // No drop allowed - if (action == LLWindowCallbacks::DNDA_TRACK) - { - mDragOverrideCursor = 0; - } - else { - mDragOverrideCursor = -1; - } - break; - case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation - mDragOverrideCursor = UI_CURSOR_NO; - break; - case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation - mDragOverrideCursor = UI_CURSOR_ARROWCOPY; - break; - default: - mDragOverrideCursor = -1; - break; - } - // This overrides the cursor being set by setCursor. - // This is a bit of a hack workaround because lots of areas - // within the viewer just blindly set the cursor. - if (mDragOverrideCursor == -1) - { - // Restore the cursor - ECursorType temp_cursor = mCurrentCursor; - // get around the "setting the same cursor" code in setCursor() - mCurrentCursor = UI_CURSOR_COUNT; - setCursor(temp_cursor); - } - else { - // Override the cursor - switch (mDragOverrideCursor) { - case 0: - setArrowCursor(); - break; - case UI_CURSOR_NO: - setNotAllowedCursor(); - case UI_CURSOR_ARROWCOPY: - setCopyCursor(); - default: - break; - }; - } - } -} - -#endif // LL_OS_DRAGDROP_ENABLED +/** + * @file llwindowmacosx.cpp + * @brief Platform-dependent implementation of llwindow + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llwindowmacosx.h" + +#include "llkeyboardmacosx.h" +#include "llwindowcallbacks.h" +#include "llpreeditor.h" + +#include "llerror.h" +#include "llgl.h" +#include "llstring.h" +#include "lldir.h" +#include "indra_constants.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +extern bool gDebugWindowProc; +bool gHiDPISupport = true; + +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; + +const S32 DEFAULT_REFRESH_RATE = 60; + +namespace +{ + NSKeyEventRef mRawKeyEvent = NULL; +} +// +// LLWindowMacOSX +// + +bool LLWindowMacOSX::sUseMultGL = false; + +// Cross-platform bits: + +bool check_for_card(const char* RENDERER, const char* bad_card) +{ + if (!strnicmp(RENDERER, bad_card, strlen(bad_card))) + { + std::string buffer = llformat( + "Your video card appears to be a %s, which Second Life does not support.\n" + "\n" + "Second Life requires a video card with 32 Mb of memory or more, as well as\n" + "multitexture support. We explicitly support nVidia GeForce 2 or better, \n" + "and ATI Radeon 8500 or better.\n" + "\n" + "If you own a supported card and continue to receive this message, try \n" + "updating to the latest video card drivers. Otherwise look in the\n" + "secondlife.com support section or e-mail technical support\n" + "\n" + "You can try to run Second Life, but it will probably crash or run\n" + "very slowly. Try anyway?", + bad_card); + S32 button = OSMessageBox(buffer.c_str(), "Unsupported video card", OSMB_YESNO); + if (OSBTN_YES == button) + { + return false; + } + else + { + return true; + } + } + + return false; +} + +// Switch to determine whether we capture all displays, or just the main one. +// We may want to base this on the setting of _DEBUG... + +#define CAPTURE_ALL_DISPLAYS 0 +//static double getDictDouble (CFDictionaryRef refDict, CFStringRef key); +static long getDictLong (CFDictionaryRef refDict, CFStringRef key); + +// MBW -- HACK ALERT +// On the Mac, to put up an OS dialog in full screen mode, we must first switch OUT of full screen mode. +// The proper way to do this is to bracket the dialog with calls to beforeDialog() and afterDialog(), but these +// require a pointer to the LLWindowMacOSX object. Stash it here and maintain in the constructor and destructor. +// This assumes that there will be only one object of this class at any time. Hopefully this is true. +static LLWindowMacOSX *gWindowImplementation = NULL; + +LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, + U32 fsaa_samples, + U32 max_vram) + : LLWindow(NULL, fullscreen, flags) +{ + // *HACK: During window construction we get lots of OS events for window + // reshape, activate, etc. that the viewer isn't ready to handle. + // Route them to a dummy callback structure until the end of constructor. + LLWindowCallbacks null_callbacks; + mCallbacks = &null_callbacks; + + // Voodoo for calling cocoa from carbon (see llwindowmacosx-objc.mm). + setupCocoa(); + + // Initialize the keyboard + gKeyboard = new LLKeyboardMacOSX(); + gKeyboard->setCallbacks(callbacks); + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mContext = NULL; + mPixelFormat = NULL; + mDisplay = CGMainDisplayID(); + mSimulatedRightClick = false; + mLastModifiers = 0; + mHandsOffEvents = false; + mCursorDecoupled = false; + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = false; + mNeedsResize = false; + mOverrideAspectRatio = 0.f; + mMaximized = false; + mMinimized = false; + mLanguageTextInputAllowed = false; + mPreeditor = NULL; + mFSAASamples = fsaa_samples; + mForceRebuild = false; + + // Get the original aspect ratio of the main device. + mOriginalAspectRatio = (double)CGDisplayPixelsWide(mDisplay) / (double)CGDisplayPixelsHigh(mDisplay); + + // Stash the window title + mWindowTitle = title; + //mWindowTitle[0] = title.length(); + + mDragOverrideCursor = -1; + + // Set up global event handlers (the fullscreen case needs this) + //InstallStandardEventHandler(GetApplicationEventTarget()); + + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) + { + if(mWindow != NULL) + { + makeWindowOrderFront(mWindow); + } + + if (!gGLManager.initGL()) + { + setupFailure( + "Second Life is unable to run because your video card drivers\n" + "are out of date or unsupported. Please make sure you have\n" + "the latest video card drivers installed.\n" + "If you continue to receive this message, contact customer service.", + "Error", + OSMB_OK); + return; + } + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + + allowLanguageTextInput(NULL, false); + } + + mCallbacks = callbacks; + stop_glerror(); + + +} + +// These functions are used as wrappers for our internal event handling callbacks. +// It's a good idea to wrap these to avoid reworking more code than we need to within LLWindow. + +bool callKeyUp(NSKeyEventRef event, unsigned short key, unsigned int mask) +{ + mRawKeyEvent = event; + bool retVal = gKeyboard->handleKeyUp(key, mask); + mRawKeyEvent = NULL; + return retVal; +} + +bool callKeyDown(NSKeyEventRef event, unsigned short key, unsigned int mask, wchar_t character) +{ + //if (mask!=MASK_NONE) + { + if((key == gKeyboard->inverseTranslateKey('Z')) && (character == 'y')) + { + key = gKeyboard->inverseTranslateKey('Y'); + } + else if ((key == gKeyboard->inverseTranslateKey('Y')) && (character == 'z')) + { + key = gKeyboard->inverseTranslateKey('Z'); + } + } + + mRawKeyEvent = event; + bool retVal = gKeyboard->handleKeyDown(key, mask); + mRawKeyEvent = NULL; + return retVal; +} + +void callResetKeys() +{ + gKeyboard->resetKeys(); +} + +bool callUnicodeCallback(wchar_t character, unsigned int mask) +{ + NativeKeyEventData eventData; + + memset(&eventData, 0, sizeof(NativeKeyEventData)); + + eventData.mKeyEvent = NativeKeyEventData::KEYCHAR; + eventData.mEventType = 0; + eventData.mEventModifiers = mask; + eventData.mEventKeyCode = 0; + eventData.mEventChars = character; + eventData.mEventUnmodChars = character; + eventData.mEventRepeat = false; + + mRawKeyEvent = &eventData; + + bool result = gWindowImplementation->getCallbacks()->handleUnicodeChar(character, mask); + mRawKeyEvent = NULL; + return result; +} + +void callFocus() +{ + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation); + } +} + +void callFocusLost() +{ + if (gWindowImplementation) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } +} + +void callRightMouseDown(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callRightMouseUp(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleRightMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callLeftMouseDown(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseDown(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callLeftMouseUp(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleMouseUp(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); + +} + +void callDoubleClick(float *pos, MASK mask) +{ + if (gWindowImplementation->allowsLanguageInput()) + { + gWindowImplementation->interruptLanguageTextInput(); + } + + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + gWindowImplementation->getCallbacks()->handleDoubleClick(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callResize(unsigned int width, unsigned int height) +{ + if (gWindowImplementation != NULL) + { + gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height); + } +} + +void callMouseMoved(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseMove(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); + //gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, 0); +} + +void callMouseDragged(float *pos, MASK mask) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + gWindowImplementation->getCallbacks()->handleMouseDragged(gWindowImplementation, outCoords, gKeyboard->currentMask(true)); +} + +void callScrollMoved(float deltaX, float deltaY) +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleScrollHWheel(gWindowImplementation, deltaX); + gWindowImplementation->getCallbacks()->handleScrollWheel(gWindowImplementation, deltaY); + } +} + +void callMouseExit() +{ + gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation); +} + +void callWindowFocus() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocus (gWindowImplementation); + } + else + { + LL_WARNS("COCOA") << "Window Implementation or callbacks not yet initialized." << LL_ENDL; + } + + +} + +void callWindowUnfocus() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation); + } +} + +void callWindowHide() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, false); + } +} + +void callWindowUnhide() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleActivate(gWindowImplementation, true); + } +} + +void callWindowDidChangeScreen() +{ + if ( gWindowImplementation && gWindowImplementation->getCallbacks() ) + { + gWindowImplementation->getCallbacks()->handleWindowDidChangeScreen(gWindowImplementation); + } +} + +void callDeltaUpdate(float *delta, MASK mask) +{ + gWindowImplementation->updateMouseDeltas(delta); +} + +void callOtherMouseDown(float *pos, MASK mask, int button) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseDown(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseDown(gWindowImplementation, outCoords, mask, button + 1); + } +} + +void callOtherMouseUp(float *pos, MASK mask, int button) +{ + LLCoordGL outCoords; + outCoords.mX = ll_round(pos[0]); + outCoords.mY = ll_round(pos[1]); + float deltas[2]; + gWindowImplementation->getMouseDeltas(deltas); + outCoords.mX += deltas[0]; + outCoords.mY += deltas[1]; + if (button == 2) + { + gWindowImplementation->getCallbacks()->handleMiddleMouseUp(gWindowImplementation, outCoords, mask); + } + else + { + gWindowImplementation->getCallbacks()->handleOtherMouseUp(gWindowImplementation, outCoords, mask, button + 1); + } +} + +void callModifier(MASK mask) +{ + gKeyboard->handleModifier(mask); +} + +void callHandleDragEntered(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING); +} + +void callHandleDragExited(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING); +} + +void callHandleDragUpdated(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK); +} + +void callHandleDragDropped(std::string url) +{ + gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED); +} + +void callQuitHandler() +{ + if (gWindowImplementation) + { + if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation)) + { + gWindowImplementation->getCallbacks()->handleQuit(gWindowImplementation); + } + } +} + +void getPreeditSelectionRange(int *position, int *length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getSelectionRange(position, length); + } +} + +void getPreeditMarkedRange(int *position, int *length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->getPreeditRange(position, length); + } +} + +void setPreeditMarkedRange(int position, int length) +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->markAsPreedit(position, length); + } +} + +bool handleUnicodeCharacter(wchar_t c) +{ + bool success = false; + if (gWindowImplementation->getPreeditor()) + { + success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c); + } + + return success; +} + +void resetPreedit() +{ + if (gWindowImplementation->getPreeditor()) + { + gWindowImplementation->getPreeditor()->resetPreedit(); + } +} + +// For reasons of convenience, handle IME updates here. +// This largely mirrors the old implementation, only sans the carbon parameters. +void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + preeditor->resetPreedit(); + // This should be a viable replacement for the kEventParamTextInputSendReplaceRange parameter. + if (replacementRange[0] < replacementRange[1]) + { + const LLWString& text = preeditor->getPreeditString(); + const S32 location = wstring_wstring_length_from_utf16_length(text, 0, replacementRange[0]); + const S32 length = wstring_wstring_length_from_utf16_length(text, location, replacementRange[1]); + preeditor->markAsPreedit(location, length); + } + + LLWString fix_str = utf16str_to_wstring(llutf16string(unitext, text_len)); + + S32 caret_position = fix_str.length(); + + preeditor->updatePreedit(fix_str, segments.seg_lengths, segments.seg_standouts, caret_position); + } +} + +void getPreeditLocation(float *location, unsigned int length) +{ + if (gWindowImplementation->getPreeditor()) + { + LLPreeditor *preeditor = gWindowImplementation->getPreeditor(); + LLCoordGL coord; + LLCoordScreen screen; + LLRect rect; + + preeditor->getPreeditLocation(length, &coord, &rect, NULL); + + float c[4] = {float(coord.mX), float(coord.mY), 0, 0}; + + convertRectToScreen(gWindowImplementation->getWindow(), c); + + location[0] = c[0]; + location[1] = c[1]; + } +} + +void LLWindowMacOSX::updateMouseDeltas(float* deltas) +{ + if (mCursorDecoupled) + { + mCursorLastEventDeltaX = ll_round(deltas[0]); + mCursorLastEventDeltaY = ll_round(-deltas[1]); + + if (mCursorIgnoreNextDelta) + { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + mCursorIgnoreNextDelta = false; + } + } else { + mCursorLastEventDeltaX = 0; + mCursorLastEventDeltaY = 0; + } +} + +void LLWindowMacOSX::getMouseDeltas(float* delta) +{ + delta[0] = mCursorLastEventDeltaX; + delta[1] = mCursorLastEventDeltaY; +} + +bool LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) +{ + mFullscreen = fullscreen; + + if (mWindow == NULL) + { + mWindow = getMainAppWindow(); + } + + if(mContext == NULL) + { + // Our OpenGL view is already defined within SecondLife.xib. + // Get the view instead. + mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); + mContext = getCGLContextObj(mGLView); + gGLManager.mVRAM = getVramSize(mGLView); + + if(!mPixelFormat) + { + CGLPixelFormatAttribute attribs[] = + { + kCGLPFANoRecovery, + kCGLPFADoubleBuffer, + kCGLPFAClosestPolicy, + kCGLPFAAccelerated, + kCGLPFAMultisample, + kCGLPFASampleBuffers, static_cast((mFSAASamples > 0 ? 1 : 0)), + kCGLPFASamples, static_cast(mFSAASamples), + kCGLPFAStencilSize, static_cast(8), + kCGLPFADepthSize, static_cast(24), + kCGLPFAAlphaSize, static_cast(8), + kCGLPFAColorSize, static_cast(24), + kCGLPFAOpenGLProfile, static_cast(kCGLOGLPVersion_GL4_Core), + static_cast(0) + }; + + GLint numPixelFormats; + CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); + + if(mPixelFormat == NULL) { + CGLChoosePixelFormat (attribs, &mPixelFormat, &numPixelFormats); + } + } + + } + + // This sets up our view to recieve text from our non-inline text input window. + setupInputWindow(mWindow, mGLView); + + // Hook up the context to a drawable + + if(mContext != NULL) + { + + + U32 err = CGLSetCurrentContext(mContext); + if (err != kCGLNoError) + { + setupFailure("Can't activate GL rendering context", "Error", OSMB_OK); + return false; + } + } + + mRefreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(mDisplay)); + if(mRefreshRate == 0) + { + //consider adding more appropriate fallback later + mRefreshRate = DEFAULT_REFRESH_RATE; + } + + // Disable vertical sync for swap + toggleVSync(enable_vsync); + + //enable multi-threaded OpenGL + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; + } + } + makeFirstResponder(mWindow, mGLView); + + return true; +} + + +// We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. +// This makes this method obsolete. +bool LLWindowMacOSX::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) +{ + return false; +} + +void LLWindowMacOSX::destroyContext() +{ + if (!mContext) + { + // We don't have a context + return; + } + // Unhook the GL context from any drawable it may have + if(mContext != NULL) + { + LL_DEBUGS("Window") << "destroyContext: unhooking drawable " << LL_ENDL; + CGLSetCurrentContext(NULL); + } + + // Clean up remaining GL state before blowing away window + gGLManager.shutdownGL(); + + // Clean up the pixel format + if(mPixelFormat != NULL) + { + CGLDestroyPixelFormat(mPixelFormat); + mPixelFormat = NULL; + } + + // Clean up the GL context + if(mContext != NULL) + { + CGLDestroyContext(mContext); + } + + // Destroy our LLOpenGLView + if(mGLView != NULL) + { + removeGLView(mGLView); + mGLView = NULL; + } + + // Close the window + if(mWindow != NULL) + { + NSWindowRef dead_window = mWindow; + mWindow = NULL; + closeWindow(dead_window); + } + +} + +LLWindowMacOSX::~LLWindowMacOSX() +{ + destroyContext(); + + if(mSupportedResolutions != NULL) + { + delete []mSupportedResolutions; + } + + gWindowImplementation = NULL; + +} + + +void LLWindowMacOSX::show() +{ +} + +void LLWindowMacOSX::hide() +{ + setMouseClipping(false); +} + +//virtual +void LLWindowMacOSX::minimize() +{ + setMouseClipping(false); + showCursor(); +} + +//virtual +void LLWindowMacOSX::restore() +{ + show(); +} + + +// close() destroys all OS-specific code associated with a window. +// Usually called from LLWindowManager::destroyWindow() +void LLWindowMacOSX::close() +{ + // Is window is already closed? + // if (!mWindow) + // { + // return; + // } + + // Make sure cursor is visible and we haven't mangled the clipping state. + setMouseClipping(false); + showCursor(); + + destroyContext(); +} + +bool LLWindowMacOSX::isValid() +{ + if(mFullscreen) + { + return(true); + } + + return (mWindow != NULL); +} + +bool LLWindowMacOSX::getVisible() +{ + bool result = false; + + if(mFullscreen) + { + result = true; + }if (mWindow) + { + result = true; + } + + return(result); +} + +bool LLWindowMacOSX::getMinimized() +{ + return mMinimized; +} + +bool LLWindowMacOSX::getMaximized() +{ + return mMaximized; +} + +bool LLWindowMacOSX::maximize() +{ + if (mWindow && !mMaximized) + { + } + + return mMaximized; +} + +bool LLWindowMacOSX::getFullscreen() +{ + return mFullscreen; +} + +void LLWindowMacOSX::gatherInput() +{ + updateCursor(); +} + +bool LLWindowMacOSX::getPosition(LLCoordScreen *position) +{ + S32 err = -1; + + if(mFullscreen) + { + position->mX = 0; + position->mY = 0; + err = noErr; + } + else if(mWindow) + { + const CGPoint & pos = getContentViewBoundsPosition(mWindow); + + position->mX = pos.x; + position->mY = pos.y; + + err = noErr; + } + else + { + LL_ERRS() << "LLWindowMacOSX::getPosition(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); +} + +bool LLWindowMacOSX::getSize(LLCoordScreen *size) +{ + S32 err = -1; + + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + + size->mX = sz.width; + size->mY = sz.height; + err = noErr; + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); +} + +bool LLWindowMacOSX::getSize(LLCoordWindow *size) +{ + S32 err = -1; + + if(mFullscreen) + { + size->mX = mFullscreenWidth; + size->mY = mFullscreenHeight; + err = noErr; + } + else if(mWindow) + { + const CGSize & sz = gHiDPISupport ? getDeviceContentViewSize(mWindow, mGLView) : getContentViewBoundsSize(mWindow); + + size->mX = sz.width; + size->mY = sz.height; + err = noErr; + + + } + else + { + LL_ERRS() << "LLWindowMacOSX::getSize(): no window and not fullscreen!" << LL_ENDL; + } + + return (err == noErr); +} + +bool LLWindowMacOSX::setPosition(const LLCoordScreen position) +{ + if(mWindow) + { + float pos[2] = {float(position.mX), float(position.mY)}; + setWindowPos(mWindow, pos); + } + + return true; +} + +bool LLWindowMacOSX::setSizeImpl(const LLCoordScreen size) +{ + if(mWindow) + { + LLCoordWindow to; + convertCoords(size, &to); + setWindowSize(mWindow, to.mX, to.mY); + return true; + } + + return false; +} + +bool LLWindowMacOSX::setSizeImpl(const LLCoordWindow size) +{ + if (mWindow) + { + const int titlePadding = 22; + setWindowSize(mWindow, size.mX, size.mY + titlePadding); + return true; + } + + return false; +} + +void LLWindowMacOSX::swapBuffers() +{ + CGLFlushDrawable(mContext); +} + +void LLWindowMacOSX::restoreGLContext() +{ + CGLSetCurrentContext(mContext); +} + +F32 LLWindowMacOSX::getGamma() +{ + F32 result = 2.2; // Default to something sane + + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) == noErr) + { + // So many choices... + // Let's just return the green channel gamma for now. + result = greenGamma; + } + + return result; +} + +U32 LLWindowMacOSX::getFSAASamples() +{ + return mFSAASamples; +} + +void LLWindowMacOSX::setFSAASamples(const U32 samples) +{ + mFSAASamples = samples; + mForceRebuild = true; +} + +bool LLWindowMacOSX::restoreGamma() +{ + CGDisplayRestoreColorSyncSettings(); + return true; +} + +bool LLWindowMacOSX::setGamma(const F32 gamma) +{ + CGGammaValue redMin; + CGGammaValue redMax; + CGGammaValue redGamma; + CGGammaValue greenMin; + CGGammaValue greenMax; + CGGammaValue greenGamma; + CGGammaValue blueMin; + CGGammaValue blueMax; + CGGammaValue blueGamma; + + // MBW -- XXX -- Should we allow this in windowed mode? + + if(CGGetDisplayTransferByFormula( + mDisplay, + &redMin, + &redMax, + &redGamma, + &greenMin, + &greenMax, + &greenGamma, + &blueMin, + &blueMax, + &blueGamma) != noErr) + { + return false; + } + + if(CGSetDisplayTransferByFormula( + mDisplay, + redMin, + redMax, + gamma, + greenMin, + greenMax, + gamma, + blueMin, + blueMax, + gamma) != noErr) + { + return false; + } + + + return true; +} + +bool LLWindowMacOSX::isCursorHidden() +{ + return mCursorHidden; +} + + + +// Constrains the mouse to the window. +void LLWindowMacOSX::setMouseClipping( bool b ) +{ + // Just stash the requested state. We'll simulate this when the cursor is hidden by decoupling. + mIsMouseClipping = b; + + if(b) + { + // LL_INFOS() << "setMouseClipping(true)" << LL_ENDL; + } + else + { + // LL_INFOS() << "setMouseClipping(false)" << LL_ENDL; + } + + adjustCursorDecouple(); +} + +bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position) +{ + bool result = false; + LLCoordScreen screen_pos; + + if (!convertCoords(position, &screen_pos)) + { + return false; + } + + CGPoint newPosition; + + // LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + + newPosition.x = screen_pos.mX; + newPosition.y = screen_pos.mY; + + CGSetLocalEventsSuppressionInterval(0.0); + if(CGWarpMouseCursorPosition(newPosition) == noErr) + { + result = true; + } + + // Under certain circumstances, this will trigger us to decouple the cursor. + adjustCursorDecouple(true); + + // trigger mouse move callback + LLCoordGL gl_pos; + convertCoords(position, &gl_pos); + float scale = getSystemUISize(); + gl_pos.mX *= scale; + gl_pos.mY *= scale; + mCallbacks->handleMouseMove(this, gl_pos, (MASK)0); + + return result; +} + +bool LLWindowMacOSX::getCursorPosition(LLCoordWindow *position) +{ + float cursor_point[2]; + LLCoordScreen screen_pos; + + if(mWindow == NULL) + return false; + + getCursorPos(mWindow, cursor_point); + + if(mCursorDecoupled) + { + // CGMouseDelta x, y; + + // If the cursor's decoupled, we need to read the latest movement delta as well. + // CGGetLastMouseDelta( &x, &y ); + // cursor_point.h += x; + // cursor_point.v += y; + + // CGGetLastMouseDelta may behave strangely when the cursor's first captured. + // Stash in the event handler instead. + cursor_point[0] += mCursorLastEventDeltaX; + cursor_point[1] += mCursorLastEventDeltaY; + } + + float scale = getSystemUISize(); + position->mX = cursor_point[0] * scale; + position->mY = cursor_point[1] * scale; + + return true; +} + +void LLWindowMacOSX::adjustCursorDecouple(bool warpingMouse) +{ + if(mIsMouseClipping && mCursorHidden) + { + if(warpingMouse) + { + // The cursor should be decoupled. Make sure it is. + if(!mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: decoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(false); + mCursorDecoupled = true; + mCursorIgnoreNextDelta = true; + } + } + } + else + { + // The cursor should not be decoupled. Make sure it isn't. + if(mCursorDecoupled) + { + // LL_INFOS() << "adjustCursorDecouple: recoupling cursor" << LL_ENDL; + CGAssociateMouseAndMouseCursorPosition(true); + mCursorDecoupled = false; + } + } +} + +F32 LLWindowMacOSX::getNativeAspectRatio() +{ + if (mFullscreen) + { + return (F32)mFullscreenWidth / (F32)mFullscreenHeight; + } + else + { + // The constructor for this class grabs the aspect ratio of the monitor before doing any resolution + // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. + + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + + return mOriginalAspectRatio; + } +} + +F32 LLWindowMacOSX::getPixelAspectRatio() +{ + //macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode + return 1.f; +} + +//static SInt32 oldWindowLevel; + +// MBW -- XXX -- There's got to be a better way than this. Find it, please... + +// Since we're no longer supporting the "typical" fullscreen mode with CGL or NSOpenGL anymore, these are unnecessary. -Geenz +void LLWindowMacOSX::beforeDialog() +{ +} + +void LLWindowMacOSX::afterDialog() +{ + //For fix problem with Core Flow view on OSX + restoreGLContext(); +} + + +void LLWindowMacOSX::flashIcon(F32 seconds) +{ + // For consistency with macOS conventions, the number of seconds given is ignored and + // left up to the OS (which will actually bounce it for one second). + requestUserAttention(); +} + +bool LLWindowMacOSX::isClipboardTextAvailable() +{ + return pasteBoardAvailable(); +} + +bool LLWindowMacOSX::pasteTextFromClipboard(LLWString &dst) +{ + unsigned short* pboard_data = copyFromPBoard(); // must free returned data + llutf16string str(pboard_data); + free(pboard_data); + + dst = utf16str_to_wstring(str); + if (dst != L"") + { + return true; + } else { + return false; + } +} + +bool LLWindowMacOSX::copyTextToClipboard(const LLWString &s) +{ + bool result = false; + llutf16string utf16str = wstring_to_utf16str(s); + + result = copyToPBoard(utf16str.data(), utf16str.length()); + + return result; +} + + +// protected +bool LLWindowMacOSX::resetDisplayResolution() +{ + // This is only called from elsewhere in this class, and it's not used by the Mac implementation. + return true; +} + + +LLWindow::LLWindowResolution* LLWindowMacOSX::getSupportedResolutions(S32 &num_resolutions) +{ + if (!mSupportedResolutions) + { + CFArrayRef modes = CGDisplayCopyAllDisplayModes(mDisplay, nullptr); + + if(modes != NULL) + { + CFIndex index, cnt; + + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + mNumSupportedResolutions = 0; + + // Examine each mode + cnt = CFArrayGetCount( modes ); + + for ( index = 0; (index < cnt) && (mNumSupportedResolutions < MAX_NUM_RESOLUTIONS); index++ ) + { + // Pull the mode dictionary out of the CFArray + CFDictionaryRef mode = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, index ); + long width = getDictLong(mode, kCGDisplayWidth); + long height = getDictLong(mode, kCGDisplayHeight); + long bits = getDictLong(mode, kCGDisplayBitsPerPixel); + + if(bits == BITS_PER_PIXEL && width >= 800 && height >= 600) + { + bool resolution_exists = false; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == width && + mSupportedResolutions[i].mHeight == height) + { + resolution_exists = true; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = width; + mSupportedResolutions[mNumSupportedResolutions].mHeight = height; + mNumSupportedResolutions++; + } + } + } + CFRelease(modes); + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + to->mX = from.mX; + to->mY = from.mY; + return true; +} + +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + to->mX = from.mX; + to->mY = from.mY; + return true; +} + +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + if(mWindow) + { + float mouse_point[2]; + + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertScreenToWindow(mWindow, mouse_point); + + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; + + return true; + } + return false; +} + +bool LLWindowMacOSX::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + if(mWindow) + { + float mouse_point[2]; + + mouse_point[0] = from.mX; + mouse_point[1] = from.mY; + + convertWindowToScreen(mWindow, mouse_point); + + to->mX = mouse_point[0]; + to->mY = mouse_point[1]; + + return true; + } + return false; +} + +bool LLWindowMacOSX::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + +bool LLWindowMacOSX::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + + + + +void LLWindowMacOSX::setupFailure(const std::string& text, const std::string& caption, U32 type) +{ + destroyContext(); + + OSMessageBox(text, caption, type); +} + + // Note on event recording - QUIT is a known special case and we are choosing NOT to record it for the record and playback feature + // it is handled at a very low-level +const char* cursorIDToName(int id) +{ + switch (id) + { + case UI_CURSOR_ARROW: return "UI_CURSOR_ARROW"; + case UI_CURSOR_WAIT: return "UI_CURSOR_WAIT"; + case UI_CURSOR_HAND: return "UI_CURSOR_HAND"; + case UI_CURSOR_IBEAM: return "UI_CURSOR_IBEAM"; + case UI_CURSOR_CROSS: return "UI_CURSOR_CROSS"; + case UI_CURSOR_SIZENWSE: return "UI_CURSOR_SIZENWSE"; + case UI_CURSOR_SIZENESW: return "UI_CURSOR_SIZENESW"; + case UI_CURSOR_SIZEWE: return "UI_CURSOR_SIZEWE"; + case UI_CURSOR_SIZENS: return "UI_CURSOR_SIZENS"; + case UI_CURSOR_SIZEALL: return "UI_CURSOR_SIZEALL"; + case UI_CURSOR_NO: return "UI_CURSOR_NO"; + case UI_CURSOR_WORKING: return "UI_CURSOR_WORKING"; + case UI_CURSOR_TOOLGRAB: return "UI_CURSOR_TOOLGRAB"; + case UI_CURSOR_TOOLLAND: return "UI_CURSOR_TOOLLAND"; + case UI_CURSOR_TOOLFOCUS: return "UI_CURSOR_TOOLFOCUS"; + case UI_CURSOR_TOOLCREATE: return "UI_CURSOR_TOOLCREATE"; + case UI_CURSOR_ARROWDRAG: return "UI_CURSOR_ARROWDRAG"; + case UI_CURSOR_ARROWCOPY: return "UI_CURSOR_ARROWCOPY"; + case UI_CURSOR_ARROWDRAGMULTI: return "UI_CURSOR_ARROWDRAGMULTI"; + case UI_CURSOR_ARROWCOPYMULTI: return "UI_CURSOR_ARROWCOPYMULTI"; + case UI_CURSOR_NOLOCKED: return "UI_CURSOR_NOLOCKED"; + case UI_CURSOR_ARROWLOCKED: return "UI_CURSOR_ARROWLOCKED"; + case UI_CURSOR_GRABLOCKED: return "UI_CURSOR_GRABLOCKED"; + case UI_CURSOR_TOOLTRANSLATE: return "UI_CURSOR_TOOLTRANSLATE"; + case UI_CURSOR_TOOLROTATE: return "UI_CURSOR_TOOLROTATE"; + case UI_CURSOR_TOOLSCALE: return "UI_CURSOR_TOOLSCALE"; + case UI_CURSOR_TOOLCAMERA: return "UI_CURSOR_TOOLCAMERA"; + case UI_CURSOR_TOOLPAN: return "UI_CURSOR_TOOLPAN"; + case UI_CURSOR_TOOLZOOMIN: return "UI_CURSOR_TOOLZOOMIN"; + case UI_CURSOR_TOOLZOOMOUT: return "UI_CURSOR_TOOLZOOMOUT"; + case UI_CURSOR_TOOLPICKOBJECT3: return "UI_CURSOR_TOOLPICKOBJECT3"; + case UI_CURSOR_TOOLPLAY: return "UI_CURSOR_TOOLPLAY"; + case UI_CURSOR_TOOLPAUSE: return "UI_CURSOR_TOOLPAUSE"; + case UI_CURSOR_TOOLMEDIAOPEN: return "UI_CURSOR_TOOLMEDIAOPEN"; + case UI_CURSOR_PIPETTE: return "UI_CURSOR_PIPETTE"; + case UI_CURSOR_TOOLSIT: return "UI_CURSOR_TOOLSIT"; + case UI_CURSOR_TOOLBUY: return "UI_CURSOR_TOOLBUY"; + case UI_CURSOR_TOOLOPEN: return "UI_CURSOR_TOOLOPEN"; + case UI_CURSOR_TOOLPATHFINDING: return "UI_CURSOR_PATHFINDING"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START: return "UI_CURSOR_PATHFINDING_START"; + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: return "UI_CURSOR_PATHFINDING_START_ADD"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END: return "UI_CURSOR_PATHFINDING_END"; + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: return "UI_CURSOR_PATHFINDING_END_ADD"; + case UI_CURSOR_TOOLNO: return "UI_CURSOR_NO"; + } + + LL_ERRS() << "cursorIDToName: unknown cursor id" << id << LL_ENDL; + + return "UI_CURSOR_ARROW"; +} + +static CursorRef gCursors[UI_CURSOR_COUNT]; + + +static void initPixmapCursor(int cursorid, int hotspotX, int hotspotY) +{ + // cursors are in /Contents/Resources/cursors_mac/UI_CURSOR_FOO.tif + std::string fullpath = gDirUtilp->add( + gDirUtilp->getAppRODataDir(), + "cursors_mac", + cursorIDToName(cursorid) + std::string(".tif")); + + gCursors[cursorid] = createImageCursor(fullpath.c_str(), hotspotX, hotspotY); +} + +void LLWindowMacOSX::updateCursor() +{ + S32 result = 0; + + if (mDragOverrideCursor != -1) + { + // A drag is in progress...remember the requested cursor and we'll + // restore it when it is done + mCurrentCursor = mNextCursor; + return; + } + + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + + if(mCurrentCursor == mNextCursor) + { + if(mCursorHidden && mHideCursorPermanent && isCGCursorVisible()) + { + hideNSCursor(); + adjustCursorDecouple(); + } + return; + } + + // RN: replace multi-drag cursors with single versions + if (mNextCursor == UI_CURSOR_ARROWDRAGMULTI) + { + mNextCursor = UI_CURSOR_ARROWDRAG; + } + else if (mNextCursor == UI_CURSOR_ARROWCOPYMULTI) + { + mNextCursor = UI_CURSOR_ARROWCOPY; + } + + switch(mNextCursor) + { + default: + case UI_CURSOR_ARROW: + setArrowCursor(); + if(mCursorHidden) + { + // Since InitCursor resets the hide level, correct for it here. + hideNSCursor(); + } + break; + + // MBW -- XXX -- Some of the standard Windows cursors have no standard Mac equivalents. + // Find out what they look like and replicate them. + + // These are essentially correct + case UI_CURSOR_WAIT: /* Apple purposely doesn't allow us to set the beachball cursor manually. Let NSApp figure out when to do this. */ break; + case UI_CURSOR_IBEAM: setIBeamCursor(); break; + case UI_CURSOR_CROSS: setCrossCursor(); break; + case UI_CURSOR_HAND: setPointingHandCursor(); break; + // case UI_CURSOR_NO: SetThemeCursor(kThemeNotAllowedCursor); break; + case UI_CURSOR_ARROWCOPY: setCopyCursor(); break; + + // Double-check these + case UI_CURSOR_NO: + case UI_CURSOR_SIZEWE: + case UI_CURSOR_SIZENS: + case UI_CURSOR_SIZENWSE: + case UI_CURSOR_SIZENESW: + case UI_CURSOR_WORKING: + case UI_CURSOR_TOOLGRAB: + case UI_CURSOR_TOOLLAND: + case UI_CURSOR_TOOLFOCUS: + case UI_CURSOR_TOOLCREATE: + case UI_CURSOR_ARROWDRAG: + case UI_CURSOR_NOLOCKED: + case UI_CURSOR_ARROWLOCKED: + case UI_CURSOR_GRABLOCKED: + case UI_CURSOR_PIPETTE: + case UI_CURSOR_TOOLTRANSLATE: + case UI_CURSOR_TOOLROTATE: + case UI_CURSOR_TOOLSCALE: + case UI_CURSOR_TOOLCAMERA: + case UI_CURSOR_TOOLPAN: + case UI_CURSOR_TOOLZOOMIN: + case UI_CURSOR_TOOLPICKOBJECT3: + case UI_CURSOR_TOOLPLAY: + case UI_CURSOR_TOOLPAUSE: + case UI_CURSOR_TOOLMEDIAOPEN: + case UI_CURSOR_TOOLSIT: + case UI_CURSOR_TOOLBUY: + case UI_CURSOR_TOOLOPEN: + case UI_CURSOR_TOOLPATHFINDING: + case UI_CURSOR_TOOLPATHFINDING_PATH_START: + case UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD: + case UI_CURSOR_TOOLPATHFINDING_PATH_END: + case UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD: + case UI_CURSOR_TOOLNO: + result = setImageCursor(gCursors[mNextCursor]); + break; + + } + + if(result != noErr) + { + setArrowCursor(); + } + + mCurrentCursor = mNextCursor; +} + +ECursorType LLWindowMacOSX::getCursor() const +{ + return mCurrentCursor; +} + +void LLWindowMacOSX::initCursors() +{ + initPixmapCursor(UI_CURSOR_NO, 8, 8); + initPixmapCursor(UI_CURSOR_WORKING, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLGRAB, 2, 14); + initPixmapCursor(UI_CURSOR_TOOLLAND, 13, 8); + initPixmapCursor(UI_CURSOR_TOOLFOCUS, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLCREATE, 7, 7); + initPixmapCursor(UI_CURSOR_ARROWDRAG, 1, 1); + initPixmapCursor(UI_CURSOR_ARROWCOPY, 1, 1); + initPixmapCursor(UI_CURSOR_NOLOCKED, 8, 8); + initPixmapCursor(UI_CURSOR_ARROWLOCKED, 1, 1); + initPixmapCursor(UI_CURSOR_GRABLOCKED, 2, 14); + initPixmapCursor(UI_CURSOR_PIPETTE, 3, 29); + initPixmapCursor(UI_CURSOR_TOOLTRANSLATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLROTATE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSCALE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLCAMERA, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLPAN, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLZOOMIN, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLZOOMOUT, 7, 6); + initPixmapCursor(UI_CURSOR_TOOLPICKOBJECT3, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPLAY, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLPAUSE, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLMEDIAOPEN, 1, 1); + initPixmapCursor(UI_CURSOR_TOOLSIT, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLBUY, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLOPEN, 20, 15); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, 16, 16); + initPixmapCursor(UI_CURSOR_TOOLNO, 8, 8); + + initPixmapCursor(UI_CURSOR_SIZENWSE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENESW, 10, 10); + initPixmapCursor(UI_CURSOR_SIZEWE, 10, 10); + initPixmapCursor(UI_CURSOR_SIZENS, 10, 10); + initPixmapCursor(UI_CURSOR_SIZEALL, 10, 10); + +} + +void LLWindowMacOSX::captureMouse() +{ + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. +} + +void LLWindowMacOSX::releaseMouse() +{ + // By registering a global CarbonEvent handler for mouse move events, we ensure that + // mouse events are always processed. Thus, capture and release are unnecessary. +} + +void LLWindowMacOSX::hideCursor() +{ + if(!mCursorHidden) + { + // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; + mCursorHidden = true; + mHideCursorPermanent = true; + hideNSCursor(); + } + else + { + // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; + } + + adjustCursorDecouple(); +} + +void LLWindowMacOSX::showCursor() +{ + if(mCursorHidden || !isCGCursorVisible()) + { + // LL_INFOS() << "showCursor: showing" << LL_ENDL; + mCursorHidden = false; + mHideCursorPermanent = false; + showNSCursor(); + } + else + { + // LL_INFOS() << "showCursor: already visible" << LL_ENDL; + } + + adjustCursorDecouple(); +} + +void LLWindowMacOSX::showCursorFromMouseMove() +{ + if (!mHideCursorPermanent) + { + showCursor(); + } +} + +void LLWindowMacOSX::hideCursorUntilMouseMove() +{ + if (!mHideCursorPermanent) + { + hideCursor(); + mHideCursorPermanent = false; + } +} + + + +// +// LLSplashScreenMacOSX +// +LLSplashScreenMacOSX::LLSplashScreenMacOSX() +{ + mWindow = NULL; +} + +LLSplashScreenMacOSX::~LLSplashScreenMacOSX() +{ +} + +void LLSplashScreenMacOSX::showImpl() +{ + // This code _could_ be used to display a spash screen... +} + +void LLSplashScreenMacOSX::updateImpl(const std::string& mesg) +{ + if(mWindow != NULL) + { + CFStringCreateWithCString(NULL, mesg.c_str(), kCFStringEncodingUTF8); + } +} + + +void LLSplashScreenMacOSX::hideImpl() +{ + if(mWindow != NULL) + { + mWindow = NULL; + } +} + +S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type) +{ + return showAlert(text, caption, type); +} + +// Open a URL with the user's default web browser. +// Must begin with protocol identifier. +void LLWindowMacOSX::spawnWebBrowser(const std::string& escaped_url, bool async) +{ + // I'm fairly certain that this is all legitimate under Apple's currently supported APIs. + + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + S32 result = 0; + CFURLRef urlRef = NULL; + + LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; + + CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); + if (stringRef) + { + // This will succeed if the string is a full URL, including the http:// + // Note that URLs specified this way need to be properly percent-escaped. + urlRef = CFURLCreateWithString(NULL, stringRef, NULL); + + // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs + + CFRelease(stringRef); + } + + if (urlRef) + { + result = LSOpenCFURLRef(urlRef, NULL); + + if (result != noErr) + { + LL_INFOS() << "Error " << result << " on open." << LL_ENDL; + } + + CFRelease(urlRef); + } + else + { + LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; + } +} + +// String should match ndof, so string mapping code was copied as is +static char mapChar( char c ) +{ + unsigned char uc = ( unsigned char ) c; + + switch( uc ) + { + case '/': return '-'; // use dash instead of slash + + case 0x7F: return ' '; + case 0x80: return 'A'; + case 0x81: return 'A'; + case 0x82: return 'C'; + case 0x83: return 'E'; + case 0x84: return 'N'; + case 0x85: return 'O'; + case 0x86: return 'U'; + case 0x87: return 'a'; + case 0x88: return 'a'; + case 0x89: return 'a'; + case 0x8A: return 'a'; + case 0x8B: return 'a'; + case 0x8C: return 'a'; + case 0x8D: return 'c'; + case 0x8E: return 'e'; + case 0x8F: return 'e'; + case 0x90: return ' '; + case 0x91: return ' '; // ? ' + case 0x92: return ' '; // ? ' + case 0x93: return ' '; // ? " + case 0x94: return ' '; // ? " + case 0x95: return ' '; + case 0x96: return ' '; + case 0x97: return ' '; + case 0x98: return ' '; + case 0x99: return ' '; + case 0x9A: return ' '; + case 0x9B: return 0x27; + case 0x9C: return 0x22; + case 0x9D: return ' '; + case 0x9E: return ' '; + case 0x9F: return ' '; + case 0xA0: return ' '; + case 0xA1: return ' '; + case 0xA2: return ' '; + case 0xA3: return ' '; + case 0xA4: return ' '; + case 0xA5: return ' '; + case 0xA6: return ' '; + case 0xA7: return ' '; + case 0xA8: return ' '; + case 0xA9: return ' '; + case 0xAA: return ' '; + case 0xAB: return ' '; + case 0xAC: return ' '; + case 0xAD: return ' '; + case 0xAE: return ' '; + case 0xAF: return ' '; + case 0xB0: return ' '; + case 0xB1: return ' '; + case 0xB2: return ' '; + case 0xB3: return ' '; + case 0xB4: return ' '; + case 0xB5: return ' '; + case 0xB6: return ' '; + case 0xB7: return ' '; + case 0xB8: return ' '; + case 0xB9: return ' '; + case 0xBA: return ' '; + case 0xBB: return ' '; + case 0xBC: return ' '; + case 0xBD: return ' '; + case 0xBE: return ' '; + case 0xBF: return ' '; + case 0xC0: return ' '; + case 0xC1: return ' '; + case 0xC2: return ' '; + case 0xC3: return ' '; + case 0xC4: return ' '; + case 0xC5: return ' '; + case 0xC6: return ' '; + case 0xC7: return ' '; + case 0xC8: return ' '; + case 0xC9: return ' '; + case 0xCA: return ' '; + case 0xCB: return 'A'; + case 0xCC: return 'A'; + case 0xCD: return 'O'; + case 0xCE: return ' '; + case 0xCF: return ' '; + case 0xD0: return '-'; + case 0xD1: return '-'; + case 0xD2: return 0x22; + case 0xD3: return 0x22; + case 0xD4: return 0x27; + case 0xD5: return 0x27; + case 0xD6: return '-'; // use dash instead of slash + case 0xD7: return ' '; + case 0xD8: return 'y'; + case 0xD9: return 'Y'; + case 0xDA: return '-'; // use dash instead of slash + case 0xDB: return ' '; + case 0xDC: return '<'; + case 0xDD: return '>'; + case 0xDE: return ' '; + case 0xDF: return ' '; + case 0xE0: return ' '; + case 0xE1: return ' '; + case 0xE2: return ','; + case 0xE3: return ','; + case 0xE4: return ' '; + case 0xE5: return 'A'; + case 0xE6: return 'E'; + case 0xE7: return 'A'; + case 0xE8: return 'E'; + case 0xE9: return 'E'; + case 0xEA: return 'I'; + case 0xEB: return 'I'; + case 0xEC: return 'I'; + case 0xED: return 'I'; + case 0xEE: return 'O'; + case 0xEF: return 'O'; + case 0xF0: return ' '; + case 0xF1: return 'O'; + case 0xF2: return 'U'; + case 0xF3: return 'U'; + case 0xF4: return 'U'; + case 0xF5: return '|'; + case 0xF6: return ' '; + case 0xF7: return ' '; + case 0xF8: return ' '; + case 0xF9: return ' '; + case 0xFA: return '.'; + case 0xFB: return ' '; + case 0xFC: return ' '; + case 0xFD: return 0x22; + case 0xFE: return ' '; + case 0xFF: return ' '; + } + return c; +} + +// String should match ndof for manufacturer based search to work +static void sanitizeString( char* inCStr ) +{ + char* charIt = inCStr; + while ( *charIt ) + { + *charIt = mapChar( *charIt ); + charIt++; + } +} + +struct HidDevice +{ + long mAxis; + long mLocalID; + char mProduct[256]; + char mManufacturer[256]; + long mUsage; + long mUsagePage; +}; + +static void populate_device_info( io_object_t io_obj_p, CFDictionaryRef device_dic, HidDevice* devicep ) +{ + CFMutableDictionaryRef io_properties = nil; + io_registry_entry_t entry1; + io_registry_entry_t entry2; + kern_return_t rc; + + // Mac OS X currently is not mirroring all USB properties to HID page so need to look at USB device page also + // get dictionary for usb properties: step up two levels and get CF dictionary for USB properties + // try to get parent1 + rc = IORegistryEntryGetParentEntry( io_obj_p, kIOServicePlane, &entry1 ); + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryGetParentEntry( entry1, kIOServicePlane, &entry2 ); + + IOObjectRelease( entry1 ); + + if ( KERN_SUCCESS == rc ) + { + rc = IORegistryEntryCreateCFProperties( entry2, &io_properties, kCFAllocatorDefault, kNilOptions ); + // either way, release parent2 + IOObjectRelease( entry2 ); + } + } + if ( KERN_SUCCESS == rc ) + { + // IORegistryEntryCreateCFProperties() succeeded + if ( io_properties != nil ) + { + CFTypeRef dict_element = 0; + // get device info + // try hid dictionary first, if fail then go to usb dictionary + + + dict_element = CFDictionaryGetValue( device_dic, CFSTR(kIOHIDProductKey) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Product Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString((CFStringRef)dict_element, devicep->mProduct, 256, kCFStringEncodingUTF8); + sanitizeString(devicep->mProduct); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mProduct" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDManufacturerKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "USB Vendor Name" ) ); + } + if ( dict_element ) + { + bool res = CFStringGetCString( (CFStringRef)dict_element, devicep->mManufacturer, 256, kCFStringEncodingUTF8 ); + sanitizeString(devicep->mManufacturer); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mManufacturer" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDLocationIDKey ) ); + if ( !dict_element ) + { + dict_element = CFDictionaryGetValue( io_properties, CFSTR( "locationID" ) ); + } + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mLocalID ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mLocalID" << LL_ENDL; + } + } + + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsagePageKey ) ); + if ( dict_element ) + { + bool res = CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsagePage ); + if ( !res ) + { + LL_WARNS("Joystick") << "Failed to populate mUsagePage" << LL_ENDL; + } + dict_element = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDPrimaryUsageKey ) ); + if ( dict_element ) + { + if ( !CFNumberGetValue( (CFNumberRef)dict_element, kCFNumberLongType, &devicep->mUsage ) ) + { + LL_WARNS("Joystick") << "Failed to populate mUsage" << LL_ENDL; + } + } + } + + //Add axis, because ndof lib checks sutability by axises as well as other elements + devicep->mAxis = 0; + CFTypeRef hid_elements = CFDictionaryGetValue( device_dic, CFSTR( kIOHIDElementKey ) ); + if ( hid_elements && CFGetTypeID( hid_elements ) == CFArrayGetTypeID( ) ) + { + long count = CFArrayGetCount( (CFArrayRef) hid_elements ); + for (int i = 0; i < count; ++i) + { + CFTypeRef element = CFArrayGetValueAtIndex((CFArrayRef) hid_elements, i); + if (element && CFGetTypeID( element ) == CFDictionaryGetTypeID( )) + { + long type = 0, usage_page = 0, usage = 0; + + CFTypeRef ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementTypeKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &type ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsagePageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage_page ); + } + + ref_value = CFDictionaryGetValue( (CFDictionaryRef) element, CFSTR( kIOHIDElementUsageKey ) ); + if ( ref_value ) + { + CFNumberGetValue( (CFNumberRef)ref_value, kCFNumberLongType, &usage ); + } + if ( type != 0 + && type != kIOHIDElementTypeCollection + && usage_page == kHIDPage_GenericDesktop) + { + switch( usage ) + { + case kHIDUsage_GD_X: + case kHIDUsage_GD_Y: + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + devicep->mAxis++; + break; + default: + break; + } + } + } + } + } + + CFRelease(io_properties); + } + else + { + LL_WARNS("Joystick") << "Failed to populate fields" << LL_ENDL; + } + } +} + +HidDevice populate_device( io_object_t io_obj ) +{ + void* interfacep = nullptr; + HidDevice device; + memset( &device, 0, sizeof( HidDevice ) ); + CFMutableDictionaryRef device_dic = 0; + kern_return_t result = IORegistryEntryCreateCFProperties( io_obj, &device_dic, kCFAllocatorDefault, kNilOptions ); + + if ( KERN_SUCCESS == result + && device_dic ) + { + IOReturn io_result = kIOReturnSuccess; + HRESULT query_result = S_OK; + SInt32 the_score = 0; + IOCFPlugInInterface **the_interface = NULL; + + + io_result = IOCreatePlugInInterfaceForService( io_obj, kIOHIDDeviceUserClientTypeID, + kIOCFPlugInInterfaceID, &the_interface, &the_score ); + if ( io_result == kIOReturnSuccess ) + { + query_result = ( *the_interface )->QueryInterface( the_interface, CFUUIDGetUUIDBytes( kIOHIDDeviceInterfaceID ), ( LPVOID * ) & ( interfacep ) ); + if ( query_result != S_OK ) + { + LL_WARNS("Joystick") << "QueryInterface failed" << LL_ENDL; + } + IODestroyPlugInInterface( the_interface ); + } + else + { + LL_WARNS("Joystick") << "IOCreatePlugInInterfaceForService failed" << LL_ENDL; + } + + if ( interfacep ) + { + result = ( *( IOHIDDeviceInterface** )interfacep )->open( interfacep, 0 ); + + if ( result != kIOReturnSuccess) + { + LL_WARNS("Joystick") << "open failed" << LL_ENDL; + } + } + // extract needed fields + populate_device_info( io_obj, device_dic, &device ); + + // Release interface + if ( interfacep ) + { + ( *( IOHIDDeviceInterface** ) interfacep )->close( interfacep ); + + ( *( IOHIDDeviceInterface** ) interfacep )->Release( interfacep ); + + interfacep = NULL; + } + + CFRelease( device_dic ); + } + else + { + LL_WARNS("Joystick") << "populate_device failed" << LL_ENDL; + } + + return device; +} + +static void get_devices(std::list &list_of_devices, + io_iterator_t inIODeviceIterator) +{ + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + io_object_t io_obj = 0; + + while ( 0 != (io_obj = IOIteratorNext( inIODeviceIterator ) ) ) + { + HidDevice device = populate_device( io_obj ); + + // Should match ndof + if (device.mAxis >= 3 + || (device.mUsagePage == kHIDPage_GenericDesktop + && (device.mUsage == kHIDUsage_GD_MultiAxisController + || device.mUsage == kHIDUsage_GD_GamePad + || device.mUsage == kHIDUsage_GD_Joystick)) + || (device.mUsagePage == kHIDPage_Game + && device.mUsage == kHIDUsage_Game_3DGameController) + || strstr(device.mManufacturer, "3Dconnexion")) + { + list_of_devices.push_back(device); + } + else + { + LL_DEBUGS("Joystick"); + list_of_devices.push_back(device); + LL_CONT << "Device axes: " << (S32)device.mAxis + << " Device HIDUsepage: " << (S32)device.mUsagePage + << " Device HIDUsage: " << (S32)device.mUsage; + LL_ENDL; + } + + + // release the device object, it is no longer needed + result = IOObjectRelease( io_obj ); + if ( KERN_SUCCESS != result ) + { + LL_WARNS("Joystick") << "IOObjectRelease failed" << LL_ENDL; + } + } +} + +bool LLWindowMacOSX::getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) +{ + bool return_value = false; + CFMutableDictionaryRef device_dict_ref; + IOReturn result = kIOReturnSuccess; // assume success( optimist! ) + + // Set up matching dictionary to search the I/O Registry for HID devices we are interested in. Dictionary reference is NULL if error. + + // A dictionary to match devices to? + device_dict_ref = IOServiceMatching( kIOHIDDeviceKey ); + + // BUG FIX! one reference is consumed by IOServiceGetMatchingServices + CFRetain( device_dict_ref ); + io_iterator_t io_iter = 0; + + // create an IO object iterator + result = IOServiceGetMatchingServices( kIOMasterPortDefault, device_dict_ref, &io_iter ); + if ( kIOReturnSuccess != result ) + { + LL_WARNS("Joystick") << "IOServiceGetMatchingServices failed" << LL_ENDL; + } + + if ( io_iter ) + { + // add all existing devices + std::list device_list; + + get_devices(device_list, io_iter); + + std::list::iterator iter; + + for (iter = device_list.begin(); iter != device_list.end(); ++iter) + { + std::string label(iter->mProduct); + LLSD data; + data["manufacturer"] = std::string(iter->mManufacturer); + data["product"] = label; + + if (osx_callback(label, data, userdata)) + { + break; //found device + } + } + return_value = true; + } + + CFRelease( device_dict_ref ); + return return_value; +} + +LLSD LLWindowMacOSX::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + if(mRawKeyEvent) + { + result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); + result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); + result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); + result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); + result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); + result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); + } + + LL_DEBUGS() << "native key data is: " << result << LL_ENDL; + + return result; +} + +bool LLWindowMacOSX::dialogColorPicker( F32 *r, F32 *g, F32 *b) +{ + bool retval = false; + OSErr error = noErr; + NColorPickerInfo info; + + memset(&info, 0, sizeof(info)); + info.theColor.color.rgb.red = (UInt16)(*r * 65535.f); + info.theColor.color.rgb.green = (UInt16)(*g * 65535.f); + info.theColor.color.rgb.blue = (UInt16)(*b * 65535.f); + info.placeWhere = kCenterOnMainScreen; + + error = NPickColor(&info); + + if (error == noErr) + { + retval = info.newColorChosen; + if (info.newColorChosen) + { + *r = ((float) info.theColor.color.rgb.red) / 65535.0; + *g = ((float) info.theColor.color.rgb.green) / 65535.0; + *b = ((float) info.theColor.color.rgb.blue) / 65535.0; + } + } + + return (retval); +} + +void *LLWindowMacOSX::getPlatformWindow() +{ + // NOTE: this will be NULL in fullscreen mode. Plan accordingly. + return (void*)mWindow; +} + +// get a double value from a dictionary +/* +static double getDictDouble (CFDictionaryRef refDict, CFStringRef key) +{ + double double_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberDoubleType, &double_value)) // or if cant convert it + return -1; // fail + return double_value; // otherwise return the long value +}*/ + +// get a long value from a dictionary +static long getDictLong (CFDictionaryRef refDict, CFStringRef key) +{ + long int_value; + CFNumberRef number_value = (CFNumberRef) CFDictionaryGetValue(refDict, key); + if (!number_value) // if can't get a number for the dictionary + return -1; // fail + if (!CFNumberGetValue(number_value, kCFNumberLongType, &int_value)) // or if cant convert it + return -1; // fail + return int_value; // otherwise return the long value +} + +void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, bool b) +{ + if (preeditor != mPreeditor && !b) + { + // This condition may occur by a call to + // setEnabled(bool) against LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + // We need to interrupt before updating mPreeditor, + // so that the fix string from input method goes to + // the old preeditor. + if (mLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + if (b == mLanguageTextInputAllowed) + { + return; + } + mLanguageTextInputAllowed = b; + allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit +} + +class sharedContext +{ +public: + CGLContextObj mContext; +}; + +void* LLWindowMacOSX::createSharedContext() +{ + sharedContext* sc = new sharedContext(); + CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); + + if (sUseMultGL) + { + CGLEnable(mContext, kCGLCEMPEngine); + } + + return (void *)sc; +} + +void LLWindowMacOSX::makeContextCurrent(void* context) +{ + CGLSetCurrentContext(((sharedContext*)context)->mContext); + + //enable multi-threaded OpenGL + if (sUseMultGL) + { + CGLError cgl_err; + CGLContextObj ctx = CGLGetCurrentContext(); + + cgl_err = CGLEnable( ctx, kCGLCEMPEngine); + + if (cgl_err != kCGLNoError ) + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL not available." << LL_ENDL; + } + else + { + LL_INFOS("GLInit") << "Multi-threaded OpenGL enabled." << LL_ENDL; + } + } + +} + +void LLWindowMacOSX::destroySharedContext(void* context) +{ + sharedContext* sc = (sharedContext*)context; + + CGLDestroyContext(sc->mContext); + + delete sc; +} + +void LLWindowMacOSX::toggleVSync(bool enable_vsync) +{ + GLint frames_per_swap = 0; + if (!enable_vsync) + { + frames_per_swap = 0; + } + else + { + frames_per_swap = 1; + } + + CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); +} + +void LLWindowMacOSX::interruptLanguageTextInput() +{ + commitCurrentPreedit(mGLView); +} + +std::vector LLWindowMacOSX::getDisplaysResolutionList() +{ + std::vector resolution_list; + + CGDirectDisplayID display_ids[10]; + uint32_t found_displays = 0; + CGError err = CGGetActiveDisplayList(10, display_ids, &found_displays); + + if (kCGErrorSuccess != err) + { + LL_WARNS() << "Couldn't get a list of active displays" << LL_ENDL; + return std::vector(); + } + + for (uint32_t i = 0; i < found_displays; i++) + { + S32 monitor_width = CGDisplayPixelsWide(display_ids[i]); + S32 monitor_height = CGDisplayPixelsHigh(display_ids[i]); + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + resolution_list.push_back(res); + } + + return resolution_list; +} + +//static +std::vector LLWindowMacOSX::getDynamicFallbackFontList() +{ + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector(); +} + +// static +MASK LLWindowMacOSX::modifiersToMask(S16 modifiers) +{ + MASK mask = 0; + if(modifiers & MAC_SHIFT_KEY) { mask |= MASK_SHIFT; } + if(modifiers & (MAC_CMD_KEY | MAC_CTRL_KEY)) { mask |= MASK_CONTROL; } + if(modifiers & MAC_ALT_KEY) { mask |= MASK_ALT; } + return mask; +} + +F32 LLWindowMacOSX::getSystemUISize() +{ + return gHiDPISupport ? ::getDeviceUnitSize(mGLView) : LLWindow::getSystemUISize(); +} + +#if LL_OS_DRAGDROP_ENABLED +/* +S16 LLWindowMacOSX::dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, + void * handlerRefCon, DragRef drag) +{ + S16 result = 0; + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + + LL_DEBUGS() << "drag tracking handler, message = " << message << LL_ENDL; + + switch(message) + { + case kDragTrackingInWindow: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_TRACK); + break; + + case kDragTrackingEnterHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_START_TRACKING); + break; + + case kDragTrackingLeaveHandler: + result = self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_STOP_TRACKING); + break; + + default: + break; + } + + return result; +} +OSErr LLWindowMacOSX::dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, + DragRef drag) +{ + LLWindowMacOSX *self = (LLWindowMacOSX*)handlerRefCon; + return self->handleDragNDrop(drag, LLWindowCallbacks::DNDA_DROPPED); + +} +*/ +void LLWindowMacOSX::handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action) +{ + MASK mask = LLWindowMacOSX::modifiersToMask(getModifiers()); + + float mouse_point[2]; + // This will return the mouse point in window coords + getCursorPos(mWindow, mouse_point); + LLCoordWindow window_coords(mouse_point[0], mouse_point[1]); + LLCoordGL gl_pos; + convertCoords(window_coords, &gl_pos); + + if(!url.empty()) + { + LLWindowCallbacks::DragNDropResult res = + mCallbacks->handleDragNDrop(this, gl_pos, mask, action, url); + + switch (res) { + case LLWindowCallbacks::DND_NONE: // No drop allowed + if (action == LLWindowCallbacks::DNDA_TRACK) + { + mDragOverrideCursor = 0; + } + else { + mDragOverrideCursor = -1; + } + break; + case LLWindowCallbacks::DND_MOVE: // Drop accepted would result in a "move" operation + mDragOverrideCursor = UI_CURSOR_NO; + break; + case LLWindowCallbacks::DND_COPY: // Drop accepted would result in a "copy" operation + mDragOverrideCursor = UI_CURSOR_ARROWCOPY; + break; + default: + mDragOverrideCursor = -1; + break; + } + // This overrides the cursor being set by setCursor. + // This is a bit of a hack workaround because lots of areas + // within the viewer just blindly set the cursor. + if (mDragOverrideCursor == -1) + { + // Restore the cursor + ECursorType temp_cursor = mCurrentCursor; + // get around the "setting the same cursor" code in setCursor() + mCurrentCursor = UI_CURSOR_COUNT; + setCursor(temp_cursor); + } + else { + // Override the cursor + switch (mDragOverrideCursor) { + case 0: + setArrowCursor(); + break; + case UI_CURSOR_NO: + setNotAllowedCursor(); + case UI_CURSOR_ARROWCOPY: + setCopyCursor(); + default: + break; + }; + } + } +} + +#endif // LL_OS_DRAGDROP_ENABLED diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 9ed51a9f15..3be89c255a 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -1,265 +1,265 @@ -/** - * @file llwindowmacosx.h - * @brief Mac implementation of LLWindow class - * - * $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$ - */ - -#ifndef LL_LLWINDOWMACOSX_H -#define LL_LLWINDOWMACOSX_H - -#include "llwindow.h" -#include "llwindowcallbacks.h" -#include "llwindowmacosx-objc.h" - -#include "lltimer.h" - -#include -#include - -// AssertMacros.h does bad things. -#include "fix_macros.h" -#undef verify -#undef require - -class LLWindowMacOSX : public LLWindow -{ -public: - void show() override; - void hide() override; - void close() override; - bool getVisible() override; - bool getMinimized() override; - bool getMaximized() override; - bool maximize() override; - void minimize() override; - void restore() override; - bool getFullscreen(); - bool getPosition(LLCoordScreen *position) override; - bool getSize(LLCoordScreen *size) override; - bool getSize(LLCoordWindow *size) override; - bool setPosition(LLCoordScreen position) override; - bool setSizeImpl(LLCoordScreen size) override; - bool setSizeImpl(LLCoordWindow size) override; - bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override; - bool setCursorPosition(LLCoordWindow position) override; - bool getCursorPosition(LLCoordWindow *position) override; - void showCursor() override; - void hideCursor() override; - void showCursorFromMouseMove() override; - void hideCursorUntilMouseMove() override; - bool isCursorHidden() override; - void updateCursor() override; - ECursorType getCursor() const override; - void captureMouse() override; - void releaseMouse() override; - void setMouseClipping( bool b ) override; - bool isClipboardTextAvailable() override; - bool pasteTextFromClipboard(LLWString &dst) override; - bool copyTextToClipboard(const LLWString & src) override; - void flashIcon(F32 seconds) override; - F32 getGamma() override; - bool setGamma(const F32 gamma) override; // Set the gamma - U32 getFSAASamples() override; - void setFSAASamples(const U32 fsaa_samples) override; - bool restoreGamma() override; // Restore original gamma table (before updating gamma) - ESwapMethod getSwapMethod() override { return mSwapMethod; } - void gatherInput() override; - void delayInputProcessing() override {}; - void swapBuffers() override; - - // handy coordinate space conversion routines - bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override; - bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override; - bool convertCoords(LLCoordWindow from, LLCoordGL *to) override; - bool convertCoords(LLCoordGL from, LLCoordWindow *to) override; - bool convertCoords(LLCoordScreen from, LLCoordGL *to) override; - bool convertCoords(LLCoordGL from, LLCoordScreen *to) override; - - LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; - F32 getNativeAspectRatio() override; - F32 getPixelAspectRatio() override; - void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - - virtual void setMaxVRAMMegabytes(U32 max_vram) override {} - - void beforeDialog() override; - void afterDialog() override; - - bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; - - void *getPlatformWindow() override; - void bringToFront() override {}; - - void allowLanguageTextInput(LLPreeditor *preeditor, bool b) override; - void interruptLanguageTextInput() override; - void spawnWebBrowser(const std::string& escaped_url, bool async) override; - F32 getSystemUISize() override; - - bool getInputDevices(U32 device_type_filter, - std::function osx_callback, - void* win_callback, - void* userdata) override; - - static std::vector getDisplaysResolutionList(); - - static std::vector getDynamicFallbackFontList(); - - // Provide native key event data - LLSD getNativeKeyData() override; - - void* getWindow() { return mWindow; } - LLWindowCallbacks* getCallbacks() { return mCallbacks; } - LLPreeditor* getPreeditor() { return mPreeditor; } - - void updateMouseDeltas(float* deltas); - void getMouseDeltas(float* delta); - - void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); - - bool allowsLanguageInput() { return mLanguageTextInputAllowed; } - - //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread - // returns a pointer to be handed back to destroySharedConext/makeContextCurrent - void* createSharedContext() override; - //make the given context current on the current thread - void makeContextCurrent(void* context) override; - //destroy the given context that was retrieved by createSharedContext() - //Must be called on the same thread that called createSharedContext() - void destroySharedContext(void* context) override; - - void toggleVSync(bool enable_vsync) override; - -protected: - LLWindowMacOSX(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, - bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_vram); - ~LLWindowMacOSX(); - - void initCursors(); - bool isValid() override; - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - - - // Changes display resolution. Returns true if successful - bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - - // Go back to last fullscreen display resolution. - bool setFullscreenResolution(); - - // Restore the display resolution to its value before we ran the app. - bool resetDisplayResolution(); - - bool shouldPostQuit() { return mPostQuit; } - - //Satisfy MAINT-3135 and MAINT-3288 with a flag. - /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } - -private: - void restoreGLContext(); - -protected: - // - // Platform specific methods - // - - // create or re-create the GL context/window. Called from the constructor and switchContext(). - bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); - void destroyContext(); - void setupFailure(const std::string& text, const std::string& caption, U32 type); - void adjustCursorDecouple(bool warpingMouse = false); - static MASK modifiersToMask(S16 modifiers); - -#if LL_OS_DRAGDROP_ENABLED - - //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); - - -#endif // LL_OS_DRAGDROP_ENABLED - - // - // Platform specific variables - // - - // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. - NSWindowRef mWindow; - GLViewRef mGLView; - CGLContextObj mContext; - CGLPixelFormatObj mPixelFormat; - CGDirectDisplayID mDisplay; - - LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - std::string mWindowTitle; - double mOriginalAspectRatio; - bool mSimulatedRightClick; - U32 mLastModifiers; - bool mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. - // Used to allow event processing when putting up dialogs in fullscreen mode. - bool mCursorDecoupled; - S32 mCursorLastEventDeltaX; - S32 mCursorLastEventDeltaY; - bool mCursorIgnoreNextDelta; - bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. - LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - bool mMaximized; - bool mMinimized; - U32 mFSAASamples; - bool mForceRebuild; - - S32 mDragOverrideCursor; - - // Input method management through Text Service Manager. - bool mLanguageTextInputAllowed; - LLPreeditor* mPreeditor; - -public: - static bool sUseMultGL; - - friend class LLWindowManager; - -}; - - -class LLSplashScreenMacOSX : public LLSplashScreen -{ -public: - LLSplashScreenMacOSX(); - virtual ~LLSplashScreenMacOSX(); - - void showImpl(); - void updateImpl(const std::string& mesg); - void hideImpl(); - -private: - WindowRef mWindow; -}; - -S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type); - -void load_url_external(const char* url); - -#endif //LL_LLWINDOWMACOSX_H +/** + * @file llwindowmacosx.h + * @brief Mac implementation of LLWindow class + * + * $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$ + */ + +#ifndef LL_LLWINDOWMACOSX_H +#define LL_LLWINDOWMACOSX_H + +#include "llwindow.h" +#include "llwindowcallbacks.h" +#include "llwindowmacosx-objc.h" + +#include "lltimer.h" + +#include +#include + +// AssertMacros.h does bad things. +#include "fix_macros.h" +#undef verify +#undef require + +class LLWindowMacOSX : public LLWindow +{ +public: + void show() override; + void hide() override; + void close() override; + bool getVisible() override; + bool getMinimized() override; + bool getMaximized() override; + bool maximize() override; + void minimize() override; + void restore() override; + bool getFullscreen(); + bool getPosition(LLCoordScreen *position) override; + bool getSize(LLCoordScreen *size) override; + bool getSize(LLCoordWindow *size) override; + bool setPosition(LLCoordScreen position) override; + bool setSizeImpl(LLCoordScreen size) override; + bool setSizeImpl(LLCoordWindow size) override; + bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL) override; + bool setCursorPosition(LLCoordWindow position) override; + bool getCursorPosition(LLCoordWindow *position) override; + void showCursor() override; + void hideCursor() override; + void showCursorFromMouseMove() override; + void hideCursorUntilMouseMove() override; + bool isCursorHidden() override; + void updateCursor() override; + ECursorType getCursor() const override; + void captureMouse() override; + void releaseMouse() override; + void setMouseClipping( bool b ) override; + bool isClipboardTextAvailable() override; + bool pasteTextFromClipboard(LLWString &dst) override; + bool copyTextToClipboard(const LLWString & src) override; + void flashIcon(F32 seconds) override; + F32 getGamma() override; + bool setGamma(const F32 gamma) override; // Set the gamma + U32 getFSAASamples() override; + void setFSAASamples(const U32 fsaa_samples) override; + bool restoreGamma() override; // Restore original gamma table (before updating gamma) + ESwapMethod getSwapMethod() override { return mSwapMethod; } + void gatherInput() override; + void delayInputProcessing() override {}; + void swapBuffers() override; + + // handy coordinate space conversion routines + bool convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + bool convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + bool convertCoords(LLCoordWindow from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordWindow *to) override; + bool convertCoords(LLCoordScreen from, LLCoordGL *to) override; + bool convertCoords(LLCoordGL from, LLCoordScreen *to) override; + + LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; + F32 getNativeAspectRatio() override; + F32 getPixelAspectRatio() override; + void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } + + virtual void setMaxVRAMMegabytes(U32 max_vram) override {} + + void beforeDialog() override; + void afterDialog() override; + + bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; + + void *getPlatformWindow() override; + void bringToFront() override {}; + + void allowLanguageTextInput(LLPreeditor *preeditor, bool b) override; + void interruptLanguageTextInput() override; + void spawnWebBrowser(const std::string& escaped_url, bool async) override; + F32 getSystemUISize() override; + + bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata) override; + + static std::vector getDisplaysResolutionList(); + + static std::vector getDynamicFallbackFontList(); + + // Provide native key event data + LLSD getNativeKeyData() override; + + void* getWindow() { return mWindow; } + LLWindowCallbacks* getCallbacks() { return mCallbacks; } + LLPreeditor* getPreeditor() { return mPreeditor; } + + void updateMouseDeltas(float* deltas); + void getMouseDeltas(float* delta); + + void handleDragNDrop(std::string url, LLWindowCallbacks::DragNDropAction action); + + bool allowsLanguageInput() { return mLanguageTextInputAllowed; } + + //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread + // returns a pointer to be handed back to destroySharedConext/makeContextCurrent + void* createSharedContext() override; + //make the given context current on the current thread + void makeContextCurrent(void* context) override; + //destroy the given context that was retrieved by createSharedContext() + //Must be called on the same thread that called createSharedContext() + void destroySharedContext(void* context) override; + + void toggleVSync(bool enable_vsync) override; + +protected: + LLWindowMacOSX(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, + bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, + U32 fsaa_samples, + U32 max_vram); + ~LLWindowMacOSX(); + + void initCursors(); + bool isValid() override; + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + + + // Changes display resolution. Returns true if successful + bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + + // Go back to last fullscreen display resolution. + bool setFullscreenResolution(); + + // Restore the display resolution to its value before we ran the app. + bool resetDisplayResolution(); + + bool shouldPostQuit() { return mPostQuit; } + + //Satisfy MAINT-3135 and MAINT-3288 with a flag. + /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } + +private: + void restoreGLContext(); + +protected: + // + // Platform specific methods + // + + // create or re-create the GL context/window. Called from the constructor and switchContext(). + bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); + void destroyContext(); + void setupFailure(const std::string& text, const std::string& caption, U32 type); + void adjustCursorDecouple(bool warpingMouse = false); + static MASK modifiersToMask(S16 modifiers); + +#if LL_OS_DRAGDROP_ENABLED + + //static OSErr dragTrackingHandler(DragTrackingMessage message, WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + //static OSErr dragReceiveHandler(WindowRef theWindow, void * handlerRefCon, DragRef theDrag); + + +#endif // LL_OS_DRAGDROP_ENABLED + + // + // Platform specific variables + // + + // Use generic pointers here. This lets us do some funky Obj-C interop using Obj-C objects without having to worry about any compilation problems that may arise. + NSWindowRef mWindow; + GLViewRef mGLView; + CGLContextObj mContext; + CGLPixelFormatObj mPixelFormat; + CGDirectDisplayID mDisplay; + + LLRect mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + std::string mWindowTitle; + double mOriginalAspectRatio; + bool mSimulatedRightClick; + U32 mLastModifiers; + bool mHandsOffEvents; // When true, temporarially disable CarbonEvent processing. + // Used to allow event processing when putting up dialogs in fullscreen mode. + bool mCursorDecoupled; + S32 mCursorLastEventDeltaX; + S32 mCursorLastEventDeltaY; + bool mCursorIgnoreNextDelta; + bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + LLCoordScreen mNeedsResizeSize; + F32 mOverrideAspectRatio; + bool mMaximized; + bool mMinimized; + U32 mFSAASamples; + bool mForceRebuild; + + S32 mDragOverrideCursor; + + // Input method management through Text Service Manager. + bool mLanguageTextInputAllowed; + LLPreeditor* mPreeditor; + +public: + static bool sUseMultGL; + + friend class LLWindowManager; + +}; + + +class LLSplashScreenMacOSX : public LLSplashScreen +{ +public: + LLSplashScreenMacOSX(); + virtual ~LLSplashScreenMacOSX(); + + void showImpl(); + void updateImpl(const std::string& mesg); + void hideImpl(); + +private: + WindowRef mWindow; +}; + +S32 OSMessageBoxMacOSX(const std::string& text, const std::string& caption, U32 type); + +void load_url_external(const char* url); + +#endif //LL_LLWINDOWMACOSX_H diff --git a/indra/llwindow/llwindowmesaheadless.cpp b/indra/llwindow/llwindowmesaheadless.cpp index a0dd2bc086..6cbd737ed2 100644 --- a/indra/llwindow/llwindowmesaheadless.cpp +++ b/indra/llwindow/llwindowmesaheadless.cpp @@ -1,78 +1,78 @@ -/** - * @file llwindowmesaheadless.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 "indra_constants.h" - -#include "llwindowmesaheadless.h" -#include "llgl.h" - -#define MESA_CHANNEL_TYPE GL_UNSIGNED_SHORT -#define MESA_CHANNEL_SIZE 2 - -U16 *gMesaBuffer = NULL; - -// -// LLWindowMesaHeadless -// -LLWindowMesaHeadless::LLWindowMesaHeadless(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(callbacks, fullscreen, flags) -{ - if (use_gl) - { - LL_INFOS() << "MESA Init" << LL_ENDL; - mMesaContext = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL ); - - /* Allocate the image buffer */ - mMesaBuffer = new unsigned char [width * height * 4 * MESA_CHANNEL_SIZE]; - llassert(mMesaBuffer); - - gMesaBuffer = (U16*)mMesaBuffer; - - /* Bind the buffer to the context and make it current */ - if (!OSMesaMakeCurrent( mMesaContext, mMesaBuffer, MESA_CHANNEL_TYPE, width, height )) - { - LL_ERRS() << "MESA: OSMesaMakeCurrent failed!" << LL_ENDL; - } - - llverify(gGLManager.initGL()); - } -} - - -LLWindowMesaHeadless::~LLWindowMesaHeadless() -{ - delete mMesaBuffer; - OSMesaDestroyContext( mMesaContext ); -} - -void LLWindowMesaHeadless::swapBuffers() -{ - glFinish(); -} +/** + * @file llwindowmesaheadless.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 "indra_constants.h" + +#include "llwindowmesaheadless.h" +#include "llgl.h" + +#define MESA_CHANNEL_TYPE GL_UNSIGNED_SHORT +#define MESA_CHANNEL_SIZE 2 + +U16 *gMesaBuffer = NULL; + +// +// LLWindowMesaHeadless +// +LLWindowMesaHeadless::LLWindowMesaHeadless(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(callbacks, fullscreen, flags) +{ + if (use_gl) + { + LL_INFOS() << "MESA Init" << LL_ENDL; + mMesaContext = OSMesaCreateContextExt( GL_RGBA, 32, 0, 0, NULL ); + + /* Allocate the image buffer */ + mMesaBuffer = new unsigned char [width * height * 4 * MESA_CHANNEL_SIZE]; + llassert(mMesaBuffer); + + gMesaBuffer = (U16*)mMesaBuffer; + + /* Bind the buffer to the context and make it current */ + if (!OSMesaMakeCurrent( mMesaContext, mMesaBuffer, MESA_CHANNEL_TYPE, width, height )) + { + LL_ERRS() << "MESA: OSMesaMakeCurrent failed!" << LL_ENDL; + } + + llverify(gGLManager.initGL()); + } +} + + +LLWindowMesaHeadless::~LLWindowMesaHeadless() +{ + delete mMesaBuffer; + OSMesaDestroyContext( mMesaContext ); +} + +void LLWindowMesaHeadless::swapBuffers() +{ + glFinish(); +} diff --git a/indra/llwindow/llwindowmesaheadless.h b/indra/llwindow/llwindowmesaheadless.h index 2188e54fb2..0bf8c46a30 100644 --- a/indra/llwindow/llwindowmesaheadless.h +++ b/indra/llwindow/llwindowmesaheadless.h @@ -1,123 +1,123 @@ -/** - * @file llwindowmesaheadless.h - * @brief Windows implementation of LLWindow class - * - * $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$ - */ - -#ifndef LL_LLWINDOWMESAHEADLESS_H -#define LL_LLWINDOWMESAHEADLESS_H - -#if LL_MESA_HEADLESS - -#include "llwindow.h" -#include "GL/glu.h" -#include "GL/osmesa.h" - -class LLWindowMesaHeadless : public LLWindow -{ -public: - /*virtual*/ void show() {}; - /*virtual*/ void hide() {}; - /*virtual*/ void close() {}; - /*virtual*/ bool getVisible() {return false;}; - /*virtual*/ bool getMinimized() {return false;}; - /*virtual*/ bool getMaximized() {return false;}; - /*virtual*/ bool maximize() {return false;}; - /*virtual*/ void minimize() {}; - /*virtual*/ void restore() {}; - /*virtual*/ bool getFullscreen() {return false;}; - /*virtual*/ bool getPosition(LLCoordScreen *position) {return false;}; - /*virtual*/ bool getSize(LLCoordScreen *size) {return false;}; - /*virtual*/ bool getSize(LLCoordWindow *size) {return false;}; - /*virtual*/ bool setPosition(LLCoordScreen position) {return false;}; - /*virtual*/ bool setSizeImpl(LLCoordScreen size) {return false;}; - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) {return false;}; - /*virtual*/ bool setCursorPosition(LLCoordWindow position) {return false;}; - /*virtual*/ bool getCursorPosition(LLCoordWindow *position) {return false;}; - /*virtual*/ void showCursor() {}; - /*virtual*/ void hideCursor() {}; - /*virtual*/ void showCursorFromMouseMove() {}; - /*virtual*/ void hideCursorUntilMouseMove() {}; - /*virtual*/ bool isCursorHidden() {return false;}; - /*virtual*/ void updateCursor() {}; - //virtual ECursorType getCursor() { return mCurrentCursor; }; - /*virtual*/ void captureMouse() {}; - /*virtual*/ void releaseMouse() {}; - /*virtual*/ void setMouseClipping( bool b ) {}; - /*virtual*/ bool isClipboardTextAvailable() {return false; }; - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) {return false; }; - /*virtual*/ bool copyTextToClipboard(const LLWString &src) {return false; }; - /*virtual*/ void flashIcon(F32 seconds) {}; - /*virtual*/ F32 getGamma() {return 1.0f; }; - /*virtual*/ bool setGamma(const F32 gamma) {return false; }; // Set the gamma - /*virtual*/ bool restoreGamma() {return false; }; // Restore original gamma table (before updating gamma) - /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } - /*virtual*/ U32 getFSAASamples() { return 0; } - //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput() {}; - /*virtual*/ void delayInputProcessing() {}; - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; - - // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) { return false; }; - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) { return false; }; - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; - /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; - /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; - /*virtual*/ void setNativeAspectRatio(F32 ratio) {} - - /*virtual*/ void *getPlatformWindow() { return 0; }; - /*virtual*/ void bringToFront() {}; - - LLWindowMesaHeadless(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); - ~LLWindowMesaHeadless(); - -private: - OSMesaContext mMesaContext; - unsigned char * mMesaBuffer; -}; - -class LLSplashScreenMesaHeadless : public LLSplashScreen -{ -public: - LLSplashScreenMesaHeadless() {}; - virtual ~LLSplashScreenMesaHeadless() {}; - - /*virtual*/ void showImpl() {}; - /*virtual*/ void updateImpl(const std::string& mesg) {}; - /*virtual*/ void hideImpl() {}; - -}; - -#endif - -#endif //LL_LLWINDOWMESAHEADLESS_H +/** + * @file llwindowmesaheadless.h + * @brief Windows implementation of LLWindow class + * + * $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$ + */ + +#ifndef LL_LLWINDOWMESAHEADLESS_H +#define LL_LLWINDOWMESAHEADLESS_H + +#if LL_MESA_HEADLESS + +#include "llwindow.h" +#include "GL/glu.h" +#include "GL/osmesa.h" + +class LLWindowMesaHeadless : public LLWindow +{ +public: + /*virtual*/ void show() {}; + /*virtual*/ void hide() {}; + /*virtual*/ void close() {}; + /*virtual*/ bool getVisible() {return false;}; + /*virtual*/ bool getMinimized() {return false;}; + /*virtual*/ bool getMaximized() {return false;}; + /*virtual*/ bool maximize() {return false;}; + /*virtual*/ void minimize() {}; + /*virtual*/ void restore() {}; + /*virtual*/ bool getFullscreen() {return false;}; + /*virtual*/ bool getPosition(LLCoordScreen *position) {return false;}; + /*virtual*/ bool getSize(LLCoordScreen *size) {return false;}; + /*virtual*/ bool getSize(LLCoordWindow *size) {return false;}; + /*virtual*/ bool setPosition(LLCoordScreen position) {return false;}; + /*virtual*/ bool setSizeImpl(LLCoordScreen size) {return false;}; + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL) {return false;}; + /*virtual*/ bool setCursorPosition(LLCoordWindow position) {return false;}; + /*virtual*/ bool getCursorPosition(LLCoordWindow *position) {return false;}; + /*virtual*/ void showCursor() {}; + /*virtual*/ void hideCursor() {}; + /*virtual*/ void showCursorFromMouseMove() {}; + /*virtual*/ void hideCursorUntilMouseMove() {}; + /*virtual*/ bool isCursorHidden() {return false;}; + /*virtual*/ void updateCursor() {}; + //virtual ECursorType getCursor() { return mCurrentCursor; }; + /*virtual*/ void captureMouse() {}; + /*virtual*/ void releaseMouse() {}; + /*virtual*/ void setMouseClipping( bool b ) {}; + /*virtual*/ bool isClipboardTextAvailable() {return false; }; + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst) {return false; }; + /*virtual*/ bool copyTextToClipboard(const LLWString &src) {return false; }; + /*virtual*/ void flashIcon(F32 seconds) {}; + /*virtual*/ F32 getGamma() {return 1.0f; }; + /*virtual*/ bool setGamma(const F32 gamma) {return false; }; // Set the gamma + /*virtual*/ bool restoreGamma() {return false; }; // Restore original gamma table (before updating gamma) + /*virtual*/ void setFSAASamples(const U32 fsaa_samples) { /* FSAA not supported yet on Mesa headless.*/ } + /*virtual*/ U32 getFSAASamples() { return 0; } + //virtual ESwapMethod getSwapMethod() { return mSwapMethod; } + /*virtual*/ void gatherInput() {}; + /*virtual*/ void delayInputProcessing() {}; + /*virtual*/ void swapBuffers(); + /*virtual*/ void restoreGLContext() {}; + + // handy coordinate space conversion routines + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to) { return false; }; + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to) { return false; }; + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) { return NULL; }; + /*virtual*/ F32 getNativeAspectRatio() { return 1.0f; }; + /*virtual*/ F32 getPixelAspectRatio() { return 1.0f; }; + /*virtual*/ void setNativeAspectRatio(F32 ratio) {} + + /*virtual*/ void *getPlatformWindow() { return 0; }; + /*virtual*/ void bringToFront() {}; + + LLWindowMesaHeadless(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); + ~LLWindowMesaHeadless(); + +private: + OSMesaContext mMesaContext; + unsigned char * mMesaBuffer; +}; + +class LLSplashScreenMesaHeadless : public LLSplashScreen +{ +public: + LLSplashScreenMesaHeadless() {}; + virtual ~LLSplashScreenMesaHeadless() {}; + + /*virtual*/ void showImpl() {}; + /*virtual*/ void updateImpl(const std::string& mesg) {}; + /*virtual*/ void hideImpl() {}; + +}; + +#endif + +#endif //LL_LLWINDOWMESAHEADLESS_H diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 0eedca354d..7433ad6bd2 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -1,2697 +1,2697 @@ -/** - * @file llwindowsdl.cpp - * @brief SDL implementation of LLWindow class - * @author This module has many fathers, and it shows. - * - * $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$ - */ - -#if LL_SDL - -#include "linden_common.h" - -#include "llwindowsdl.h" - -#include "llwindowcallbacks.h" -#include "llkeyboardsdl.h" - -#include "llerror.h" -#include "llgl.h" -#include "llstring.h" -#include "lldir.h" -#include "llfindlocale.h" - -#if LL_GTK -extern "C" { -# include "gtk/gtk.h" -} -#include -#endif // LL_GTK - -extern "C" { -# include "fontconfig/fontconfig.h" -} - -#if LL_LINUX -// not necessarily available on random SDL platforms, so #if LL_LINUX -// for execv(), waitpid(), fork() -# include -# include -# include -#endif // LL_LINUX - -extern bool gDebugWindowProc; - -const S32 MAX_NUM_RESOLUTIONS = 200; - -// static variable for ATI mouse cursor crash work-around: -static bool ATIbug = false; - -// -// LLWindowSDL -// - -#if LL_X11 -# include -#endif //LL_X11 - -// TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar -// set of reasons): Stash a pointer to the LLWindowSDL object here and -// maintain in the constructor and destructor. This assumes that there will -// be only one object of this class at any time. Currently this is true. -static LLWindowSDL *gWindowImplementation = NULL; - - -void maybe_lock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Lock_Display) { - gWindowImplementation->Lock_Display(); - } -} - - -void maybe_unlock_display(void) -{ - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { - gWindowImplementation->Unlock_Display(); - } -} - - -#if LL_GTK -// Lazily initialize and check the runtime GTK version for goodness. -// static -bool LLWindowSDL::ll_try_gtk_init(void) -{ - static bool done_gtk_diag = false; - static bool gtk_is_good = false; - static bool done_setlocale = false; - static bool tried_gtk_init = false; - - if (!done_setlocale) - { - LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; - maybe_lock_display(); - gtk_disable_setlocale(); - maybe_unlock_display(); - done_setlocale = true; - } - - if (!tried_gtk_init) - { - tried_gtk_init = true; - if (!g_thread_supported ()) g_thread_init (NULL); - maybe_lock_display(); - gtk_is_good = gtk_init_check(NULL, NULL); - maybe_unlock_display(); - if (!gtk_is_good) - LL_WARNS() << "GTK Initialization failed." << LL_ENDL; - } - - if (gtk_is_good && !done_gtk_diag) - { - LL_INFOS() << "GTK Initialized." << LL_ENDL; - LL_INFOS() << "- Compiled against GTK version " - << GTK_MAJOR_VERSION << "." - << GTK_MINOR_VERSION << "." - << GTK_MICRO_VERSION << LL_ENDL; - LL_INFOS() << "- Running against GTK version " - << gtk_major_version << "." - << gtk_minor_version << "." - << gtk_micro_version << LL_ENDL; - maybe_lock_display(); - const gchar* gtk_warning = gtk_check_version( - GTK_MAJOR_VERSION, - GTK_MINOR_VERSION, - GTK_MICRO_VERSION); - maybe_unlock_display(); - if (gtk_warning) - { - LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << - gtk_warning << LL_ENDL; - gtk_is_good = false; - } else { - LL_INFOS() << "- GTK version is good." << LL_ENDL; - } - - done_gtk_diag = true; - } - - return gtk_is_good; -} -#endif // LL_GTK - - -#if LL_X11 -// static -Window LLWindowSDL::get_SDL_XWindowID(void) -{ - if (gWindowImplementation) { - return gWindowImplementation->mSDL_XWindowID; - } - return None; -} - -//static -Display* LLWindowSDL::get_SDL_Display(void) -{ - if (gWindowImplementation) { - return gWindowImplementation->mSDL_Display; - } - return NULL; -} -#endif // LL_X11 - - -LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, - const std::string& title, 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(callbacks, fullscreen, flags), - Lock_Display(NULL), - Unlock_Display(NULL), mGamma(1.0f) -{ - // Initialize the keyboard - gKeyboard = new LLKeyboardSDL(); - gKeyboard->setCallbacks(callbacks); - // Note that we can't set up key-repeat until after SDL has init'd video - - // Ignore use_gl for now, only used for drones on PC - mWindow = NULL; - mNeedsResize = false; - mOverrideAspectRatio = 0.f; - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - mHaveInputFocus = -1; - mIsMinimized = -1; - mFSAASamples = fsaa_samples; - -#if LL_X11 - mSDL_XWindowID = None; - mSDL_Display = NULL; -#endif // LL_X11 - -#if LL_GTK - // We MUST be the first to initialize GTK so that GTK doesn't get badly - // initialized with a non-C locale and cause lots of serious random - // weirdness. - ll_try_gtk_init(); -#endif // LL_GTK - - // Assume 4:3 aspect ratio until we know better - mOriginalAspectRatio = 1024.0 / 768.0; - - if (title.empty()) - mWindowTitle = "SDL Window"; // *FIX: (?) - else - mWindowTitle = title; - - // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) - { - gGLManager.initGL(); - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - } - - stop_glerror(); - - // Stash an object pointer for OSMessageBox() - gWindowImplementation = this; - -#if LL_X11 - mFlashing = false; -#endif // LL_X11 - - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; -} - -static SDL_Surface *Load_BMP_Resource(const char *basename) -{ - const int PATH_BUFFER_SIZE=1000; - char path_buffer[PATH_BUFFER_SIZE]; /* Flawfinder: ignore */ - - // Figure out where our BMP is living on the disk - snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", - gDirUtilp->getAppRODataDir().c_str(), - gDirUtilp->getDirDelimiter().c_str(), - gDirUtilp->getDirDelimiter().c_str(), - basename); - path_buffer[PATH_BUFFER_SIZE-1] = '\0'; - - return SDL_LoadBMP(path_buffer); -} - -#if LL_X11 -// This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM -// on this machine. It works by searching /var/log/var/log/Xorg.?.log or -// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where -// '?' is the X11 display number derived from $DISPLAY -static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) -{ - const int line_buf_size = 1000; - char line_buf[line_buf_size]; - while (fgets(line_buf, line_buf_size, fp)) - { - //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; - - // Why the ad-hoc parser instead of using a regex? Our - // favourite regex implementation - libboost_regex - is - // quite a heavy and troublesome dependency for the client, so - // it seems a shame to introduce it for such a simple task. - // *FIXME: libboost_regex is a dependency now anyway, so we may - // as well use it instead of this hand-rolled nonsense. - const char *part1_template = prefix_str; - const char part2_template[] = " kB"; - char *part1 = strstr(line_buf, part1_template); - if (part1) // found start of matching line - { - part1 = &part1[strlen(part1_template)]; // -> after - char *part2 = strstr(part1, part2_template); - if (part2) // found end of matching line - { - // now everything between part1 and part2 is - // supposed to be numeric, describing the - // number of kB of Video RAM supported - int rtn = 0; - for (; part1 < part2; ++part1) - { - if (*part1 < '0' || *part1 > '9') - { - // unexpected char, abort parse - rtn = 0; - break; - } - rtn *= 10; - rtn += (*part1) - '0'; - } - if (rtn > 0) - { - // got the kB number. return it now. - return rtn; - } - } - } - } - return 0; // 'could not detect' -} - -static int x11_detect_VRAM_kb() -{ - std::string x_log_location("/var/log/"); - std::string fname; - int rtn = 0; // 'could not detect' - int display_num = 0; - FILE *fp; - char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc - // parse DISPLAY number so we can go grab the right log file - if (display_env[0] == ':' && - display_env[1] >= '0' && display_env[1] <= '9') - { - display_num = display_env[1] - '0'; - } - - // *TODO: we could be smarter and see which of Xorg/XFree86 has the - // freshest time-stamp. - - // Try Xorg log first - fname = x_log_location; - fname += "Xorg."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - // Try old XFree86 log otherwise - fname = x_log_location; - fname += "XFree86."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - } - } - return rtn; -} -#endif // LL_X11 - -bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync) -{ - //bool glneedsinit = false; - - LL_INFOS() << "createContext, fullscreen=" << fullscreen << - " size=" << width << "x" << height << LL_ENDL; - - // captures don't survive contexts - mGrabbyKeyFlags = 0; - mReallyCapturedCount = 0; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) - { - LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); - return false; - } - - SDL_version c_sdl_version; - SDL_VERSION(&c_sdl_version); - LL_INFOS() << "Compiled against SDL " - << int(c_sdl_version.major) << "." - << int(c_sdl_version.minor) << "." - << int(c_sdl_version.patch) << LL_ENDL; - const SDL_version *r_sdl_version; - r_sdl_version = SDL_Linked_Version(); - LL_INFOS() << " Running against SDL " - << int(r_sdl_version->major) << "." - << int(r_sdl_version->minor) << "." - << int(r_sdl_version->patch) << LL_ENDL; - - const SDL_VideoInfo *video_info = SDL_GetVideoInfo( ); - if (!video_info) - { - LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; - setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); - return false; - } - - if (video_info->current_h > 0) - { - mOriginalAspectRatio = (float)video_info->current_w / (float)video_info->current_h; - LL_INFOS() << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << LL_ENDL; - } - - SDL_EnableUNICODE(1); - SDL_WM_SetCaption(mWindowTitle.c_str(), mWindowTitle.c_str()); - - // Set the application icon. - SDL_Surface *bmpsurface; - bmpsurface = Load_BMP_Resource("ll_icon.BMP"); - if (bmpsurface) - { - // This attempts to give a black-keyed mask to the icon. - SDL_SetColorKey(bmpsurface, - SDL_SRCCOLORKEY, - SDL_MapRGB(bmpsurface->format, 0,0,0) ); - SDL_WM_SetIcon(bmpsurface, NULL); - // The SDL examples cheerfully avoid freeing the icon - // surface, but I'm betting that's leaky. - SDL_FreeSurface(bmpsurface); - bmpsurface = NULL; - } - - // note: these SetAttributes make Tom's 9600-on-AMD64 fail to - // get a visual, but it's broken anyway when it does, and without - // these SetAttributes we might easily get an avoidable substandard - // visual to work with on most other machines. - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); - // We need stencil support for a few (minor) things. - if (!getenv("LL_GL_NO_STENCIL")) - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); - - // *FIX: try to toggle vsync here? - - mFullscreen = fullscreen; - - int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; - - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - if (mFSAASamples > 0) - { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); - } - - mSDLFlags = sdlflags; - - if (mFullscreen) - { - LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; - - // 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_INFOS() << "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_INFOS() << "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_INFOS() << " (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; - } - - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); - if (!mWindow && bits > 16) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); - } - - if (mWindow) - { - mFullscreen = true; - mFullscreenWidth = mWindow->w; - mFullscreenHeight = mWindow->h; - mFullscreenBits = mWindow->format->BitsPerPixel; - mFullscreenRefresh = -1; - - LL_INFOS() << "Running at " << mFullscreenWidth - << "x" << mFullscreenHeight - << "x" << mFullscreenBits - << " @ " << mFullscreenRefresh - << LL_ENDL; - } - else - { - LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; - // 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)) - { - if (width == 0) - width = 1024; - if (height == 0) - width = 768; - - LL_INFOS() << "createContext: creating window " << width << "x" << height << "x" << bits << LL_ENDL; - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); - if (!mWindow && bits > 16) - { - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); - } - - if (!mWindow) - { - LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; - setupFailure("Window creation error", "Error", OSMB_OK); - return false; - } - } else if (!mFullscreen && (mWindow != NULL)) - { - LL_INFOS() << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << LL_ENDL; - } - - // Detect video memory size. -# if LL_X11 - gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024; - if (gGLManager.mVRAM != 0) - { - LL_INFOS() << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; - } else -# endif // LL_X11 - { - // fallback to letting SDL detect VRAM. - // note: I've not seen SDL's detection ever actually find - // VRAM != 0, but if SDL *does* detect it then that's a bonus. - gGLManager.mVRAM = video_info->video_mem / 1024; - if (gGLManager.mVRAM != 0) - { - LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; - } - } - // If VRAM is not detected, that is handled later - - // *TODO: Now would be an appropriate time to check for some - // explicitly unsupported cards. - //const char* RENDERER = (const char*) glGetString(GL_RENDERER); - - GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits; - - glGetIntegerv(GL_RED_BITS, &redBits); - glGetIntegerv(GL_GREEN_BITS, &greenBits); - glGetIntegerv(GL_BLUE_BITS, &blueBits); - glGetIntegerv(GL_ALPHA_BITS, &alphaBits); - glGetIntegerv(GL_DEPTH_BITS, &depthBits); - glGetIntegerv(GL_STENCIL_BITS, &stencilBits); - - LL_INFOS() << "GL buffer:" << LL_ENDL; - LL_INFOS() << " Red Bits " << S32(redBits) << LL_ENDL; - LL_INFOS() << " Green Bits " << S32(greenBits) << LL_ENDL; - LL_INFOS() << " Blue Bits " << S32(blueBits) << LL_ENDL; - LL_INFOS() << " Alpha Bits " << S32(alphaBits) << LL_ENDL; - LL_INFOS() << " Depth Bits " << S32(depthBits) << LL_ENDL; - LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL; - - GLint colorBits = redBits + greenBits + blueBits + alphaBits; - // fixme: actually, it's REALLY important for picking that we get at - // least 8 bits each of red,green,blue. Alpha we can be a bit more - // relaxed about if we have to. - 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 0 // *FIX: we're going to brave it for now... - 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; - } -#endif - -#if LL_X11 - /* Grab the window manager specific information */ - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - if ( SDL_GetWMInfo(&info) ) - { - /* Save the information for later use */ - if ( info.subsystem == SDL_SYSWM_X11 ) - { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.wmwindow; - Lock_Display = info.info.x11.lock_func; - Unlock_Display = info.info.x11.unlock_func; - } - else - { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; - } - } - else - { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; - } -#endif // LL_X11 - - - //make sure multisampling is disabled by default - glDisable(GL_MULTISAMPLE_ARB); - - // We need to do this here, once video is init'd - if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, - SDL_DEFAULT_REPEAT_INTERVAL)) - LL_WARNS() << "Couldn't enable key-repeat: " << SDL_GetError() <mX = 0; - position->mY = 0; - return true; -} - -bool LLWindowSDL::getSize(LLCoordScreen *size) -{ - if (mWindow) - { - size->mX = mWindow->w; - size->mY = mWindow->h; - return (true); - } - - return (false); -} - -bool LLWindowSDL::getSize(LLCoordWindow *size) -{ - if (mWindow) - { - size->mX = mWindow->w; - size->mY = mWindow->h; - return (true); - } - - return (false); -} - -bool LLWindowSDL::setPosition(const LLCoordScreen position) -{ - if(mWindow) - { - // *FIX: (?) - //MacMoveWindow(mWindow, position.mX, position.mY, false); - } - - return true; -} - -bool LLWindowSDL::setSizeImpl(const LLCoordScreen size) -{ - if(mWindow) - { - // Push a resize event onto SDL's queue - we'll handle it - // when it comes out again. - SDL_Event event; - event.type = SDL_VIDEORESIZE; - event.resize.w = size.mX; - event.resize.h = size.mY; - SDL_PushEvent(&event); // copied into queue - - return true; - } - - return false; -} - -bool LLWindowSDL::setSizeImpl(const LLCoordWindow size) -{ - if(mWindow) - { - // Push a resize event onto SDL's queue - we'll handle it - // when it comes out again. - SDL_Event event; - event.type = SDL_VIDEORESIZE; - event.resize.w = size.mX; - event.resize.h = size.mY; - SDL_PushEvent(&event); // copied into queue - - return true; - } - - return false; -} - - -void LLWindowSDL::swapBuffers() -{ - if (mWindow) - { - SDL_GL_SwapBuffers(); - } -} - -U32 LLWindowSDL::getFSAASamples() -{ - return mFSAASamples; -} - -void LLWindowSDL::setFSAASamples(const U32 samples) -{ - mFSAASamples = samples; -} - -F32 LLWindowSDL::getGamma() -{ - return 1/mGamma; -} - -bool LLWindowSDL::restoreGamma() -{ - //CGDisplayRestoreColorSyncSettings(); - SDL_SetGamma(1.0f, 1.0f, 1.0f); - return true; -} - -bool LLWindowSDL::setGamma(const F32 gamma) -{ - mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; - mGamma = 1/mGamma; - SDL_SetGamma(mGamma, mGamma, mGamma); - return true; -} - -bool LLWindowSDL::isCursorHidden() -{ - return mCursorHidden; -} - - - -// Constrains the mouse to the window. -void LLWindowSDL::setMouseClipping( bool b ) -{ - //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); -} - -// virtual -void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately) -{ - LLWindow::setMinSize(min_width, min_height, enforce_immediately); - -#if LL_X11 - // Set the minimum size limits for X11 window - // so the window manager doesn't allow resizing below those limits. - XSizeHints* hints = XAllocSizeHints(); - hints->flags |= PMinSize; - hints->min_width = mMinWindowWidth; - hints->min_height = mMinWindowHeight; - - XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); - - XFree(hints); -#endif -} - -bool LLWindowSDL::setCursorPosition(const LLCoordWindow position) -{ - bool result = true; - LLCoordScreen screen_pos; - - if (!convertCoords(position, &screen_pos)) - { - return false; - } - - //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; - - // do the actual forced cursor move. - SDL_WarpMouse(screen_pos.mX, screen_pos.mY); - - //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; - - return result; -} - -bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) -{ - //Point cursor_point; - LLCoordScreen screen_pos; - - //GetMouse(&cursor_point); - int x, y; - SDL_GetMouseState(&x, &y); - - screen_pos.mX = x; - screen_pos.mY = y; - - return convertCoords(screen_pos, position); -} - - -F32 LLWindowSDL::getNativeAspectRatio() -{ -#if 0 - // RN: this hack presumes that the largest supported resolution is monitor-limited - // and that pixels in that mode are square, therefore defining the native aspect ratio - // of the monitor...this seems to work to a close approximation for most CRTs/LCDs - S32 num_resolutions; - LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - - - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); - //rn: AC -#endif - - // MBW -- there are a couple of bad assumptions here. One is that the display list won't include - // ridiculous resolutions nobody would ever use. The other is that the list is in order. - - // New assumptions: - // - pixels are square (the only reasonable choice, really) - // - The user runs their display at a native resolution, so the resolution of the display - // when the app is launched has an aspect ratio that matches the monitor. - - //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has - // been born out in my experience. - // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) - // The ordering of display list is a blind assumption though, so we should check for max values - // Things might be different on the Mac though, so I'll defer to MBW - - // 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 LLWindowSDL::getPixelAspectRatio() -{ - F32 pixel_aspect = 1.f; - if (getFullscreen()) - { - LLCoordScreen screen_size; - if (getSize(&screen_size)) - { - pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } - } - - return pixel_aspect; -} - - -// This is to support 'temporarily windowed' mode so that -// dialogs are still usable in fullscreen. -void LLWindowSDL::beforeDialog() -{ - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - - LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; - - if (SDLReallyCaptureInput(false)) // must ungrab input so popup works! - { - if (mFullscreen) - { - // need to temporarily go non-fullscreen; bless SDL - // for providing a SDL_WM_ToggleFullScreen() - though - // it only works in X11 - if (running_x11 && mWindow) - { - SDL_WM_ToggleFullScreen(mWindow); - } - } - } - -#if LL_X11 - if (mSDL_Display) - { - // Everything that we/SDL asked for should happen before we - // potentially hand control over to GTK. - maybe_lock_display(); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -#endif // LL_X11 - -#if LL_GTK - // this is a good time to grab some GTK version information for - // diagnostics, if not already done. - ll_try_gtk_init(); -#endif // LL_GTK - - maybe_lock_display(); -} - -void LLWindowSDL::afterDialog() -{ - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - - LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; - - maybe_unlock_display(); - - if (mFullscreen) - { - // need to restore fullscreen mode after dialog - only works - // in X11 - if (running_x11 && mWindow) - { - SDL_WM_ToggleFullScreen(mWindow); - } - } -} - - -#if LL_X11 -// set/reset the XWMHints flag for 'urgency' that usually makes the icon flash -void LLWindowSDL::x11_set_urgent(bool urgent) -{ - if (mSDL_Display && !mFullscreen) - { - XWMHints *wm_hints; - - LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; - - maybe_lock_display(); - wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); - if (!wm_hints) - wm_hints = XAllocWMHints(); - - if (urgent) - wm_hints->flags |= XUrgencyHint; - else - wm_hints->flags &= ~XUrgencyHint; - - XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); - XFree(wm_hints); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -} -#endif // LL_X11 - -void LLWindowSDL::flashIcon(F32 seconds) -{ -#if !LL_X11 - LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; -#else - LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; - - F32 remaining_time = mFlashTimer.getRemainingTimeF32(); - if (remaining_time < seconds) - remaining_time = seconds; - mFlashTimer.reset(); - mFlashTimer.setTimerExpirySec(remaining_time); - - x11_set_urgent(true); - mFlashing = true; -#endif // LL_X11 -} - - -#if LL_GTK -bool LLWindowSDL::isClipboardTextAvailable() -{ - if (ll_try_gtk_init()) - { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - return gtk_clipboard_wait_is_text_available(clipboard) ? - true : false; - } - return false; // failure -} - -bool LLWindowSDL::pasteTextFromClipboard(LLWString &text) -{ - if (ll_try_gtk_init()) - { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - gchar * const data = gtk_clipboard_wait_for_text(clipboard); - if (data) - { - text = LLWString(utf8str_to_wstring(data)); - g_free(data); - return true; - } - } - return false; // failure -} - -bool LLWindowSDL::copyTextToClipboard(const LLWString &text) -{ - if (ll_try_gtk_init()) - { - const std::string utf8 = wstring_to_utf8str(text); - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_NONE); - gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); - return true; - } - return false; // failure -} - - -bool LLWindowSDL::isPrimaryTextAvailable() -{ - if (ll_try_gtk_init()) - { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - return gtk_clipboard_wait_is_text_available(clipboard) ? - true : false; - } - return false; // failure -} - -bool LLWindowSDL::pasteTextFromPrimary(LLWString &text) -{ - if (ll_try_gtk_init()) - { - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gchar * const data = gtk_clipboard_wait_for_text(clipboard); - if (data) - { - text = LLWString(utf8str_to_wstring(data)); - g_free(data); - return true; - } - } - return false; // failure -} - -bool LLWindowSDL::copyTextToPrimary(const LLWString &text) -{ - if (ll_try_gtk_init()) - { - const std::string utf8 = wstring_to_utf8str(text); - GtkClipboard * const clipboard = - gtk_clipboard_get(GDK_SELECTION_PRIMARY); - gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); - return true; - } - return false; // failure -} - -#else - -bool LLWindowSDL::isClipboardTextAvailable() -{ - return false; // unsupported -} - -bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) -{ - return false; // unsupported -} - -bool LLWindowSDL::copyTextToClipboard(const LLWString &s) -{ - return false; // unsupported -} - -bool LLWindowSDL::isPrimaryTextAvailable() -{ - return false; // unsupported -} - -bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) -{ - return false; // unsupported -} - -bool LLWindowSDL::copyTextToPrimary(const LLWString &s) -{ - return false; // unsupported -} - -#endif // LL_GTK - -LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) -{ - if (!mSupportedResolutions) - { - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - mNumSupportedResolutions = 0; - - SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); - if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) - { - int count = 0; - while (*modes && countw; - int h = r->h; - if ((w >= 800) && (h >= 600)) - { - // make sure we don't add the same resolution multiple times! - if ( (mNumSupportedResolutions == 0) || - ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && - (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = w; - mSupportedResolutions[mNumSupportedResolutions].mHeight = h; - mNumSupportedResolutions++; - } - } - } - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; -} - -bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ - if (!to) - return false; - - to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; - - return true; -} - -bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ - if (!to) - return false; - - to->mX = from.mX; - to->mY = mWindow->h - from.mY - 1; - - return true; -} - -bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - if (!to) - return false; - - // In the fullscreen case, window and screen coordinates are the same. - to->mX = from.mX; - to->mY = from.mY; - return (true); -} - -bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ - if (!to) - return false; - - // In the fullscreen case, window and screen coordinates are the same. - to->mX = from.mX; - to->mY = from.mY; - return (true); -} - -bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - -bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ - LLCoordWindow window_coord; - - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); -} - - - - -void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) -{ - destroyContext(); - - OSMessageBox(text, caption, type); -} - -bool LLWindowSDL::SDLReallyCaptureInput(bool capture) -{ - // note: this used to be safe to call nestedly, but in the - // end that's not really a wise usage pattern, so don't. - - if (capture) - mReallyCapturedCount = 1; - else - mReallyCapturedCount = 0; - - SDL_GrabMode wantmode, newmode; - if (mReallyCapturedCount <= 0) // uncapture - { - wantmode = SDL_GRAB_OFF; - } else // capture - { - wantmode = SDL_GRAB_ON; - } - - if (mReallyCapturedCount < 0) // yuck, imbalance. - { - mReallyCapturedCount = 0; - LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; - } - - if (!mFullscreen) /* only bother if we're windowed anyway */ - { -#if LL_X11 - if (mSDL_Display) - { - /* we dirtily mix raw X11 with SDL so that our pointer - isn't (as often) constrained to the limits of the - window while grabbed, which feels nicer and - hopefully eliminates some reported 'sticky pointer' - problems. We use raw X11 instead of - SDL_WM_GrabInput() because the latter constrains - the pointer to the window and also steals all - *keyboard* input from the window manager, which was - frustrating users. */ - int result; - if (wantmode == SDL_GRAB_ON) - { - //LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; - //newmode = SDL_WM_GrabInput(wantmode); - maybe_lock_display(); - result = XGrabPointer(mSDL_Display, mSDL_XWindowID, - True, 0, GrabModeAsync, - GrabModeAsync, - None, None, CurrentTime); - maybe_unlock_display(); - if (GrabSuccess == result) - newmode = SDL_GRAB_ON; - else - newmode = SDL_GRAB_OFF; - } else if (wantmode == SDL_GRAB_OFF) - { - //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; - newmode = SDL_GRAB_OFF; - //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); - - maybe_lock_display(); - XUngrabPointer(mSDL_Display, CurrentTime); - // Make sure the ungrab happens RIGHT NOW. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } else - { - newmode = SDL_GRAB_QUERY; // neutral - } - } else // not actually running on X11, for some reason - newmode = wantmode; -#endif // LL_X11 - } else { - // pretend we got what we wanted, when really we don't care. - newmode = wantmode; - } - - // return boolean success for whether we ended up in the desired state - return (capture && SDL_GRAB_ON==newmode) || - (!capture && SDL_GRAB_OFF==newmode); -} - -U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) -{ - /* part of the fix for SL-13243: Some popular window managers like - to totally eat alt-drag for the purposes of moving windows. We - spoil their day by acquiring the exclusive X11 mouse lock for as - long as ALT is held down, so the window manager can't easily - see what's happening. Tested successfully with Metacity. - And... do the same with CTRL, for other darn WMs. We don't - care about other metakeys as SL doesn't use them with dragging - (for now). */ - - /* We maintain a bitmap of critical keys which are up and down - instead of simply key-counting, because SDL sometimes reports - misbalanced keyup/keydown event pairs to us for whatever reason. */ - - U32 mask = 0; - switch (keysym) - { - case SDLK_LALT: - mask = 1U << 0; break; - case SDLK_RALT: - mask = 1U << 1; break; - case SDLK_LCTRL: - mask = 1U << 2; break; - case SDLK_RCTRL: - mask = 1U << 3; break; - default: - break; - } - - if (gain) - mGrabbyKeyFlags |= mask; - else - mGrabbyKeyFlags &= ~mask; - - //LL_INFOS() << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << LL_ENDL; - - /* 0 means we don't need to mousegrab, otherwise grab. */ - return mGrabbyKeyFlags; -} - - -void check_vm_bloat() -{ -#if LL_LINUX - // watch our own VM and RSS sizes, warn if we bloated rapidly - static const std::string STATS_FILE = "/proc/self/stat"; - FILE *fp = fopen(STATS_FILE.c_str(), "r"); - if (fp) - { - static long long last_vm_size = 0; - static long long last_rss_size = 0; - const long long significant_vm_difference = 250 * 1024*1024; - const long long significant_rss_difference = 50 * 1024*1024; - long long this_vm_size = 0; - long long this_rss_size = 0; - - ssize_t res; - size_t dummy; - char *ptr = NULL; - for (int i=0; i<22; ++i) // parse past the values we don't want - { - res = getdelim(&ptr, &dummy, ' ', fp); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - free(ptr); - ptr = NULL; - } - // 23rd space-delimited entry is vsize - res = getdelim(&ptr, &dummy, ' ', fp); - llassert(ptr); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - this_vm_size = atoll(ptr); - free(ptr); - ptr = NULL; - // 24th space-delimited entry is RSS - res = getdelim(&ptr, &dummy, ' ', fp); - llassert(ptr); - if (-1 == res) - { - LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; - goto finally; - } - this_rss_size = getpagesize() * atoll(ptr); - free(ptr); - ptr = NULL; - - LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; - - if (llabs(last_vm_size - this_vm_size) > - significant_vm_difference) - { - if (this_vm_size > last_vm_size) - { - LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - else - { - LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - } - - if (llabs(last_rss_size - this_rss_size) > - significant_rss_difference) - { - if (this_rss_size > last_rss_size) - { - LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - else - { - LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; - } - } - - last_rss_size = this_rss_size; - last_vm_size = this_vm_size; - -finally: - if (NULL != ptr) - { - free(ptr); - ptr = NULL; - } - fclose(fp); - } -#endif // LL_LINUX -} - - -// virtual -void LLWindowSDL::processMiscNativeEvents() -{ -#if LL_GTK - // Pump GTK events to avoid starvation for: - // * DBUS servicing - // * Anything else which quietly hooks into the default glib/GTK loop - if (ll_try_gtk_init()) - { - // Yuck, Mozilla's GTK callbacks play with the locale - push/pop - // the locale to protect it, as exotic/non-C locales - // causes our code lots of general critical weirdness - // and crashness. (SL-35450) - static std::string saved_locale; - saved_locale = ll_safe_string(setlocale(LC_ALL, NULL)); - - // Pump until we've nothing left to do or passed 1/15th of a - // second pumping for this frame. - static LLTimer pump_timer; - pump_timer.reset(); - pump_timer.setTimerExpirySec(1.0f / 15.0f); - do { - // Always do at least one non-blocking pump - gtk_main_iteration_do(false); - } while (gtk_events_pending() && - !pump_timer.hasExpired()); - - setlocale(LC_ALL, saved_locale.c_str() ); - } -#endif // LL_GTK - - // hack - doesn't belong here - but this is just for debugging - if (getenv("LL_DEBUG_BLOAT")) - { - check_vm_bloat(); - } -} - -void LLWindowSDL::gatherInput() -{ - const Uint32 CLICK_THRESHOLD = 300; // milliseconds - static int leftClick = 0; - static int rightClick = 0; - static Uint32 lastLeftDown = 0; - static Uint32 lastRightDown = 0; - SDL_Event event; - - // Handle all outstanding SDL events - while (SDL_PollEvent(&event)) - { - switch (event.type) - { - case SDL_MOUSEMOTION: - { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); - mCallbacks->handleMouseMove(this, openGlCoord, mask); - break; - } - - case SDL_KEYDOWN: - mKeyScanCode = event.key.keysym.scancode; - mKeyVirtualKey = event.key.keysym.unicode; - mKeyModifiers = event.key.keysym.mod; - - gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); - // part of the fix for SL-13243 - if (SDLCheckGrabbyKeys(event.key.keysym.sym, true) != 0) - SDLReallyCaptureInput(true); - - if (event.key.keysym.unicode) - { - handleUnicodeUTF16(event.key.keysym.unicode, - gKeyboard->currentMask(false)); - } - break; - - case SDL_KEYUP: - mKeyScanCode = event.key.keysym.scancode; - mKeyVirtualKey = event.key.keysym.unicode; - mKeyModifiers = event.key.keysym.mod; - - if (SDLCheckGrabbyKeys(event.key.keysym.sym, false) == 0) - SDLReallyCaptureInput(false); // part of the fix for SL-13243 - - gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); - break; - - case SDL_MOUSEBUTTONDOWN: - { - bool isDoubleClick = false; - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); - - if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... - { - Uint32 now = SDL_GetTicks(); - if ((now - lastLeftDown) > CLICK_THRESHOLD) - leftClick = 1; - else - { - if (++leftClick >= 2) - { - leftClick = 0; - isDoubleClick = true; - } - } - lastLeftDown = now; - } - else if (event.button.button == SDL_BUTTON_RIGHT) - { - Uint32 now = SDL_GetTicks(); - if ((now - lastRightDown) > CLICK_THRESHOLD) - rightClick = 1; - else - { - if (++rightClick >= 2) - { - rightClick = 0; - isDoubleClick = true; - } - } - lastRightDown = now; - } - - if (event.button.button == SDL_BUTTON_LEFT) // left - { - if (isDoubleClick) - mCallbacks->handleDoubleClick(this, openGlCoord, mask); - else - mCallbacks->handleMouseDown(this, openGlCoord, mask); - } - - else if (event.button.button == SDL_BUTTON_RIGHT) // right - { - mCallbacks->handleRightMouseDown(this, openGlCoord, mask); - } - - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle - { - mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); - } - else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, -1); - else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, 1); - - break; - } - - case SDL_MOUSEBUTTONUP: - { - LLCoordWindow winCoord(event.button.x, event.button.y); - LLCoordGL openGlCoord; - convertCoords(winCoord, &openGlCoord); - MASK mask = gKeyboard->currentMask(true); - - if (event.button.button == SDL_BUTTON_LEFT) // left - mCallbacks->handleMouseUp(this, openGlCoord, mask); - else if (event.button.button == SDL_BUTTON_RIGHT) // right - mCallbacks->handleRightMouseUp(this, openGlCoord, mask); - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle - mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); - // don't handle mousewheel here... - - break; - } - - case SDL_VIDEOEXPOSE: // VIDEOEXPOSE doesn't specify the damage, but hey, it's OpenGL...repaint the whole thing! - mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h); - break; - - case SDL_VIDEORESIZE: // *FIX: handle this? - { - LL_INFOS() << "Handling a resize event: " << event.resize.w << - "x" << event.resize.h << LL_ENDL; - - S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); - S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); - - // *FIX: I'm not sure this is necessary! - mWindow = SDL_SetVideoMode(width, height, 32, mSDLFlags); - if (!mWindow) - { - // *FIX: More informative dialog? - LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL; - if(mCallbacks->handleCloseRequest(this)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - break; - } - - mCallbacks->handleResize(this, width, height); - break; - } - case SDL_ACTIVEEVENT: - if (event.active.state & SDL_APPINPUTFOCUS) - { - // Note that for SDL (particularly on X11), keyboard - // and mouse focus are independent things. Here we are - // tracking keyboard focus state changes. - - // We have to do our own state massaging because SDL - // can send us two unfocus events in a row for example, - // which confuses the focus code [SL-24071]. - if (event.active.gain != mHaveInputFocus) - { - mHaveInputFocus = !!event.active.gain; - - if (mHaveInputFocus) - mCallbacks->handleFocus(this); - else - mCallbacks->handleFocusLost(this); - } - } - if (event.active.state & SDL_APPACTIVE) - { - // Change in iconification/minimization state. - if ((!event.active.gain) != mIsMinimized) - { - mIsMinimized = (!event.active.gain); - - mCallbacks->handleActivate(this, !mIsMinimized); - LL_INFOS() << "SDL deiconification state switched to " << bool(event.active.gain) << LL_ENDL; - } - else - { - LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << bool(event.active.gain) << LL_ENDL; - } - } - break; - - case SDL_QUIT: - if(mCallbacks->handleCloseRequest(this)) - { - // Get the app to initiate cleanup. - mCallbacks->handleQuit(this); - // The app is responsible for calling destroyWindow when done with GL - } - break; - default: - //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; - break; - } - } - - updateCursor(); - -#if LL_X11 - // This is a good time to stop flashing the icon if our mFlashTimer has - // expired. - if (mFlashing && mFlashTimer.hasExpired()) - { - x11_set_urgent(false); - mFlashing = false; - } -#endif // LL_X11 -} - -static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) -{ - SDL_Cursor *sdlcursor = NULL; - SDL_Surface *bmpsurface; - - // Load cursor pixel data from BMP file - bmpsurface = Load_BMP_Resource(filename); - if (bmpsurface && bmpsurface->w%8==0) - { - SDL_Surface *cursurface; - LL_DEBUGS() << "Loaded cursor file " << filename << " " - << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; - cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, - bmpsurface->w, - bmpsurface->h, - 32, - SDL_SwapLE32(0xFFU), - SDL_SwapLE32(0xFF00U), - SDL_SwapLE32(0xFF0000U), - SDL_SwapLE32(0xFF000000U)); - SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); - - // Blit the cursor pixel data onto a 32-bit RGBA surface so we - // only have to cope with processing one type of pixel format. - if (0 == SDL_BlitSurface(bmpsurface, NULL, - cursurface, NULL)) - { - // n.b. we already checked that width is a multiple of 8. - const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; - unsigned char *cursor_data = new unsigned char[bitmap_bytes]; - unsigned char *cursor_mask = new unsigned char[bitmap_bytes]; - memset(cursor_data, 0, bitmap_bytes); - memset(cursor_mask, 0, bitmap_bytes); - int i,j; - // Walk the RGBA cursor pixel data, extracting both data and - // mask to build SDL-friendly cursor bitmaps from. The mask - // is inferred by color-keying against 200,200,200 - for (i=0; ih; ++i) { - for (j=0; jw; ++j) { - U8 *pixelp = - ((U8*)cursurface->pixels) - + cursurface->pitch * i - + j*cursurface->format->BytesPerPixel; - U8 srcred = pixelp[0]; - U8 srcgreen = pixelp[1]; - U8 srcblue = pixelp[2]; - bool mask_bit = (srcred != 200) - || (srcgreen != 200) - || (srcblue != 200); - bool data_bit = mask_bit && (srcgreen <= 80);//not 0x80 - unsigned char bit_offset = (cursurface->w/8) * i - + j/8; - cursor_data[bit_offset] |= (data_bit) << (7 - (j&7)); - cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7)); - } - } - sdlcursor = SDL_CreateCursor((Uint8*)cursor_data, - (Uint8*)cursor_mask, - cursurface->w, cursurface->h, - hotx, hoty); - delete[] cursor_data; - delete[] cursor_mask; - } else { - LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; - } - SDL_FreeSurface(cursurface); - SDL_FreeSurface(bmpsurface); - } else { - LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; - } - - return sdlcursor; -} - -void LLWindowSDL::updateCursor() -{ - if (ATIbug) { - // cursor-updating is very flaky when this bug is - // present; do nothing. - return; - } - - if (mCurrentCursor != mNextCursor) - { - if (mNextCursor < UI_CURSOR_COUNT) - { - SDL_Cursor *sdlcursor = mSDLCursors[mNextCursor]; - // Try to default to the arrow for any cursors that - // did not load correctly. - if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW]) - sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; - if (sdlcursor) - SDL_SetCursor(sdlcursor); - } else { - LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; - } - mCurrentCursor = mNextCursor; - } -} - -void LLWindowSDL::initCursors() -{ - int i; - // Blank the cursor pointer array for those we may miss. - for (i=0; ibeforeDialog(); - - if (LLWindowSDL::ll_try_gtk_init()) - { - GtkWidget *win = NULL; - - LL_INFOS() << "Creating a dialog because we're in windowed mode and GTK is happy." << LL_ENDL; - - GtkDialogFlags flags = GTK_DIALOG_MODAL; - GtkMessageType messagetype; - GtkButtonsType buttons; - switch (type) - { - default: - case OSMB_OK: - messagetype = GTK_MESSAGE_WARNING; - buttons = GTK_BUTTONS_OK; - break; - case OSMB_OKCANCEL: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_OK_CANCEL; - break; - case OSMB_YESNO: - messagetype = GTK_MESSAGE_QUESTION; - buttons = GTK_BUTTONS_YES_NO; - break; - } - win = gtk_message_dialog_new(NULL, flags, messagetype, buttons, "%s", - text.c_str()); - -# if LL_X11 - // Make GTK tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (gWindowImplementation && - gWindowImplementation->mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - gtk_window_set_position(GTK_WINDOW(win), - GTK_WIN_POS_CENTER_ON_PARENT); - - gtk_window_set_type_hint(GTK_WINDOW(win), - GDK_WINDOW_TYPE_HINT_DIALOG); - - if (!caption.empty()) - gtk_window_set_title(GTK_WINDOW(win), caption.c_str()); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - - // we should be able to use a gtk_dialog_run(), but it's - // apparently not written to exist in a world without a higher - // gtk_main(), so we manage its signal/destruction outselves. - gtk_widget_show_all (win); - gtk_main(); - - //LL_INFOS() << "response: " << response << LL_ENDL; - switch (response) - { - case GTK_RESPONSE_OK: rtn = OSBTN_OK; break; - case GTK_RESPONSE_YES: rtn = OSBTN_YES; break; - case GTK_RESPONSE_NO: rtn = OSBTN_NO; break; - case GTK_RESPONSE_APPLY: rtn = OSBTN_OK; break; - case GTK_RESPONSE_NONE: - case GTK_RESPONSE_CANCEL: - case GTK_RESPONSE_CLOSE: - case GTK_RESPONSE_DELETE_EVENT: - default: rtn = OSBTN_CANCEL; - } - } - else - { - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - LL_INFOS() << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << LL_ENDL; - rtn = OSBTN_OK; - } - - if(gWindowImplementation != NULL) - gWindowImplementation->afterDialog(); - - return rtn; -} - -static void color_changed_callback(GtkWidget *widget, - gpointer user_data) -{ - GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget); - GdkColor *colorp = (GdkColor*)user_data; - - gtk_color_selection_get_current_color(colorsel, colorp); -} - - -/* - Make the raw keyboard data available - used to poke through to LLQtWebKit so - that Qt/Webkit has access to the virtual keycodes etc. that it needs -*/ -LLSD LLWindowSDL::getNativeKeyData() -{ - LLSD result = LLSD::emptyMap(); - - U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! - - // we go through so many levels of device abstraction that I can't really guess - // what a plugin under GDK under Qt under SL under SDL under X11 considers - // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* - // to match GDK consts, but that may be co-incidence. - modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; - modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift - modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; - modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; - modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl - modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested - modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested - // *todo: test ALTs - I don't have a case for testing these. Do you? - // *todo: NUM? - I don't care enough right now (and it's not a GDK modifier). - - result["scan_code"] = (S32)mKeyScanCode; - result["virtual_key"] = (S32)mKeyVirtualKey; - result["modifiers"] = (S32)modifiers; - - return result; -} - - -bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - bool rtn = false; - - beforeDialog(); - - if (ll_try_gtk_init()) - { - GtkWidget *win = NULL; - - win = gtk_color_selection_dialog_new(NULL); - -# if LL_X11 - // Get GTK to tell the window manager to associate this - // dialog with our non-GTK SDL window, which should try - // to keep it on top etc. - if (mSDL_XWindowID != None) - { - gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin - GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); - gdk_window_set_transient_for(GTK_WIDGET(win)->window, - gdkwin); - } -# endif //LL_X11 - - GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); - - GdkColor color, orig_color; - orig_color.pixel = 0; - orig_color.red = guint16(65535 * *r); - orig_color.green= guint16(65535 * *g); - orig_color.blue = guint16(65535 * *b); - color = orig_color; - - gtk_color_selection_set_previous_color (colorsel, &color); - gtk_color_selection_set_current_color (colorsel, &color); - gtk_color_selection_set_has_palette (colorsel, true); - gtk_color_selection_set_has_opacity_control(colorsel, false); - - gint response = GTK_RESPONSE_NONE; - g_signal_connect (win, - "response", - G_CALLBACK (response_callback), - &response); - - g_signal_connect (G_OBJECT (colorsel), "color_changed", - G_CALLBACK (color_changed_callback), - &color); - - gtk_window_set_modal(GTK_WINDOW(win), true); - gtk_widget_show_all(win); - // hide the help button - we don't service it. - gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); - gtk_main(); - - if (response == GTK_RESPONSE_OK && - (orig_color.red != color.red - || orig_color.green != color.green - || orig_color.blue != color.blue) ) - { - *r = color.red / 65535.0f; - *g = color.green / 65535.0f; - *b = color.blue / 65535.0f; - rtn = true; - } - } - - afterDialog(); - - return rtn; -} -#else -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) -{ - LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; - return 0; -} - -bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ - return (false); -} -#endif // LL_GTK - -#if LL_LINUX -// extracted from spawnWebBrowser for clarity and to eliminate -// compiler confusion regarding close(int fd) vs. LLWindow::close() -void exec_cmd(const std::string& cmd, const std::string& arg) -{ - char* const argv[] = {(char*)cmd.c_str(), (char*)arg.c_str(), NULL}; - fflush(NULL); - pid_t pid = fork(); - if (pid == 0) - { // child - // disconnect from stdin/stdout/stderr, or child will - // keep our output pipe undesirably alive if it outlives us. - close(0); - close(1); - close(2); - // end ourself by running the command - execv(cmd.c_str(), argv); /* Flawfinder: ignore */ - // if execv returns at all, there was a problem. - LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; - _exit(1); // _exit because we don't want atexit() clean-up! - } else { - if (pid > 0) - { - // parent - wait for child to die - int childExitStatus; - waitpid(pid, &childExitStatus, 0); - } else { - LL_WARNS() << "fork failure." << LL_ENDL; - } - } -} -#endif - -// Open a URL with the user's default web browser. -// Must begin with protocol identifier. -void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) -{ - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; - -#if LL_LINUX -# if LL_X11 - if (mSDL_Display) - { - maybe_lock_display(); - // Just in case - before forking. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -# endif // LL_X11 - - std::string cmd, arg; - cmd = gDirUtilp->getAppRODataDir(); - cmd += gDirUtilp->getDirDelimiter(); - cmd += "etc"; - cmd += gDirUtilp->getDirDelimiter(); - cmd += "launch_url.sh"; - arg = escaped_url; - exec_cmd(cmd, arg); -#endif // LL_LINUX - - LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; -} - - -void *LLWindowSDL::getPlatformWindow() -{ -#if LL_GTK && LL_LLMOZLIB_ENABLED - if (LLWindowSDL::ll_try_gtk_init()) - { - maybe_lock_display(); - - GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP); - // Why a layout widget? A MozContainer would be ideal, but - // it involves exposing Mozilla headers to mozlib-using apps. - // A layout widget with a GtkWindow parent has the desired - // properties of being plain GTK, having a window, and being - // derived from a GtkContainer. - GtkWidget *rtnw = gtk_layout_new(NULL, NULL); - gtk_container_add(GTK_CONTAINER(owin), rtnw); - gtk_widget_realize(rtnw); - GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); - - maybe_unlock_display(); - - return rtnw; - } -#endif // LL_GTK && LL_LLMOZLIB_ENABLED - // Unixoid mozilla really needs GTK. - return NULL; -} - -void LLWindowSDL::bringToFront() -{ - // This is currently used when we are 'launched' to a specific - // map position externally. - LL_INFOS() << "bringToFront" << LL_ENDL; -#if LL_X11 - if (mSDL_Display && !mFullscreen) - { - maybe_lock_display(); - XRaiseWindow(mSDL_Display, mSDL_XWindowID); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -#endif // LL_X11 -} - -//static -std::vector LLWindowSDL::getDynamicFallbackFontList() -{ - // Use libfontconfig to find us a nice ordered list of fallback fonts - // specific to this system. - std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); - const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them - // Our 'ideal' font properties which define the sorting results. - // slant=0 means Roman, index=0 means the first face in a font file - // (the one we actually use), weight=80 means medium weight, - // spacing=0 means proportional spacing. - std::string sort_order("slant=0:index=0:weight=80:spacing=0"); - // elide_unicode_coverage removes fonts from the list whose unicode - // range is covered by fonts earlier in the list. This usually - // removes ~90% of the fonts as redundant (which is great because - // the font list can be huge), but might unnecessarily reduce the - // renderable range if for some reason our FreeType actually fails - // to use some of the fonts we want it to. - const bool elide_unicode_coverage = true; - std::vector rtns; - FcFontSet *fs = NULL; - FcPattern *sortpat = NULL; - - LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; - - // If the user has a system-wide language preference, then favor - // fonts from that language group. This doesn't affect the types - // of languages that can be displayed, but ensures that their - // preferred language is rendered from a single consistent font where - // possible. - FL_Locale *locale = NULL; - FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); - if (success != 0) - { - if (success >= 2 && locale->lang) // confident! - { - LL_INFOS("AppInit") << "Language " << locale->lang << LL_ENDL; - LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; - LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; - - LL_INFOS() << "Preferring fonts of language: " - << locale->lang - << LL_ENDL; - sort_order = "lang=" + std::string(locale->lang) + ":" - + sort_order; - } - } - FL_FreeLocale(&locale); - - if (!FcInit()) - { - LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; - rtns.push_back(final_fallback); - return rtns; - } - - sortpat = FcNameParse((FcChar8*) sort_order.c_str()); - if (sortpat) - { - // Sort the list of system fonts from most-to-least-desirable. - FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); - FcPatternDestroy(sortpat); - } - - int found_font_count = 0; - if (fs) - { - // Get the full pathnames to the fonts, where available, - // which is what we really want. - found_font_count = fs->nfont; - for (int i=0; infont; ++i) - { - FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && filename) - { - rtns.push_back(std::string((const char*)filename)); - if (rtns.size() >= max_font_count_cutoff) - break; // hit limit - } - } - FcFontSetDestroy (fs); - } - - LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector::iterator it = rtns.begin(); - it != rtns.end(); - ++it) - { - LL_DEBUGS() << " file: " << *it << LL_ENDL; - } - LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; - - rtns.push_back(final_fallback); - return rtns; -} - -#endif // LL_SDL +/** + * @file llwindowsdl.cpp + * @brief SDL implementation of LLWindow class + * @author This module has many fathers, and it shows. + * + * $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$ + */ + +#if LL_SDL + +#include "linden_common.h" + +#include "llwindowsdl.h" + +#include "llwindowcallbacks.h" +#include "llkeyboardsdl.h" + +#include "llerror.h" +#include "llgl.h" +#include "llstring.h" +#include "lldir.h" +#include "llfindlocale.h" + +#if LL_GTK +extern "C" { +# include "gtk/gtk.h" +} +#include +#endif // LL_GTK + +extern "C" { +# include "fontconfig/fontconfig.h" +} + +#if LL_LINUX +// not necessarily available on random SDL platforms, so #if LL_LINUX +// for execv(), waitpid(), fork() +# include +# include +# include +#endif // LL_LINUX + +extern bool gDebugWindowProc; + +const S32 MAX_NUM_RESOLUTIONS = 200; + +// static variable for ATI mouse cursor crash work-around: +static bool ATIbug = false; + +// +// LLWindowSDL +// + +#if LL_X11 +# include +#endif //LL_X11 + +// TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar +// set of reasons): Stash a pointer to the LLWindowSDL object here and +// maintain in the constructor and destructor. This assumes that there will +// be only one object of this class at any time. Currently this is true. +static LLWindowSDL *gWindowImplementation = NULL; + + +void maybe_lock_display(void) +{ + if (gWindowImplementation && gWindowImplementation->Lock_Display) { + gWindowImplementation->Lock_Display(); + } +} + + +void maybe_unlock_display(void) +{ + if (gWindowImplementation && gWindowImplementation->Unlock_Display) { + gWindowImplementation->Unlock_Display(); + } +} + + +#if LL_GTK +// Lazily initialize and check the runtime GTK version for goodness. +// static +bool LLWindowSDL::ll_try_gtk_init(void) +{ + static bool done_gtk_diag = false; + static bool gtk_is_good = false; + static bool done_setlocale = false; + static bool tried_gtk_init = false; + + if (!done_setlocale) + { + LL_INFOS() << "Starting GTK Initialization." << LL_ENDL; + maybe_lock_display(); + gtk_disable_setlocale(); + maybe_unlock_display(); + done_setlocale = true; + } + + if (!tried_gtk_init) + { + tried_gtk_init = true; + if (!g_thread_supported ()) g_thread_init (NULL); + maybe_lock_display(); + gtk_is_good = gtk_init_check(NULL, NULL); + maybe_unlock_display(); + if (!gtk_is_good) + LL_WARNS() << "GTK Initialization failed." << LL_ENDL; + } + + if (gtk_is_good && !done_gtk_diag) + { + LL_INFOS() << "GTK Initialized." << LL_ENDL; + LL_INFOS() << "- Compiled against GTK version " + << GTK_MAJOR_VERSION << "." + << GTK_MINOR_VERSION << "." + << GTK_MICRO_VERSION << LL_ENDL; + LL_INFOS() << "- Running against GTK version " + << gtk_major_version << "." + << gtk_minor_version << "." + << gtk_micro_version << LL_ENDL; + maybe_lock_display(); + const gchar* gtk_warning = gtk_check_version( + GTK_MAJOR_VERSION, + GTK_MINOR_VERSION, + GTK_MICRO_VERSION); + maybe_unlock_display(); + if (gtk_warning) + { + LL_WARNS() << "- GTK COMPATIBILITY WARNING: " << + gtk_warning << LL_ENDL; + gtk_is_good = false; + } else { + LL_INFOS() << "- GTK version is good." << LL_ENDL; + } + + done_gtk_diag = true; + } + + return gtk_is_good; +} +#endif // LL_GTK + + +#if LL_X11 +// static +Window LLWindowSDL::get_SDL_XWindowID(void) +{ + if (gWindowImplementation) { + return gWindowImplementation->mSDL_XWindowID; + } + return None; +} + +//static +Display* LLWindowSDL::get_SDL_Display(void) +{ + if (gWindowImplementation) { + return gWindowImplementation->mSDL_Display; + } + return NULL; +} +#endif // LL_X11 + + +LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, + const std::string& title, 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(callbacks, fullscreen, flags), + Lock_Display(NULL), + Unlock_Display(NULL), mGamma(1.0f) +{ + // Initialize the keyboard + gKeyboard = new LLKeyboardSDL(); + gKeyboard->setCallbacks(callbacks); + // Note that we can't set up key-repeat until after SDL has init'd video + + // Ignore use_gl for now, only used for drones on PC + mWindow = NULL; + mNeedsResize = false; + mOverrideAspectRatio = 0.f; + mGrabbyKeyFlags = 0; + mReallyCapturedCount = 0; + mHaveInputFocus = -1; + mIsMinimized = -1; + mFSAASamples = fsaa_samples; + +#if LL_X11 + mSDL_XWindowID = None; + mSDL_Display = NULL; +#endif // LL_X11 + +#if LL_GTK + // We MUST be the first to initialize GTK so that GTK doesn't get badly + // initialized with a non-C locale and cause lots of serious random + // weirdness. + ll_try_gtk_init(); +#endif // LL_GTK + + // Assume 4:3 aspect ratio until we know better + mOriginalAspectRatio = 1024.0 / 768.0; + + if (title.empty()) + mWindowTitle = "SDL Window"; // *FIX: (?) + else + mWindowTitle = title; + + // Create the GL context and set it up for windowed or fullscreen, as appropriate. + if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + { + gGLManager.initGL(); + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + } + + stop_glerror(); + + // Stash an object pointer for OSMessageBox() + gWindowImplementation = this; + +#if LL_X11 + mFlashing = false; +#endif // LL_X11 + + mKeyScanCode = 0; + mKeyVirtualKey = 0; + mKeyModifiers = KMOD_NONE; +} + +static SDL_Surface *Load_BMP_Resource(const char *basename) +{ + const int PATH_BUFFER_SIZE=1000; + char path_buffer[PATH_BUFFER_SIZE]; /* Flawfinder: ignore */ + + // Figure out where our BMP is living on the disk + snprintf(path_buffer, PATH_BUFFER_SIZE-1, "%s%sres-sdl%s%s", + gDirUtilp->getAppRODataDir().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + gDirUtilp->getDirDelimiter().c_str(), + basename); + path_buffer[PATH_BUFFER_SIZE-1] = '\0'; + + return SDL_LoadBMP(path_buffer); +} + +#if LL_X11 +// This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM +// on this machine. It works by searching /var/log/var/log/Xorg.?.log or +// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where +// '?' is the X11 display number derived from $DISPLAY +static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) +{ + const int line_buf_size = 1000; + char line_buf[line_buf_size]; + while (fgets(line_buf, line_buf_size, fp)) + { + //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; + + // Why the ad-hoc parser instead of using a regex? Our + // favourite regex implementation - libboost_regex - is + // quite a heavy and troublesome dependency for the client, so + // it seems a shame to introduce it for such a simple task. + // *FIXME: libboost_regex is a dependency now anyway, so we may + // as well use it instead of this hand-rolled nonsense. + const char *part1_template = prefix_str; + const char part2_template[] = " kB"; + char *part1 = strstr(line_buf, part1_template); + if (part1) // found start of matching line + { + part1 = &part1[strlen(part1_template)]; // -> after + char *part2 = strstr(part1, part2_template); + if (part2) // found end of matching line + { + // now everything between part1 and part2 is + // supposed to be numeric, describing the + // number of kB of Video RAM supported + int rtn = 0; + for (; part1 < part2; ++part1) + { + if (*part1 < '0' || *part1 > '9') + { + // unexpected char, abort parse + rtn = 0; + break; + } + rtn *= 10; + rtn += (*part1) - '0'; + } + if (rtn > 0) + { + // got the kB number. return it now. + return rtn; + } + } + } + } + return 0; // 'could not detect' +} + +static int x11_detect_VRAM_kb() +{ + std::string x_log_location("/var/log/"); + std::string fname; + int rtn = 0; // 'could not detect' + int display_num = 0; + FILE *fp; + char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc + // parse DISPLAY number so we can go grab the right log file + if (display_env[0] == ':' && + display_env[1] >= '0' && display_env[1] <= '9') + { + display_num = display_env[1] - '0'; + } + + // *TODO: we could be smarter and see which of Xorg/XFree86 has the + // freshest time-stamp. + + // Try Xorg log first + fname = x_log_location; + fname += "Xorg."; + fname += ('0' + display_num); + fname += ".log"; + fp = fopen(fname.c_str(), "r"); + if (fp) + { + LL_INFOS() << "Looking in " << fname + << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); + fclose(fp); + } + } + } + } + } + else + { + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; + // Try old XFree86 log otherwise + fname = x_log_location; + fname += "XFree86."; + fname += ('0' + display_num); + fname += ".log"; + fp = fopen(fname.c_str(), "r"); + if (fp) + { + LL_INFOS() << "Looking in " << fname + << " for VRAM info..." << LL_ENDL; + rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); + fclose(fp); + if (0 == rtn) + { + fp = fopen(fname.c_str(), "r"); + if (fp) + { + rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); + fclose(fp); + } + } + } + else + { + LL_INFOS() << "Could not open " << fname + << " - skipped." << LL_ENDL; + } + } + return rtn; +} +#endif // LL_X11 + +bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync) +{ + //bool glneedsinit = false; + + LL_INFOS() << "createContext, fullscreen=" << fullscreen << + " size=" << width << "x" << height << LL_ENDL; + + // captures don't survive contexts + mGrabbyKeyFlags = 0; + mReallyCapturedCount = 0; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + LL_INFOS() << "sdl_init() failed! " << SDL_GetError() << LL_ENDL; + setupFailure("sdl_init() failure, window creation error", "error", OSMB_OK); + return false; + } + + SDL_version c_sdl_version; + SDL_VERSION(&c_sdl_version); + LL_INFOS() << "Compiled against SDL " + << int(c_sdl_version.major) << "." + << int(c_sdl_version.minor) << "." + << int(c_sdl_version.patch) << LL_ENDL; + const SDL_version *r_sdl_version; + r_sdl_version = SDL_Linked_Version(); + LL_INFOS() << " Running against SDL " + << int(r_sdl_version->major) << "." + << int(r_sdl_version->minor) << "." + << int(r_sdl_version->patch) << LL_ENDL; + + const SDL_VideoInfo *video_info = SDL_GetVideoInfo( ); + if (!video_info) + { + LL_INFOS() << "SDL_GetVideoInfo() failed! " << SDL_GetError() << LL_ENDL; + setupFailure("SDL_GetVideoInfo() failed, Window creation error", "Error", OSMB_OK); + return false; + } + + if (video_info->current_h > 0) + { + mOriginalAspectRatio = (float)video_info->current_w / (float)video_info->current_h; + LL_INFOS() << "Original aspect ratio was " << video_info->current_w << ":" << video_info->current_h << "=" << mOriginalAspectRatio << LL_ENDL; + } + + SDL_EnableUNICODE(1); + SDL_WM_SetCaption(mWindowTitle.c_str(), mWindowTitle.c_str()); + + // Set the application icon. + SDL_Surface *bmpsurface; + bmpsurface = Load_BMP_Resource("ll_icon.BMP"); + if (bmpsurface) + { + // This attempts to give a black-keyed mask to the icon. + SDL_SetColorKey(bmpsurface, + SDL_SRCCOLORKEY, + SDL_MapRGB(bmpsurface->format, 0,0,0) ); + SDL_WM_SetIcon(bmpsurface, NULL); + // The SDL examples cheerfully avoid freeing the icon + // surface, but I'm betting that's leaky. + SDL_FreeSurface(bmpsurface); + bmpsurface = NULL; + } + + // note: these SetAttributes make Tom's 9600-on-AMD64 fail to + // get a visual, but it's broken anyway when it does, and without + // these SetAttributes we might easily get an avoidable substandard + // visual to work with on most other machines. + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE,8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bits <= 16) ? 16 : 24); + // We need stencil support for a few (minor) things. + if (!getenv("LL_GL_NO_STENCIL")) + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, (bits <= 16) ? 1 : 8); + + // *FIX: try to toggle vsync here? + + mFullscreen = fullscreen; + + int sdlflags = SDL_OPENGL | SDL_RESIZABLE | SDL_ANYFORMAT; + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + if (mFSAASamples > 0) + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); + } + + mSDLFlags = sdlflags; + + if (mFullscreen) + { + LL_INFOS() << "createContext: setting up fullscreen " << width << "x" << height << LL_ENDL; + + // 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_INFOS() << "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_INFOS() << "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_INFOS() << " (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; + } + + mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); + if (!mWindow && bits > 16) + { + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + mWindow = SDL_SetVideoMode(width, height, bits, sdlflags | SDL_FULLSCREEN); + } + + if (mWindow) + { + mFullscreen = true; + mFullscreenWidth = mWindow->w; + mFullscreenHeight = mWindow->h; + mFullscreenBits = mWindow->format->BitsPerPixel; + mFullscreenRefresh = -1; + + LL_INFOS() << "Running at " << mFullscreenWidth + << "x" << mFullscreenHeight + << "x" << mFullscreenBits + << " @ " << mFullscreenRefresh + << LL_ENDL; + } + else + { + LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; + // 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)) + { + if (width == 0) + width = 1024; + if (height == 0) + width = 768; + + LL_INFOS() << "createContext: creating window " << width << "x" << height << "x" << bits << LL_ENDL; + mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); + if (!mWindow && bits > 16) + { + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + mWindow = SDL_SetVideoMode(width, height, bits, sdlflags); + } + + if (!mWindow) + { + LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("Window creation error", "Error", OSMB_OK); + return false; + } + } else if (!mFullscreen && (mWindow != NULL)) + { + LL_INFOS() << "createContext: SKIPPING - !fullscreen, but +mWindow " << width << "x" << height << "x" << bits << LL_ENDL; + } + + // Detect video memory size. +# if LL_X11 + gGLManager.mVRAM = x11_detect_VRAM_kb() / 1024; + if (gGLManager.mVRAM != 0) + { + LL_INFOS() << "X11 log-parser detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + } else +# endif // LL_X11 + { + // fallback to letting SDL detect VRAM. + // note: I've not seen SDL's detection ever actually find + // VRAM != 0, but if SDL *does* detect it then that's a bonus. + gGLManager.mVRAM = video_info->video_mem / 1024; + if (gGLManager.mVRAM != 0) + { + LL_INFOS() << "SDL detected " << gGLManager.mVRAM << "MB VRAM." << LL_ENDL; + } + } + // If VRAM is not detected, that is handled later + + // *TODO: Now would be an appropriate time to check for some + // explicitly unsupported cards. + //const char* RENDERER = (const char*) glGetString(GL_RENDERER); + + GLint depthBits, stencilBits, redBits, greenBits, blueBits, alphaBits; + + glGetIntegerv(GL_RED_BITS, &redBits); + glGetIntegerv(GL_GREEN_BITS, &greenBits); + glGetIntegerv(GL_BLUE_BITS, &blueBits); + glGetIntegerv(GL_ALPHA_BITS, &alphaBits); + glGetIntegerv(GL_DEPTH_BITS, &depthBits); + glGetIntegerv(GL_STENCIL_BITS, &stencilBits); + + LL_INFOS() << "GL buffer:" << LL_ENDL; + LL_INFOS() << " Red Bits " << S32(redBits) << LL_ENDL; + LL_INFOS() << " Green Bits " << S32(greenBits) << LL_ENDL; + LL_INFOS() << " Blue Bits " << S32(blueBits) << LL_ENDL; + LL_INFOS() << " Alpha Bits " << S32(alphaBits) << LL_ENDL; + LL_INFOS() << " Depth Bits " << S32(depthBits) << LL_ENDL; + LL_INFOS() << " Stencil Bits " << S32(stencilBits) << LL_ENDL; + + GLint colorBits = redBits + greenBits + blueBits + alphaBits; + // fixme: actually, it's REALLY important for picking that we get at + // least 8 bits each of red,green,blue. Alpha we can be a bit more + // relaxed about if we have to. + 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 0 // *FIX: we're going to brave it for now... + 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; + } +#endif + +#if LL_X11 + /* Grab the window manager specific information */ + SDL_SysWMinfo info; + SDL_VERSION(&info.version); + if ( SDL_GetWMInfo(&info) ) + { + /* Save the information for later use */ + if ( info.subsystem == SDL_SYSWM_X11 ) + { + mSDL_Display = info.info.x11.display; + mSDL_XWindowID = info.info.x11.wmwindow; + Lock_Display = info.info.x11.lock_func; + Unlock_Display = info.info.x11.unlock_func; + } + else + { + LL_WARNS() << "We're not running under X11? Wild." + << LL_ENDL; + } + } + else + { + LL_WARNS() << "We're not running under any known WM. Wild." + << LL_ENDL; + } +#endif // LL_X11 + + + //make sure multisampling is disabled by default + glDisable(GL_MULTISAMPLE_ARB); + + // We need to do this here, once video is init'd + if (-1 == SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, + SDL_DEFAULT_REPEAT_INTERVAL)) + LL_WARNS() << "Couldn't enable key-repeat: " << SDL_GetError() <mX = 0; + position->mY = 0; + return true; +} + +bool LLWindowSDL::getSize(LLCoordScreen *size) +{ + if (mWindow) + { + size->mX = mWindow->w; + size->mY = mWindow->h; + return (true); + } + + return (false); +} + +bool LLWindowSDL::getSize(LLCoordWindow *size) +{ + if (mWindow) + { + size->mX = mWindow->w; + size->mY = mWindow->h; + return (true); + } + + return (false); +} + +bool LLWindowSDL::setPosition(const LLCoordScreen position) +{ + if(mWindow) + { + // *FIX: (?) + //MacMoveWindow(mWindow, position.mX, position.mY, false); + } + + return true; +} + +bool LLWindowSDL::setSizeImpl(const LLCoordScreen size) +{ + if(mWindow) + { + // Push a resize event onto SDL's queue - we'll handle it + // when it comes out again. + SDL_Event event; + event.type = SDL_VIDEORESIZE; + event.resize.w = size.mX; + event.resize.h = size.mY; + SDL_PushEvent(&event); // copied into queue + + return true; + } + + return false; +} + +bool LLWindowSDL::setSizeImpl(const LLCoordWindow size) +{ + if(mWindow) + { + // Push a resize event onto SDL's queue - we'll handle it + // when it comes out again. + SDL_Event event; + event.type = SDL_VIDEORESIZE; + event.resize.w = size.mX; + event.resize.h = size.mY; + SDL_PushEvent(&event); // copied into queue + + return true; + } + + return false; +} + + +void LLWindowSDL::swapBuffers() +{ + if (mWindow) + { + SDL_GL_SwapBuffers(); + } +} + +U32 LLWindowSDL::getFSAASamples() +{ + return mFSAASamples; +} + +void LLWindowSDL::setFSAASamples(const U32 samples) +{ + mFSAASamples = samples; +} + +F32 LLWindowSDL::getGamma() +{ + return 1/mGamma; +} + +bool LLWindowSDL::restoreGamma() +{ + //CGDisplayRestoreColorSyncSettings(); + SDL_SetGamma(1.0f, 1.0f, 1.0f); + return true; +} + +bool LLWindowSDL::setGamma(const F32 gamma) +{ + mGamma = gamma; + if (mGamma == 0) mGamma = 0.1f; + mGamma = 1/mGamma; + SDL_SetGamma(mGamma, mGamma, mGamma); + return true; +} + +bool LLWindowSDL::isCursorHidden() +{ + return mCursorHidden; +} + + + +// Constrains the mouse to the window. +void LLWindowSDL::setMouseClipping( bool b ) +{ + //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); +} + +// virtual +void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately) +{ + LLWindow::setMinSize(min_width, min_height, enforce_immediately); + +#if LL_X11 + // Set the minimum size limits for X11 window + // so the window manager doesn't allow resizing below those limits. + XSizeHints* hints = XAllocSizeHints(); + hints->flags |= PMinSize; + hints->min_width = mMinWindowWidth; + hints->min_height = mMinWindowHeight; + + XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); + + XFree(hints); +#endif +} + +bool LLWindowSDL::setCursorPosition(const LLCoordWindow position) +{ + bool result = true; + LLCoordScreen screen_pos; + + if (!convertCoords(position, &screen_pos)) + { + return false; + } + + //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; + + // do the actual forced cursor move. + SDL_WarpMouse(screen_pos.mX, screen_pos.mY); + + //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; + + return result; +} + +bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) +{ + //Point cursor_point; + LLCoordScreen screen_pos; + + //GetMouse(&cursor_point); + int x, y; + SDL_GetMouseState(&x, &y); + + screen_pos.mX = x; + screen_pos.mY = y; + + return convertCoords(screen_pos, position); +} + + +F32 LLWindowSDL::getNativeAspectRatio() +{ +#if 0 + // RN: this hack presumes that the largest supported resolution is monitor-limited + // and that pixels in that mode are square, therefore defining the native aspect ratio + // of the monitor...this seems to work to a close approximation for most CRTs/LCDs + S32 num_resolutions; + LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); + + + return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); + //rn: AC +#endif + + // MBW -- there are a couple of bad assumptions here. One is that the display list won't include + // ridiculous resolutions nobody would ever use. The other is that the list is in order. + + // New assumptions: + // - pixels are square (the only reasonable choice, really) + // - The user runs their display at a native resolution, so the resolution of the display + // when the app is launched has an aspect ratio that matches the monitor. + + //RN: actually, the assumption that there are no ridiculous resolutions (above the display's native capabilities) has + // been born out in my experience. + // Pixels are often not square (just ask the people who run their LCDs at 1024x768 or 800x600 when running fullscreen, like me) + // The ordering of display list is a blind assumption though, so we should check for max values + // Things might be different on the Mac though, so I'll defer to MBW + + // 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 LLWindowSDL::getPixelAspectRatio() +{ + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + if (getSize(&screen_size)) + { + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } + } + + return pixel_aspect; +} + + +// This is to support 'temporarily windowed' mode so that +// dialogs are still usable in fullscreen. +void LLWindowSDL::beforeDialog() +{ + bool running_x11 = false; +#if LL_X11 + running_x11 = (mSDL_XWindowID != None); +#endif //LL_X11 + + LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; + + if (SDLReallyCaptureInput(false)) // must ungrab input so popup works! + { + if (mFullscreen) + { + // need to temporarily go non-fullscreen; bless SDL + // for providing a SDL_WM_ToggleFullScreen() - though + // it only works in X11 + if (running_x11 && mWindow) + { + SDL_WM_ToggleFullScreen(mWindow); + } + } + } + +#if LL_X11 + if (mSDL_Display) + { + // Everything that we/SDL asked for should happen before we + // potentially hand control over to GTK. + maybe_lock_display(); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +#endif // LL_X11 + +#if LL_GTK + // this is a good time to grab some GTK version information for + // diagnostics, if not already done. + ll_try_gtk_init(); +#endif // LL_GTK + + maybe_lock_display(); +} + +void LLWindowSDL::afterDialog() +{ + bool running_x11 = false; +#if LL_X11 + running_x11 = (mSDL_XWindowID != None); +#endif //LL_X11 + + LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; + + maybe_unlock_display(); + + if (mFullscreen) + { + // need to restore fullscreen mode after dialog - only works + // in X11 + if (running_x11 && mWindow) + { + SDL_WM_ToggleFullScreen(mWindow); + } + } +} + + +#if LL_X11 +// set/reset the XWMHints flag for 'urgency' that usually makes the icon flash +void LLWindowSDL::x11_set_urgent(bool urgent) +{ + if (mSDL_Display && !mFullscreen) + { + XWMHints *wm_hints; + + LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; + + maybe_lock_display(); + wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); + if (!wm_hints) + wm_hints = XAllocWMHints(); + + if (urgent) + wm_hints->flags |= XUrgencyHint; + else + wm_hints->flags &= ~XUrgencyHint; + + XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); + XFree(wm_hints); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +} +#endif // LL_X11 + +void LLWindowSDL::flashIcon(F32 seconds) +{ +#if !LL_X11 + LL_INFOS() << "Stub LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; +#else + LL_INFOS() << "X11 LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; + + F32 remaining_time = mFlashTimer.getRemainingTimeF32(); + if (remaining_time < seconds) + remaining_time = seconds; + mFlashTimer.reset(); + mFlashTimer.setTimerExpirySec(remaining_time); + + x11_set_urgent(true); + mFlashing = true; +#endif // LL_X11 +} + + +#if LL_GTK +bool LLWindowSDL::isClipboardTextAvailable() +{ + if (ll_try_gtk_init()) + { + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_NONE); + return gtk_clipboard_wait_is_text_available(clipboard) ? + true : false; + } + return false; // failure +} + +bool LLWindowSDL::pasteTextFromClipboard(LLWString &text) +{ + if (ll_try_gtk_init()) + { + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_NONE); + gchar * const data = gtk_clipboard_wait_for_text(clipboard); + if (data) + { + text = LLWString(utf8str_to_wstring(data)); + g_free(data); + return true; + } + } + return false; // failure +} + +bool LLWindowSDL::copyTextToClipboard(const LLWString &text) +{ + if (ll_try_gtk_init()) + { + const std::string utf8 = wstring_to_utf8str(text); + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_NONE); + gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); + return true; + } + return false; // failure +} + + +bool LLWindowSDL::isPrimaryTextAvailable() +{ + if (ll_try_gtk_init()) + { + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_SELECTION_PRIMARY); + return gtk_clipboard_wait_is_text_available(clipboard) ? + true : false; + } + return false; // failure +} + +bool LLWindowSDL::pasteTextFromPrimary(LLWString &text) +{ + if (ll_try_gtk_init()) + { + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_SELECTION_PRIMARY); + gchar * const data = gtk_clipboard_wait_for_text(clipboard); + if (data) + { + text = LLWString(utf8str_to_wstring(data)); + g_free(data); + return true; + } + } + return false; // failure +} + +bool LLWindowSDL::copyTextToPrimary(const LLWString &text) +{ + if (ll_try_gtk_init()) + { + const std::string utf8 = wstring_to_utf8str(text); + GtkClipboard * const clipboard = + gtk_clipboard_get(GDK_SELECTION_PRIMARY); + gtk_clipboard_set_text(clipboard, utf8.c_str(), utf8.length()); + return true; + } + return false; // failure +} + +#else + +bool LLWindowSDL::isClipboardTextAvailable() +{ + return false; // unsupported +} + +bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) +{ + return false; // unsupported +} + +bool LLWindowSDL::copyTextToClipboard(const LLWString &s) +{ + return false; // unsupported +} + +bool LLWindowSDL::isPrimaryTextAvailable() +{ + return false; // unsupported +} + +bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) +{ + return false; // unsupported +} + +bool LLWindowSDL::copyTextToPrimary(const LLWString &s) +{ + return false; // unsupported +} + +#endif // LL_GTK + +LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) +{ + if (!mSupportedResolutions) + { + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + mNumSupportedResolutions = 0; + + SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN); + if ( (modes != NULL) && (modes != ((SDL_Rect **) -1)) ) + { + int count = 0; + while (*modes && countw; + int h = r->h; + if ((w >= 800) && (h >= 600)) + { + // make sure we don't add the same resolution multiple times! + if ( (mNumSupportedResolutions == 0) || + ((mSupportedResolutions[mNumSupportedResolutions-1].mWidth != w) && + (mSupportedResolutions[mNumSupportedResolutions-1].mHeight != h)) ) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = w; + mSupportedResolutions[mNumSupportedResolutions].mHeight = h; + mNumSupportedResolutions++; + } + } + } + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + +bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + if (!to) + return false; + + to->mX = from.mX; + to->mY = mWindow->h - from.mY - 1; + + return true; +} + +bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + if (!to) + return false; + + to->mX = from.mX; + to->mY = mWindow->h - from.mY - 1; + + return true; +} + +bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + if (!to) + return false; + + // In the fullscreen case, window and screen coordinates are the same. + to->mX = from.mX; + to->mY = from.mY; + return (true); +} + +bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + if (!to) + return false; + + // In the fullscreen case, window and screen coordinates are the same. + to->mX = from.mX; + to->mY = from.mY; + return (true); +} + +bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + +bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; + + return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +} + + + + +void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) +{ + destroyContext(); + + OSMessageBox(text, caption, type); +} + +bool LLWindowSDL::SDLReallyCaptureInput(bool capture) +{ + // note: this used to be safe to call nestedly, but in the + // end that's not really a wise usage pattern, so don't. + + if (capture) + mReallyCapturedCount = 1; + else + mReallyCapturedCount = 0; + + SDL_GrabMode wantmode, newmode; + if (mReallyCapturedCount <= 0) // uncapture + { + wantmode = SDL_GRAB_OFF; + } else // capture + { + wantmode = SDL_GRAB_ON; + } + + if (mReallyCapturedCount < 0) // yuck, imbalance. + { + mReallyCapturedCount = 0; + LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; + } + + if (!mFullscreen) /* only bother if we're windowed anyway */ + { +#if LL_X11 + if (mSDL_Display) + { + /* we dirtily mix raw X11 with SDL so that our pointer + isn't (as often) constrained to the limits of the + window while grabbed, which feels nicer and + hopefully eliminates some reported 'sticky pointer' + problems. We use raw X11 instead of + SDL_WM_GrabInput() because the latter constrains + the pointer to the window and also steals all + *keyboard* input from the window manager, which was + frustrating users. */ + int result; + if (wantmode == SDL_GRAB_ON) + { + //LL_INFOS() << "X11 POINTER GRABBY" << LL_ENDL; + //newmode = SDL_WM_GrabInput(wantmode); + maybe_lock_display(); + result = XGrabPointer(mSDL_Display, mSDL_XWindowID, + True, 0, GrabModeAsync, + GrabModeAsync, + None, None, CurrentTime); + maybe_unlock_display(); + if (GrabSuccess == result) + newmode = SDL_GRAB_ON; + else + newmode = SDL_GRAB_OFF; + } else if (wantmode == SDL_GRAB_OFF) + { + //LL_INFOS() << "X11 POINTER UNGRABBY" << LL_ENDL; + newmode = SDL_GRAB_OFF; + //newmode = SDL_WM_GrabInput(SDL_GRAB_OFF); + + maybe_lock_display(); + XUngrabPointer(mSDL_Display, CurrentTime); + // Make sure the ungrab happens RIGHT NOW. + XSync(mSDL_Display, False); + maybe_unlock_display(); + } else + { + newmode = SDL_GRAB_QUERY; // neutral + } + } else // not actually running on X11, for some reason + newmode = wantmode; +#endif // LL_X11 + } else { + // pretend we got what we wanted, when really we don't care. + newmode = wantmode; + } + + // return boolean success for whether we ended up in the desired state + return (capture && SDL_GRAB_ON==newmode) || + (!capture && SDL_GRAB_OFF==newmode); +} + +U32 LLWindowSDL::SDLCheckGrabbyKeys(SDLKey keysym, bool gain) +{ + /* part of the fix for SL-13243: Some popular window managers like + to totally eat alt-drag for the purposes of moving windows. We + spoil their day by acquiring the exclusive X11 mouse lock for as + long as ALT is held down, so the window manager can't easily + see what's happening. Tested successfully with Metacity. + And... do the same with CTRL, for other darn WMs. We don't + care about other metakeys as SL doesn't use them with dragging + (for now). */ + + /* We maintain a bitmap of critical keys which are up and down + instead of simply key-counting, because SDL sometimes reports + misbalanced keyup/keydown event pairs to us for whatever reason. */ + + U32 mask = 0; + switch (keysym) + { + case SDLK_LALT: + mask = 1U << 0; break; + case SDLK_RALT: + mask = 1U << 1; break; + case SDLK_LCTRL: + mask = 1U << 2; break; + case SDLK_RCTRL: + mask = 1U << 3; break; + default: + break; + } + + if (gain) + mGrabbyKeyFlags |= mask; + else + mGrabbyKeyFlags &= ~mask; + + //LL_INFOS() << "mGrabbyKeyFlags=" << mGrabbyKeyFlags << LL_ENDL; + + /* 0 means we don't need to mousegrab, otherwise grab. */ + return mGrabbyKeyFlags; +} + + +void check_vm_bloat() +{ +#if LL_LINUX + // watch our own VM and RSS sizes, warn if we bloated rapidly + static const std::string STATS_FILE = "/proc/self/stat"; + FILE *fp = fopen(STATS_FILE.c_str(), "r"); + if (fp) + { + static long long last_vm_size = 0; + static long long last_rss_size = 0; + const long long significant_vm_difference = 250 * 1024*1024; + const long long significant_rss_difference = 50 * 1024*1024; + long long this_vm_size = 0; + long long this_rss_size = 0; + + ssize_t res; + size_t dummy; + char *ptr = NULL; + for (int i=0; i<22; ++i) // parse past the values we don't want + { + res = getdelim(&ptr, &dummy, ' ', fp); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + free(ptr); + ptr = NULL; + } + // 23rd space-delimited entry is vsize + res = getdelim(&ptr, &dummy, ' ', fp); + llassert(ptr); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + this_vm_size = atoll(ptr); + free(ptr); + ptr = NULL; + // 24th space-delimited entry is RSS + res = getdelim(&ptr, &dummy, ' ', fp); + llassert(ptr); + if (-1 == res) + { + LL_WARNS() << "Unable to parse " << STATS_FILE << LL_ENDL; + goto finally; + } + this_rss_size = getpagesize() * atoll(ptr); + free(ptr); + ptr = NULL; + + LL_INFOS() << "VM SIZE IS NOW " << (this_vm_size/(1024*1024)) << " MB, RSS SIZE IS NOW " << (this_rss_size/(1024*1024)) << " MB" << LL_ENDL; + + if (llabs(last_vm_size - this_vm_size) > + significant_vm_difference) + { + if (this_vm_size > last_vm_size) + { + LL_WARNS() << "VM size grew by " << (this_vm_size - last_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + else + { + LL_INFOS() << "VM size shrank by " << (last_vm_size - this_vm_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + } + + if (llabs(last_rss_size - this_rss_size) > + significant_rss_difference) + { + if (this_rss_size > last_rss_size) + { + LL_WARNS() << "RSS size grew by " << (this_rss_size - last_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + else + { + LL_INFOS() << "RSS size shrank by " << (last_rss_size - this_rss_size)/(1024*1024) << " MB in last frame" << LL_ENDL; + } + } + + last_rss_size = this_rss_size; + last_vm_size = this_vm_size; + +finally: + if (NULL != ptr) + { + free(ptr); + ptr = NULL; + } + fclose(fp); + } +#endif // LL_LINUX +} + + +// virtual +void LLWindowSDL::processMiscNativeEvents() +{ +#if LL_GTK + // Pump GTK events to avoid starvation for: + // * DBUS servicing + // * Anything else which quietly hooks into the default glib/GTK loop + if (ll_try_gtk_init()) + { + // Yuck, Mozilla's GTK callbacks play with the locale - push/pop + // the locale to protect it, as exotic/non-C locales + // causes our code lots of general critical weirdness + // and crashness. (SL-35450) + static std::string saved_locale; + saved_locale = ll_safe_string(setlocale(LC_ALL, NULL)); + + // Pump until we've nothing left to do or passed 1/15th of a + // second pumping for this frame. + static LLTimer pump_timer; + pump_timer.reset(); + pump_timer.setTimerExpirySec(1.0f / 15.0f); + do { + // Always do at least one non-blocking pump + gtk_main_iteration_do(false); + } while (gtk_events_pending() && + !pump_timer.hasExpired()); + + setlocale(LC_ALL, saved_locale.c_str() ); + } +#endif // LL_GTK + + // hack - doesn't belong here - but this is just for debugging + if (getenv("LL_DEBUG_BLOAT")) + { + check_vm_bloat(); + } +} + +void LLWindowSDL::gatherInput() +{ + const Uint32 CLICK_THRESHOLD = 300; // milliseconds + static int leftClick = 0; + static int rightClick = 0; + static Uint32 lastLeftDown = 0; + static Uint32 lastRightDown = 0; + SDL_Event event; + + // Handle all outstanding SDL events + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_MOUSEMOTION: + { + LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); + mCallbacks->handleMouseMove(this, openGlCoord, mask); + break; + } + + case SDL_KEYDOWN: + mKeyScanCode = event.key.keysym.scancode; + mKeyVirtualKey = event.key.keysym.unicode; + mKeyModifiers = event.key.keysym.mod; + + gKeyboard->handleKeyDown(event.key.keysym.sym, event.key.keysym.mod); + // part of the fix for SL-13243 + if (SDLCheckGrabbyKeys(event.key.keysym.sym, true) != 0) + SDLReallyCaptureInput(true); + + if (event.key.keysym.unicode) + { + handleUnicodeUTF16(event.key.keysym.unicode, + gKeyboard->currentMask(false)); + } + break; + + case SDL_KEYUP: + mKeyScanCode = event.key.keysym.scancode; + mKeyVirtualKey = event.key.keysym.unicode; + mKeyModifiers = event.key.keysym.mod; + + if (SDLCheckGrabbyKeys(event.key.keysym.sym, false) == 0) + SDLReallyCaptureInput(false); // part of the fix for SL-13243 + + gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); + break; + + case SDL_MOUSEBUTTONDOWN: + { + bool isDoubleClick = false; + LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); + + if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... + { + Uint32 now = SDL_GetTicks(); + if ((now - lastLeftDown) > CLICK_THRESHOLD) + leftClick = 1; + else + { + if (++leftClick >= 2) + { + leftClick = 0; + isDoubleClick = true; + } + } + lastLeftDown = now; + } + else if (event.button.button == SDL_BUTTON_RIGHT) + { + Uint32 now = SDL_GetTicks(); + if ((now - lastRightDown) > CLICK_THRESHOLD) + rightClick = 1; + else + { + if (++rightClick >= 2) + { + rightClick = 0; + isDoubleClick = true; + } + } + lastRightDown = now; + } + + if (event.button.button == SDL_BUTTON_LEFT) // left + { + if (isDoubleClick) + mCallbacks->handleDoubleClick(this, openGlCoord, mask); + else + mCallbacks->handleMouseDown(this, openGlCoord, mask); + } + + else if (event.button.button == SDL_BUTTON_RIGHT) // right + { + mCallbacks->handleRightMouseDown(this, openGlCoord, mask); + } + + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + { + mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); + } + else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". + mCallbacks->handleScrollWheel(this, -1); + else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". + mCallbacks->handleScrollWheel(this, 1); + + break; + } + + case SDL_MOUSEBUTTONUP: + { + LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordGL openGlCoord; + convertCoords(winCoord, &openGlCoord); + MASK mask = gKeyboard->currentMask(true); + + if (event.button.button == SDL_BUTTON_LEFT) // left + mCallbacks->handleMouseUp(this, openGlCoord, mask); + else if (event.button.button == SDL_BUTTON_RIGHT) // right + mCallbacks->handleRightMouseUp(this, openGlCoord, mask); + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle + mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); + // don't handle mousewheel here... + + break; + } + + case SDL_VIDEOEXPOSE: // VIDEOEXPOSE doesn't specify the damage, but hey, it's OpenGL...repaint the whole thing! + mCallbacks->handlePaint(this, 0, 0, mWindow->w, mWindow->h); + break; + + case SDL_VIDEORESIZE: // *FIX: handle this? + { + LL_INFOS() << "Handling a resize event: " << event.resize.w << + "x" << event.resize.h << LL_ENDL; + + S32 width = llmax(event.resize.w, (S32)mMinWindowWidth); + S32 height = llmax(event.resize.h, (S32)mMinWindowHeight); + + // *FIX: I'm not sure this is necessary! + mWindow = SDL_SetVideoMode(width, height, 32, mSDLFlags); + if (!mWindow) + { + // *FIX: More informative dialog? + LL_INFOS() << "Could not recreate context after resize! Quitting..." << LL_ENDL; + if(mCallbacks->handleCloseRequest(this)) + { + // Get the app to initiate cleanup. + mCallbacks->handleQuit(this); + // The app is responsible for calling destroyWindow when done with GL + } + break; + } + + mCallbacks->handleResize(this, width, height); + break; + } + case SDL_ACTIVEEVENT: + if (event.active.state & SDL_APPINPUTFOCUS) + { + // Note that for SDL (particularly on X11), keyboard + // and mouse focus are independent things. Here we are + // tracking keyboard focus state changes. + + // We have to do our own state massaging because SDL + // can send us two unfocus events in a row for example, + // which confuses the focus code [SL-24071]. + if (event.active.gain != mHaveInputFocus) + { + mHaveInputFocus = !!event.active.gain; + + if (mHaveInputFocus) + mCallbacks->handleFocus(this); + else + mCallbacks->handleFocusLost(this); + } + } + if (event.active.state & SDL_APPACTIVE) + { + // Change in iconification/minimization state. + if ((!event.active.gain) != mIsMinimized) + { + mIsMinimized = (!event.active.gain); + + mCallbacks->handleActivate(this, !mIsMinimized); + LL_INFOS() << "SDL deiconification state switched to " << bool(event.active.gain) << LL_ENDL; + } + else + { + LL_INFOS() << "Ignored bogus redundant SDL deiconification state switch to " << bool(event.active.gain) << LL_ENDL; + } + } + break; + + case SDL_QUIT: + if(mCallbacks->handleCloseRequest(this)) + { + // Get the app to initiate cleanup. + mCallbacks->handleQuit(this); + // The app is responsible for calling destroyWindow when done with GL + } + break; + default: + //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; + break; + } + } + + updateCursor(); + +#if LL_X11 + // This is a good time to stop flashing the icon if our mFlashTimer has + // expired. + if (mFlashing && mFlashTimer.hasExpired()) + { + x11_set_urgent(false); + mFlashing = false; + } +#endif // LL_X11 +} + +static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) +{ + SDL_Cursor *sdlcursor = NULL; + SDL_Surface *bmpsurface; + + // Load cursor pixel data from BMP file + bmpsurface = Load_BMP_Resource(filename); + if (bmpsurface && bmpsurface->w%8==0) + { + SDL_Surface *cursurface; + LL_DEBUGS() << "Loaded cursor file " << filename << " " + << bmpsurface->w << "x" << bmpsurface->h << LL_ENDL; + cursurface = SDL_CreateRGBSurface (SDL_SWSURFACE, + bmpsurface->w, + bmpsurface->h, + 32, + SDL_SwapLE32(0xFFU), + SDL_SwapLE32(0xFF00U), + SDL_SwapLE32(0xFF0000U), + SDL_SwapLE32(0xFF000000U)); + SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); + + // Blit the cursor pixel data onto a 32-bit RGBA surface so we + // only have to cope with processing one type of pixel format. + if (0 == SDL_BlitSurface(bmpsurface, NULL, + cursurface, NULL)) + { + // n.b. we already checked that width is a multiple of 8. + const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; + unsigned char *cursor_data = new unsigned char[bitmap_bytes]; + unsigned char *cursor_mask = new unsigned char[bitmap_bytes]; + memset(cursor_data, 0, bitmap_bytes); + memset(cursor_mask, 0, bitmap_bytes); + int i,j; + // Walk the RGBA cursor pixel data, extracting both data and + // mask to build SDL-friendly cursor bitmaps from. The mask + // is inferred by color-keying against 200,200,200 + for (i=0; ih; ++i) { + for (j=0; jw; ++j) { + U8 *pixelp = + ((U8*)cursurface->pixels) + + cursurface->pitch * i + + j*cursurface->format->BytesPerPixel; + U8 srcred = pixelp[0]; + U8 srcgreen = pixelp[1]; + U8 srcblue = pixelp[2]; + bool mask_bit = (srcred != 200) + || (srcgreen != 200) + || (srcblue != 200); + bool data_bit = mask_bit && (srcgreen <= 80);//not 0x80 + unsigned char bit_offset = (cursurface->w/8) * i + + j/8; + cursor_data[bit_offset] |= (data_bit) << (7 - (j&7)); + cursor_mask[bit_offset] |= (mask_bit) << (7 - (j&7)); + } + } + sdlcursor = SDL_CreateCursor((Uint8*)cursor_data, + (Uint8*)cursor_mask, + cursurface->w, cursurface->h, + hotx, hoty); + delete[] cursor_data; + delete[] cursor_mask; + } else { + LL_WARNS() << "CURSOR BLIT FAILURE, cursurface: " << cursurface << LL_ENDL; + } + SDL_FreeSurface(cursurface); + SDL_FreeSurface(bmpsurface); + } else { + LL_WARNS() << "CURSOR LOAD FAILURE " << filename << LL_ENDL; + } + + return sdlcursor; +} + +void LLWindowSDL::updateCursor() +{ + if (ATIbug) { + // cursor-updating is very flaky when this bug is + // present; do nothing. + return; + } + + if (mCurrentCursor != mNextCursor) + { + if (mNextCursor < UI_CURSOR_COUNT) + { + SDL_Cursor *sdlcursor = mSDLCursors[mNextCursor]; + // Try to default to the arrow for any cursors that + // did not load correctly. + if (!sdlcursor && mSDLCursors[UI_CURSOR_ARROW]) + sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; + if (sdlcursor) + SDL_SetCursor(sdlcursor); + } else { + LL_WARNS() << "Tried to set invalid cursor number " << mNextCursor << LL_ENDL; + } + mCurrentCursor = mNextCursor; + } +} + +void LLWindowSDL::initCursors() +{ + int i; + // Blank the cursor pointer array for those we may miss. + for (i=0; ibeforeDialog(); + + if (LLWindowSDL::ll_try_gtk_init()) + { + GtkWidget *win = NULL; + + LL_INFOS() << "Creating a dialog because we're in windowed mode and GTK is happy." << LL_ENDL; + + GtkDialogFlags flags = GTK_DIALOG_MODAL; + GtkMessageType messagetype; + GtkButtonsType buttons; + switch (type) + { + default: + case OSMB_OK: + messagetype = GTK_MESSAGE_WARNING; + buttons = GTK_BUTTONS_OK; + break; + case OSMB_OKCANCEL: + messagetype = GTK_MESSAGE_QUESTION; + buttons = GTK_BUTTONS_OK_CANCEL; + break; + case OSMB_YESNO: + messagetype = GTK_MESSAGE_QUESTION; + buttons = GTK_BUTTONS_YES_NO; + break; + } + win = gtk_message_dialog_new(NULL, flags, messagetype, buttons, "%s", + text.c_str()); + +# if LL_X11 + // Make GTK tell the window manager to associate this + // dialog with our non-GTK SDL window, which should try + // to keep it on top etc. + if (gWindowImplementation && + gWindowImplementation->mSDL_XWindowID != None) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(gWindowImplementation->mSDL_XWindowID); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, + gdkwin); + } +# endif //LL_X11 + + gtk_window_set_position(GTK_WINDOW(win), + GTK_WIN_POS_CENTER_ON_PARENT); + + gtk_window_set_type_hint(GTK_WINDOW(win), + GDK_WINDOW_TYPE_HINT_DIALOG); + + if (!caption.empty()) + gtk_window_set_title(GTK_WINDOW(win), caption.c_str()); + + gint response = GTK_RESPONSE_NONE; + g_signal_connect (win, + "response", + G_CALLBACK (response_callback), + &response); + + // we should be able to use a gtk_dialog_run(), but it's + // apparently not written to exist in a world without a higher + // gtk_main(), so we manage its signal/destruction outselves. + gtk_widget_show_all (win); + gtk_main(); + + //LL_INFOS() << "response: " << response << LL_ENDL; + switch (response) + { + case GTK_RESPONSE_OK: rtn = OSBTN_OK; break; + case GTK_RESPONSE_YES: rtn = OSBTN_YES; break; + case GTK_RESPONSE_NO: rtn = OSBTN_NO; break; + case GTK_RESPONSE_APPLY: rtn = OSBTN_OK; break; + case GTK_RESPONSE_NONE: + case GTK_RESPONSE_CANCEL: + case GTK_RESPONSE_CLOSE: + case GTK_RESPONSE_DELETE_EVENT: + default: rtn = OSBTN_CANCEL; + } + } + else + { + LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; + LL_INFOS() << "Skipping dialog because we're in fullscreen mode or GTK is not happy." << LL_ENDL; + rtn = OSBTN_OK; + } + + if(gWindowImplementation != NULL) + gWindowImplementation->afterDialog(); + + return rtn; +} + +static void color_changed_callback(GtkWidget *widget, + gpointer user_data) +{ + GtkColorSelection *colorsel = GTK_COLOR_SELECTION(widget); + GdkColor *colorp = (GdkColor*)user_data; + + gtk_color_selection_get_current_color(colorsel, colorp); +} + + +/* + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs +*/ +LLSD LLWindowSDL::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! + + // we go through so many levels of device abstraction that I can't really guess + // what a plugin under GDK under Qt under SL under SDL under X11 considers + // a 'native' modifier mask. this has been sort of reverse-engineered... they *appear* + // to match GDK consts, but that may be co-incidence. + modifiers |= (mKeyModifiers & KMOD_LSHIFT) ? 0x0001 : 0; + modifiers |= (mKeyModifiers & KMOD_RSHIFT) ? 0x0001 : 0;// munge these into the same shift + modifiers |= (mKeyModifiers & KMOD_CAPS) ? 0x0002 : 0; + modifiers |= (mKeyModifiers & KMOD_LCTRL) ? 0x0004 : 0; + modifiers |= (mKeyModifiers & KMOD_RCTRL) ? 0x0004 : 0;// munge these into the same ctrl + modifiers |= (mKeyModifiers & KMOD_LALT) ? 0x0008 : 0;// untested + modifiers |= (mKeyModifiers & KMOD_RALT) ? 0x0008 : 0;// untested + // *todo: test ALTs - I don't have a case for testing these. Do you? + // *todo: NUM? - I don't care enough right now (and it's not a GDK modifier). + + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["modifiers"] = (S32)modifiers; + + return result; +} + + +bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) +{ + bool rtn = false; + + beforeDialog(); + + if (ll_try_gtk_init()) + { + GtkWidget *win = NULL; + + win = gtk_color_selection_dialog_new(NULL); + +# if LL_X11 + // Get GTK to tell the window manager to associate this + // dialog with our non-GTK SDL window, which should try + // to keep it on top etc. + if (mSDL_XWindowID != None) + { + gtk_widget_realize(GTK_WIDGET(win)); // so we can get its gdkwin + GdkWindow *gdkwin = gdk_window_foreign_new(mSDL_XWindowID); + gdk_window_set_transient_for(GTK_WIDGET(win)->window, + gdkwin); + } +# endif //LL_X11 + + GtkColorSelection *colorsel = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG(win)->colorsel); + + GdkColor color, orig_color; + orig_color.pixel = 0; + orig_color.red = guint16(65535 * *r); + orig_color.green= guint16(65535 * *g); + orig_color.blue = guint16(65535 * *b); + color = orig_color; + + gtk_color_selection_set_previous_color (colorsel, &color); + gtk_color_selection_set_current_color (colorsel, &color); + gtk_color_selection_set_has_palette (colorsel, true); + gtk_color_selection_set_has_opacity_control(colorsel, false); + + gint response = GTK_RESPONSE_NONE; + g_signal_connect (win, + "response", + G_CALLBACK (response_callback), + &response); + + g_signal_connect (G_OBJECT (colorsel), "color_changed", + G_CALLBACK (color_changed_callback), + &color); + + gtk_window_set_modal(GTK_WINDOW(win), true); + gtk_widget_show_all(win); + // hide the help button - we don't service it. + gtk_widget_hide(GTK_COLOR_SELECTION_DIALOG(win)->help_button); + gtk_main(); + + if (response == GTK_RESPONSE_OK && + (orig_color.red != color.red + || orig_color.green != color.green + || orig_color.blue != color.blue) ) + { + *r = color.red / 65535.0f; + *g = color.green / 65535.0f; + *b = color.blue / 65535.0f; + rtn = true; + } + } + + afterDialog(); + + return rtn; +} +#else +S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) +{ + LL_INFOS() << "MSGBOX: " << caption << ": " << text << LL_ENDL; + return 0; +} + +bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) +{ + return (false); +} +#endif // LL_GTK + +#if LL_LINUX +// extracted from spawnWebBrowser for clarity and to eliminate +// compiler confusion regarding close(int fd) vs. LLWindow::close() +void exec_cmd(const std::string& cmd, const std::string& arg) +{ + char* const argv[] = {(char*)cmd.c_str(), (char*)arg.c_str(), NULL}; + fflush(NULL); + pid_t pid = fork(); + if (pid == 0) + { // child + // disconnect from stdin/stdout/stderr, or child will + // keep our output pipe undesirably alive if it outlives us. + close(0); + close(1); + close(2); + // end ourself by running the command + execv(cmd.c_str(), argv); /* Flawfinder: ignore */ + // if execv returns at all, there was a problem. + LL_WARNS() << "execv failure when trying to start " << cmd << LL_ENDL; + _exit(1); // _exit because we don't want atexit() clean-up! + } else { + if (pid > 0) + { + // parent - wait for child to die + int childExitStatus; + waitpid(pid, &childExitStatus, 0); + } else { + LL_WARNS() << "fork failure." << LL_ENDL; + } + } +} +#endif + +// Open a URL with the user's default web browser. +// Must begin with protocol identifier. +void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) +{ + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) != std::string::npos) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS() << "spawn_web_browser called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; + +#if LL_LINUX +# if LL_X11 + if (mSDL_Display) + { + maybe_lock_display(); + // Just in case - before forking. + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +# endif // LL_X11 + + std::string cmd, arg; + cmd = gDirUtilp->getAppRODataDir(); + cmd += gDirUtilp->getDirDelimiter(); + cmd += "etc"; + cmd += gDirUtilp->getDirDelimiter(); + cmd += "launch_url.sh"; + arg = escaped_url; + exec_cmd(cmd, arg); +#endif // LL_LINUX + + LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; +} + + +void *LLWindowSDL::getPlatformWindow() +{ +#if LL_GTK && LL_LLMOZLIB_ENABLED + if (LLWindowSDL::ll_try_gtk_init()) + { + maybe_lock_display(); + + GtkWidget *owin = gtk_window_new(GTK_WINDOW_POPUP); + // Why a layout widget? A MozContainer would be ideal, but + // it involves exposing Mozilla headers to mozlib-using apps. + // A layout widget with a GtkWindow parent has the desired + // properties of being plain GTK, having a window, and being + // derived from a GtkContainer. + GtkWidget *rtnw = gtk_layout_new(NULL, NULL); + gtk_container_add(GTK_CONTAINER(owin), rtnw); + gtk_widget_realize(rtnw); + GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(rtnw), GTK_NO_WINDOW); + + maybe_unlock_display(); + + return rtnw; + } +#endif // LL_GTK && LL_LLMOZLIB_ENABLED + // Unixoid mozilla really needs GTK. + return NULL; +} + +void LLWindowSDL::bringToFront() +{ + // This is currently used when we are 'launched' to a specific + // map position externally. + LL_INFOS() << "bringToFront" << LL_ENDL; +#if LL_X11 + if (mSDL_Display && !mFullscreen) + { + maybe_lock_display(); + XRaiseWindow(mSDL_Display, mSDL_XWindowID); + XSync(mSDL_Display, False); + maybe_unlock_display(); + } +#endif // LL_X11 +} + +//static +std::vector LLWindowSDL::getDynamicFallbackFontList() +{ + // Use libfontconfig to find us a nice ordered list of fallback fonts + // specific to this system. + std::string final_fallback("/usr/share/fonts/truetype/kochi/kochi-gothic.ttf"); + const int max_font_count_cutoff = 40; // fonts are expensive in the current system, don't enumerate an arbitrary number of them + // Our 'ideal' font properties which define the sorting results. + // slant=0 means Roman, index=0 means the first face in a font file + // (the one we actually use), weight=80 means medium weight, + // spacing=0 means proportional spacing. + std::string sort_order("slant=0:index=0:weight=80:spacing=0"); + // elide_unicode_coverage removes fonts from the list whose unicode + // range is covered by fonts earlier in the list. This usually + // removes ~90% of the fonts as redundant (which is great because + // the font list can be huge), but might unnecessarily reduce the + // renderable range if for some reason our FreeType actually fails + // to use some of the fonts we want it to. + const bool elide_unicode_coverage = true; + std::vector rtns; + FcFontSet *fs = NULL; + FcPattern *sortpat = NULL; + + LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; + + // If the user has a system-wide language preference, then favor + // fonts from that language group. This doesn't affect the types + // of languages that can be displayed, but ensures that their + // preferred language is rendered from a single consistent font where + // possible. + FL_Locale *locale = NULL; + FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); + if (success != 0) + { + if (success >= 2 && locale->lang) // confident! + { + LL_INFOS("AppInit") << "Language " << locale->lang << LL_ENDL; + LL_INFOS("AppInit") << "Location " << locale->country << LL_ENDL; + LL_INFOS("AppInit") << "Variant " << locale->variant << LL_ENDL; + + LL_INFOS() << "Preferring fonts of language: " + << locale->lang + << LL_ENDL; + sort_order = "lang=" + std::string(locale->lang) + ":" + + sort_order; + } + } + FL_FreeLocale(&locale); + + if (!FcInit()) + { + LL_WARNS() << "FontConfig failed to initialize." << LL_ENDL; + rtns.push_back(final_fallback); + return rtns; + } + + sortpat = FcNameParse((FcChar8*) sort_order.c_str()); + if (sortpat) + { + // Sort the list of system fonts from most-to-least-desirable. + FcResult result; + fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, + NULL, &result); + FcPatternDestroy(sortpat); + } + + int found_font_count = 0; + if (fs) + { + // Get the full pathnames to the fonts, where available, + // which is what we really want. + found_font_count = fs->nfont; + for (int i=0; infont; ++i) + { + FcChar8 *filename; + if (FcResultMatch == FcPatternGetString(fs->fonts[i], + FC_FILE, 0, + &filename) + && filename) + { + rtns.push_back(std::string((const char*)filename)); + if (rtns.size() >= max_font_count_cutoff) + break; // hit limit + } + } + FcFontSetDestroy (fs); + } + + LL_DEBUGS() << "Using font list: " << LL_ENDL; + for (std::vector::iterator it = rtns.begin(); + it != rtns.end(); + ++it) + { + LL_DEBUGS() << " file: " << *it << LL_ENDL; + } + LL_INFOS() << "Using " << rtns.size() << "/" << found_font_count << " system fonts." << LL_ENDL; + + rtns.push_back(final_fallback); + return rtns; +} + +#endif // LL_SDL diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 7f12464a37..196ad2986d 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -1,231 +1,231 @@ -/** - * @file llwindowsdl.h - * @brief SDL implementation of LLWindow class - * - * $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$ - */ - -#ifndef LL_LLWINDOWSDL_H -#define LL_LLWINDOWSDL_H - -// Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class - -#include "llwindow.h" -#include "lltimer.h" - -#include "SDL/SDL.h" -#include "SDL/SDL_endian.h" - -#if LL_X11 -// get X11-specific headers for use in low-level stuff like copy-and-paste support -#include "SDL/SDL_syswm.h" -#endif - -// AssertMacros.h does bad things. -#include "fix_macros.h" -#undef verify -#undef require - - -class LLWindowSDL : public LLWindow -{ -public: - /*virtual*/ void show(); - /*virtual*/ void hide(); - /*virtual*/ void close(); - /*virtual*/ bool getVisible(); - /*virtual*/ bool getMinimized(); - /*virtual*/ bool getMaximized(); - /*virtual*/ bool maximize(); - /*virtual*/ void minimize(); - /*virtual*/ void restore(); - /*virtual*/ bool getFullscreen(); - /*virtual*/ bool getPosition(LLCoordScreen *position); - /*virtual*/ bool getSize(LLCoordScreen *size); - /*virtual*/ bool getSize(LLCoordWindow *size); - /*virtual*/ bool setPosition(LLCoordScreen position); - /*virtual*/ bool setSizeImpl(LLCoordScreen size); - /*virtual*/ bool setSizeImpl(LLCoordWindow size); - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL); - /*virtual*/ bool setCursorPosition(LLCoordWindow position); - /*virtual*/ bool getCursorPosition(LLCoordWindow *position); - /*virtual*/ void showCursor(); - /*virtual*/ void hideCursor(); - /*virtual*/ void showCursorFromMouseMove(); - /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ bool isCursorHidden(); - /*virtual*/ void updateCursor(); - /*virtual*/ void captureMouse(); - /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( bool b ); - /*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - - /*virtual*/ bool isClipboardTextAvailable(); - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); - /*virtual*/ bool copyTextToClipboard(const LLWString & src); - - /*virtual*/ bool isPrimaryTextAvailable(); - /*virtual*/ bool pasteTextFromPrimary(LLWString &dst); - /*virtual*/ bool copyTextToPrimary(const LLWString & src); - - /*virtual*/ void flashIcon(F32 seconds); - /*virtual*/ F32 getGamma(); - /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma - /*virtual*/ U32 getFSAASamples(); - /*virtual*/ void setFSAASamples(const U32 samples); - /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) - /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void processMiscNativeEvents(); - /*virtual*/ void gatherInput(); - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; - - /*virtual*/ void delayInputProcessing() { }; - - // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } - - /*virtual*/ void beforeDialog(); - /*virtual*/ void afterDialog(); - - /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b); - - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); - - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); - - static std::vector getDynamicFallbackFontList(); - - // Not great that these are public, but they have to be accessible - // by non-class code and it's better than making them global. -#if LL_X11 - Window mSDL_XWindowID; - Display *mSDL_Display; -#endif - void (*Lock_Display)(void); - void (*Unlock_Display)(void); - -#if LL_GTK - // Lazily initialize and check the runtime GTK version for goodness. - static bool ll_try_gtk_init(void); -#endif // LL_GTK - -#if LL_X11 - static Window get_SDL_XWindowID(void); - static Display* get_SDL_Display(void); -#endif // LL_X11 - -protected: - LLWindowSDL(LLWindowCallbacks* callbacks, - const std::string& title, int x, int y, int width, int height, U32 flags, - bool fullscreen, bool clearBg, bool disable_vsync, bool use_gl, - bool ignore_pixel_depth, U32 fsaa_samples); - ~LLWindowSDL(); - - /*virtual*/ bool isValid(); - /*virtual*/ LLSD getNativeKeyData(); - - void initCursors(); - void quitCursors(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - - // Changes display resolution. Returns true if successful - bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - - // Go back to last fullscreen display resolution. - bool setFullscreenResolution(); - - bool shouldPostQuit() { return mPostQuit; } - -protected: - // - // Platform specific methods - // - - // create or re-create the GL context/window. Called from the constructor and switchContext(). - bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync); - void destroyContext(); - void setupFailure(const std::string& text, const std::string& caption, U32 type); - void fixWindowSize(void); - U32 SDLCheckGrabbyKeys(SDLKey keysym, bool gain); - bool SDLReallyCaptureInput(bool capture); - - // - // Platform specific variables - // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; - SDL_Surface * mWindow; - std::string mWindowTitle; - double mOriginalAspectRatio; - bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. - LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - F32 mGamma; - U32 mFSAASamples; - - int mSDLFlags; - - SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ - - friend class LLWindowManager; - -private: -#if LL_X11 - void x11_set_urgent(bool urgent); - bool mFlashing; - LLTimer mFlashTimer; -#endif //LL_X11 - - U32 mKeyScanCode; - U32 mKeyVirtualKey; - SDLMod mKeyModifiers; -}; - - -class LLSplashScreenSDL : public LLSplashScreen -{ -public: - LLSplashScreenSDL(); - virtual ~LLSplashScreenSDL(); - - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); -}; - -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); - -#endif //LL_LLWINDOWSDL_H +/** + * @file llwindowsdl.h + * @brief SDL implementation of LLWindow class + * + * $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$ + */ + +#ifndef LL_LLWINDOWSDL_H +#define LL_LLWINDOWSDL_H + +// Simple Directmedia Layer (http://libsdl.org/) implementation of LLWindow class + +#include "llwindow.h" +#include "lltimer.h" + +#include "SDL/SDL.h" +#include "SDL/SDL_endian.h" + +#if LL_X11 +// get X11-specific headers for use in low-level stuff like copy-and-paste support +#include "SDL/SDL_syswm.h" +#endif + +// AssertMacros.h does bad things. +#include "fix_macros.h" +#undef verify +#undef require + + +class LLWindowSDL : public LLWindow +{ +public: + /*virtual*/ void show(); + /*virtual*/ void hide(); + /*virtual*/ void close(); + /*virtual*/ bool getVisible(); + /*virtual*/ bool getMinimized(); + /*virtual*/ bool getMaximized(); + /*virtual*/ bool maximize(); + /*virtual*/ void minimize(); + /*virtual*/ void restore(); + /*virtual*/ bool getFullscreen(); + /*virtual*/ bool getPosition(LLCoordScreen *position); + /*virtual*/ bool getSize(LLCoordScreen *size); + /*virtual*/ bool getSize(LLCoordWindow *size); + /*virtual*/ bool setPosition(LLCoordScreen position); + /*virtual*/ bool setSizeImpl(LLCoordScreen size); + /*virtual*/ bool setSizeImpl(LLCoordWindow size); + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ bool setCursorPosition(LLCoordWindow position); + /*virtual*/ bool getCursorPosition(LLCoordWindow *position); + /*virtual*/ void showCursor(); + /*virtual*/ void hideCursor(); + /*virtual*/ void showCursorFromMouseMove(); + /*virtual*/ void hideCursorUntilMouseMove(); + /*virtual*/ bool isCursorHidden(); + /*virtual*/ void updateCursor(); + /*virtual*/ void captureMouse(); + /*virtual*/ void releaseMouse(); + /*virtual*/ void setMouseClipping( bool b ); + /*virtual*/ void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); + + /*virtual*/ bool isClipboardTextAvailable(); + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); + /*virtual*/ bool copyTextToClipboard(const LLWString & src); + + /*virtual*/ bool isPrimaryTextAvailable(); + /*virtual*/ bool pasteTextFromPrimary(LLWString &dst); + /*virtual*/ bool copyTextToPrimary(const LLWString & src); + + /*virtual*/ void flashIcon(F32 seconds); + /*virtual*/ F32 getGamma(); + /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma + /*virtual*/ U32 getFSAASamples(); + /*virtual*/ void setFSAASamples(const U32 samples); + /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } + /*virtual*/ void processMiscNativeEvents(); + /*virtual*/ void gatherInput(); + /*virtual*/ void swapBuffers(); + /*virtual*/ void restoreGLContext() {}; + + /*virtual*/ void delayInputProcessing() { }; + + // handy coordinate space conversion routines + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); + /*virtual*/ F32 getNativeAspectRatio(); + /*virtual*/ F32 getPixelAspectRatio(); + /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + + /*virtual*/ void beforeDialog(); + /*virtual*/ void afterDialog(); + + /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b); + + /*virtual*/ void *getPlatformWindow(); + /*virtual*/ void bringToFront(); + + /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + + static std::vector getDynamicFallbackFontList(); + + // Not great that these are public, but they have to be accessible + // by non-class code and it's better than making them global. +#if LL_X11 + Window mSDL_XWindowID; + Display *mSDL_Display; +#endif + void (*Lock_Display)(void); + void (*Unlock_Display)(void); + +#if LL_GTK + // Lazily initialize and check the runtime GTK version for goodness. + static bool ll_try_gtk_init(void); +#endif // LL_GTK + +#if LL_X11 + static Window get_SDL_XWindowID(void); + static Display* get_SDL_Display(void); +#endif // LL_X11 + +protected: + LLWindowSDL(LLWindowCallbacks* callbacks, + const std::string& title, int x, int y, int width, int height, U32 flags, + bool fullscreen, bool clearBg, bool disable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples); + ~LLWindowSDL(); + + /*virtual*/ bool isValid(); + /*virtual*/ LLSD getNativeKeyData(); + + void initCursors(); + void quitCursors(); + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + + // Changes display resolution. Returns true if successful + bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + + // Go back to last fullscreen display resolution. + bool setFullscreenResolution(); + + bool shouldPostQuit() { return mPostQuit; } + +protected: + // + // Platform specific methods + // + + // create or re-create the GL context/window. Called from the constructor and switchContext(). + bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync); + void destroyContext(); + void setupFailure(const std::string& text, const std::string& caption, U32 type); + void fixWindowSize(void); + U32 SDLCheckGrabbyKeys(SDLKey keysym, bool gain); + bool SDLReallyCaptureInput(bool capture); + + // + // Platform specific variables + // + U32 mGrabbyKeyFlags; + int mReallyCapturedCount; + SDL_Surface * mWindow; + std::string mWindowTitle; + double mOriginalAspectRatio; + bool mNeedsResize; // Constructor figured out the window is too big, it needs a resize. + LLCoordScreen mNeedsResizeSize; + F32 mOverrideAspectRatio; + F32 mGamma; + U32 mFSAASamples; + + int mSDLFlags; + + SDL_Cursor* mSDLCursors[UI_CURSOR_COUNT]; + int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ + int mIsMinimized; /* 0=no, 1=yes, else unknown */ + + friend class LLWindowManager; + +private: +#if LL_X11 + void x11_set_urgent(bool urgent); + bool mFlashing; + LLTimer mFlashTimer; +#endif //LL_X11 + + U32 mKeyScanCode; + U32 mKeyVirtualKey; + SDLMod mKeyModifiers; +}; + + +class LLSplashScreenSDL : public LLSplashScreen +{ +public: + LLSplashScreenSDL(); + virtual ~LLSplashScreenSDL(); + + /*virtual*/ void showImpl(); + /*virtual*/ void updateImpl(const std::string& mesg); + /*virtual*/ void hideImpl(); +}; + +S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); + +#endif //LL_LLWINDOWSDL_H diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index dad70aea51..7ea53816cf 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1,5000 +1,5000 @@ -/** - * @file llwindowwin32.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" - -#if LL_WINDOWS && !LL_MESA_HEADLESS - -#include "llwindowwin32.h" - -// LLWindow library includes -#include "llkeyboardwin32.h" -#include "lldragdropwin32.h" -#include "llpreeditor.h" -#include "llwindowcallbacks.h" - -// Linden library includes -#include "llerror.h" -#include "llexception.h" -#include "llfasttimer.h" -#include "llgl.h" -#include "llstring.h" -#include "lldir.h" -#include "llsdutil.h" -#include "llglslshader.h" -#include "llthreadsafequeue.h" -#include "stringize.h" -#include "llframetimer.h" - -// System includes -#include -#include -#include -#include // for _spawn -#include -#include -#include -#include -#include -#include -#include // std::pair - -#include -#include -#include - -// Require DirectInput version 8 -#define DIRECTINPUT_VERSION 0x0800 - -#include -#include -#include // needed for llurlentry test to build on some systems -#pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems -#pragma comment(lib, "dinput8") - -const S32 MAX_MESSAGE_PER_UPDATE = 20; -const S32 BITS_PER_PIXEL = 32; -const S32 MAX_NUM_RESOLUTIONS = 32; -const F32 ICON_FLASH_TIME = 0.5f; - -#ifndef WM_DPICHANGED -#define WM_DPICHANGED 0x02E0 -#endif - -#ifndef USER_DEFAULT_SCREEN_DPI -#define USER_DEFAULT_SCREEN_DPI 96 // Win7 -#endif - -// Claim a couple unused GetMessage() message IDs -const UINT WM_DUMMY_(WM_USER + 0x0017); -const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); - -extern bool gDebugWindowProc; - -static std::thread::id sWindowThreadId; -static std::thread::id sMainThreadId; - -#if 1 // flip to zero to enable assertions for functions being called from wrong thread -#define ASSERT_MAIN_THREAD() -#define ASSERT_WINDOW_THREAD() -#else -#define ASSERT_MAIN_THREAD() llassert(LLThread::currentID() == sMainThreadId) -#define ASSERT_WINDOW_THREAD() llassert(LLThread::currentID() == sWindowThreadId) -#endif - - -LPWSTR gIconResource = IDI_APPLICATION; -LPDIRECTINPUT8 gDirectInput8; - -LLW32MsgCallback gAsyncMsgCallback = NULL; - -#ifndef DPI_ENUMS_DECLARED - -typedef enum PROCESS_DPI_AWARENESS { - PROCESS_DPI_UNAWARE = 0, - PROCESS_SYSTEM_DPI_AWARE = 1, - PROCESS_PER_MONITOR_DPI_AWARE = 2 -} PROCESS_DPI_AWARENESS; - -typedef enum MONITOR_DPI_TYPE { - MDT_EFFECTIVE_DPI = 0, - MDT_ANGULAR_DPI = 1, - MDT_RAW_DPI = 2, - MDT_DEFAULT = MDT_EFFECTIVE_DPI -} MONITOR_DPI_TYPE; - -#endif - -typedef HRESULT(STDAPICALLTYPE *SetProcessDpiAwarenessType)(_In_ PROCESS_DPI_AWARENESS value); - -typedef HRESULT(STDAPICALLTYPE *GetProcessDpiAwarenessType)( - _In_ HANDLE hprocess, - _Out_ PROCESS_DPI_AWARENESS *value); - -typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( - _In_ HMONITOR hmonitor, - _In_ MONITOR_DPI_TYPE dpiType, - _Out_ UINT *dpiX, - _Out_ UINT *dpiY); - -// -// LLWindowWin32 -// - -void show_window_creation_error(const std::string& title) -{ - LL_WARNS("Window") << title << LL_ENDL; -} - -HGLRC SafeCreateContext(HDC &hdc) -{ - __try - { - return wglCreateContext(hdc); - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - return NULL; - } -} - -GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) -{ - __try - { - return ChoosePixelFormat(hdc, ppfd); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - // convert to C++ styled exception - // C exception don't allow classes, so it's a regular char array - char integer_string[32]; - sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); - throw std::exception(integer_string); - } -} - -//static -bool LLWindowWin32::sIsClassRegistered = false; - -bool LLWindowWin32::sLanguageTextInputAllowed = true; -bool LLWindowWin32::sWinIMEOpened = false; -HKL LLWindowWin32::sWinInputLocale = 0; -DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; -DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; -LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); - -// The following class LLWinImm delegates Windows IMM APIs. -// It was originally introduced to support US Windows XP, on which we needed -// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry -// points. Now that that's moot, we retain this wrapper only for hooks for -// metrics. - -class LLWinImm -{ -public: - static bool isAvailable() { return true; } - -public: - // Wrappers for IMM API. - static bool isIME(HKL hkl); - static HIMC getContext(HWND hwnd); - static bool releaseContext(HWND hwnd, HIMC himc); - static bool getOpenStatus(HIMC himc); - static bool setOpenStatus(HIMC himc, bool status); - static bool getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); - static bool setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); - static bool getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static bool setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); - static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); - static bool setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); - static bool setCompositionFont(HIMC himc, LPLOGFONTW logfont); - static bool setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); - static bool notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); -}; - -// static -bool LLWinImm::isIME(HKL hkl) -{ - return ImmIsIME(hkl); -} - -// static -HIMC LLWinImm::getContext(HWND hwnd) -{ - return ImmGetContext(hwnd); -} - -//static -bool LLWinImm::releaseContext(HWND hwnd, HIMC himc) -{ - return ImmReleaseContext(hwnd, himc); -} - -// static -bool LLWinImm::getOpenStatus(HIMC himc) -{ - return ImmGetOpenStatus(himc); -} - -// static -bool LLWinImm::setOpenStatus(HIMC himc, bool status) -{ - return ImmSetOpenStatus(himc, status); -} - -// static -bool LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) -{ - return ImmGetConversionStatus(himc, conversion, sentence); -} - -// static -bool LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) -{ - return ImmSetConversionStatus(himc, conversion, sentence); -} - -// static -bool LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - return ImmGetCompositionWindow(himc, form); -} - -// static -bool LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) -{ - return ImmSetCompositionWindow(himc, form); -} - - -// static -LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) -{ - return ImmGetCompositionString(himc, index, data, length); -} - - -// static -bool LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) -{ - return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); -} - -// static -bool LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) -{ - return ImmSetCompositionFont(himc, pFont); -} - -// static -bool LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) -{ - return ImmSetCandidateWindow(himc, form); -} - -// static -bool LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) -{ - return ImmNotifyIME(himc, action, index, value); -} - - - -class LLMonitorInfo -{ -public: - - std::vector getResolutionsList() { return mResList; } - - LLMonitorInfo() - { - EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); - } - -private: - - static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) - { - int monitor_width = lprcMonitor->right - lprcMonitor->left; - int monitor_height = lprcMonitor->bottom - lprcMonitor->top; - - std::ostringstream sstream; - sstream << monitor_width << "x" << monitor_height;; - std::string res = sstream.str(); - - LLMonitorInfo* pThis = reinterpret_cast(pData); - pThis->mResList.push_back(res); - - return TRUE; - } - - std::vector mResList; -}; - -static LLMonitorInfo sMonitorInfo; - - -// Thread that owns the Window Handle -// This whole struct is private to LLWindowWin32, which needs to mess with its -// members, which is why it's a struct rather than a class. In effect, we make -// the containing class a friend. -struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool -{ - static const int MAX_QUEUE_SIZE = 2048; - - LLThreadSafeQueue mMessageQueue; - - LLWindowWin32Thread(); - - void run() override; - void close() override; - - // closes queue, wakes thread, waits until thread closes - void wakeAndDestroy(); - - void glReady() - { - mGLReady = true; - } - - // initialzie DXGI adapter (for querying available VRAM) - void initDX(); - - // initialize D3D (if DXGI cannot be used) - void initD3D(); - - //clean up DXGI/D3D resources - void cleanupDX(); - - /// called by main thread to post work to this window thread - template - void post(CALLABLE&& func) - { - // Ignore bool return. Shutdown timing is tricky: the main thread can - // end up trying to post a cursor position after having closed the - // WorkQueue. - getQueue().post(std::forward(func)); - } - - /** - * Like post(), Post() is a way of conveying a single work item to this - * thread. Its virtue is that it will definitely be executed "soon" rather - * than potentially waiting for the next frame: it uses PostMessage() to - * break us out of the window thread's blocked GetMessage() call. It's - * more expensive, though, not only from the Windows API latency of - * PostMessage() and GetMessage(), but also because it involves heap - * allocation and release. - * - * Require HWND from caller, even though we store an HWND locally. - * Otherwise, if our mWindowHandle was accessed from both threads, we'd - * have to protect it with a mutex. - */ - template - void Post(HWND windowHandle, CALLABLE&& func) - { - // Move func to the heap. If we knew FuncType could fit into LPARAM, - // we could simply instantiate FuncType and pass it by value. But - // since we don't, we must put that on the heap as well as the - // internal heap allocation it likely requires to store func. - auto ptr = new FuncType(std::move(func)); - WPARAM wparam{ 0xF1C }; - LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle - << ", " << WM_POST_FUNCTION_ - << ", " << wparam << std::dec << LL_ENDL; - PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr)); - } - - using FuncType = std::function; - // call GetMessage() and pull enqueue messages for later processing - void gatherInput(); - HWND mWindowHandleThrd = NULL; - HDC mhDCThrd = 0; - - // *HACK: Attempt to prevent startup crashes by deferring memory accounting - // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 - bool mGLReady = false; - - U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) - - IDXGIAdapter3* mDXGIAdapter = nullptr; - LPDIRECT3D9 mD3D = nullptr; - LPDIRECT3DDEVICE9 mD3DDevice = nullptr; -}; - - -LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, S32 x, S32 y, S32 width, - S32 height, U32 flags, - bool fullscreen, bool clearBg, - bool enable_vsync, bool use_gl, - bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_cores, - U32 max_vram, - F32 max_gl_version) - : - LLWindow(callbacks, fullscreen, flags), - mMaxGLVersion(max_gl_version), - mMaxCores(max_cores) -{ - sMainThreadId = LLThread::currentID(); - mWindowThread = new LLWindowWin32Thread(); - mWindowThread->mMaxVRAM = max_vram; - - //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways - LoadLibrary(L"opengl32.dll"); - - - if (mMaxCores != 0) - { - HANDLE hProcess = GetCurrentProcess(); - mMaxCores = llmin(mMaxCores, (U32) 64); - DWORD_PTR mask = 0; - - for (int i = 0; i < mMaxCores; ++i) - { - mask |= ((DWORD_PTR) 1) << i; - } - - SetProcessAffinityMask(hProcess, mask); - } - -#if 0 // this is probably a bad idea, but keep it in your back pocket if you see what looks like - // process deprioritization during profiles - // force high thread priority - HANDLE hProcess = GetCurrentProcess(); - - if (hProcess) - { - int priority = GetPriorityClass(hProcess); - if (priority < REALTIME_PRIORITY_CLASS) - { - if (SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS)) - { - LL_INFOS() << "Set process priority to REALTIME_PRIORITY_CLASS" << LL_ENDL; - } - else - { - LL_INFOS() << "Failed to set process priority: " << std::hex << GetLastError() << LL_ENDL; - } - } - } -#endif - -#if 0 // this is also probably a bad idea, but keep it in your back pocket for getting main thread off of background thread cores (see also LLThread::threadRun) - HANDLE hThread = GetCurrentThread(); - - SYSTEM_INFO sysInfo; - - GetSystemInfo(&sysInfo); - U32 core_count = sysInfo.dwNumberOfProcessors; - - if (max_cores != 0) - { - core_count = llmin(core_count, max_cores); - } - - if (hThread) - { - int priority = GetThreadPriority(hThread); - - if (priority < THREAD_PRIORITY_TIME_CRITICAL) - { - if (SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) - { - LL_INFOS() << "Set thread priority to THREAD_PRIORITY_TIME_CRITICAL" << LL_ENDL; - } - else - { - LL_INFOS() << "Failed to set thread priority: " << std::hex << GetLastError() << LL_ENDL; - } - - // tell main thread to prefer core 0 - SetThreadIdealProcessor(hThread, 0); - } - } -#endif - - - mFSAASamples = fsaa_samples; - mIconResource = gIconResource; - mOverrideAspectRatio = 0.f; - mNativeAspectRatio = 0.f; - mInputProcessingPaused = false; - mPreeditor = NULL; - mKeyCharCode = 0; - mKeyScanCode = 0; - mKeyVirtualKey = 0; - mhDC = NULL; - mhRC = NULL; - memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); - memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); - mCustomGammaSet = false; - mWindowHandle = NULL; - - mRect = {0, 0, 0, 0}; - mClientRect = {0, 0, 0, 0}; - - if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) - { - mMouseVanish = true; - } - - // Initialize the keyboard - gKeyboard = new LLKeyboardWin32(); - gKeyboard->setCallbacks(callbacks); - - // Initialize the Drag and Drop functionality - mDragDrop = new LLDragDropWin32; - - // Initialize (boot strap) the Language text input management, - // based on the system's (user's) default settings. - allowLanguageTextInput(mPreeditor, false); - - WNDCLASS wc; - RECT window_rect; - - // Set the window title - if (title.empty()) - { - mWindowTitle = new WCHAR[50]; - wsprintf(mWindowTitle, L"OpenGL Window"); - } - else - { - mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowTitle, title.c_str(), 255); - mWindowTitle[255] = 0; - } - - // Set the window class name - if (name.empty()) - { - mWindowClassName = new WCHAR[50]; - wsprintf(mWindowClassName, L"OpenGL Window"); - } - else - { - mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. - mbstowcs(mWindowClassName, name.c_str(), 255); - mWindowClassName[255] = 0; - } - - - // We're not clipping yet - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - - // Make an instance of our window then define the window class - mhInstance = GetModuleHandle(NULL); - - // Init Direct Input - needed for joystick / Spacemouse - - LPDIRECTINPUT8 di8_interface; - HRESULT status = DirectInput8Create( - mhInstance, // HINSTANCE hinst, - DIRECTINPUT_VERSION, // DWORD dwVersion, - IID_IDirectInput8, // REFIID riidltf, - (LPVOID*)&di8_interface, // LPVOID * ppvOut, - NULL // LPUNKNOWN punkOuter - ); - if (status == DI_OK) - { - gDirectInput8 = di8_interface; - } - - mSwapMethod = SWAP_METHOD_UNDEFINED; - - // No WPARAM yet. - mLastSizeWParam = 0; - - // Windows GDI rects don't include rightmost pixel - window_rect.left = (long) 0; - window_rect.right = (long) width; - window_rect.top = (long) 0; - window_rect.bottom = (long) height; - - // Grab screen size to sanitize the window - S32 window_border_y = GetSystemMetrics(SM_CYBORDER); - S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); - S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); - S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); - S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); - - if (x < virtual_screen_x) x = virtual_screen_x; - if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; - - if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; - if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; - - if (!sIsClassRegistered) - { - // Force redraw when resized and create a private device context - - // Makes double click messages. - wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; - - // Set message handler function - wc.lpfnWndProc = (WNDPROC) mainWindowProc; - - // unused - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - - wc.hInstance = mhInstance; - wc.hIcon = LoadIcon(mhInstance, mIconResource); - - // We will set the cursor ourselves - wc.hCursor = NULL; - - // background color is not used - if (clearBg) - { - wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); - } - else - { - wc.hbrBackground = (HBRUSH) NULL; - } - - // we don't use windows menus - wc.lpszMenuName = NULL; - - wc.lpszClassName = mWindowClassName; - - if (!RegisterClass(&wc)) - { - OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), - mCallbacks->translateString("MBError"), OSMB_OK); - return; - } - sIsClassRegistered = true; - } - - //----------------------------------------------------------------------- - // Get the current refresh rate - //----------------------------------------------------------------------- - - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); - } - else - { - current_refresh = 60; - } - mRefreshRate = current_refresh; - //----------------------------------------------------------------------- - // Drop resolution and go fullscreen - // use a display mode with our desired size and depth, with a refresh - // rate as close at possible to the users' default - //----------------------------------------------------------------------- - if (mFullscreen) - { - bool success = false; - DWORD closest_refresh = 0; - - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = true; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } - - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - //success = false; - - if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - success = false; - } - else - { - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; - window_rect.right=width=dev_mode.dmPelsWidth; - window_rect.bottom=height=dev_mode.dmPelsHeight; - success = true; - } - else - { - LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; - success = false; - } - } - } - - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } - - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - // If it failed, we don't want to run fullscreen - if (success) - { - mFullscreen = true; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; - - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; - } - else - { - mFullscreen = false; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - std::map args; - args["[WIDTH]"] = llformat("%d", width); - args["[HEIGHT]"] = llformat ("%d", height); - OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), - mCallbacks->translateString("MBError"), OSMB_OK); - } - } - - // TODO: add this after resolving _WIN32_WINNT issue - // if (!fullscreen) - // { - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = mWindowHandle; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - // } - - // SL-12971 dual GPU display - DISPLAY_DEVICEA display_device; - int display_index = -1; - DWORD display_flags = 0; // EDD_GET_DEVICE_INTERFACE_NAME ? - const size_t display_bytes = sizeof(display_device); - - do - { - if (display_index >= 0) - { - // CHAR DeviceName [ 32] Adapter name - // CHAR DeviceString[128] - CHAR text[256]; - - size_t name_len = strlen(display_device.DeviceName ); - size_t desc_len = strlen(display_device.DeviceString); - - CHAR *name = name_len ? display_device.DeviceName : "???"; - CHAR *desc = desc_len ? display_device.DeviceString : "???"; - - sprintf(text, "Display Device %d: %s, %s", display_index, name, desc); - LL_INFOS("Window") << text << LL_ENDL; - } - - ::ZeroMemory(&display_device,display_bytes); - display_device.cb = display_bytes; - - display_index++; - } while( EnumDisplayDevicesA(NULL, display_index, &display_device, display_flags )); - - LL_INFOS("Window") << "Total Display Devices: " << display_index << LL_ENDL; - - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - LLCoordScreen windowPos(x,y); - LLCoordScreen windowSize(window_rect.right - window_rect.left, - window_rect.bottom - window_rect.top); - if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) - { - return; - } - - //start with arrow cursor - initCursors(); - setCursor( UI_CURSOR_ARROW ); - - mRawMouse.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC - mRawMouse.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE - mRawMouse.dwFlags = 0; // adds mouse and also ignores legacy mouse messages - mRawMouse.hwndTarget = 0; - - RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse)); - - // Initialize (boot strap) the Language text input management, - // based on the system's (or user's) default settings. - allowLanguageTextInput(NULL, false); -} - - -LLWindowWin32::~LLWindowWin32() -{ - delete mDragDrop; - - delete [] mWindowTitle; - mWindowTitle = NULL; - - delete [] mSupportedResolutions; - mSupportedResolutions = NULL; - - delete [] mWindowClassName; - mWindowClassName = NULL; - - delete mWindowThread; -} - -void LLWindowWin32::show() -{ - LL_DEBUGS("Window") << "Setting window to show" << LL_ENDL; - ShowWindow(mWindowHandle, SW_SHOW); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); -} - -void LLWindowWin32::hide() -{ - setMouseClipping(false); - ShowWindow(mWindowHandle, SW_HIDE); -} - -//virtual -void LLWindowWin32::minimize() -{ - setMouseClipping(false); - showCursor(); - ShowWindow(mWindowHandle, SW_MINIMIZE); -} - -//virtual -void LLWindowWin32::restore() -{ - ShowWindow(mWindowHandle, SW_RESTORE); - SetForegroundWindow(mWindowHandle); - SetFocus(mWindowHandle); -} - -// See SL-12170 -// According to callstack "c0000005 Access violation" happened inside __try block, -// deep in DestroyWindow and crashed viewer, which shouldn't be possible. -// I tried manually causing this exception and it was caught without issues, so -// I'm turning off optimizations for this part to be sure code executes as intended -// (it is a straw, but I have no idea why else __try can get overruled) -#pragma optimize("", off) -bool destroy_window_handler(HWND hWnd) -{ - bool res; - __try - { - res = DestroyWindow(hWnd); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - res = false; - } - return res; -} -#pragma optimize("", on) - -// close() destroys all OS-specific code associated with a window. -// Usually called from LLWindowManager::destroyWindow() -void LLWindowWin32::close() -{ - LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; - // Is window is already closed? - if (!mWindowHandle) - { - return; - } - - mDragDrop->reset(); - - - // Go back to screen mode written in the registry. - if (mFullscreen) - { - resetDisplayResolution(); - } - - // Make sure cursor is visible and we haven't mangled the clipping state. - showCursor(); - setMouseClipping(false); - if (gKeyboard) - { - gKeyboard->resetKeys(); - } - - // Clean up remaining GL state - if (gGLManager.mInited) - { - LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL; - gGLManager.shutdownGL(); - } - - LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; - } - - // Restore gamma to the system values. - restoreGamma(); - - LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; - - mhDC = NULL; - mWindowHandle = NULL; - - mWindowThread->wakeAndDestroy(); -} - -bool LLWindowWin32::isValid() -{ - return (mWindowHandle != NULL); -} - -bool LLWindowWin32::getVisible() -{ - return (mWindowHandle && IsWindowVisible(mWindowHandle)); -} - -bool LLWindowWin32::getMinimized() -{ - return (mWindowHandle && IsIconic(mWindowHandle)); -} - -bool LLWindowWin32::getMaximized() -{ - return (mWindowHandle && IsZoomed(mWindowHandle)); -} - -bool LLWindowWin32::maximize() -{ - bool success = false; - if (!mWindowHandle) return success; - - mWindowThread->post([=] - { - WINDOWPLACEMENT placement; - placement.length = sizeof(WINDOWPLACEMENT); - - if (GetWindowPlacement(mWindowHandle, &placement)) - { - placement.showCmd = SW_MAXIMIZE; - SetWindowPlacement(mWindowHandle, &placement); - } - }); - - return true; -} - -bool LLWindowWin32::getFullscreen() -{ - return mFullscreen; -} - -bool LLWindowWin32::getPosition(LLCoordScreen *position) -{ - position->mX = mRect.left; - position->mY = mRect.top; - return true; -} - -bool LLWindowWin32::getSize(LLCoordScreen *size) -{ - size->mX = mRect.right - mRect.left; - size->mY = mRect.bottom - mRect.top; - return true; -} - -bool LLWindowWin32::getSize(LLCoordWindow *size) -{ - size->mX = mClientRect.right - mClientRect.left; - size->mY = mClientRect.bottom - mClientRect.top; - return true; -} - -bool LLWindowWin32::setPosition(const LLCoordScreen position) -{ - LLCoordScreen size; - - if (!mWindowHandle) - { - return false; - } - getSize(&size); - moveWindow(position, size); - return true; -} - -bool LLWindowWin32::setSizeImpl(const LLCoordScreen size) -{ - LLCoordScreen position; - - getPosition(&position); - if (!mWindowHandle) - { - return false; - } - - mWindowThread->post([=]() - { - WINDOWPLACEMENT placement; - placement.length = sizeof(WINDOWPLACEMENT); - - if (GetWindowPlacement(mWindowHandle, &placement)) - { - placement.showCmd = SW_RESTORE; - SetWindowPlacement(mWindowHandle, &placement); - } - }); - - moveWindow(position, size); - return true; -} - -bool LLWindowWin32::setSizeImpl(const LLCoordWindow size) -{ - RECT window_rect = {0, 0, size.mX, size.mY }; - DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - DWORD dw_style = WS_OVERLAPPEDWINDOW; - - AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); - - return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); -} - -// changing fullscreen resolution -bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bool enable_vsync, const LLCoordScreen* const posp) -{ - //called from main thread - GLuint pixel_format; - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - DWORD dw_ex_style; - DWORD dw_style; - RECT window_rect = { 0, 0, 0, 0 }; - S32 width = size.mX; - S32 height = size.mY; - bool auto_show = false; - - if (mhRC) - { - auto_show = true; - resetDisplayResolution(); - } - - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - } - else - { - current_refresh = 60; - } - mRefreshRate = current_refresh; - - gGLManager.shutdownGL(); - //destroy gl context - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } - - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } - - mhRC = NULL; - } - - if (fullscreen) - { - mFullscreen = true; - bool success = false; - DWORD closest_refresh = 0; - - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = true; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } - - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - return false; - } - - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } - - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - - if (success) - { - mFullscreen = true; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; - - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; - - window_rect.left = (long)0; - window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel - window_rect.top = (long)0; - window_rect.bottom = (long)height; - dw_ex_style = WS_EX_APPWINDOW; - dw_style = WS_POPUP; - - // Move window borders out not to cover window contents. - // This converts client rect to window rect, i.e. expands it by the window border size. - AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); - } - // If it failed, we don't want to run fullscreen - else - { - mFullscreen = false; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; - - LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; - return false; - } - } - else - { - mFullscreen = false; - window_rect.left = (long)(posp ? posp->mX : 0); - window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel - window_rect.top = (long)(posp ? posp->mY : 0); - window_rect.bottom = (long)height + window_rect.top; - // Window with an edge - dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - dw_style = WS_OVERLAPPEDWINDOW; - } - - - // don't post quit messages when destroying old windows - mPostQuit = false; - - - // create window - LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left - << " Y: " << window_rect.top - << " Width: " << (window_rect.right - window_rect.left) - << " Height: " << (window_rect.bottom - window_rect.top) - << " Fullscreen: " << mFullscreen - << LL_ENDL; - - recreateWindow(window_rect, dw_ex_style, dw_style); - - if (mWindowHandle) - { - LL_INFOS("Window") << "window is created." << LL_ENDL ; - } - else - { - LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; - } - - //----------------------------------------------------------------------- - // Create GL drawing context - //----------------------------------------------------------------------- - static PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, - PFD_TYPE_RGBA, - BITS_PER_PIXEL, - 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused - 8, // alpha bits - 0, // alpha shift - 0, // accum bits - 0, 0, 0, 0, // accum RGBA - 24, // depth bits - 8, // stencil bits, avi added for stencil test - 0, - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - if (!mhDC) - { - close(); - OSMessageBox(mCallbacks->translateString("MBDevContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - return false; - } - - LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; - - try - { - // Looks like ChoosePixelFormat can crash in case of faulty driver - if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd))) - { - LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL; - OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - } - catch (...) - { - LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); - OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash - LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; - LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; - LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; - LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; - LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; - LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; - LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; - LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; - LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; - LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; - LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - - if (!(mhRC = SafeCreateContext(mhDC))) - { - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; - - gGLManager.initWGL(); - - if (wglChoosePixelFormatARB) - { - // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we - // can get exactly what we want. - GLint attrib_list[256]; - S32 cur_attrib = 0; - - attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - //attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) - //attrib_list[cur_attrib++] = 8; - - attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; - attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; - - attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; - attrib_list[cur_attrib++] = 24; - - attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; - attrib_list[cur_attrib++] = 0; - - U32 end_attrib = 0; - if (mFSAASamples > 0) - { - end_attrib = cur_attrib; - attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; - attrib_list[cur_attrib++] = GL_TRUE; - - attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; - attrib_list[cur_attrib++] = mFSAASamples; - } - - // End the list - attrib_list[cur_attrib++] = 0; - - GLint pixel_formats[256]; - U32 num_formats = 0; - - // First we try and get a 32 bit depth pixel format - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - - while(!result && mFSAASamples > 0) - { - LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; - - mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing - if(mFSAASamples < 2) - { - mFSAASamples = 0 ; - } - - if (mFSAASamples > 0) - { - attrib_list[end_attrib + 3] = mFSAASamples; - } - else - { - cur_attrib = end_attrib ; - end_attrib = 0 ; - attrib_list[cur_attrib++] = 0 ; //end - } - result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - - if(result) - { - LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; - } - } - - if (!result) - { - LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; - - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); - return false; - } - - if (!num_formats) - { - if (end_attrib > 0) - { - LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; - attrib_list[end_attrib] = 0; - - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); - return false; - } - } - - if (!num_formats) - { - LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; - // Try 24-bit format - attrib_list[1] = 24; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); - return false; - } - - if (!num_formats) - { - LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; - attrib_list[1] = 16; - BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); - if (!result || !num_formats) - { - close(); - show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); - return false; - } - } - } - - LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; - } - - LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; - - S32 swap_method = 0; - S32 cur_format = 0; -const S32 max_format = (S32)num_formats - 1; - GLint swap_query = WGL_SWAP_METHOD_ARB; - - // SL-14705 Fix name tags showing in front of objects with AMD GPUs. - // On AMD hardware we need to iterate from the first pixel format to the end. - // Spec: - // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt - while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) - { - if (swap_method == WGL_SWAP_UNDEFINED_ARB) - { - break; - } - else if (cur_format >= max_format) - { - cur_format = 0; - break; - } - - ++cur_format; - } - - pixel_format = pixel_formats[cur_format]; - - if (mhDC != 0) // Does The Window Have A Device Context? - { - wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero - if (mhRC != 0) // Does The Window Have A Rendering Context? - { - wglDeleteContext (mhRC); // Release The Rendering Context - mhRC = 0; // Zero The Rendering Context - } - } - - // will release and recreate mhDC, mWindowHandle - recreateWindow(window_rect, dw_ex_style, dw_style); - - RECT rect; - RECT client_rect; - //initialize immediately on main thread - if (GetWindowRect(mWindowHandle, &rect) && - GetClientRect(mWindowHandle, &client_rect)) - { - mRect = rect; - mClientRect = client_rect; - }; - - if (mWindowHandle) - { - LL_INFOS("Window") << "recreate window done." << LL_ENDL ; - } - else - { - // Note: if value is NULL GetDC retrieves the DC for the entire screen. - LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; - } - - if (!mhDC) - { - OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - if (!SetPixelFormat(mhDC, pixel_format, &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), - mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) - { - switch (swap_method) - { - case WGL_SWAP_EXCHANGE_ARB: - mSwapMethod = SWAP_METHOD_EXCHANGE; - LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; - break; - case WGL_SWAP_COPY_ARB: - mSwapMethod = SWAP_METHOD_COPY; - LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; - break; - case WGL_SWAP_UNDEFINED_ARB: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; - break; - default: - mSwapMethod = SWAP_METHOD_UNDEFINED; - LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; - break; - } - } - } - else - { - LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr")); - // mWindowHandle is 0, going to crash either way - LL_ERRS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL; - } - - // Verify what pixel format we actually received. - if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), - &pfd)) - { - OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) - << " Alpha Bits " << S32(pfd.cAlphaBits) - << " Depth Bits " << S32(pfd.cDepthBits) - << LL_ENDL; - - mhRC = 0; - if (wglCreateContextAttribsARB) - { //attempt to create a specific versioned context - mhRC = (HGLRC) createSharedContext(); - if (!mhRC) - { - return false; - } - } - - if (!wglMakeCurrent(mhDC, mhRC)) - { - OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - if (!gGLManager.initGL()) - { - OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); - close(); - return false; - } - - // Disable vertical sync for swap - toggleVSync(enable_vsync); - - SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); - - // register this window as handling drag/drop events from the OS - DragAcceptFiles( mWindowHandle, TRUE ); - - mDragDrop->init( mWindowHandle ); - - //register joystick timer callback - SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer - - // ok to post quit messages now - mPostQuit = true; - - // *HACK: Attempt to prevent startup crashes by deferring memory accounting - // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 - mWindowThread->post([=]() - { - mWindowThread->glReady(); - }); - - if (auto_show) - { - show(); - glClearColor(0.0f, 0.0f, 0.0f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - swapBuffers(); - } - - LL_PROFILER_GPU_CONTEXT; - - return true; -} - -void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) -{ - auto oldWindowHandle = mWindowHandle; - auto oldDCHandle = mhDC; - - // zero out mWindowHandle and mhDC before destroying window so window - // thread falls back to peekmessage - mWindowHandle = 0; - mhDC = 0; - - std::promise> promise; - // What follows must be done on the window thread. - auto window_work = - [this, - self=mWindowThread, - oldWindowHandle, - oldDCHandle, - // bind CreateWindowEx() parameters by value instead of - // back-referencing LLWindowWin32 members - windowClassName=mWindowClassName, - windowTitle=mWindowTitle, - hInstance=mhInstance, - window_rect, - dw_ex_style, - dw_style, - &promise] - () - { - LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL; - self->mWindowHandleThrd = 0; - self->mhDCThrd = 0; - - if (oldWindowHandle) - { - if (oldDCHandle && !ReleaseDC(oldWindowHandle, oldDCHandle)) - { - LL_WARNS("Window") << "Failed to ReleaseDC" << LL_ENDL; - } - - // important to call DestroyWindow() from the window thread - if (!destroy_window_handler(oldWindowHandle)) - { - - LL_WARNS("Window") << "Failed to properly close window before recreating it!" - << LL_ENDL; - } - } - - auto handle = CreateWindowEx(dw_ex_style, - windowClassName, - windowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - hInstance, - NULL); - - if (! handle) - { - // Failed to create window: clear the variables. This - // assignment is valid because we're running on mWindowThread. - self->mWindowHandleThrd = NULL; - self->mhDCThrd = 0; - } - else - { - // Update mWindowThread's own mWindowHandle and mhDC. - self->mWindowHandleThrd = handle; - self->mhDCThrd = GetDC(handle); - } - - updateWindowRect(); - - // It's important to wake up the future either way. - promise.set_value(std::make_pair(self->mWindowHandleThrd, self->mhDCThrd)); - LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL; - }; - // But how we pass window_work to the window thread depends on whether we - // already have a window handle. - if (!oldWindowHandle) - { - // Pass window_work using the WorkQueue: without an existing window - // handle, the window thread can't call GetMessage(). - LL_DEBUGS("Window") << "posting window_work to WorkQueue" << LL_ENDL; - mWindowThread->post(window_work); - } - else - { - // Pass window_work using PostMessage(). We can still - // PostMessage(oldHandle) because oldHandle won't be destroyed until - // the window thread has retrieved and executed window_work. - LL_DEBUGS("Window") << "posting window_work to message queue" << LL_ENDL; - mWindowThread->Post(oldWindowHandle, window_work); - } - - auto future = promise.get_future(); - // This blocks until mWindowThread processes CreateWindowEx() and calls - // promise.set_value(). - auto pair = future.get(); - mWindowHandle = pair.first; - mhDC = pair.second; -} - -void* LLWindowWin32::createSharedContext() -{ - mMaxGLVersion = llclamp(mMaxGLVersion, 3.f, 4.6f); - - S32 version_major = llfloor(mMaxGLVersion); - S32 version_minor = llround((mMaxGLVersion-version_major)*10); - - S32 attribs[] = - { - WGL_CONTEXT_MAJOR_VERSION_ARB, version_major, - WGL_CONTEXT_MINOR_VERSION_ARB, version_minor, - WGL_CONTEXT_PROFILE_MASK_ARB, LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, - 0 - }; - - HGLRC rc = 0; - - bool done = false; - while (!done) - { - rc = wglCreateContextAttribsARB(mhDC, mhRC, attribs); - - if (!rc) - { - if (attribs[3] > 0) - { //decrement minor version - attribs[3]--; - } - else if (attribs[1] > 3) - { //decrement major version and start minor version over at 3 - attribs[1]--; - attribs[3] = 3; - } - else - { //we reached 3.0 and still failed, bail out - done = true; - } - } - else - { - LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << - (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL; - done = true; - } - } - - if (!rc && !(rc = wglCreateContext(mhDC))) - { - close(); - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - } - - return rc; -} - -void LLWindowWin32::makeContextCurrent(void* contextPtr) -{ - wglMakeCurrent(mhDC, (HGLRC) contextPtr); - LL_PROFILER_GPU_CONTEXT; -} - -void LLWindowWin32::destroySharedContext(void* contextPtr) -{ - wglDeleteContext((HGLRC)contextPtr); -} - -void LLWindowWin32::toggleVSync(bool enable_vsync) -{ - if (wglSwapIntervalEXT == nullptr) - { - LL_INFOS("Window") << "VSync: wglSwapIntervalEXT not initialized" << LL_ENDL; - } - else if (!enable_vsync) - { - LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; - wglSwapIntervalEXT(0); - } - else - { - LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; - wglSwapIntervalEXT(1); - } -} - -void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) -{ - if( mIsMouseClipping ) - { - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - ClipCursor( &client_rect_in_screen_space ); - } - } - - // if the window was already maximized, MoveWindow seems to still set the maximized flag even if - // the window is smaller than maximized. - // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). - - // THIS CAUSES DEV-15484 and DEV-15949 - //ShowWindow(mWindowHandle, SW_RESTORE); - // NOW we can call MoveWindow - mWindowThread->post([=]() - { - MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); - }); -} - -void LLWindowWin32::setTitle(const std::string title) -{ - // TODO: Do we need to use the wide string version of this call - // to support non-ascii usernames (and region names?) - mWindowThread->post([=]() - { - SetWindowTextA(mWindowHandle, title.c_str()); - }); -} - -bool LLWindowWin32::setCursorPosition(const LLCoordWindow position) -{ - ASSERT_MAIN_THREAD(); - - if (!mWindowHandle) - { - return false; - } - - LLCoordScreen screen_pos(position.convert()); - - // instantly set the cursor position from the app's point of view - mCursorPosition = position; - mLastCursorPosition = position; - - // Inform the application of the new mouse position (needed for per-frame - // hover/picking to function). - mCallbacks->handleMouseMove(this, position.convert(), (MASK)0); - - // actually set the cursor position on the window thread - mWindowThread->post([=]() - { - // actually set the OS cursor position - SetCursorPos(screen_pos.mX, screen_pos.mY); - }); - - return true; -} - -bool LLWindowWin32::getCursorPosition(LLCoordWindow *position) -{ - ASSERT_MAIN_THREAD(); - if (!position) - { - return false; - } - - *position = mCursorPosition; - return true; -} - -bool LLWindowWin32::getCursorDelta(LLCoordCommon* delta) -{ - if (delta == nullptr) - { - return false; - } - - *delta = mMouseFrameDelta; - - return true; -} - -void LLWindowWin32::hideCursor() -{ - ASSERT_MAIN_THREAD(); - - mWindowThread->post([=]() - { - while (ShowCursor(FALSE) >= 0) - { - // nothing, wait for cursor to push down - } - }); - - mCursorHidden = true; - mHideCursorPermanent = true; -} - -void LLWindowWin32::showCursor() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - - ASSERT_MAIN_THREAD(); - - mWindowThread->post([=]() - { - // makes sure the cursor shows up - while (ShowCursor(TRUE) < 0) - { - // do nothing, wait for cursor to pop out - } - }); - - mCursorHidden = false; - mHideCursorPermanent = false; -} - -void LLWindowWin32::showCursorFromMouseMove() -{ - if (!mHideCursorPermanent) - { - showCursor(); - } -} - -void LLWindowWin32::hideCursorUntilMouseMove() -{ - if (!mHideCursorPermanent && mMouseVanish) - { - hideCursor(); - mHideCursorPermanent = false; - } -} - -bool LLWindowWin32::isCursorHidden() -{ - return mCursorHidden; -} - - -HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) -{ - return (HCURSOR)LoadImage(mhInstance, - name, - IMAGE_CURSOR, - 0, // default width - 0, // default height - LR_DEFAULTCOLOR); -} - - -void LLWindowWin32::initCursors() -{ - mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); - mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); - mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); - mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); - mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); - mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); - mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); - mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); - mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); - mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL); - mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); - mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); - - HMODULE module = GetModuleHandle(NULL); - mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); - mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); - mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); - mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); - mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); - mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); - mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); - mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); - mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); - mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); - mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); - mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); - mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); - mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); - mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); - mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); - mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); - mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT")); - mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); - mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); - mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); - mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); - mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); - mCursor[ UI_CURSOR_TOOLPATHFINDING ] = LoadCursor(module, TEXT("TOOLPATHFINDING")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTARTADD")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTART")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHEND")); - mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHENDADD")); - mCursor[ UI_CURSOR_TOOLNO ] = LoadCursor(module, TEXT("TOOLNO")); - - // Color cursors - mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); - mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); - mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); - - // Note: custom cursors that are not found make LoadCursor() return NULL. - for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) - { - if( !mCursor[i] ) - { - mCursor[i] = LoadCursor(NULL, IDC_ARROW); - } - } -} - - - -void LLWindowWin32::updateCursor() -{ - ASSERT_MAIN_THREAD(); - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 - if (mNextCursor == UI_CURSOR_ARROW - && mBusyCount > 0) - { - mNextCursor = UI_CURSOR_WORKING; - } - - if( mCurrentCursor != mNextCursor ) - { - mCurrentCursor = mNextCursor; - auto nextCursor = mCursor[mNextCursor]; - mWindowThread->post([=]() - { - SetCursor(nextCursor); - }); - } -} - -ECursorType LLWindowWin32::getCursor() const -{ - return mCurrentCursor; -} - -void LLWindowWin32::captureMouse() -{ - SetCapture(mWindowHandle); -} - -void LLWindowWin32::releaseMouse() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - ReleaseCapture(); -} - - -void LLWindowWin32::delayInputProcessing() -{ - mInputProcessingPaused = true; -} - - -void LLWindowWin32::gatherInput() -{ - ASSERT_MAIN_THREAD(); - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 - MSG msg; - - { - LLMutexLock lock(&mRawMouseMutex); - mMouseFrameDelta = mRawMouseDelta; - - mRawMouseDelta.mX = 0; - mRawMouseDelta.mY = 0; - } - - - if (mWindowThread->getQueue().size()) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage"); - kickWindowThread(); - } - - while (mWindowThread->mMessageQueue.tryPopBack(msg)) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue"); - if (mInputProcessingPaused) - { - continue; - } - - // For async host by name support. Really hacky. - if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - callback"); - gAsyncMsgCallback(msg); - } - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PeekMessage"); - S32 msg_count = 0; - while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - msg_count++; - } - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - function queue"); - //process any pending functions - std::function curFunc; - while (mFunctionQueue.tryPopBack(curFunc)) - { - curFunc(); - } - } - - // send one and only one mouse move event per frame BEFORE handling mouse button presses - if (mLastCursorPosition != mCursorPosition) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move"); - mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask); - } - - mLastCursorPosition = mCursorPosition; - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse queue"); - // handle mouse button presses AFTER updating mouse cursor position - std::function curFunc; - while (mMouseQueue.tryPopBack(curFunc)) - { - curFunc(); - } - } - - mInputProcessingPaused = false; - - updateCursor(); -} - -static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); -static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); - -#define WINDOW_IMP_POST(x) window_imp->post([=]() { x; }) - -LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) -{ - ASSERT_WINDOW_THREAD(); - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - - if (u_msg == WM_POST_FUNCTION_) - { - // from LLWindowWin32Thread::Post() - // Cast l_param back to the pointer to the heap FuncType - // allocated by Post(). Capture in unique_ptr so we'll delete - // once we're done with it. - std::unique_ptr - ptr(reinterpret_cast(l_param)); - (*ptr)(); - return 0; - } - - // Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN. - // This helps prevent avatar walking after maximizing the window by double-clicking the title bar. - static bool sHandleLeftMouseUp = true; - - // Ignore the double click received right after activating app. - // This is to avoid triggering double click teleport after returning focus (see MAINT-3786). - static bool sHandleDoubleClick = true; - - LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); - - if (NULL != window_imp) - { - // Juggle to make sure we can get negative positions for when - // mouse is outside window. - LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); - - // pass along extended flag in mask - MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; - bool eat_keystroke = true; - - switch (u_msg) - { - RECT update_rect; - S32 update_width; - S32 update_height; - - case WM_TIMER: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_TIMER"); - WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp)); - break; - } - - case WM_DEVICECHANGE: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE"); - if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); - - return 1; - } - break; - } - - case WM_PAINT: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT"); - GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); - update_width = update_rect.right - update_rect.left + 1; - update_height = update_rect.bottom - update_rect.top + 1; - - WINDOW_IMP_POST(window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, - update_width, update_height)); - break; - } - case WM_PARENTNOTIFY: - { - break; - } - - case WM_SETCURSOR: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETCURSOR"); - // This message is sent whenever the cursor is moved in a window. - // You need to set the appropriate cursor appearance. - - // Only take control of cursor over client region of window - // This allows Windows(tm) to handle resize cursors, etc. - if (LOWORD(l_param) == HTCLIENT) - { - SetCursor(window_imp->mCursor[window_imp->mCurrentCursor]); - return 0; - } - break; - } - case WM_ENTERMENULOOP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENTERMENULOOP"); - WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp)); - break; - } - - case WM_EXITMENULOOP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_EXITMENULOOP"); - WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp)); - break; - } - - case WM_ACTIVATEAPP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP"); - window_imp->post([=]() - { - // This message should be sent whenever the app gains or loses focus. - BOOL activating = (BOOL)w_param; - - if (window_imp->mFullscreen) - { - // When we run fullscreen, restoring or minimizing the app needs - // to switch the screen resolution - if (activating) - { - window_imp->setFullscreenResolution(); - window_imp->restore(); - } - else - { - window_imp->minimize(); - window_imp->resetDisplayResolution(); - } - } - - if (!activating) - { - sHandleDoubleClick = false; - } - - window_imp->mCallbacks->handleActivateApp(window_imp, activating); - }); - break; - } - case WM_ACTIVATE: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATE"); - window_imp->post([=]() - { - // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE - BOOL activating = (LOWORD(w_param) != WA_INACTIVE); - - if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - }); - - break; - } - - case WM_QUERYOPEN: - // TODO: use this to return a nice icon - break; - - case WM_SYSCOMMAND: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND"); - switch (w_param) - { - case SC_KEYMENU: - // Disallow the ALT key from triggering the default system menu. - return 0; - - case SC_SCREENSAVE: - case SC_MONITORPOWER: - // eat screen save messages and prevent them! - return 0; - } - break; - } - case WM_CLOSE: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE"); - window_imp->post([=]() - { - // Will the app allow the window to close? - if (window_imp->mCallbacks->handleCloseRequest(window_imp)) - { - // Get the app to initiate cleanup. - window_imp->mCallbacks->handleQuit(window_imp); - // The app is responsible for calling destroyWindow when done with GL - } - }); - return 0; - } - case WM_DESTROY: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DESTROY"); - if (window_imp->shouldPostQuit()) - { - PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 - } - return 0; - } - case WM_COMMAND: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND"); - if (!HIWORD(w_param)) // this message is from a menu - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param))); - } - break; - } - case WM_SYSKEYDOWN: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN"); - // allow system keys, such as ALT-F4 to be processed by Windows - eat_keystroke = false; - // intentional fall-through here - [[fallthrough]]; - } - case WM_KEYDOWN: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYDOWN"); - window_imp->post([=]() - { - window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next - window_imp->mKeyScanCode = (l_param >> 16) & 0xff; - window_imp->mKeyVirtualKey = w_param; - window_imp->mRawMsg = u_msg; - window_imp->mRawWParam = w_param; - window_imp->mRawLParam = l_param; - - gKeyboard->handleKeyDown(w_param, mask); - }); - if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress - break; - } - case WM_SYSKEYUP: - eat_keystroke = false; - // intentional fall-through here - [[fallthrough]]; - case WM_KEYUP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP"); - window_imp->post([=]() - { - window_imp->mKeyScanCode = (l_param >> 16) & 0xff; - window_imp->mKeyVirtualKey = w_param; - window_imp->mRawMsg = u_msg; - window_imp->mRawWParam = w_param; - window_imp->mRawLParam = l_param; - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP"); - gKeyboard->handleKeyUp(w_param, mask); - } - }); - if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress - break; - } - case WM_IME_SETCONTEXT: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT"); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; - // Invoke DefWinProc with the modified LPARAM. - } - break; - } - case WM_IME_STARTCOMPOSITION: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION"); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - WINDOW_IMP_POST(window_imp->handleStartCompositionMessage()); - return 0; - } - break; - } - case WM_IME_ENDCOMPOSITION: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION"); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - return 0; - } - break; - } - case WM_IME_COMPOSITION: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION"); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - WINDOW_IMP_POST(window_imp->handleCompositionMessage(l_param)); - return 0; - } - break; - } - case WM_IME_REQUEST: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST"); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - LRESULT result; - window_imp->handleImeRequests(w_param, l_param, &result); - return result; - } - break; - } - case WM_CHAR: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CHAR"); - window_imp->post([=]() - { - window_imp->mKeyCharCode = w_param; - window_imp->mRawMsg = u_msg; - window_imp->mRawWParam = w_param; - window_imp->mRawLParam = l_param; - - // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need - // to figure out how that works. - Doug - // - // ... Well, I don't think so. - // How it works is explained in Win32 API document, but WM_UNICHAR didn't work - // as specified at least on Windows XP SP1 Japanese version. I have never used - // it since then, and I'm not sure whether it has been fixed now, but I don't think - // it is worth trying. The good old WM_CHAR works just fine even for supplementary - // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's - // by ourselves. It is not that tough. -- Alissa Sabre @ SL - - // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, bool) returned false, - // we *did* processed the event, so I believe we should not pass it to DefWindowProc... - window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(false)); - }); - return 0; - } - case WM_NCLBUTTONDOWN: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_NCLBUTTONDOWN"); - { - // A click in a non-client area, e.g. title bar or window border. - window_imp->post([=]() - { - sHandleLeftMouseUp = false; - sHandleDoubleClick = true; - }); - } - break; - } - case WM_LBUTTONDOWN: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN"); - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - window_imp->postMouseButtonEvent([=]() - { - sHandleLeftMouseUp = true; - - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - - MASK mask = gKeyboard->currentMask(true); - auto gl_coord = window_imp->mCursorPosition.convert(); - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask); - }); - - return 0; - } - break; - } - - case WM_LBUTTONDBLCLK: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDBLCLK"); - window_imp->postMouseButtonEvent([=]() - { - //RN: ignore right button double clicks for now - //case WM_RBUTTONDBLCLK: - if (!sHandleDoubleClick) - { - sHandleDoubleClick = true; - return; - } - MASK mask = gKeyboard->currentMask(true); - - // generate move event to update mouse coordinates - window_imp->mCursorPosition = window_coord; - window_imp->mCallbacks->handleDoubleClick(window_imp, window_imp->mCursorPosition.convert(), mask); - }); - - return 0; - } - case WM_LBUTTONUP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONUP"); - { - window_imp->postMouseButtonEvent([=]() - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - if (!sHandleLeftMouseUp) - { - sHandleLeftMouseUp = true; - return; - } - sHandleDoubleClick = true; - - - MASK mask = gKeyboard->currentMask(true); - // generate move event to update mouse coordinates - window_imp->mCursorPosition = window_coord; - window_imp->mCallbacks->handleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); - }); - } - return 0; - } - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN"); - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - window_imp->post([=]() - { - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - WINDOW_IMP_POST(window_imp->interruptLanguageTextInput()); - } - - MASK mask = gKeyboard->currentMask(true); - // generate move event to update mouse coordinates - auto gl_coord = window_imp->mCursorPosition.convert(); - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask); - }); - } - return 0; - } - break; - - case WM_RBUTTONUP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP"); - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - window_imp->postMouseButtonEvent([=]() - { - MASK mask = gKeyboard->currentMask(true); - window_imp->mCallbacks->handleRightMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); - }); - } - } - break; - - case WM_MBUTTONDOWN: - // case WM_MBUTTONDBLCLK: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN"); - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - window_imp->postMouseButtonEvent([=]() - { - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - - MASK mask = gKeyboard->currentMask(true); - window_imp->mCallbacks->handleMiddleMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask); - }); - } - } - break; - - case WM_MBUTTONUP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP"); - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - window_imp->postMouseButtonEvent([=]() - { - MASK mask = gKeyboard->currentMask(true); - window_imp->mCallbacks->handleMiddleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); - }); - } - } - break; - case WM_XBUTTONDOWN: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN"); - window_imp->postMouseButtonEvent([=]() - { - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - S32 button = GET_XBUTTON_WPARAM(w_param); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - - MASK mask = gKeyboard->currentMask(true); - // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 - window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); - }); - - } - break; - - case WM_XBUTTONUP: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP"); - window_imp->postMouseButtonEvent([=]() - { - - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - - S32 button = GET_XBUTTON_WPARAM(w_param); - MASK mask = gKeyboard->currentMask(true); - // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 - window_imp->mCallbacks->handleOtherMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); - }); - } - break; - - case WM_MOUSEWHEEL: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL"); - static short z_delta = 0; - - RECT client_rect; - - // eat scroll events that occur outside our window, since we use mouse position to direct scroll - // instead of keyboard focus - // NOTE: mouse_coord is in *window* coordinates for scroll events - POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) }; - - if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) - && GetClientRect(window_imp->mWindowHandle, &client_rect)) - { - // we have a valid mouse point and client rect - if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x - || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) - { - // mouse is outside of client rect, so don't do anything - return 0; - } - } - - S16 incoming_z_delta = HIWORD(w_param); - z_delta += incoming_z_delta; - // cout << "z_delta " << z_delta << endl; - - // current mouse wheels report changes in increments of zDelta (+120, -120) - // Future, higher resolution mouse wheels may report smaller deltas. - // So we sum the deltas and only act when we've exceeded WHEEL_DELTA - // - // If the user rapidly spins the wheel, we can get messages with - // large deltas, like 480 or so. Thus we need to scroll more quickly. - if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) - { - short clicks = -z_delta / WHEEL_DELTA; - WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollWheel(window_imp, clicks)); - z_delta = 0; - } - return 0; - } - /* - // TODO: add this after resolving _WIN32_WINNT issue - case WM_MOUSELEAVE: - { - window_imp->mCallbacks->handleMouseLeave(window_imp); - - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = h_wnd; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - return 0; - } - */ - case WM_MOUSEHWHEEL: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL"); - static short h_delta = 0; - - RECT client_rect; - - // eat scroll events that occur outside our window, since we use mouse position to direct scroll - // instead of keyboard focus - // NOTE: mouse_coord is in *window* coordinates for scroll events - POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) }; - - if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) - && GetClientRect(window_imp->mWindowHandle, &client_rect)) - { - // we have a valid mouse point and client rect - if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x - || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) - { - // mouse is outside of client rect, so don't do anything - return 0; - } - } - - S16 incoming_h_delta = HIWORD(w_param); - h_delta += incoming_h_delta; - - // If the user rapidly spins the wheel, we can get messages with - // large deltas, like 480 or so. Thus we need to scroll more quickly. - if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA)); - h_delta = 0; - } - return 0; - } - // Handle mouse movement within the window - case WM_MOUSEMOVE: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE"); - // DO NOT use mouse event queue for move events to ensure cursor position is updated - // when button events are handled - WINDOW_IMP_POST( - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda"); - - MASK mask = gKeyboard->currentMask(true); - window_imp->mMouseMask = mask; - window_imp->mCursorPosition = window_coord; - }); - return 0; - } - - case WM_GETMINMAXINFO: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_GETMINMAXINFO"); - LPMINMAXINFO min_max = (LPMINMAXINFO)l_param; - min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth; - min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight; - return 0; - } - - case WM_MOVE: - { - window_imp->updateWindowRect(); - return 0; - } - case WM_SIZE: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE"); - window_imp->updateWindowRect(); - - // There's an odd behavior with WM_SIZE that I would call a bug. If - // the window is maximized, and you call MoveWindow() with a size smaller - // than a maximized window, it ends up sending WM_SIZE with w_param set - // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. - // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see - // LLWindowWin32::moveWindow in this file). - - // If we are now restored, but we weren't before, this - // means that the window was un-minimized. - if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true)); - } - - // handle case of window being maximized from fully minimized state - if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true)); - } - - // Also handle the minimization case - if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) - { - WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, false)); - } - - // Actually resize all of our views - if (w_param != SIZE_MINIMIZED) - { - // Ignore updates for minimizing and minimized "windows" - WINDOW_IMP_POST(window_imp->mCallbacks->handleResize(window_imp, - LOWORD(l_param), - HIWORD(l_param))); - } - - window_imp->mLastSizeWParam = w_param; - - return 0; - } - - case WM_DPICHANGED: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED"); - LPRECT lprc_new_scale; - F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI); - lprc_new_scale = (LPRECT)l_param; - S32 new_width = lprc_new_scale->right - lprc_new_scale->left; - S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; - WINDOW_IMP_POST(window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height)); - - SetWindowPos(h_wnd, - HWND_TOP, - lprc_new_scale->left, - lprc_new_scale->top, - new_width, - new_height, - SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - - case WM_SETFOCUS: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS"); - WINDOW_IMP_POST(window_imp->mCallbacks->handleFocus(window_imp)); - return 0; - } - - case WM_KILLFOCUS: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS"); - WINDOW_IMP_POST(window_imp->mCallbacks->handleFocusLost(window_imp)); - return 0; - } - - case WM_COPYDATA: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COPYDATA"); - { - // received a URL - PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param; - void* data = new U8[myCDS->cbData]; - memcpy(data, myCDS->lpData, myCDS->cbData); - auto myType = myCDS->dwData; - - window_imp->post([=]() - { - window_imp->mCallbacks->handleDataCopy(window_imp, myType, data); - delete[] data; - }); - }; - return 0; - } - case WM_SETTINGCHANGE: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE"); - if (w_param == SPI_SETMOUSEVANISH) - { - if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0)) - { - WINDOW_IMP_POST(window_imp->mMouseVanish = true); - } - } - } - break; - - case WM_INPUT: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT"); - - UINT dwSize = 0; - GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); - llassert(dwSize < 1024); - - U8 lpb[1024]; - - if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) - { - RAWINPUT* raw = (RAWINPUT*)lpb; - - if (raw->header.dwType == RIM_TYPEMOUSE) - { - LLMutexLock lock(&window_imp->mRawMouseMutex); - - bool absolute_coordinates = (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE); - - if (absolute_coordinates) - { - static S32 prev_absolute_x = 0; - static S32 prev_absolute_y = 0; - S32 absolute_x; - S32 absolute_y; - - if ((raw->data.mouse.usFlags & 0x10) == 0x10) // touch screen? touch? Not defined in header - { - // touch screen spams (0,0) coordinates in a number of situations - // (0,0) might need to be filtered - absolute_x = raw->data.mouse.lLastX; - absolute_y = raw->data.mouse.lLastY; - } - else - { - bool v_desktop = (raw->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) == MOUSE_VIRTUAL_DESKTOP; - - S32 width = GetSystemMetrics(v_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN); - S32 height = GetSystemMetrics(v_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN); - - absolute_x = (raw->data.mouse.lLastX / 65535.0f) * width; - absolute_y = (raw->data.mouse.lLastY / 65535.0f) * height; - } - - window_imp->mRawMouseDelta.mX += absolute_x - prev_absolute_x; - window_imp->mRawMouseDelta.mY -= absolute_y - prev_absolute_y; - - prev_absolute_x = absolute_x; - prev_absolute_y = absolute_y; - } - else - { - S32 speed; - const S32 DEFAULT_SPEED(10); - SystemParametersInfo(SPI_GETMOUSESPEED, 0, &speed, 0); - if (speed == DEFAULT_SPEED) - { - window_imp->mRawMouseDelta.mX += raw->data.mouse.lLastX; - window_imp->mRawMouseDelta.mY -= raw->data.mouse.lLastY; - } - else - { - window_imp->mRawMouseDelta.mX += round((F32)raw->data.mouse.lLastX * (F32)speed / DEFAULT_SPEED); - window_imp->mRawMouseDelta.mY -= round((F32)raw->data.mouse.lLastY * (F32)speed / DEFAULT_SPEED); - } - } - } - } - } - break; - - //list of messages we get often that we don't care to log about - case WM_NCHITTEST: - case WM_NCMOUSEMOVE: - case WM_NCMOUSELEAVE: - case WM_MOVING: - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: - break; - - default: - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default"); - LL_DEBUGS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL; - } - break; - } - } - else - { - // (NULL == window_imp) - LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; - } - - // pass unhandled messages down to Windows - LRESULT ret; - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - DefWindowProc"); - ret = DefWindowProc(h_wnd, u_msg, w_param, l_param); - } - return ret; -} - -bool LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) -{ - S32 client_height; - RECT client_rect; - LLCoordWindow window_position; - - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - 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 LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) -{ - S32 client_height; - RECT client_rect; - - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - 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 LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) -{ - POINT mouse_point; - - mouse_point.x = from.mX; - mouse_point.y = from.mY; - bool result = ScreenToClient(mWindowHandle, &mouse_point); - - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } - - return result; -} - -bool LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) -{ - POINT mouse_point; - - mouse_point.x = from.mX; - mouse_point.y = from.mY; - bool result = ClientToScreen(mWindowHandle, &mouse_point); - - if (result) - { - to->mX = mouse_point.x; - to->mY = mouse_point.y; - } - - return result; -} - -bool LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) -{ - LLCoordWindow window_coord; - - if (!mWindowHandle || (NULL == to)) - { - return false; - } - - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return true; -} - -bool LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) -{ - LLCoordWindow window_coord; - - if (!mWindowHandle || (NULL == to)) - { - return false; - } - - convertCoords(from, &window_coord); - convertCoords(window_coord, to); - return true; -} - - -bool LLWindowWin32::isClipboardTextAvailable() -{ - return IsClipboardFormatAvailable(CF_UNICODETEXT); -} - - -bool LLWindowWin32::pasteTextFromClipboard(LLWString &dst) -{ - bool success = false; - - if (IsClipboardFormatAvailable(CF_UNICODETEXT)) - { - if (OpenClipboard(mWindowHandle)) - { - HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); - if (h_data) - { - WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); - if (utf16str) - { - dst = utf16str_to_wstring(utf16str); - LLWStringUtil::removeWindowsCR(dst); - GlobalUnlock(h_data); - success = true; - } - } - CloseClipboard(); - } - } - - return success; -} - - -bool LLWindowWin32::copyTextToClipboard(const LLWString& wstr) -{ - bool success = false; - - if (OpenClipboard(mWindowHandle)) - { - EmptyClipboard(); - - // Provide a copy of the data in Unicode format. - LLWString sanitized_string(wstr); - LLWStringUtil::addCRLF(sanitized_string); - llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); - const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); - - // Memory is allocated and then ownership of it is transfered to the system. - HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); - if (hglobal_copy_utf16) - { - WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); - if (copy_utf16) - { - memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ - GlobalUnlock(hglobal_copy_utf16); - - if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) - { - success = true; - } - } - } - - CloseClipboard(); - } - - return success; -} - -// Constrains the mouse to the window. -void LLWindowWin32::setMouseClipping( bool b ) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - ASSERT_MAIN_THREAD(); - if( b != mIsMouseClipping ) - { - bool success = false; - - if( b ) - { - GetClipCursor( &mOldMouseClip ); - - RECT client_rect_in_screen_space; - if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) - { - success = ClipCursor( &client_rect_in_screen_space ); - } - } - else - { - // Must restore the old mouse clip, which may be set by another window. - success = ClipCursor( &mOldMouseClip ); - SetRect( &mOldMouseClip, 0, 0, 0, 0 ); - } - - if( success ) - { - mIsMouseClipping = b; - } - } -} - -bool LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) -{ - bool success = false; - - RECT client_rect; - if (mWindowHandle && GetClientRect(mWindowHandle, &client_rect)) - { - POINT top_left; - top_left.x = client_rect.left; - top_left.y = client_rect.top; - ClientToScreen(mWindowHandle, &top_left); - - POINT bottom_right; - bottom_right.x = client_rect.right; - bottom_right.y = client_rect.bottom; - ClientToScreen(mWindowHandle, &bottom_right); - - SetRect(rectp, - top_left.x, - top_left.y, - bottom_right.x, - bottom_right.y); - - success = true; - } - - return success; -} - -void LLWindowWin32::flashIcon(F32 seconds) -{ - mWindowThread->post([=]() - { - FLASHWINFO flash_info; - - flash_info.cbSize = sizeof(FLASHWINFO); - flash_info.hwnd = mWindowHandle; - flash_info.dwFlags = FLASHW_TRAY; - flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); - flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds - FlashWindowEx(&flash_info); - }); -} - -F32 LLWindowWin32::getGamma() -{ - return mCurrentGamma; -} - -bool LLWindowWin32::restoreGamma() -{ - ASSERT_MAIN_THREAD(); - if (mCustomGammaSet) - { - LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; - mCustomGammaSet = false; - return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); - } - return true; -} - -bool LLWindowWin32::setGamma(const F32 gamma) -{ - ASSERT_MAIN_THREAD(); - mCurrentGamma = gamma; - - //Get the previous gamma ramp to restore later. - if (!mCustomGammaSet) - { - if (!gGLManager.mIsIntel) // skip for Intel GPUs (see SL-11341) - { - LL_DEBUGS("Window") << "Getting the previous gamma ramp to restore later" << LL_ENDL; - if (!GetDeviceGammaRamp(mhDC, mPrevGammaRamp)) - { - LL_WARNS("Window") << "Failed to get the previous gamma ramp" << LL_ENDL; - return false; - } - } - mCustomGammaSet = true; - } - - LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; - - for ( int i = 0; i < 256; ++i ) - { - int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); - - int value = mult * i; - - if ( value > 0xffff ) - value = 0xffff; - - mCurrentGammaRamp[0][i] = - mCurrentGammaRamp[1][i] = - mCurrentGammaRamp[2][i] = (WORD) value; - }; - - return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); -} - -void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) -{ - ASSERT_MAIN_THREAD(); - mFSAASamples = fsaa_samples; -} - -U32 LLWindowWin32::getFSAASamples() -{ - return mFSAASamples; -} - -LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) -{ - ASSERT_MAIN_THREAD(); - if (!mSupportedResolutions) - { - mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - - mNumSupportedResolutions = 0; - for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } - - if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && - dev_mode.dmPelsWidth >= 800 && - dev_mode.dmPelsHeight >= 600) - { - bool resolution_exists = false; - for(S32 i = 0; i < mNumSupportedResolutions; i++) - { - if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && - mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) - { - resolution_exists = true; - } - } - if (!resolution_exists) - { - mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; - mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; - mNumSupportedResolutions++; - } - } - } - } - - num_resolutions = mNumSupportedResolutions; - return mSupportedResolutions; -} - - -F32 LLWindowWin32::getNativeAspectRatio() -{ - if (mOverrideAspectRatio > 0.f) - { - return mOverrideAspectRatio; - } - else if (mNativeAspectRatio > 0.f) - { - // we grabbed this value at startup, based on the user's desktop settings - return mNativeAspectRatio; - } - // RN: this hack presumes that the largest supported resolution is monitor-limited - // and that pixels in that mode are square, therefore defining the native aspect ratio - // of the monitor...this seems to work to a close approximation for most CRTs/LCDs - S32 num_resolutions; - LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); - - return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); -} - -F32 LLWindowWin32::getPixelAspectRatio() -{ - F32 pixel_aspect = 1.f; - if (getFullscreen()) - { - LLCoordScreen screen_size; - getSize(&screen_size); - pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } - - return pixel_aspect; -} - -// Change display resolution. Returns true if successful. -// protected -bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) -{ - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - bool success = false; - - // Don't change anything if we don't have to - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == bits && - dev_mode.dmDisplayFrequency == refresh ) - { - // ...display mode identical, do nothing - return true; - } - } - - memset(&dev_mode, 0, sizeof(dev_mode)); - dev_mode.dmSize = sizeof(dev_mode); - dev_mode.dmPelsWidth = width; - dev_mode.dmPelsHeight = height; - dev_mode.dmBitsPerPel = bits; - dev_mode.dmDisplayFrequency = refresh; - dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; - - // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. - LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); - - success = (DISP_CHANGE_SUCCESSFUL == cds_result); - - if (!success) - { - LL_WARNS("Window") << "setDisplayResolution failed, " - << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; - } - - return success; -} - -// protected -bool LLWindowWin32::setFullscreenResolution() -{ - if (mFullscreen) - { - return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); - } - else - { - return false; - } -} - -// protected -bool LLWindowWin32::resetDisplayResolution() -{ - LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; - - LONG cds_result = ChangeDisplaySettings(NULL, 0); - - bool success = (DISP_CHANGE_SUCCESSFUL == cds_result); - - if (!success) - { - LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; - } - - LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; - - return success; -} - -void LLWindowWin32::swapBuffers() -{ - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - SwapBuffers(mhDC); - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("GPU Collect"); - LL_PROFILER_GPU_COLLECT; - } -} - - -// -// LLSplashScreenImp -// -LLSplashScreenWin32::LLSplashScreenWin32() -: mWindow(NULL) -{ -} - -LLSplashScreenWin32::~LLSplashScreenWin32() -{ -} - -void LLSplashScreenWin32::showImpl() -{ - // This appears to work. ??? - HINSTANCE hinst = GetModuleHandle(NULL); - - mWindow = CreateDialog(hinst, - TEXT("SPLASHSCREEN"), - NULL, // no parent - (DLGPROC) LLSplashScreenWin32::windowProc); - ShowWindow(mWindow, SW_SHOW); - - // Should set taskbar text without creating a header for the window (caption) - SetWindowTextA(mWindow, "Second Life"); -} - - -void LLSplashScreenWin32::updateImpl(const std::string& mesg) -{ - if (!mWindow) return; - - int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); - if( output_str_len>1024 ) - return; - - WCHAR w_mesg[1025];//big enought to keep null terminatos - - MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); - - //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 - w_mesg[output_str_len] = 0; - - SendDlgItemMessage(mWindow, - 666, // HACK: text id - WM_SETTEXT, - FALSE, - (LPARAM)w_mesg); -} - - -void LLSplashScreenWin32::hideImpl() -{ - if (mWindow) - { - if (!destroy_window_handler(mWindow)) - { - LL_WARNS("Window") << "Failed to properly close splash screen window!" << LL_ENDL; - } - mWindow = NULL; - } -} - - -// static -LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param) -{ - // Just give it to windows - return DefWindowProc(h_wnd, u_msg, w_param, l_param); -} - -// -// Helper Funcs -// - -S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) -{ - UINT uType; - - switch(type) - { - case OSMB_OK: - uType = MB_OK; - break; - case OSMB_OKCANCEL: - uType = MB_OKCANCEL; - break; - case OSMB_YESNO: - uType = MB_YESNO; - break; - default: - uType = MB_OK; - break; - } - - int retval_win = MessageBoxW(NULL, // HWND - ll_convert_string_to_wide(text).c_str(), - ll_convert_string_to_wide(caption).c_str(), - uType); - S32 retval; - - switch(retval_win) - { - case IDYES: - retval = OSBTN_YES; - break; - case IDNO: - retval = OSBTN_NO; - break; - case IDOK: - retval = OSBTN_OK; - break; - case IDCANCEL: - retval = OSBTN_CANCEL; - break; - default: - retval = OSBTN_CANCEL; - break; - } - - return retval; -} - - -void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) -{ - bool found = false; - S32 i; - for (i = 0; i < gURLProtocolWhitelistCount; i++) - { - if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) - { - found = true; - break; - } - } - - if (!found) - { - LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; - return; - } - - LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; - - // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work - // reliablly on Vista. - - // this is madness.. no, this is.. - LLWString url_wstring = utf8str_to_wstring( escaped_url ); - llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); - - // let the OS decide what to use to open the URL - SHELLEXECUTEINFO sei = { sizeof( sei ) }; - // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange - // necessary for ShellExecuteEx to complete - if (async) - { - sei.fMask = SEE_MASK_ASYNCOK; - } - sei.nShow = SW_SHOWNORMAL; - sei.lpVerb = L"open"; - sei.lpFile = url_utf16.c_str(); - ShellExecuteEx( &sei ); -} - -/* - Make the raw keyboard data available - used to poke through to LLQtWebKit so - that Qt/Webkit has access to the virtual keycodes etc. that it needs -*/ -LLSD LLWindowWin32::getNativeKeyData() -{ - LLSD result = LLSD::emptyMap(); - - result["scan_code"] = (S32)mKeyScanCode; - result["virtual_key"] = (S32)mKeyVirtualKey; - result["msg"] = ll_sd_from_U32(mRawMsg); - result["w_param"] = ll_sd_from_U32(mRawWParam); - result["l_param"] = ll_sd_from_U32(mRawLParam); - - return result; -} - -bool LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) -{ - bool retval = false; - - static CHOOSECOLOR cc; - static COLORREF crCustColors[16]; - cc.lStructSize = sizeof(CHOOSECOLOR); - cc.hwndOwner = mWindowHandle; - cc.hInstance = NULL; - cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); - //cc.rgbResult = RGB (0x80,0x80,0x80); - cc.lpCustColors = crCustColors; - cc.Flags = CC_RGBINIT | CC_FULLOPEN; - cc.lCustData = 0; - cc.lpfnHook = NULL; - cc.lpTemplateName = NULL; - - // This call is modal, so pause agent - //send_agent_pause(); // this is in newview and we don't want to set up a dependency - { - retval = ChooseColor(&cc); - } - //send_agent_resume(); // this is in newview and we don't want to set up a dependency - - *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; - - *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; - - *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; - - return (retval); -} - -void *LLWindowWin32::getPlatformWindow() -{ - return (void*)mWindowHandle; -} - -void LLWindowWin32::bringToFront() -{ - mWindowThread->post([=]() - { - BringWindowToTop(mWindowHandle); - }); -} - -// set (OS) window focus back to the client -void LLWindowWin32::focusClient() -{ - mWindowThread->post([=]() - { - SetFocus(mWindowHandle); - }); -} - -void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, bool b) -{ - if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) - { - return; - } - - if (preeditor != mPreeditor && !b) - { - // This condition may occur with a call to - // setEnabled(bool) from LLTextEditor or LLLineEditor - // when the control is not focused. - // We need to silently ignore the case so that - // the language input status of the focused control - // is not disturbed. - return; - } - - // Take care of old and new preeditors. - if (preeditor != mPreeditor || !b) - { - if (sLanguageTextInputAllowed) - { - interruptLanguageTextInput(); - } - mPreeditor = (b ? preeditor : NULL); - } - - sLanguageTextInputAllowed = b; - - if (sLanguageTextInputAllowed) - { - mWindowThread->post([=]() - { - // Allowing: Restore the previous IME status, so that the user has a feeling that the previous - // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps - // using same Input Locale (aka Keyboard Layout). - if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setOpenStatus(himc, true); - LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); - LLWinImm::releaseContext(mWindowHandle, himc); - } - }); - } - else - { - mWindowThread->post([=]() - { - // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly. - // However, do it after saving the current IME status. We need to restore the status when - // allowing language text input again. - sWinInputLocale = GetKeyboardLayout(0); - sWinIMEOpened = LLWinImm::isIME(sWinInputLocale); - if (sWinIMEOpened) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - sWinIMEOpened = LLWinImm::getOpenStatus(himc); - if (sWinIMEOpened) - { - LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); - - // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's - // keyboard hooking, because Some IME reacts only on the former and some other on the latter... - LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); - LLWinImm::setOpenStatus(himc, false); - } - LLWinImm::releaseContext(mWindowHandle, himc); - } - }); - } -} - -void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, - CANDIDATEFORM *form) -{ - LLCoordWindow caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - - memset(form, 0, sizeof(CANDIDATEFORM)); - form->dwStyle = CFS_EXCLUDE; - form->ptCurrentPos.x = caret_coord.mX; - form->ptCurrentPos.y = caret_coord.mY; - form->rcArea.left = top_left.mX; - form->rcArea.top = top_left.mY; - form->rcArea.right = bottom_right.mX; - form->rcArea.bottom = bottom_right.mY; -} - - -// Put the IME window at the right place (near current text input). Point coordinates should be the top of the current text line. -void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) -{ - if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - - LLCoordWindow win_pos; - convertCoords( position, &win_pos ); - - if ( win_pos.mX >= 0 && win_pos.mY >= 0 && - (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) - { - COMPOSITIONFORM ime_form; - memset( &ime_form, 0, sizeof(ime_form) ); - ime_form.dwStyle = CFS_POINT; - ime_form.ptCurrentPos.x = win_pos.mX; - ime_form.ptCurrentPos.y = win_pos.mY; - - LLWinImm::setCompositionWindow( himc, &ime_form ); - - sWinIMEWindowPosition = win_pos; - } - - LLWinImm::releaseContext(mWindowHandle, himc); - } -} - - -void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, - IMECHARPOSITION *char_position) -{ - LLCoordScreen caret_coord, top_left, bottom_right; - convertCoords(caret, &caret_coord); - convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); - convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); - - char_position->pt.x = caret_coord.mX; - char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... - char_position->cLineHeight = bottom_right.mY - top_left.mY; - char_position->rcDocument.left = top_left.mX; - char_position->rcDocument.top = top_left.mY; - char_position->rcDocument.right = bottom_right.mX; - char_position->rcDocument.bottom = bottom_right.mY; -} - -void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) -{ - // Our font is a list of FreeType recognized font files that may - // not have a corresponding ones in Windows' fonts. Hence, we - // can't simply tell Windows which font we are using. We will - // notify a _standard_ font for a current input locale instead. - // We use a hard-coded knowledge about the Windows' standard - // configuration to do so... - - memset(logfont, 0, sizeof(LOGFONT)); - - const WORD lang_id = LOWORD(GetKeyboardLayout(0)); - switch (PRIMARYLANGID(lang_id)) - { - case LANG_CHINESE: - // We need to identify one of two Chinese fonts. - switch (SUBLANGID(lang_id)) - { - case SUBLANG_CHINESE_SIMPLIFIED: - case SUBLANG_CHINESE_SINGAPORE: - logfont->lfCharSet = GB2312_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("SimHei")); - break; - case SUBLANG_CHINESE_TRADITIONAL: - case SUBLANG_CHINESE_HONGKONG: - case SUBLANG_CHINESE_MACAU: - default: - logfont->lfCharSet = CHINESEBIG5_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); - break; - } - break; - case LANG_JAPANESE: - logfont->lfCharSet = SHIFTJIS_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); - break; - case LANG_KOREAN: - logfont->lfCharSet = HANGUL_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Gulim")); - break; - default: - logfont->lfCharSet = ANSI_CHARSET; - lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); - break; - } - - logfont->lfHeight = mPreeditor->getPreeditFontSize(); - logfont->lfWeight = FW_NORMAL; -} - -U32 LLWindowWin32::fillReconvertString(const LLWString &text, - S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) -{ - const llutf16string text_utf16 = wstring_to_utf16str(text); - const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); - if (reconvert_string && reconvert_string->dwSize >= required_size) - { - const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); - const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); - - reconvert_string->dwVersion = 0; - reconvert_string->dwStrLen = text_utf16.length(); - reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); - reconvert_string->dwCompStrLen = focus_utf16_length; - reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); - reconvert_string->dwTargetStrLen = 0; - reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); - - const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); - memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); - } - return required_size; -} - -void LLWindowWin32::updateLanguageTextInputArea() -{ - if (!mPreeditor || !LLWinImm::isAvailable()) - { - return; - } - - LLCoordGL caret_coord; - LLRect preedit_bounds; - if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) - { - mLanguageTextInputPointGL = caret_coord; - mLanguageTextInputAreaGL = preedit_bounds; - - CANDIDATEFORM candidate_form; - fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); - - HIMC himc = LLWinImm::getContext(mWindowHandle); - // Win32 document says there may be up to 4 candidate windows. - // This magic number 4 appears only in the document, and - // there are no constant/macro for the value... - for (int i = 3; i >= 0; --i) - { - candidate_form.dwIndex = i; - LLWinImm::setCandidateWindow(himc, &candidate_form); - } - LLWinImm::releaseContext(mWindowHandle, himc); - } -} - -void LLWindowWin32::interruptLanguageTextInput() -{ - ASSERT_MAIN_THREAD(); - if (mPreeditor && LLWinImm::isAvailable()) - { - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - } -} - -void LLWindowWin32::handleStartCompositionMessage() -{ - // Let IME know the font to use in feedback UI. - LOGFONT logfont; - fillCompositionLogfont(&logfont); - HIMC himc = LLWinImm::getContext(mWindowHandle); - LLWinImm::setCompositionFont(himc, &logfont); - LLWinImm::releaseContext(mWindowHandle, himc); -} - -// Handle WM_IME_COMPOSITION message. - -void LLWindowWin32::handleCompositionMessage(const U32 indexes) -{ - if (!mPreeditor) - { - return; - } - bool needs_update = false; - LLWString result_string; - LLWString preedit_string; - S32 preedit_string_utf16_length = 0; - LLPreeditor::segment_lengths_t preedit_segment_lengths; - LLPreeditor::standouts_t preedit_standouts; - - // Step I: Receive details of preedits from IME. - - HIMC himc = LLWinImm::getContext(mWindowHandle); - - if (indexes & GCS_RESULTSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); - if (size > 0) - { - result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = true; - } - } - - if (indexes & GCS_COMPSTR) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); - if (size >= 0) - { - const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; - size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); - if (size > 0) - { - preedit_string_utf16_length = size / sizeof(WCHAR); - preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); - } - delete[] data; - needs_update = true; - } - } - - if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); - if (size > 0) - { - const LPDWORD data = new DWORD[size / sizeof(DWORD)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); - if (size >= sizeof(DWORD) * 2 - && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) - { - preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); - preedit_segment_lengths[i] = length; - offset += length; - } - } - delete[] data; - } - } - - if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) - { - LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); - if (size > 0) - { - const LPBYTE data = new BYTE[size / sizeof(BYTE)]; - size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); - if (size == preedit_string_utf16_length) - { - preedit_standouts.assign(preedit_segment_lengths.size(), false); - S32 offset = 0; - for (U32 i = 0; i < preedit_segment_lengths.size(); i++) - { - if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) - { - preedit_standouts[i] = true; - } - offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); - } - } - delete[] data; - } - } - - S32 caret_position = preedit_string.length(); - if (indexes & GCS_CURSORPOS) - { - const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); - if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) - { - caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); - } - } - - if (indexes == 0) - { - // I'm not sure this condition really happens, but - // Windows SDK document says it is an indication - // of "reset everything." - needs_update = true; - } - - LLWinImm::releaseContext(mWindowHandle, himc); - - // Step II: Update the active preeditor. - - if (needs_update) - { - if (preedit_string.length() != 0 || result_string.length() != 0) - { - mPreeditor->resetPreedit(); - } - - if (result_string.length() > 0) - { - for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) - { - mPreeditor->handleUnicodeCharHere(*i); - } - } - - if (preedit_string.length() == 0) - { - preedit_segment_lengths.clear(); - preedit_standouts.clear(); - } - else - { - if (preedit_segment_lengths.size() == 0) - { - preedit_segment_lengths.assign(1, preedit_string.length()); - } - if (preedit_standouts.size() == 0) - { - preedit_standouts.assign(preedit_segment_lengths.size(), false); - } - } - mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); - - // Some IME doesn't query char position after WM_IME_COMPOSITION, - // so we need to update them actively. - updateLanguageTextInputArea(); - } -} - -// Given a text and a focus range, find_context finds and returns a -// surrounding context of the focused subtext. A variable pointed -// to by offset receives the offset in llwchars of the beginning of -// the returned context string in the given wtext. - -static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) -{ - static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. - - const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); - S32 end = focus + focus_length; - while (end < e && '\n' != wtext[end]) - { - end++; - } - - const S32 s = llmax(0, focus - CONTEXT_EXCESS); - S32 start = focus; - while (start > s && '\n' != wtext[start - 1]) - { - --start; - } - - *offset = start; - return wtext.substr(start, end - start); -} - -// final stage of handling drop requests - both from WM_DROPFILES message -// for files and via IDropTarget interface requests. -LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ) -{ - ASSERT_MAIN_THREAD(); - return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); -} - -// Handle WM_IME_REQUEST message. -// If it handled the message, returns true. Otherwise, false. -// When it handled the message, the value to be returned from -// the Window Procedure is set to *result. - -bool LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result) -{ - if ( mPreeditor ) - { - switch (request) - { - case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx - { - LLCoordGL caret_coord; - LLRect preedit_bounds; - mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); - - CANDIDATEFORM *const form = (CANDIDATEFORM *)param; - DWORD const dwIndex = form->dwIndex; - fillCandidateForm(caret_coord, preedit_bounds, form); - form->dwIndex = dwIndex; - - *result = 1; - return true; - } - case IMR_QUERYCHARPOSITION: - { - IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; - - // char_position->dwCharPos counts in number of - // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the - // number to getPreeditLocation. - - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - LLCoordGL caret_coord; - LLRect preedit_bounds, text_control; - const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); - - if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) - { - LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; - return false; - } - - fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); - - *result = 1; - return true; - } - case IMR_COMPOSITIONFONT: - { - fillCompositionLogfont((LOGFONT *)param); - - *result = 1; - return true; - } - case IMR_RECONVERTSTRING: - { - mPreeditor->resetPreedit(); - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 select, select_length; - mPreeditor->getSelectionRange(&select, &select_length); - - S32 context_offset; - const LLWString context = find_context(wtext, select, select_length, &context_offset); - - RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; - const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); - if (reconvert_string) - { - if (select_length == 0) - { - // Let the IME to decide the reconversion range, and - // adjust the reconvert_string structure accordingly. - HIMC himc = LLWinImm::getContext(mWindowHandle); - const bool adjusted = LLWinImm::setCompositionString(himc, - SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); - LLWinImm::releaseContext(mWindowHandle, himc); - if (adjusted) - { - const llutf16string & text_utf16 = wstring_to_utf16str(context); - const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); - const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; - select = utf16str_wstring_length(text_utf16, new_preedit_start); - select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; - select += context_offset; - } - } - mPreeditor->markAsPreedit(select, select_length); - } - - *result = size; - return true; - } - case IMR_CONFIRMRECONVERTSTRING: - { - *result = 0; - return true; - } - case IMR_DOCUMENTFEED: - { - const LLWString & wtext = mPreeditor->getPreeditString(); - S32 preedit, preedit_length; - mPreeditor->getPreeditRange(&preedit, &preedit_length); - - S32 context_offset; - LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); - preedit -= context_offset; - preedit_length = llmin(preedit_length, (S32)context.length() - preedit); - if (preedit_length > 0 && preedit >= 0) - { - // IMR_DOCUMENTFEED may be called when we have an active preedit. - // We should pass the context string *excluding* the preedit string. - // Otherwise, some IME are confused. - context.erase(preedit, preedit_length); - } - - RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; - *result = fillReconvertString(context, preedit, 0, reconvert_string); - return true; - } - default: - return false; - } - } - - return false; -} - -//static -void LLWindowWin32::setDPIAwareness() -{ - HMODULE hShcore = LoadLibrary(L"shcore.dll"); - if (hShcore != NULL) - { - SetProcessDpiAwarenessType pSPDA; - pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); - if (pSPDA) - { - - HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); - if (hr != S_OK) - { - LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; - } - } - FreeLibrary(hShcore); - } - else - { - LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; - } -} - -void* LLWindowWin32::getDirectInput8() -{ - return &gDirectInput8; -} - -bool LLWindowWin32::getInputDevices(U32 device_type_filter, - std::function osx_callback, - void * di8_devices_callback, - void* userdata) -{ - if (gDirectInput8 != NULL) - { - // Enumerate devices - HRESULT status = gDirectInput8->EnumDevices( - (DWORD) device_type_filter, // DWORD dwDevType, - (LPDIENUMDEVICESCALLBACK)di8_devices_callback, // LPDIENUMDEVICESCALLBACK lpCallback, // BOOL DIEnumDevicesCallback( LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef ) // BOOL CALLBACK DinputDevice::DevicesCallback - (LPVOID*)userdata, // LPVOID pvRef - DIEDFL_ATTACHEDONLY // DWORD dwFlags - ); - - return status == DI_OK; - } - return false; -} - -F32 LLWindowWin32::getSystemUISize() -{ - F32 scale_value = 1.f; - HWND hWnd = (HWND)getPlatformWindow(); - HDC hdc = GetDC(hWnd); - HMONITOR hMonitor; - HANDLE hProcess = GetCurrentProcess(); - PROCESS_DPI_AWARENESS dpi_awareness; - - HMODULE hShcore = LoadLibrary(L"shcore.dll"); - - if (hShcore != NULL) - { - GetProcessDpiAwarenessType pGPDA; - pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); - GetDpiForMonitorType pGDFM; - pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); - if (pGPDA != NULL && pGDFM != NULL) - { - pGPDA(hProcess, &dpi_awareness); - if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) - { - POINT pt; - UINT dpix = 0, dpiy = 0; - HRESULT hr = E_FAIL; - RECT rect; - - GetWindowRect(hWnd, &rect); - // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor - pt.x = (rect.left + rect.right) / 2; - pt.y = (rect.top + rect.bottom) / 2; - hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); - hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); - if (hr == S_OK) - { - scale_value = F32(dpix) / F32(USER_DEFAULT_SCREEN_DPI); - } - else - { - LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; - scale_value = 1.0f; - } - } - else - { - LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; - scale_value = 1.0f; - } - } - FreeLibrary(hShcore); - } - else - { - LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; - scale_value = F32(GetDeviceCaps(hdc, LOGPIXELSX)) / F32(USER_DEFAULT_SCREEN_DPI); - } - - ReleaseDC(hWnd, hdc); - return scale_value; -} - -//static -std::vector LLWindowWin32::getDisplaysResolutionList() -{ - return sMonitorInfo.getResolutionsList(); -} - -//static -std::vector LLWindowWin32::getDynamicFallbackFontList() -{ - // Fonts previously in getFontListSans() have moved to fonts.xml. - return std::vector(); -} - -void LLWindowWin32::setMaxVRAMMegabytes(U32 max_vram) -{ - if (mWindowThread) - { - mWindowThread->mMaxVRAM = max_vram; - } -} - -#endif // LL_WINDOWS - -inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/) -{ - LL::ThreadPool::start(); -} - -void LLWindowWin32::LLWindowWin32Thread::close() -{ - if (!mQueue->isClosed()) - { - LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL; - LL::ThreadPool::close(); - - // Workaround for SL-18721 in case window closes too early and abruptly - LLSplashScreen::show(); - LLSplashScreen::update("..."); // will be updated later - } -} - - -/** - * LogChange is to log changes in status while trying to avoid spamming the - * log with repeated messages, especially in a tight loop. It refuses to log - * a continuous run of identical messages, but logs every time the message - * changes. (It will happily spam when messages quickly bounce back and - * forth.) - */ -class LogChange -{ -public: - LogChange(const std::string& tag): - mTag(tag) - {} - - template - void always(Items&&... items) - { - // This odd construct ensures that the stringize() call is only - // executed if DEBUG logging is enabled for the passed tag. - LL_DEBUGS(mTag.c_str()); - log(LL_CONT, stringize(std::forward(items)...)); - LL_ENDL; - } - - template - void onChange(Items&&... items) - { - LL_DEBUGS(mTag.c_str()); - auto str = stringize(std::forward(items)...); - if (str != mPrev) - { - log(LL_CONT, str); - } - LL_ENDL; - } - -private: - void log(std::ostream& out, const std::string& message) - { - mPrev = message; - out << message; - } - std::string mTag; - std::string mPrev; -}; - -// Print hardware debug info about available graphics adapters in ordinal order -void debugEnumerateGraphicsAdapters() -{ - LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL; - - IDXGIFactory1* factory; - HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory); - if (FAILED(res) || !factory) - { - LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - UINT graphics_adapter_index = 0; - IDXGIAdapter3* dxgi_adapter; - while (true) - { - res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&dxgi_adapter)); - if (FAILED(res)) - { - if (graphics_adapter_index == 0) - { - LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL; - } - } - else - { - DXGI_ADAPTER_DESC desc; - dxgi_adapter->GetDesc(&desc); - std::wstring description_w((wchar_t*)desc.Description); - std::string description(description_w.begin(), description_w.end()); - LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", " - << "Description: " << description << ", " - << "DeviceId: " << desc.DeviceId << ", " - << "SubSysId: " << desc.SubSysId << ", " - << "AdapterLuid: " << desc.AdapterLuid.HighPart << "_" << desc.AdapterLuid.LowPart << ", " - << "DedicatedVideoMemory: " << desc.DedicatedVideoMemory / 1024 / 1024 << ", " - << "DedicatedSystemMemory: " << desc.DedicatedSystemMemory / 1024 / 1024 << ", " - << "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL; - } - - if (dxgi_adapter) - { - dxgi_adapter->Release(); - dxgi_adapter = NULL; - } - else - { - break; - } - - graphics_adapter_index++; - } - } - - if (factory) - { - factory->Release(); - } -} - -void LLWindowWin32::LLWindowWin32Thread::initDX() -{ - if (!mGLReady) { return; } - - if (mDXGIAdapter == NULL) - { - debugEnumerateGraphicsAdapters(); - - IDXGIFactory4* pFactory = nullptr; - - HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory); - - if (FAILED(res)) - { - LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - res = pFactory->EnumAdapters(0, reinterpret_cast(&mDXGIAdapter)); - if (FAILED(res)) - { - LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - LL_INFOS() << "EnumAdapters success" << LL_ENDL; - } - } - - if (pFactory) - { - pFactory->Release(); - } - } -} - -void LLWindowWin32::LLWindowWin32Thread::initD3D() -{ - if (!mGLReady) { return; } - - if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) - { - mD3D = Direct3DCreate9(D3D_SDK_VERSION); - - D3DPRESENT_PARAMETERS d3dpp; - - ZeroMemory(&d3dpp, sizeof(d3dpp)); - d3dpp.Windowed = TRUE; - d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - - HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); - - if (FAILED(res)) - { - LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL; - } - } -} - -void LLWindowWin32::LLWindowWin32Thread::cleanupDX() -{ - //clean up DXGI/D3D resources - if (mDXGIAdapter) - { - mDXGIAdapter->Release(); - mDXGIAdapter = nullptr; - } - - if (mD3DDevice) - { - mD3DDevice->Release(); - mD3DDevice = nullptr; - } - - if (mD3D) - { - mD3D->Release(); - mD3D = nullptr; - } -} - -void LLWindowWin32::LLWindowWin32Thread::run() -{ - sWindowThreadId = std::this_thread::get_id(); - LogChange logger("Window"); - - //as good a place as any to up the MM timer resolution (see ms_sleep) - //attempt to set timer resolution to 1ms - TIMECAPS tc; - if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) - { - timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax)); - } - - while (! getQueue().done()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - - // lazily call initD3D inside this loop to catch when mGLReady has been set to true - initDX(); - - if (mWindowHandleThrd != 0) - { - // lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true - // *TODO: Shutdown if this fails when mWindowHandle exists - initD3D(); - - MSG msg; - BOOL status; - if (mhDCThrd == 0) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage"); - logger.onChange("PeekMessage(", std::hex, mWindowHandleThrd, ")"); - status = PeekMessage(&msg, mWindowHandleThrd, 0, 0, PM_REMOVE); - } - else - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage"); - logger.always("GetMessage(", std::hex, mWindowHandleThrd, ")"); - status = GetMessage(&msg, NULL, 0, 0); - } - if (status > 0) - { - logger.always("got MSG (", std::hex, msg.hwnd, ", ", msg.message, - ", ", msg.wParam, ")"); - TranslateMessage(&msg); - DispatchMessage(&msg); - - mMessageQueue.pushFront(msg); - } - } - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue"); - logger.onChange("runPending()"); - //process any pending functions - getQueue().runPending(); - } - -#if 0 - { - LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep"); - logger.always("sleep(1)"); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } -#endif - } - - cleanupDX(); -} - -void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() -{ - if (mQueue->isClosed()) - { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; - return; - } - - // Make sure we don't leave a blank toolbar button. - // Also hiding window now prevents user from suspending it - // via some action (like dragging it around) - ShowWindow(mWindowHandleThrd, SW_HIDE); - - // Schedule destruction - HWND old_handle = mWindowHandleThrd; - post([this]() - { - if (IsWindow(mWindowHandleThrd)) - { - if (mhDCThrd) - { - if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) - { - LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; - } - mhDCThrd = NULL; - } - - // This causes WM_DESTROY to be sent *immediately* - if (!destroy_window_handler(mWindowHandleThrd)) - { - LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; - } - } - else - { - // Something killed the window while we were busy destroying gl or handle somehow got broken - LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; - } - mWindowHandleThrd = NULL; - mhDCThrd = NULL; - mGLReady = false; - }); - - LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL; - mQueue->close(); - - // Post a nonsense user message to wake up the thread in - // case it is waiting for a getMessage() - if (old_handle) - { - WPARAM wparam{ 0xB0B0 }; - LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle - << ", " << WM_DUMMY_ - << ", " << wparam << ")" << std::dec << LL_ENDL; - PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); - } - - // There are cases where window will refuse to close, - // can't wait forever on join, check state instead - LLTimer timeout; - timeout.setTimerExpirySec(2.0); - while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd) - { - ms_sleep(100); - } - - if (getQueue().done() || mWindowHandleThrd == NULL) - { - // Window is closed, started closing or is cleaning up - // now wait for our single thread to die. - if (mWindowHandleThrd) - { - LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; - } - else - { - LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; - } - for (auto& pair : mThreads) - { - pair.second.join(); - } - } - else - { - // Something suspended window thread, can't afford to wait forever - // so kill thread instead - // Ex: This can happen if user starts dragging window arround (if it - // was visible) or a modal notification pops up - LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL; - - for (auto& pair : mThreads) - { - // very unsafe - TerminateThread(pair.second.native_handle(), 0); - pair.second.detach(); - cleanupDX(); - } - } - LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; -} - -void LLWindowWin32::post(const std::function& func) -{ - mFunctionQueue.pushFront(func); -} - -void LLWindowWin32::postMouseButtonEvent(const std::function& func) -{ - mMouseQueue.pushFront(func); -} - -void LLWindowWin32::kickWindowThread(HWND windowHandle) -{ - if (! windowHandle) - windowHandle = mWindowHandle; - if (windowHandle) - { - // post a nonsense user message to wake up the Window Thread in - // case any functions are pending and no windows events came - // through this frame - WPARAM wparam{ 0xB0B0 }; - LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle - << ", " << WM_DUMMY_ - << ", " << wparam << ")" << std::dec << LL_ENDL; - PostMessage(windowHandle, WM_DUMMY_, wparam, 0x1337); - } -} - -void LLWindowWin32::updateWindowRect() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - //called from window thread - RECT rect; - RECT client_rect; - - if (GetWindowRect(mWindowHandle, &rect) && - GetClientRect(mWindowHandle, &client_rect)) - { - post([=] - { - mRect = rect; - mClientRect = client_rect; - }); - } -} +/** + * @file llwindowwin32.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" + +#if LL_WINDOWS && !LL_MESA_HEADLESS + +#include "llwindowwin32.h" + +// LLWindow library includes +#include "llkeyboardwin32.h" +#include "lldragdropwin32.h" +#include "llpreeditor.h" +#include "llwindowcallbacks.h" + +// Linden library includes +#include "llerror.h" +#include "llexception.h" +#include "llfasttimer.h" +#include "llgl.h" +#include "llstring.h" +#include "lldir.h" +#include "llsdutil.h" +#include "llglslshader.h" +#include "llthreadsafequeue.h" +#include "stringize.h" +#include "llframetimer.h" + +// System includes +#include +#include +#include +#include // for _spawn +#include +#include +#include +#include +#include +#include +#include // std::pair + +#include +#include +#include + +// Require DirectInput version 8 +#define DIRECTINPUT_VERSION 0x0800 + +#include +#include +#include // needed for llurlentry test to build on some systems +#pragma comment(lib, "dxguid.lib") // needed for llurlentry test to build on some systems +#pragma comment(lib, "dinput8") + +const S32 MAX_MESSAGE_PER_UPDATE = 20; +const S32 BITS_PER_PIXEL = 32; +const S32 MAX_NUM_RESOLUTIONS = 32; +const F32 ICON_FLASH_TIME = 0.5f; + +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif + +#ifndef USER_DEFAULT_SCREEN_DPI +#define USER_DEFAULT_SCREEN_DPI 96 // Win7 +#endif + +// Claim a couple unused GetMessage() message IDs +const UINT WM_DUMMY_(WM_USER + 0x0017); +const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); + +extern bool gDebugWindowProc; + +static std::thread::id sWindowThreadId; +static std::thread::id sMainThreadId; + +#if 1 // flip to zero to enable assertions for functions being called from wrong thread +#define ASSERT_MAIN_THREAD() +#define ASSERT_WINDOW_THREAD() +#else +#define ASSERT_MAIN_THREAD() llassert(LLThread::currentID() == sMainThreadId) +#define ASSERT_WINDOW_THREAD() llassert(LLThread::currentID() == sWindowThreadId) +#endif + + +LPWSTR gIconResource = IDI_APPLICATION; +LPDIRECTINPUT8 gDirectInput8; + +LLW32MsgCallback gAsyncMsgCallback = NULL; + +#ifndef DPI_ENUMS_DECLARED + +typedef enum PROCESS_DPI_AWARENESS { + PROCESS_DPI_UNAWARE = 0, + PROCESS_SYSTEM_DPI_AWARE = 1, + PROCESS_PER_MONITOR_DPI_AWARE = 2 +} PROCESS_DPI_AWARENESS; + +typedef enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI = 0, + MDT_ANGULAR_DPI = 1, + MDT_RAW_DPI = 2, + MDT_DEFAULT = MDT_EFFECTIVE_DPI +} MONITOR_DPI_TYPE; + +#endif + +typedef HRESULT(STDAPICALLTYPE *SetProcessDpiAwarenessType)(_In_ PROCESS_DPI_AWARENESS value); + +typedef HRESULT(STDAPICALLTYPE *GetProcessDpiAwarenessType)( + _In_ HANDLE hprocess, + _Out_ PROCESS_DPI_AWARENESS *value); + +typedef HRESULT(STDAPICALLTYPE *GetDpiForMonitorType)( + _In_ HMONITOR hmonitor, + _In_ MONITOR_DPI_TYPE dpiType, + _Out_ UINT *dpiX, + _Out_ UINT *dpiY); + +// +// LLWindowWin32 +// + +void show_window_creation_error(const std::string& title) +{ + LL_WARNS("Window") << title << LL_ENDL; +} + +HGLRC SafeCreateContext(HDC &hdc) +{ + __try + { + return wglCreateContext(hdc); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + return NULL; + } +} + +GLuint SafeChoosePixelFormat(HDC &hdc, const PIXELFORMATDESCRIPTOR *ppfd) +{ + __try + { + return ChoosePixelFormat(hdc, ppfd); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + // convert to C++ styled exception + // C exception don't allow classes, so it's a regular char array + char integer_string[32]; + sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); + throw std::exception(integer_string); + } +} + +//static +bool LLWindowWin32::sIsClassRegistered = false; + +bool LLWindowWin32::sLanguageTextInputAllowed = true; +bool LLWindowWin32::sWinIMEOpened = false; +HKL LLWindowWin32::sWinInputLocale = 0; +DWORD LLWindowWin32::sWinIMEConversionMode = IME_CMODE_NATIVE; +DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; +LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); + +// The following class LLWinImm delegates Windows IMM APIs. +// It was originally introduced to support US Windows XP, on which we needed +// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry +// points. Now that that's moot, we retain this wrapper only for hooks for +// metrics. + +class LLWinImm +{ +public: + static bool isAvailable() { return true; } + +public: + // Wrappers for IMM API. + static bool isIME(HKL hkl); + static HIMC getContext(HWND hwnd); + static bool releaseContext(HWND hwnd, HIMC himc); + static bool getOpenStatus(HIMC himc); + static bool setOpenStatus(HIMC himc, bool status); + static bool getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence); + static bool setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence); + static bool getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static bool setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form); + static LONG getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length); + static bool setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength); + static bool setCompositionFont(HIMC himc, LPLOGFONTW logfont); + static bool setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); + static bool notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); +}; + +// static +bool LLWinImm::isIME(HKL hkl) +{ + return ImmIsIME(hkl); +} + +// static +HIMC LLWinImm::getContext(HWND hwnd) +{ + return ImmGetContext(hwnd); +} + +//static +bool LLWinImm::releaseContext(HWND hwnd, HIMC himc) +{ + return ImmReleaseContext(hwnd, himc); +} + +// static +bool LLWinImm::getOpenStatus(HIMC himc) +{ + return ImmGetOpenStatus(himc); +} + +// static +bool LLWinImm::setOpenStatus(HIMC himc, bool status) +{ + return ImmSetOpenStatus(himc, status); +} + +// static +bool LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) +{ + return ImmGetConversionStatus(himc, conversion, sentence); +} + +// static +bool LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) +{ + return ImmSetConversionStatus(himc, conversion, sentence); +} + +// static +bool LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + return ImmGetCompositionWindow(himc, form); +} + +// static +bool LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) +{ + return ImmSetCompositionWindow(himc, form); +} + + +// static +LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) +{ + return ImmGetCompositionString(himc, index, data, length); +} + + +// static +bool LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) +{ + return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); +} + +// static +bool LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) +{ + return ImmSetCompositionFont(himc, pFont); +} + +// static +bool LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) +{ + return ImmSetCandidateWindow(himc, form); +} + +// static +bool LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) +{ + return ImmNotifyIME(himc, action, index, value); +} + + + +class LLMonitorInfo +{ +public: + + std::vector getResolutionsList() { return mResList; } + + LLMonitorInfo() + { + EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this); + } + +private: + + static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData) + { + int monitor_width = lprcMonitor->right - lprcMonitor->left; + int monitor_height = lprcMonitor->bottom - lprcMonitor->top; + + std::ostringstream sstream; + sstream << monitor_width << "x" << monitor_height;; + std::string res = sstream.str(); + + LLMonitorInfo* pThis = reinterpret_cast(pData); + pThis->mResList.push_back(res); + + return TRUE; + } + + std::vector mResList; +}; + +static LLMonitorInfo sMonitorInfo; + + +// Thread that owns the Window Handle +// This whole struct is private to LLWindowWin32, which needs to mess with its +// members, which is why it's a struct rather than a class. In effect, we make +// the containing class a friend. +struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool +{ + static const int MAX_QUEUE_SIZE = 2048; + + LLThreadSafeQueue mMessageQueue; + + LLWindowWin32Thread(); + + void run() override; + void close() override; + + // closes queue, wakes thread, waits until thread closes + void wakeAndDestroy(); + + void glReady() + { + mGLReady = true; + } + + // initialzie DXGI adapter (for querying available VRAM) + void initDX(); + + // initialize D3D (if DXGI cannot be used) + void initD3D(); + + //clean up DXGI/D3D resources + void cleanupDX(); + + /// called by main thread to post work to this window thread + template + void post(CALLABLE&& func) + { + // Ignore bool return. Shutdown timing is tricky: the main thread can + // end up trying to post a cursor position after having closed the + // WorkQueue. + getQueue().post(std::forward(func)); + } + + /** + * Like post(), Post() is a way of conveying a single work item to this + * thread. Its virtue is that it will definitely be executed "soon" rather + * than potentially waiting for the next frame: it uses PostMessage() to + * break us out of the window thread's blocked GetMessage() call. It's + * more expensive, though, not only from the Windows API latency of + * PostMessage() and GetMessage(), but also because it involves heap + * allocation and release. + * + * Require HWND from caller, even though we store an HWND locally. + * Otherwise, if our mWindowHandle was accessed from both threads, we'd + * have to protect it with a mutex. + */ + template + void Post(HWND windowHandle, CALLABLE&& func) + { + // Move func to the heap. If we knew FuncType could fit into LPARAM, + // we could simply instantiate FuncType and pass it by value. But + // since we don't, we must put that on the heap as well as the + // internal heap allocation it likely requires to store func. + auto ptr = new FuncType(std::move(func)); + WPARAM wparam{ 0xF1C }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle + << ", " << WM_POST_FUNCTION_ + << ", " << wparam << std::dec << LL_ENDL; + PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr)); + } + + using FuncType = std::function; + // call GetMessage() and pull enqueue messages for later processing + void gatherInput(); + HWND mWindowHandleThrd = NULL; + HDC mhDCThrd = 0; + + // *HACK: Attempt to prevent startup crashes by deferring memory accounting + // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 + bool mGLReady = false; + + U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) + + IDXGIAdapter3* mDXGIAdapter = nullptr; + LPDIRECT3D9 mD3D = nullptr; + LPDIRECT3DDEVICE9 mD3DDevice = nullptr; +}; + + +LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, + S32 height, U32 flags, + bool fullscreen, bool clearBg, + bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, + U32 fsaa_samples, + U32 max_cores, + U32 max_vram, + F32 max_gl_version) + : + LLWindow(callbacks, fullscreen, flags), + mMaxGLVersion(max_gl_version), + mMaxCores(max_cores) +{ + sMainThreadId = LLThread::currentID(); + mWindowThread = new LLWindowWin32Thread(); + mWindowThread->mMaxVRAM = max_vram; + + //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways + LoadLibrary(L"opengl32.dll"); + + + if (mMaxCores != 0) + { + HANDLE hProcess = GetCurrentProcess(); + mMaxCores = llmin(mMaxCores, (U32) 64); + DWORD_PTR mask = 0; + + for (int i = 0; i < mMaxCores; ++i) + { + mask |= ((DWORD_PTR) 1) << i; + } + + SetProcessAffinityMask(hProcess, mask); + } + +#if 0 // this is probably a bad idea, but keep it in your back pocket if you see what looks like + // process deprioritization during profiles + // force high thread priority + HANDLE hProcess = GetCurrentProcess(); + + if (hProcess) + { + int priority = GetPriorityClass(hProcess); + if (priority < REALTIME_PRIORITY_CLASS) + { + if (SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS)) + { + LL_INFOS() << "Set process priority to REALTIME_PRIORITY_CLASS" << LL_ENDL; + } + else + { + LL_INFOS() << "Failed to set process priority: " << std::hex << GetLastError() << LL_ENDL; + } + } + } +#endif + +#if 0 // this is also probably a bad idea, but keep it in your back pocket for getting main thread off of background thread cores (see also LLThread::threadRun) + HANDLE hThread = GetCurrentThread(); + + SYSTEM_INFO sysInfo; + + GetSystemInfo(&sysInfo); + U32 core_count = sysInfo.dwNumberOfProcessors; + + if (max_cores != 0) + { + core_count = llmin(core_count, max_cores); + } + + if (hThread) + { + int priority = GetThreadPriority(hThread); + + if (priority < THREAD_PRIORITY_TIME_CRITICAL) + { + if (SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL)) + { + LL_INFOS() << "Set thread priority to THREAD_PRIORITY_TIME_CRITICAL" << LL_ENDL; + } + else + { + LL_INFOS() << "Failed to set thread priority: " << std::hex << GetLastError() << LL_ENDL; + } + + // tell main thread to prefer core 0 + SetThreadIdealProcessor(hThread, 0); + } + } +#endif + + + mFSAASamples = fsaa_samples; + mIconResource = gIconResource; + mOverrideAspectRatio = 0.f; + mNativeAspectRatio = 0.f; + mInputProcessingPaused = false; + mPreeditor = NULL; + mKeyCharCode = 0; + mKeyScanCode = 0; + mKeyVirtualKey = 0; + mhDC = NULL; + mhRC = NULL; + memset(mCurrentGammaRamp, 0, sizeof(mCurrentGammaRamp)); + memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); + mCustomGammaSet = false; + mWindowHandle = NULL; + + mRect = {0, 0, 0, 0}; + mClientRect = {0, 0, 0, 0}; + + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) + { + mMouseVanish = true; + } + + // Initialize the keyboard + gKeyboard = new LLKeyboardWin32(); + gKeyboard->setCallbacks(callbacks); + + // Initialize the Drag and Drop functionality + mDragDrop = new LLDragDropWin32; + + // Initialize (boot strap) the Language text input management, + // based on the system's (user's) default settings. + allowLanguageTextInput(mPreeditor, false); + + WNDCLASS wc; + RECT window_rect; + + // Set the window title + if (title.empty()) + { + mWindowTitle = new WCHAR[50]; + wsprintf(mWindowTitle, L"OpenGL Window"); + } + else + { + mWindowTitle = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowTitle, title.c_str(), 255); + mWindowTitle[255] = 0; + } + + // Set the window class name + if (name.empty()) + { + mWindowClassName = new WCHAR[50]; + wsprintf(mWindowClassName, L"OpenGL Window"); + } + else + { + mWindowClassName = new WCHAR[256]; // Assume title length < 255 chars. + mbstowcs(mWindowClassName, name.c_str(), 255); + mWindowClassName[255] = 0; + } + + + // We're not clipping yet + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + + // Make an instance of our window then define the window class + mhInstance = GetModuleHandle(NULL); + + // Init Direct Input - needed for joystick / Spacemouse + + LPDIRECTINPUT8 di8_interface; + HRESULT status = DirectInput8Create( + mhInstance, // HINSTANCE hinst, + DIRECTINPUT_VERSION, // DWORD dwVersion, + IID_IDirectInput8, // REFIID riidltf, + (LPVOID*)&di8_interface, // LPVOID * ppvOut, + NULL // LPUNKNOWN punkOuter + ); + if (status == DI_OK) + { + gDirectInput8 = di8_interface; + } + + mSwapMethod = SWAP_METHOD_UNDEFINED; + + // No WPARAM yet. + mLastSizeWParam = 0; + + // Windows GDI rects don't include rightmost pixel + window_rect.left = (long) 0; + window_rect.right = (long) width; + window_rect.top = (long) 0; + window_rect.bottom = (long) height; + + // Grab screen size to sanitize the window + S32 window_border_y = GetSystemMetrics(SM_CYBORDER); + S32 virtual_screen_x = GetSystemMetrics(SM_XVIRTUALSCREEN); + S32 virtual_screen_y = GetSystemMetrics(SM_YVIRTUALSCREEN); + S32 virtual_screen_width = GetSystemMetrics(SM_CXVIRTUALSCREEN); + S32 virtual_screen_height = GetSystemMetrics(SM_CYVIRTUALSCREEN); + + if (x < virtual_screen_x) x = virtual_screen_x; + if (y < virtual_screen_y - window_border_y) y = virtual_screen_y - window_border_y; + + if (x + width > virtual_screen_x + virtual_screen_width) x = virtual_screen_x + virtual_screen_width - width; + if (y + height > virtual_screen_y + virtual_screen_height) y = virtual_screen_y + virtual_screen_height - height; + + if (!sIsClassRegistered) + { + // Force redraw when resized and create a private device context + + // Makes double click messages. + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + + // Set message handler function + wc.lpfnWndProc = (WNDPROC) mainWindowProc; + + // unused + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + + wc.hInstance = mhInstance; + wc.hIcon = LoadIcon(mhInstance, mIconResource); + + // We will set the cursor ourselves + wc.hCursor = NULL; + + // background color is not used + if (clearBg) + { + wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); + } + else + { + wc.hbrBackground = (HBRUSH) NULL; + } + + // we don't use windows menus + wc.lpszMenuName = NULL; + + wc.lpszClassName = mWindowClassName; + + if (!RegisterClass(&wc)) + { + OSMessageBox(mCallbacks->translateString("MBRegClassFailed"), + mCallbacks->translateString("MBError"), OSMB_OK); + return; + } + sIsClassRegistered = true; + } + + //----------------------------------------------------------------------- + // Get the current refresh rate + //----------------------------------------------------------------------- + + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + DWORD current_refresh; + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + mNativeAspectRatio = ((F32)dev_mode.dmPelsWidth) / ((F32)dev_mode.dmPelsHeight); + } + else + { + current_refresh = 60; + } + mRefreshRate = current_refresh; + //----------------------------------------------------------------------- + // Drop resolution and go fullscreen + // use a display mode with our desired size and depth, with a refresh + // rate as close at possible to the users' default + //----------------------------------------------------------------------- + if (mFullscreen) + { + bool success = false; + DWORD closest_refresh = 0; + + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = true; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } + + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + //success = false; + + if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + success = false; + } + else + { + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + LL_WARNS("Window") << "Current BBP is OK falling back to that" << LL_ENDL; + window_rect.right=width=dev_mode.dmPelsWidth; + window_rect.bottom=height=dev_mode.dmPelsHeight; + success = true; + } + else + { + LL_WARNS("Window") << "Current BBP is BAD" << LL_ENDL; + success = false; + } + } + } + + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } + + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + + // If it failed, we don't want to run fullscreen + if (success) + { + mFullscreen = true; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + } + else + { + mFullscreen = false; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + std::map args; + args["[WIDTH]"] = llformat("%d", width); + args["[HEIGHT]"] = llformat ("%d", height); + OSMessageBox(mCallbacks->translateString("MBFullScreenErr", args), + mCallbacks->translateString("MBError"), OSMB_OK); + } + } + + // TODO: add this after resolving _WIN32_WINNT issue + // if (!fullscreen) + // { + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = mWindowHandle; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + // } + + // SL-12971 dual GPU display + DISPLAY_DEVICEA display_device; + int display_index = -1; + DWORD display_flags = 0; // EDD_GET_DEVICE_INTERFACE_NAME ? + const size_t display_bytes = sizeof(display_device); + + do + { + if (display_index >= 0) + { + // CHAR DeviceName [ 32] Adapter name + // CHAR DeviceString[128] + CHAR text[256]; + + size_t name_len = strlen(display_device.DeviceName ); + size_t desc_len = strlen(display_device.DeviceString); + + CHAR *name = name_len ? display_device.DeviceName : "???"; + CHAR *desc = desc_len ? display_device.DeviceString : "???"; + + sprintf(text, "Display Device %d: %s, %s", display_index, name, desc); + LL_INFOS("Window") << text << LL_ENDL; + } + + ::ZeroMemory(&display_device,display_bytes); + display_device.cb = display_bytes; + + display_index++; + } while( EnumDisplayDevicesA(NULL, display_index, &display_device, display_flags )); + + LL_INFOS("Window") << "Total Display Devices: " << display_index << LL_ENDL; + + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + LLCoordScreen windowPos(x,y); + LLCoordScreen windowSize(window_rect.right - window_rect.left, + window_rect.bottom - window_rect.top); + if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) + { + return; + } + + //start with arrow cursor + initCursors(); + setCursor( UI_CURSOR_ARROW ); + + mRawMouse.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + mRawMouse.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE + mRawMouse.dwFlags = 0; // adds mouse and also ignores legacy mouse messages + mRawMouse.hwndTarget = 0; + + RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse)); + + // Initialize (boot strap) the Language text input management, + // based on the system's (or user's) default settings. + allowLanguageTextInput(NULL, false); +} + + +LLWindowWin32::~LLWindowWin32() +{ + delete mDragDrop; + + delete [] mWindowTitle; + mWindowTitle = NULL; + + delete [] mSupportedResolutions; + mSupportedResolutions = NULL; + + delete [] mWindowClassName; + mWindowClassName = NULL; + + delete mWindowThread; +} + +void LLWindowWin32::show() +{ + LL_DEBUGS("Window") << "Setting window to show" << LL_ENDL; + ShowWindow(mWindowHandle, SW_SHOW); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); +} + +void LLWindowWin32::hide() +{ + setMouseClipping(false); + ShowWindow(mWindowHandle, SW_HIDE); +} + +//virtual +void LLWindowWin32::minimize() +{ + setMouseClipping(false); + showCursor(); + ShowWindow(mWindowHandle, SW_MINIMIZE); +} + +//virtual +void LLWindowWin32::restore() +{ + ShowWindow(mWindowHandle, SW_RESTORE); + SetForegroundWindow(mWindowHandle); + SetFocus(mWindowHandle); +} + +// See SL-12170 +// According to callstack "c0000005 Access violation" happened inside __try block, +// deep in DestroyWindow and crashed viewer, which shouldn't be possible. +// I tried manually causing this exception and it was caught without issues, so +// I'm turning off optimizations for this part to be sure code executes as intended +// (it is a straw, but I have no idea why else __try can get overruled) +#pragma optimize("", off) +bool destroy_window_handler(HWND hWnd) +{ + bool res; + __try + { + res = DestroyWindow(hWnd); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + res = false; + } + return res; +} +#pragma optimize("", on) + +// close() destroys all OS-specific code associated with a window. +// Usually called from LLWindowManager::destroyWindow() +void LLWindowWin32::close() +{ + LL_DEBUGS("Window") << "Closing LLWindowWin32" << LL_ENDL; + // Is window is already closed? + if (!mWindowHandle) + { + return; + } + + mDragDrop->reset(); + + + // Go back to screen mode written in the registry. + if (mFullscreen) + { + resetDisplayResolution(); + } + + // Make sure cursor is visible and we haven't mangled the clipping state. + showCursor(); + setMouseClipping(false); + if (gKeyboard) + { + gKeyboard->resetKeys(); + } + + // Clean up remaining GL state + if (gGLManager.mInited) + { + LL_INFOS("Window") << "Cleaning up GL" << LL_ENDL; + gGLManager.shutdownGL(); + } + + LL_DEBUGS("Window") << "Releasing Context" << LL_ENDL; + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } + + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } + + mhRC = NULL; + } + + // Restore gamma to the system values. + restoreGamma(); + + LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; + + mhDC = NULL; + mWindowHandle = NULL; + + mWindowThread->wakeAndDestroy(); +} + +bool LLWindowWin32::isValid() +{ + return (mWindowHandle != NULL); +} + +bool LLWindowWin32::getVisible() +{ + return (mWindowHandle && IsWindowVisible(mWindowHandle)); +} + +bool LLWindowWin32::getMinimized() +{ + return (mWindowHandle && IsIconic(mWindowHandle)); +} + +bool LLWindowWin32::getMaximized() +{ + return (mWindowHandle && IsZoomed(mWindowHandle)); +} + +bool LLWindowWin32::maximize() +{ + bool success = false; + if (!mWindowHandle) return success; + + mWindowThread->post([=] + { + WINDOWPLACEMENT placement; + placement.length = sizeof(WINDOWPLACEMENT); + + if (GetWindowPlacement(mWindowHandle, &placement)) + { + placement.showCmd = SW_MAXIMIZE; + SetWindowPlacement(mWindowHandle, &placement); + } + }); + + return true; +} + +bool LLWindowWin32::getFullscreen() +{ + return mFullscreen; +} + +bool LLWindowWin32::getPosition(LLCoordScreen *position) +{ + position->mX = mRect.left; + position->mY = mRect.top; + return true; +} + +bool LLWindowWin32::getSize(LLCoordScreen *size) +{ + size->mX = mRect.right - mRect.left; + size->mY = mRect.bottom - mRect.top; + return true; +} + +bool LLWindowWin32::getSize(LLCoordWindow *size) +{ + size->mX = mClientRect.right - mClientRect.left; + size->mY = mClientRect.bottom - mClientRect.top; + return true; +} + +bool LLWindowWin32::setPosition(const LLCoordScreen position) +{ + LLCoordScreen size; + + if (!mWindowHandle) + { + return false; + } + getSize(&size); + moveWindow(position, size); + return true; +} + +bool LLWindowWin32::setSizeImpl(const LLCoordScreen size) +{ + LLCoordScreen position; + + getPosition(&position); + if (!mWindowHandle) + { + return false; + } + + mWindowThread->post([=]() + { + WINDOWPLACEMENT placement; + placement.length = sizeof(WINDOWPLACEMENT); + + if (GetWindowPlacement(mWindowHandle, &placement)) + { + placement.showCmd = SW_RESTORE; + SetWindowPlacement(mWindowHandle, &placement); + } + }); + + moveWindow(position, size); + return true; +} + +bool LLWindowWin32::setSizeImpl(const LLCoordWindow size) +{ + RECT window_rect = {0, 0, size.mX, size.mY }; + DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + DWORD dw_style = WS_OVERLAPPEDWINDOW; + + AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); + + return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); +} + +// changing fullscreen resolution +bool LLWindowWin32::switchContext(bool fullscreen, const LLCoordScreen& size, bool enable_vsync, const LLCoordScreen* const posp) +{ + //called from main thread + GLuint pixel_format; + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + DWORD current_refresh; + DWORD dw_ex_style; + DWORD dw_style; + RECT window_rect = { 0, 0, 0, 0 }; + S32 width = size.mX; + S32 height = size.mY; + bool auto_show = false; + + if (mhRC) + { + auto_show = true; + resetDisplayResolution(); + } + + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + } + else + { + current_refresh = 60; + } + mRefreshRate = current_refresh; + + gGLManager.shutdownGL(); + //destroy gl context + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } + + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } + + mhRC = NULL; + } + + if (fullscreen) + { + mFullscreen = true; + bool success = false; + DWORD closest_refresh = 0; + + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = true; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } + + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + return false; + } + + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } + + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + + if (success) + { + mFullscreen = true; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + + window_rect.left = (long)0; + window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel + window_rect.top = (long)0; + window_rect.bottom = (long)height; + dw_ex_style = WS_EX_APPWINDOW; + dw_style = WS_POPUP; + + // Move window borders out not to cover window contents. + // This converts client rect to window rect, i.e. expands it by the window border size. + AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); + } + // If it failed, we don't want to run fullscreen + else + { + mFullscreen = false; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; + + LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; + return false; + } + } + else + { + mFullscreen = false; + window_rect.left = (long)(posp ? posp->mX : 0); + window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel + window_rect.top = (long)(posp ? posp->mY : 0); + window_rect.bottom = (long)height + window_rect.top; + // Window with an edge + dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dw_style = WS_OVERLAPPEDWINDOW; + } + + + // don't post quit messages when destroying old windows + mPostQuit = false; + + + // create window + LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left + << " Y: " << window_rect.top + << " Width: " << (window_rect.right - window_rect.left) + << " Height: " << (window_rect.bottom - window_rect.top) + << " Fullscreen: " << mFullscreen + << LL_ENDL; + + recreateWindow(window_rect, dw_ex_style, dw_style); + + if (mWindowHandle) + { + LL_INFOS("Window") << "window is created." << LL_ENDL ; + } + else + { + LL_WARNS("Window") << "Window creation failed, code: " << GetLastError() << LL_ENDL; + } + + //----------------------------------------------------------------------- + // Create GL drawing context + //----------------------------------------------------------------------- + static PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, + PFD_TYPE_RGBA, + BITS_PER_PIXEL, + 0, 0, 0, 0, 0, 0, // RGB bits and shift, unused + 8, // alpha bits + 0, // alpha shift + 0, // accum bits + 0, 0, 0, 0, // accum RGBA + 24, // depth bits + 8, // stencil bits, avi added for stencil test + 0, + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + if (!mhDC) + { + close(); + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + return false; + } + + LL_INFOS("Window") << "Device context retrieved." << LL_ENDL ; + + try + { + // Looks like ChoosePixelFormat can crash in case of faulty driver + if (!(pixel_format = SafeChoosePixelFormat(mhDC, &pfd))) + { + LL_WARNS("Window") << "ChoosePixelFormat failed, code: " << GetLastError() << LL_ENDL; + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + } + catch (...) + { + LOG_UNHANDLED_EXCEPTION("ChoosePixelFormat"); + OSMessageBox(mCallbacks->translateString("MBPixelFmtErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + LL_INFOS("Window") << "Pixel format chosen." << LL_ENDL ; + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + // (EXP-1765) dump pixel data to see if there is a pattern that leads to unreproducible crash + LL_INFOS("Window") << "--- begin pixel format dump ---" << LL_ENDL ; + LL_INFOS("Window") << "pixel_format is " << pixel_format << LL_ENDL ; + LL_INFOS("Window") << "pfd.nSize: " << pfd.nSize << LL_ENDL ; + LL_INFOS("Window") << "pfd.nVersion: " << pfd.nVersion << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwFlags: 0x" << std::hex << pfd.dwFlags << std::dec << LL_ENDL ; + LL_INFOS("Window") << "pfd.iPixelType: " << (int)pfd.iPixelType << LL_ENDL ; + LL_INFOS("Window") << "pfd.cColorBits: " << (int)pfd.cColorBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedBits: " << (int)pfd.cRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cRedShift: " << (int)pfd.cRedShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenBits: " << (int)pfd.cGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cGreenShift: " << (int)pfd.cGreenShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueBits: " << (int)pfd.cBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cBlueShift: " << (int)pfd.cBlueShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaBits: " << (int)pfd.cAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAlphaShift: " << (int)pfd.cAlphaShift << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBits: " << (int)pfd.cAccumBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumRedBits: " << (int)pfd.cAccumRedBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumGreenBits: " << (int)pfd.cAccumGreenBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumBlueBits: " << (int)pfd.cAccumBlueBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAccumAlphaBits: " << (int)pfd.cAccumAlphaBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cDepthBits: " << (int)pfd.cDepthBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cStencilBits: " << (int)pfd.cStencilBits << LL_ENDL ; + LL_INFOS("Window") << "pfd.cAuxBuffers: " << (int)pfd.cAuxBuffers << LL_ENDL ; + LL_INFOS("Window") << "pfd.iLayerType: " << (int)pfd.iLayerType << LL_ENDL ; + LL_INFOS("Window") << "pfd.bReserved: " << (int)pfd.bReserved << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwLayerMask: " << pfd.dwLayerMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwVisibleMask: " << pfd.dwVisibleMask << LL_ENDL ; + LL_INFOS("Window") << "pfd.dwDamageMask: " << pfd.dwDamageMask << LL_ENDL ; + LL_INFOS("Window") << "--- end pixel format dump ---" << LL_ENDL ; + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + + if (!(mhRC = SafeCreateContext(mhDC))) + { + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + if (!wglMakeCurrent(mhDC, mhRC)) + { + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + LL_INFOS("Window") << "Drawing context is created." << LL_ENDL ; + + gGLManager.initWGL(); + + if (wglChoosePixelFormatARB) + { + // OK, at this point, use the ARB wglChoosePixelFormatsARB function to see if we + // can get exactly what we want. + GLint attrib_list[256]; + S32 cur_attrib = 0; + + attrib_list[cur_attrib++] = WGL_DEPTH_BITS_ARB; + attrib_list[cur_attrib++] = 24; + + //attrib_list[cur_attrib++] = WGL_STENCIL_BITS_ARB; //stencil buffer is deprecated (performance penalty) + //attrib_list[cur_attrib++] = 8; + + attrib_list[cur_attrib++] = WGL_DRAW_TO_WINDOW_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_ACCELERATION_ARB; + attrib_list[cur_attrib++] = WGL_FULL_ACCELERATION_ARB; + + attrib_list[cur_attrib++] = WGL_SUPPORT_OPENGL_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_DOUBLE_BUFFER_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_COLOR_BITS_ARB; + attrib_list[cur_attrib++] = 24; + + attrib_list[cur_attrib++] = WGL_ALPHA_BITS_ARB; + attrib_list[cur_attrib++] = 0; + + U32 end_attrib = 0; + if (mFSAASamples > 0) + { + end_attrib = cur_attrib; + attrib_list[cur_attrib++] = WGL_SAMPLE_BUFFERS_ARB; + attrib_list[cur_attrib++] = GL_TRUE; + + attrib_list[cur_attrib++] = WGL_SAMPLES_ARB; + attrib_list[cur_attrib++] = mFSAASamples; + } + + // End the list + attrib_list[cur_attrib++] = 0; + + GLint pixel_formats[256]; + U32 num_formats = 0; + + // First we try and get a 32 bit depth pixel format + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + + while(!result && mFSAASamples > 0) + { + LL_WARNS() << "FSAASamples: " << mFSAASamples << " not supported." << LL_ENDL ; + + mFSAASamples /= 2 ; //try to decrease sample pixel number until to disable anti-aliasing + if(mFSAASamples < 2) + { + mFSAASamples = 0 ; + } + + if (mFSAASamples > 0) + { + attrib_list[end_attrib + 3] = mFSAASamples; + } + else + { + cur_attrib = end_attrib ; + end_attrib = 0 ; + attrib_list[cur_attrib++] = 0 ; //end + } + result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + + if(result) + { + LL_WARNS() << "Only support FSAASamples: " << mFSAASamples << LL_ENDL ; + } + } + + if (!result) + { + LL_WARNS() << "mFSAASamples: " << mFSAASamples << LL_ENDL ; + + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit"); + return false; + } + + if (!num_formats) + { + if (end_attrib > 0) + { + LL_INFOS("Window") << "No valid pixel format for " << mFSAASamples << "x anti-aliasing." << LL_ENDL; + attrib_list[end_attrib] = 0; + + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 32-bit no AA"); + return false; + } + } + + if (!num_formats) + { + LL_INFOS("Window") << "No 32 bit z-buffer, trying 24 bits instead" << LL_ENDL; + // Try 24-bit format + attrib_list[1] = 24; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 24-bit"); + return false; + } + + if (!num_formats) + { + LL_WARNS("Window") << "Couldn't get 24 bit z-buffer,trying 16 bits instead!" << LL_ENDL; + attrib_list[1] = 16; + BOOL result = wglChoosePixelFormatARB(mhDC, attrib_list, NULL, 256, pixel_formats, &num_formats); + if (!result || !num_formats) + { + close(); + show_window_creation_error("Error after wglChoosePixelFormatARB 16-bit"); + return false; + } + } + } + + LL_INFOS("Window") << "Choosing pixel formats: " << num_formats << " pixel formats returned" << LL_ENDL; + } + + LL_INFOS("Window") << "pixel formats done." << LL_ENDL ; + + S32 swap_method = 0; + S32 cur_format = 0; +const S32 max_format = (S32)num_formats - 1; + GLint swap_query = WGL_SWAP_METHOD_ARB; + + // SL-14705 Fix name tags showing in front of objects with AMD GPUs. + // On AMD hardware we need to iterate from the first pixel format to the end. + // Spec: + // https://www.khronos.org/registry/OpenGL/extensions/ARB/WGL_ARB_pixel_format.txt + while (wglGetPixelFormatAttribivARB(mhDC, pixel_formats[cur_format], 0, 1, &swap_query, &swap_method)) + { + if (swap_method == WGL_SWAP_UNDEFINED_ARB) + { + break; + } + else if (cur_format >= max_format) + { + cur_format = 0; + break; + } + + ++cur_format; + } + + pixel_format = pixel_formats[cur_format]; + + if (mhDC != 0) // Does The Window Have A Device Context? + { + wglMakeCurrent(mhDC, 0); // Set The Current Active Rendering Context To Zero + if (mhRC != 0) // Does The Window Have A Rendering Context? + { + wglDeleteContext (mhRC); // Release The Rendering Context + mhRC = 0; // Zero The Rendering Context + } + } + + // will release and recreate mhDC, mWindowHandle + recreateWindow(window_rect, dw_ex_style, dw_style); + + RECT rect; + RECT client_rect; + //initialize immediately on main thread + if (GetWindowRect(mWindowHandle, &rect) && + GetClientRect(mWindowHandle, &client_rect)) + { + mRect = rect; + mClientRect = client_rect; + }; + + if (mWindowHandle) + { + LL_INFOS("Window") << "recreate window done." << LL_ENDL ; + } + else + { + // Note: if value is NULL GetDC retrieves the DC for the entire screen. + LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; + } + + if (!mhDC) + { + OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + if (!SetPixelFormat(mhDC, pixel_format, &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtSetErr"), + mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + if (wglGetPixelFormatAttribivARB(mhDC, pixel_format, 0, 1, &swap_query, &swap_method)) + { + switch (swap_method) + { + case WGL_SWAP_EXCHANGE_ARB: + mSwapMethod = SWAP_METHOD_EXCHANGE; + LL_DEBUGS("Window") << "Swap Method: Exchange" << LL_ENDL; + break; + case WGL_SWAP_COPY_ARB: + mSwapMethod = SWAP_METHOD_COPY; + LL_DEBUGS("Window") << "Swap Method: Copy" << LL_ENDL; + break; + case WGL_SWAP_UNDEFINED_ARB: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Undefined" << LL_ENDL; + break; + default: + mSwapMethod = SWAP_METHOD_UNDEFINED; + LL_DEBUGS("Window") << "Swap Method: Unknown" << LL_ENDL; + break; + } + } + } + else + { + LLError::LLUserWarningMsg::show(mCallbacks->translateString("MBVideoDrvErr")); + // mWindowHandle is 0, going to crash either way + LL_ERRS("Window") << "No wgl_ARB_pixel_format extension!" << LL_ENDL; + } + + // Verify what pixel format we actually received. + if (!DescribePixelFormat(mhDC, pixel_format, sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + OSMessageBox(mCallbacks->translateString("MBPixelFmtDescErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + LL_INFOS("Window") << "GL buffer: Color Bits " << S32(pfd.cColorBits) + << " Alpha Bits " << S32(pfd.cAlphaBits) + << " Depth Bits " << S32(pfd.cDepthBits) + << LL_ENDL; + + mhRC = 0; + if (wglCreateContextAttribsARB) + { //attempt to create a specific versioned context + mhRC = (HGLRC) createSharedContext(); + if (!mhRC) + { + return false; + } + } + + if (!wglMakeCurrent(mhDC, mhRC)) + { + OSMessageBox(mCallbacks->translateString("MBGLContextActErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + if (!gGLManager.initGL()) + { + OSMessageBox(mCallbacks->translateString("MBVideoDrvErr"), mCallbacks->translateString("MBError"), OSMB_OK); + close(); + return false; + } + + // Disable vertical sync for swap + toggleVSync(enable_vsync); + + SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); + + // register this window as handling drag/drop events from the OS + DragAcceptFiles( mWindowHandle, TRUE ); + + mDragDrop->init( mWindowHandle ); + + //register joystick timer callback + SetTimer( mWindowHandle, 0, 1000 / 30, NULL ); // 30 fps timer + + // ok to post quit messages now + mPostQuit = true; + + // *HACK: Attempt to prevent startup crashes by deferring memory accounting + // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 + mWindowThread->post([=]() + { + mWindowThread->glReady(); + }); + + if (auto_show) + { + show(); + glClearColor(0.0f, 0.0f, 0.0f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + swapBuffers(); + } + + LL_PROFILER_GPU_CONTEXT; + + return true; +} + +void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) +{ + auto oldWindowHandle = mWindowHandle; + auto oldDCHandle = mhDC; + + // zero out mWindowHandle and mhDC before destroying window so window + // thread falls back to peekmessage + mWindowHandle = 0; + mhDC = 0; + + std::promise> promise; + // What follows must be done on the window thread. + auto window_work = + [this, + self=mWindowThread, + oldWindowHandle, + oldDCHandle, + // bind CreateWindowEx() parameters by value instead of + // back-referencing LLWindowWin32 members + windowClassName=mWindowClassName, + windowTitle=mWindowTitle, + hInstance=mhInstance, + window_rect, + dw_ex_style, + dw_style, + &promise] + () + { + LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL; + self->mWindowHandleThrd = 0; + self->mhDCThrd = 0; + + if (oldWindowHandle) + { + if (oldDCHandle && !ReleaseDC(oldWindowHandle, oldDCHandle)) + { + LL_WARNS("Window") << "Failed to ReleaseDC" << LL_ENDL; + } + + // important to call DestroyWindow() from the window thread + if (!destroy_window_handler(oldWindowHandle)) + { + + LL_WARNS("Window") << "Failed to properly close window before recreating it!" + << LL_ENDL; + } + } + + auto handle = CreateWindowEx(dw_ex_style, + windowClassName, + windowTitle, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height + NULL, + NULL, + hInstance, + NULL); + + if (! handle) + { + // Failed to create window: clear the variables. This + // assignment is valid because we're running on mWindowThread. + self->mWindowHandleThrd = NULL; + self->mhDCThrd = 0; + } + else + { + // Update mWindowThread's own mWindowHandle and mhDC. + self->mWindowHandleThrd = handle; + self->mhDCThrd = GetDC(handle); + } + + updateWindowRect(); + + // It's important to wake up the future either way. + promise.set_value(std::make_pair(self->mWindowHandleThrd, self->mhDCThrd)); + LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL; + }; + // But how we pass window_work to the window thread depends on whether we + // already have a window handle. + if (!oldWindowHandle) + { + // Pass window_work using the WorkQueue: without an existing window + // handle, the window thread can't call GetMessage(). + LL_DEBUGS("Window") << "posting window_work to WorkQueue" << LL_ENDL; + mWindowThread->post(window_work); + } + else + { + // Pass window_work using PostMessage(). We can still + // PostMessage(oldHandle) because oldHandle won't be destroyed until + // the window thread has retrieved and executed window_work. + LL_DEBUGS("Window") << "posting window_work to message queue" << LL_ENDL; + mWindowThread->Post(oldWindowHandle, window_work); + } + + auto future = promise.get_future(); + // This blocks until mWindowThread processes CreateWindowEx() and calls + // promise.set_value(). + auto pair = future.get(); + mWindowHandle = pair.first; + mhDC = pair.second; +} + +void* LLWindowWin32::createSharedContext() +{ + mMaxGLVersion = llclamp(mMaxGLVersion, 3.f, 4.6f); + + S32 version_major = llfloor(mMaxGLVersion); + S32 version_minor = llround((mMaxGLVersion-version_major)*10); + + S32 attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, version_major, + WGL_CONTEXT_MINOR_VERSION_ARB, version_minor, + WGL_CONTEXT_PROFILE_MASK_ARB, LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, + 0 + }; + + HGLRC rc = 0; + + bool done = false; + while (!done) + { + rc = wglCreateContextAttribsARB(mhDC, mhRC, attribs); + + if (!rc) + { + if (attribs[3] > 0) + { //decrement minor version + attribs[3]--; + } + else if (attribs[1] > 3) + { //decrement major version and start minor version over at 3 + attribs[1]--; + attribs[3] = 3; + } + else + { //we reached 3.0 and still failed, bail out + done = true; + } + } + else + { + LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << + (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL; + done = true; + } + } + + if (!rc && !(rc = wglCreateContext(mhDC))) + { + close(); + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + } + + return rc; +} + +void LLWindowWin32::makeContextCurrent(void* contextPtr) +{ + wglMakeCurrent(mhDC, (HGLRC) contextPtr); + LL_PROFILER_GPU_CONTEXT; +} + +void LLWindowWin32::destroySharedContext(void* contextPtr) +{ + wglDeleteContext((HGLRC)contextPtr); +} + +void LLWindowWin32::toggleVSync(bool enable_vsync) +{ + if (wglSwapIntervalEXT == nullptr) + { + LL_INFOS("Window") << "VSync: wglSwapIntervalEXT not initialized" << LL_ENDL; + } + else if (!enable_vsync) + { + LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(0); + } + else + { + LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(1); + } +} + +void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) +{ + if( mIsMouseClipping ) + { + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + ClipCursor( &client_rect_in_screen_space ); + } + } + + // if the window was already maximized, MoveWindow seems to still set the maximized flag even if + // the window is smaller than maximized. + // So we're going to do a restore first (which is a ShowWindow call) (SL-44655). + + // THIS CAUSES DEV-15484 and DEV-15949 + //ShowWindow(mWindowHandle, SW_RESTORE); + // NOW we can call MoveWindow + mWindowThread->post([=]() + { + MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); + }); +} + +void LLWindowWin32::setTitle(const std::string title) +{ + // TODO: Do we need to use the wide string version of this call + // to support non-ascii usernames (and region names?) + mWindowThread->post([=]() + { + SetWindowTextA(mWindowHandle, title.c_str()); + }); +} + +bool LLWindowWin32::setCursorPosition(const LLCoordWindow position) +{ + ASSERT_MAIN_THREAD(); + + if (!mWindowHandle) + { + return false; + } + + LLCoordScreen screen_pos(position.convert()); + + // instantly set the cursor position from the app's point of view + mCursorPosition = position; + mLastCursorPosition = position; + + // Inform the application of the new mouse position (needed for per-frame + // hover/picking to function). + mCallbacks->handleMouseMove(this, position.convert(), (MASK)0); + + // actually set the cursor position on the window thread + mWindowThread->post([=]() + { + // actually set the OS cursor position + SetCursorPos(screen_pos.mX, screen_pos.mY); + }); + + return true; +} + +bool LLWindowWin32::getCursorPosition(LLCoordWindow *position) +{ + ASSERT_MAIN_THREAD(); + if (!position) + { + return false; + } + + *position = mCursorPosition; + return true; +} + +bool LLWindowWin32::getCursorDelta(LLCoordCommon* delta) +{ + if (delta == nullptr) + { + return false; + } + + *delta = mMouseFrameDelta; + + return true; +} + +void LLWindowWin32::hideCursor() +{ + ASSERT_MAIN_THREAD(); + + mWindowThread->post([=]() + { + while (ShowCursor(FALSE) >= 0) + { + // nothing, wait for cursor to push down + } + }); + + mCursorHidden = true; + mHideCursorPermanent = true; +} + +void LLWindowWin32::showCursor() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + + ASSERT_MAIN_THREAD(); + + mWindowThread->post([=]() + { + // makes sure the cursor shows up + while (ShowCursor(TRUE) < 0) + { + // do nothing, wait for cursor to pop out + } + }); + + mCursorHidden = false; + mHideCursorPermanent = false; +} + +void LLWindowWin32::showCursorFromMouseMove() +{ + if (!mHideCursorPermanent) + { + showCursor(); + } +} + +void LLWindowWin32::hideCursorUntilMouseMove() +{ + if (!mHideCursorPermanent && mMouseVanish) + { + hideCursor(); + mHideCursorPermanent = false; + } +} + +bool LLWindowWin32::isCursorHidden() +{ + return mCursorHidden; +} + + +HCURSOR LLWindowWin32::loadColorCursor(LPCTSTR name) +{ + return (HCURSOR)LoadImage(mhInstance, + name, + IMAGE_CURSOR, + 0, // default width + 0, // default height + LR_DEFAULTCOLOR); +} + + +void LLWindowWin32::initCursors() +{ + mCursor[ UI_CURSOR_ARROW ] = LoadCursor(NULL, IDC_ARROW); + mCursor[ UI_CURSOR_WAIT ] = LoadCursor(NULL, IDC_WAIT); + mCursor[ UI_CURSOR_HAND ] = LoadCursor(NULL, IDC_HAND); + mCursor[ UI_CURSOR_IBEAM ] = LoadCursor(NULL, IDC_IBEAM); + mCursor[ UI_CURSOR_CROSS ] = LoadCursor(NULL, IDC_CROSS); + mCursor[ UI_CURSOR_SIZENWSE ] = LoadCursor(NULL, IDC_SIZENWSE); + mCursor[ UI_CURSOR_SIZENESW ] = LoadCursor(NULL, IDC_SIZENESW); + mCursor[ UI_CURSOR_SIZEWE ] = LoadCursor(NULL, IDC_SIZEWE); + mCursor[ UI_CURSOR_SIZENS ] = LoadCursor(NULL, IDC_SIZENS); + mCursor[ UI_CURSOR_SIZEALL ] = LoadCursor(NULL, IDC_SIZEALL); + mCursor[ UI_CURSOR_NO ] = LoadCursor(NULL, IDC_NO); + mCursor[ UI_CURSOR_WORKING ] = LoadCursor(NULL, IDC_APPSTARTING); + + HMODULE module = GetModuleHandle(NULL); + mCursor[ UI_CURSOR_TOOLGRAB ] = LoadCursor(module, TEXT("TOOLGRAB")); + mCursor[ UI_CURSOR_TOOLLAND ] = LoadCursor(module, TEXT("TOOLLAND")); + mCursor[ UI_CURSOR_TOOLFOCUS ] = LoadCursor(module, TEXT("TOOLFOCUS")); + mCursor[ UI_CURSOR_TOOLCREATE ] = LoadCursor(module, TEXT("TOOLCREATE")); + mCursor[ UI_CURSOR_ARROWDRAG ] = LoadCursor(module, TEXT("ARROWDRAG")); + mCursor[ UI_CURSOR_ARROWCOPY ] = LoadCursor(module, TEXT("ARROWCOPY")); + mCursor[ UI_CURSOR_ARROWDRAGMULTI ] = LoadCursor(module, TEXT("ARROWDRAGMULTI")); + mCursor[ UI_CURSOR_ARROWCOPYMULTI ] = LoadCursor(module, TEXT("ARROWCOPYMULTI")); + mCursor[ UI_CURSOR_NOLOCKED ] = LoadCursor(module, TEXT("NOLOCKED")); + mCursor[ UI_CURSOR_ARROWLOCKED ]= LoadCursor(module, TEXT("ARROWLOCKED")); + mCursor[ UI_CURSOR_GRABLOCKED ] = LoadCursor(module, TEXT("GRABLOCKED")); + mCursor[ UI_CURSOR_TOOLTRANSLATE ] = LoadCursor(module, TEXT("TOOLTRANSLATE")); + mCursor[ UI_CURSOR_TOOLROTATE ] = LoadCursor(module, TEXT("TOOLROTATE")); + mCursor[ UI_CURSOR_TOOLSCALE ] = LoadCursor(module, TEXT("TOOLSCALE")); + mCursor[ UI_CURSOR_TOOLCAMERA ] = LoadCursor(module, TEXT("TOOLCAMERA")); + mCursor[ UI_CURSOR_TOOLPAN ] = LoadCursor(module, TEXT("TOOLPAN")); + mCursor[ UI_CURSOR_TOOLZOOMIN ] = LoadCursor(module, TEXT("TOOLZOOMIN")); + mCursor[ UI_CURSOR_TOOLZOOMOUT ] = LoadCursor(module, TEXT("TOOLZOOMOUT")); + mCursor[ UI_CURSOR_TOOLPICKOBJECT3 ] = LoadCursor(module, TEXT("TOOLPICKOBJECT3")); + mCursor[ UI_CURSOR_PIPETTE ] = LoadCursor(module, TEXT("TOOLPIPETTE")); + mCursor[ UI_CURSOR_TOOLSIT ] = LoadCursor(module, TEXT("TOOLSIT")); + mCursor[ UI_CURSOR_TOOLBUY ] = LoadCursor(module, TEXT("TOOLBUY")); + mCursor[ UI_CURSOR_TOOLOPEN ] = LoadCursor(module, TEXT("TOOLOPEN")); + mCursor[ UI_CURSOR_TOOLPATHFINDING ] = LoadCursor(module, TEXT("TOOLPATHFINDING")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTARTADD")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_START ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHSTART")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHEND")); + mCursor[ UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD ] = LoadCursor(module, TEXT("TOOLPATHFINDINGPATHENDADD")); + mCursor[ UI_CURSOR_TOOLNO ] = LoadCursor(module, TEXT("TOOLNO")); + + // Color cursors + mCursor[ UI_CURSOR_TOOLPLAY ] = loadColorCursor(TEXT("TOOLPLAY")); + mCursor[ UI_CURSOR_TOOLPAUSE ] = loadColorCursor(TEXT("TOOLPAUSE")); + mCursor[ UI_CURSOR_TOOLMEDIAOPEN ] = loadColorCursor(TEXT("TOOLMEDIAOPEN")); + + // Note: custom cursors that are not found make LoadCursor() return NULL. + for( S32 i = 0; i < UI_CURSOR_COUNT; i++ ) + { + if( !mCursor[i] ) + { + mCursor[i] = LoadCursor(NULL, IDC_ARROW); + } + } +} + + + +void LLWindowWin32::updateCursor() +{ + ASSERT_MAIN_THREAD(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 + if (mNextCursor == UI_CURSOR_ARROW + && mBusyCount > 0) + { + mNextCursor = UI_CURSOR_WORKING; + } + + if( mCurrentCursor != mNextCursor ) + { + mCurrentCursor = mNextCursor; + auto nextCursor = mCursor[mNextCursor]; + mWindowThread->post([=]() + { + SetCursor(nextCursor); + }); + } +} + +ECursorType LLWindowWin32::getCursor() const +{ + return mCurrentCursor; +} + +void LLWindowWin32::captureMouse() +{ + SetCapture(mWindowHandle); +} + +void LLWindowWin32::releaseMouse() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + ReleaseCapture(); +} + + +void LLWindowWin32::delayInputProcessing() +{ + mInputProcessingPaused = true; +} + + +void LLWindowWin32::gatherInput() +{ + ASSERT_MAIN_THREAD(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 + MSG msg; + + { + LLMutexLock lock(&mRawMouseMutex); + mMouseFrameDelta = mRawMouseDelta; + + mRawMouseDelta.mX = 0; + mRawMouseDelta.mY = 0; + } + + + if (mWindowThread->getQueue().size()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage"); + kickWindowThread(); + } + + while (mWindowThread->mMessageQueue.tryPopBack(msg)) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue"); + if (mInputProcessingPaused) + { + continue; + } + + // For async host by name support. Really hacky. + if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - callback"); + gAsyncMsgCallback(msg); + } + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PeekMessage"); + S32 msg_count = 0; + while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + msg_count++; + } + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - function queue"); + //process any pending functions + std::function curFunc; + while (mFunctionQueue.tryPopBack(curFunc)) + { + curFunc(); + } + } + + // send one and only one mouse move event per frame BEFORE handling mouse button presses + if (mLastCursorPosition != mCursorPosition) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move"); + mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask); + } + + mLastCursorPosition = mCursorPosition; + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse queue"); + // handle mouse button presses AFTER updating mouse cursor position + std::function curFunc; + while (mMouseQueue.tryPopBack(curFunc)) + { + curFunc(); + } + } + + mInputProcessingPaused = false; + + updateCursor(); +} + +static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); +static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); + +#define WINDOW_IMP_POST(x) window_imp->post([=]() { x; }) + +LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) +{ + ASSERT_WINDOW_THREAD(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + + if (u_msg == WM_POST_FUNCTION_) + { + // from LLWindowWin32Thread::Post() + // Cast l_param back to the pointer to the heap FuncType + // allocated by Post(). Capture in unique_ptr so we'll delete + // once we're done with it. + std::unique_ptr + ptr(reinterpret_cast(l_param)); + (*ptr)(); + return 0; + } + + // Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN. + // This helps prevent avatar walking after maximizing the window by double-clicking the title bar. + static bool sHandleLeftMouseUp = true; + + // Ignore the double click received right after activating app. + // This is to avoid triggering double click teleport after returning focus (see MAINT-3786). + static bool sHandleDoubleClick = true; + + LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); + + if (NULL != window_imp) + { + // Juggle to make sure we can get negative positions for when + // mouse is outside window. + LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); + + // pass along extended flag in mask + MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; + bool eat_keystroke = true; + + switch (u_msg) + { + RECT update_rect; + S32 update_width; + S32 update_height; + + case WM_TIMER: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_TIMER"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp)); + break; + } + + case WM_DEVICECHANGE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE"); + if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); + + return 1; + } + break; + } + + case WM_PAINT: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT"); + GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); + update_width = update_rect.right - update_rect.left + 1; + update_height = update_rect.bottom - update_rect.top + 1; + + WINDOW_IMP_POST(window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, + update_width, update_height)); + break; + } + case WM_PARENTNOTIFY: + { + break; + } + + case WM_SETCURSOR: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETCURSOR"); + // This message is sent whenever the cursor is moved in a window. + // You need to set the appropriate cursor appearance. + + // Only take control of cursor over client region of window + // This allows Windows(tm) to handle resize cursors, etc. + if (LOWORD(l_param) == HTCLIENT) + { + SetCursor(window_imp->mCursor[window_imp->mCurrentCursor]); + return 0; + } + break; + } + case WM_ENTERMENULOOP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENTERMENULOOP"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp)); + break; + } + + case WM_EXITMENULOOP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_EXITMENULOOP"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp)); + break; + } + + case WM_ACTIVATEAPP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP"); + window_imp->post([=]() + { + // This message should be sent whenever the app gains or loses focus. + BOOL activating = (BOOL)w_param; + + if (window_imp->mFullscreen) + { + // When we run fullscreen, restoring or minimizing the app needs + // to switch the screen resolution + if (activating) + { + window_imp->setFullscreenResolution(); + window_imp->restore(); + } + else + { + window_imp->minimize(); + window_imp->resetDisplayResolution(); + } + } + + if (!activating) + { + sHandleDoubleClick = false; + } + + window_imp->mCallbacks->handleActivateApp(window_imp, activating); + }); + break; + } + case WM_ACTIVATE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATE"); + window_imp->post([=]() + { + // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE + BOOL activating = (LOWORD(w_param) != WA_INACTIVE); + + if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + }); + + break; + } + + case WM_QUERYOPEN: + // TODO: use this to return a nice icon + break; + + case WM_SYSCOMMAND: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND"); + switch (w_param) + { + case SC_KEYMENU: + // Disallow the ALT key from triggering the default system menu. + return 0; + + case SC_SCREENSAVE: + case SC_MONITORPOWER: + // eat screen save messages and prevent them! + return 0; + } + break; + } + case WM_CLOSE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE"); + window_imp->post([=]() + { + // Will the app allow the window to close? + if (window_imp->mCallbacks->handleCloseRequest(window_imp)) + { + // Get the app to initiate cleanup. + window_imp->mCallbacks->handleQuit(window_imp); + // The app is responsible for calling destroyWindow when done with GL + } + }); + return 0; + } + case WM_DESTROY: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DESTROY"); + if (window_imp->shouldPostQuit()) + { + PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 + } + return 0; + } + case WM_COMMAND: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND"); + if (!HIWORD(w_param)) // this message is from a menu + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param))); + } + break; + } + case WM_SYSKEYDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN"); + // allow system keys, such as ALT-F4 to be processed by Windows + eat_keystroke = false; + // intentional fall-through here + [[fallthrough]]; + } + case WM_KEYDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYDOWN"); + window_imp->post([=]() + { + window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next + window_imp->mKeyScanCode = (l_param >> 16) & 0xff; + window_imp->mKeyVirtualKey = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; + + gKeyboard->handleKeyDown(w_param, mask); + }); + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + break; + } + case WM_SYSKEYUP: + eat_keystroke = false; + // intentional fall-through here + [[fallthrough]]; + case WM_KEYUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP"); + window_imp->post([=]() + { + window_imp->mKeyScanCode = (l_param >> 16) & 0xff; + window_imp->mKeyVirtualKey = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP"); + gKeyboard->handleKeyUp(w_param, mask); + } + }); + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + break; + } + case WM_IME_SETCONTEXT: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT"); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; + // Invoke DefWinProc with the modified LPARAM. + } + break; + } + case WM_IME_STARTCOMPOSITION: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION"); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->handleStartCompositionMessage()); + return 0; + } + break; + } + case WM_IME_ENDCOMPOSITION: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION"); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + return 0; + } + break; + } + case WM_IME_COMPOSITION: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION"); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->handleCompositionMessage(l_param)); + return 0; + } + break; + } + case WM_IME_REQUEST: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST"); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + LRESULT result; + window_imp->handleImeRequests(w_param, l_param, &result); + return result; + } + break; + } + case WM_CHAR: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CHAR"); + window_imp->post([=]() + { + window_imp->mKeyCharCode = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; + + // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need + // to figure out how that works. - Doug + // + // ... Well, I don't think so. + // How it works is explained in Win32 API document, but WM_UNICHAR didn't work + // as specified at least on Windows XP SP1 Japanese version. I have never used + // it since then, and I'm not sure whether it has been fixed now, but I don't think + // it is worth trying. The good old WM_CHAR works just fine even for supplementary + // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's + // by ourselves. It is not that tough. -- Alissa Sabre @ SL + + // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, bool) returned false, + // we *did* processed the event, so I believe we should not pass it to DefWindowProc... + window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(false)); + }); + return 0; + } + case WM_NCLBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_NCLBUTTONDOWN"); + { + // A click in a non-client area, e.g. title bar or window border. + window_imp->post([=]() + { + sHandleLeftMouseUp = false; + sHandleDoubleClick = true; + }); + } + break; + } + case WM_LBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + sHandleLeftMouseUp = true; + + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + MASK mask = gKeyboard->currentMask(true); + auto gl_coord = window_imp->mCursorPosition.convert(); + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask); + }); + + return 0; + } + break; + } + + case WM_LBUTTONDBLCLK: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDBLCLK"); + window_imp->postMouseButtonEvent([=]() + { + //RN: ignore right button double clicks for now + //case WM_RBUTTONDBLCLK: + if (!sHandleDoubleClick) + { + sHandleDoubleClick = true; + return; + } + MASK mask = gKeyboard->currentMask(true); + + // generate move event to update mouse coordinates + window_imp->mCursorPosition = window_coord; + window_imp->mCallbacks->handleDoubleClick(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + + return 0; + } + case WM_LBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONUP"); + { + window_imp->postMouseButtonEvent([=]() + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + if (!sHandleLeftMouseUp) + { + sHandleLeftMouseUp = true; + return; + } + sHandleDoubleClick = true; + + + MASK mask = gKeyboard->currentMask(true); + // generate move event to update mouse coordinates + window_imp->mCursorPosition = window_coord; + window_imp->mCallbacks->handleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + return 0; + } + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->post([=]() + { + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->interruptLanguageTextInput()); + } + + MASK mask = gKeyboard->currentMask(true); + // generate move event to update mouse coordinates + auto gl_coord = window_imp->mCursorPosition.convert(); + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask); + }); + } + return 0; + } + break; + + case WM_RBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + MASK mask = gKeyboard->currentMask(true); + window_imp->mCallbacks->handleRightMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + } + break; + + case WM_MBUTTONDOWN: + // case WM_MBUTTONDBLCLK: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + MASK mask = gKeyboard->currentMask(true); + window_imp->mCallbacks->handleMiddleMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + } + break; + + case WM_MBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + MASK mask = gKeyboard->currentMask(true); + window_imp->mCallbacks->handleMiddleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + } + break; + case WM_XBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN"); + window_imp->postMouseButtonEvent([=]() + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + MASK mask = gKeyboard->currentMask(true); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); + }); + + } + break; + + case WM_XBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP"); + window_imp->postMouseButtonEvent([=]() + { + + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + + S32 button = GET_XBUTTON_WPARAM(w_param); + MASK mask = gKeyboard->currentMask(true); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + window_imp->mCallbacks->handleOtherMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); + }); + } + break; + + case WM_MOUSEWHEEL: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL"); + static short z_delta = 0; + + RECT client_rect; + + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) }; + + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } + + S16 incoming_z_delta = HIWORD(w_param); + z_delta += incoming_z_delta; + // cout << "z_delta " << z_delta << endl; + + // current mouse wheels report changes in increments of zDelta (+120, -120) + // Future, higher resolution mouse wheels may report smaller deltas. + // So we sum the deltas and only act when we've exceeded WHEEL_DELTA + // + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) + { + short clicks = -z_delta / WHEEL_DELTA; + WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollWheel(window_imp, clicks)); + z_delta = 0; + } + return 0; + } + /* + // TODO: add this after resolving _WIN32_WINNT issue + case WM_MOUSELEAVE: + { + window_imp->mCallbacks->handleMouseLeave(window_imp); + + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = h_wnd; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + return 0; + } + */ + case WM_MOUSEHWHEEL: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL"); + static short h_delta = 0; + + RECT client_rect; + + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) }; + + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } + + S16 incoming_h_delta = HIWORD(w_param); + h_delta += incoming_h_delta; + + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA)); + h_delta = 0; + } + return 0; + } + // Handle mouse movement within the window + case WM_MOUSEMOVE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE"); + // DO NOT use mouse event queue for move events to ensure cursor position is updated + // when button events are handled + WINDOW_IMP_POST( + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda"); + + MASK mask = gKeyboard->currentMask(true); + window_imp->mMouseMask = mask; + window_imp->mCursorPosition = window_coord; + }); + return 0; + } + + case WM_GETMINMAXINFO: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_GETMINMAXINFO"); + LPMINMAXINFO min_max = (LPMINMAXINFO)l_param; + min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth; + min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight; + return 0; + } + + case WM_MOVE: + { + window_imp->updateWindowRect(); + return 0; + } + case WM_SIZE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE"); + window_imp->updateWindowRect(); + + // There's an odd behavior with WM_SIZE that I would call a bug. If + // the window is maximized, and you call MoveWindow() with a size smaller + // than a maximized window, it ends up sending WM_SIZE with w_param set + // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. + // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see + // LLWindowWin32::moveWindow in this file). + + // If we are now restored, but we weren't before, this + // means that the window was un-minimized. + if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true)); + } + + // handle case of window being maximized from fully minimized state + if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, true)); + } + + // Also handle the minimization case + if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, false)); + } + + // Actually resize all of our views + if (w_param != SIZE_MINIMIZED) + { + // Ignore updates for minimizing and minimized "windows" + WINDOW_IMP_POST(window_imp->mCallbacks->handleResize(window_imp, + LOWORD(l_param), + HIWORD(l_param))); + } + + window_imp->mLastSizeWParam = w_param; + + return 0; + } + + case WM_DPICHANGED: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED"); + LPRECT lprc_new_scale; + F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI); + lprc_new_scale = (LPRECT)l_param; + S32 new_width = lprc_new_scale->right - lprc_new_scale->left; + S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; + WINDOW_IMP_POST(window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height)); + + SetWindowPos(h_wnd, + HWND_TOP, + lprc_new_scale->left, + lprc_new_scale->top, + new_width, + new_height, + SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + + case WM_SETFOCUS: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleFocus(window_imp)); + return 0; + } + + case WM_KILLFOCUS: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleFocusLost(window_imp)); + return 0; + } + + case WM_COPYDATA: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COPYDATA"); + { + // received a URL + PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param; + void* data = new U8[myCDS->cbData]; + memcpy(data, myCDS->lpData, myCDS->cbData); + auto myType = myCDS->dwData; + + window_imp->post([=]() + { + window_imp->mCallbacks->handleDataCopy(window_imp, myType, data); + delete[] data; + }); + }; + return 0; + } + case WM_SETTINGCHANGE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE"); + if (w_param == SPI_SETMOUSEVANISH) + { + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0)) + { + WINDOW_IMP_POST(window_imp->mMouseVanish = true); + } + } + } + break; + + case WM_INPUT: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT"); + + UINT dwSize = 0; + GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); + llassert(dwSize < 1024); + + U8 lpb[1024]; + + if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) + { + RAWINPUT* raw = (RAWINPUT*)lpb; + + if (raw->header.dwType == RIM_TYPEMOUSE) + { + LLMutexLock lock(&window_imp->mRawMouseMutex); + + bool absolute_coordinates = (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE); + + if (absolute_coordinates) + { + static S32 prev_absolute_x = 0; + static S32 prev_absolute_y = 0; + S32 absolute_x; + S32 absolute_y; + + if ((raw->data.mouse.usFlags & 0x10) == 0x10) // touch screen? touch? Not defined in header + { + // touch screen spams (0,0) coordinates in a number of situations + // (0,0) might need to be filtered + absolute_x = raw->data.mouse.lLastX; + absolute_y = raw->data.mouse.lLastY; + } + else + { + bool v_desktop = (raw->data.mouse.usFlags & MOUSE_VIRTUAL_DESKTOP) == MOUSE_VIRTUAL_DESKTOP; + + S32 width = GetSystemMetrics(v_desktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN); + S32 height = GetSystemMetrics(v_desktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN); + + absolute_x = (raw->data.mouse.lLastX / 65535.0f) * width; + absolute_y = (raw->data.mouse.lLastY / 65535.0f) * height; + } + + window_imp->mRawMouseDelta.mX += absolute_x - prev_absolute_x; + window_imp->mRawMouseDelta.mY -= absolute_y - prev_absolute_y; + + prev_absolute_x = absolute_x; + prev_absolute_y = absolute_y; + } + else + { + S32 speed; + const S32 DEFAULT_SPEED(10); + SystemParametersInfo(SPI_GETMOUSESPEED, 0, &speed, 0); + if (speed == DEFAULT_SPEED) + { + window_imp->mRawMouseDelta.mX += raw->data.mouse.lLastX; + window_imp->mRawMouseDelta.mY -= raw->data.mouse.lLastY; + } + else + { + window_imp->mRawMouseDelta.mX += round((F32)raw->data.mouse.lLastX * (F32)speed / DEFAULT_SPEED); + window_imp->mRawMouseDelta.mY -= round((F32)raw->data.mouse.lLastY * (F32)speed / DEFAULT_SPEED); + } + } + } + } + } + break; + + //list of messages we get often that we don't care to log about + case WM_NCHITTEST: + case WM_NCMOUSEMOVE: + case WM_NCMOUSELEAVE: + case WM_MOVING: + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + break; + + default: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default"); + LL_DEBUGS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL; + } + break; + } + } + else + { + // (NULL == window_imp) + LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; + } + + // pass unhandled messages down to Windows + LRESULT ret; + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - DefWindowProc"); + ret = DefWindowProc(h_wnd, u_msg, w_param, l_param); + } + return ret; +} + +bool LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) +{ + S32 client_height; + RECT client_rect; + LLCoordWindow window_position; + + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + 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 LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordGL* to) +{ + S32 client_height; + RECT client_rect; + + if (!mWindowHandle || + !GetClientRect(mWindowHandle, &client_rect) || + 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 LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordWindow* to) +{ + POINT mouse_point; + + mouse_point.x = from.mX; + mouse_point.y = from.mY; + bool result = ScreenToClient(mWindowHandle, &mouse_point); + + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } + + return result; +} + +bool LLWindowWin32::convertCoords(LLCoordWindow from, LLCoordScreen *to) +{ + POINT mouse_point; + + mouse_point.x = from.mX; + mouse_point.y = from.mY; + bool result = ClientToScreen(mWindowHandle, &mouse_point); + + if (result) + { + to->mX = mouse_point.x; + to->mY = mouse_point.y; + } + + return result; +} + +bool LLWindowWin32::convertCoords(LLCoordScreen from, LLCoordGL *to) +{ + LLCoordWindow window_coord; + + if (!mWindowHandle || (NULL == to)) + { + return false; + } + + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return true; +} + +bool LLWindowWin32::convertCoords(LLCoordGL from, LLCoordScreen *to) +{ + LLCoordWindow window_coord; + + if (!mWindowHandle || (NULL == to)) + { + return false; + } + + convertCoords(from, &window_coord); + convertCoords(window_coord, to); + return true; +} + + +bool LLWindowWin32::isClipboardTextAvailable() +{ + return IsClipboardFormatAvailable(CF_UNICODETEXT); +} + + +bool LLWindowWin32::pasteTextFromClipboard(LLWString &dst) +{ + bool success = false; + + if (IsClipboardFormatAvailable(CF_UNICODETEXT)) + { + if (OpenClipboard(mWindowHandle)) + { + HGLOBAL h_data = GetClipboardData(CF_UNICODETEXT); + if (h_data) + { + WCHAR *utf16str = (WCHAR*) GlobalLock(h_data); + if (utf16str) + { + dst = utf16str_to_wstring(utf16str); + LLWStringUtil::removeWindowsCR(dst); + GlobalUnlock(h_data); + success = true; + } + } + CloseClipboard(); + } + } + + return success; +} + + +bool LLWindowWin32::copyTextToClipboard(const LLWString& wstr) +{ + bool success = false; + + if (OpenClipboard(mWindowHandle)) + { + EmptyClipboard(); + + // Provide a copy of the data in Unicode format. + LLWString sanitized_string(wstr); + LLWStringUtil::addCRLF(sanitized_string); + llutf16string out_utf16 = wstring_to_utf16str(sanitized_string); + const size_t size_utf16 = (out_utf16.length() + 1) * sizeof(WCHAR); + + // Memory is allocated and then ownership of it is transfered to the system. + HGLOBAL hglobal_copy_utf16 = GlobalAlloc(GMEM_MOVEABLE, size_utf16); + if (hglobal_copy_utf16) + { + WCHAR* copy_utf16 = (WCHAR*) GlobalLock(hglobal_copy_utf16); + if (copy_utf16) + { + memcpy(copy_utf16, out_utf16.c_str(), size_utf16); /* Flawfinder: ignore */ + GlobalUnlock(hglobal_copy_utf16); + + if (SetClipboardData(CF_UNICODETEXT, hglobal_copy_utf16)) + { + success = true; + } + } + } + + CloseClipboard(); + } + + return success; +} + +// Constrains the mouse to the window. +void LLWindowWin32::setMouseClipping( bool b ) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + ASSERT_MAIN_THREAD(); + if( b != mIsMouseClipping ) + { + bool success = false; + + if( b ) + { + GetClipCursor( &mOldMouseClip ); + + RECT client_rect_in_screen_space; + if( getClientRectInScreenSpace( &client_rect_in_screen_space ) ) + { + success = ClipCursor( &client_rect_in_screen_space ); + } + } + else + { + // Must restore the old mouse clip, which may be set by another window. + success = ClipCursor( &mOldMouseClip ); + SetRect( &mOldMouseClip, 0, 0, 0, 0 ); + } + + if( success ) + { + mIsMouseClipping = b; + } + } +} + +bool LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) +{ + bool success = false; + + RECT client_rect; + if (mWindowHandle && GetClientRect(mWindowHandle, &client_rect)) + { + POINT top_left; + top_left.x = client_rect.left; + top_left.y = client_rect.top; + ClientToScreen(mWindowHandle, &top_left); + + POINT bottom_right; + bottom_right.x = client_rect.right; + bottom_right.y = client_rect.bottom; + ClientToScreen(mWindowHandle, &bottom_right); + + SetRect(rectp, + top_left.x, + top_left.y, + bottom_right.x, + bottom_right.y); + + success = true; + } + + return success; +} + +void LLWindowWin32::flashIcon(F32 seconds) +{ + mWindowThread->post([=]() + { + FLASHWINFO flash_info; + + flash_info.cbSize = sizeof(FLASHWINFO); + flash_info.hwnd = mWindowHandle; + flash_info.dwFlags = FLASHW_TRAY; + flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); + flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds + FlashWindowEx(&flash_info); + }); +} + +F32 LLWindowWin32::getGamma() +{ + return mCurrentGamma; +} + +bool LLWindowWin32::restoreGamma() +{ + ASSERT_MAIN_THREAD(); + if (mCustomGammaSet) + { + LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; + mCustomGammaSet = false; + return SetDeviceGammaRamp(mhDC, mPrevGammaRamp); + } + return true; +} + +bool LLWindowWin32::setGamma(const F32 gamma) +{ + ASSERT_MAIN_THREAD(); + mCurrentGamma = gamma; + + //Get the previous gamma ramp to restore later. + if (!mCustomGammaSet) + { + if (!gGLManager.mIsIntel) // skip for Intel GPUs (see SL-11341) + { + LL_DEBUGS("Window") << "Getting the previous gamma ramp to restore later" << LL_ENDL; + if (!GetDeviceGammaRamp(mhDC, mPrevGammaRamp)) + { + LL_WARNS("Window") << "Failed to get the previous gamma ramp" << LL_ENDL; + return false; + } + } + mCustomGammaSet = true; + } + + LL_DEBUGS("Window") << "Setting gamma to " << gamma << LL_ENDL; + + for ( int i = 0; i < 256; ++i ) + { + int mult = 256 - ( int ) ( ( gamma - 1.0f ) * 128.0f ); + + int value = mult * i; + + if ( value > 0xffff ) + value = 0xffff; + + mCurrentGammaRamp[0][i] = + mCurrentGammaRamp[1][i] = + mCurrentGammaRamp[2][i] = (WORD) value; + }; + + return SetDeviceGammaRamp ( mhDC, mCurrentGammaRamp ); +} + +void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) +{ + ASSERT_MAIN_THREAD(); + mFSAASamples = fsaa_samples; +} + +U32 LLWindowWin32::getFSAASamples() +{ + return mFSAASamples; +} + +LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) +{ + ASSERT_MAIN_THREAD(); + if (!mSupportedResolutions) + { + mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + + mNumSupportedResolutions = 0; + for (S32 mode_num = 0; mNumSupportedResolutions < MAX_NUM_RESOLUTIONS; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } + + if (dev_mode.dmBitsPerPel == BITS_PER_PIXEL && + dev_mode.dmPelsWidth >= 800 && + dev_mode.dmPelsHeight >= 600) + { + bool resolution_exists = false; + for(S32 i = 0; i < mNumSupportedResolutions; i++) + { + if (mSupportedResolutions[i].mWidth == dev_mode.dmPelsWidth && + mSupportedResolutions[i].mHeight == dev_mode.dmPelsHeight) + { + resolution_exists = true; + } + } + if (!resolution_exists) + { + mSupportedResolutions[mNumSupportedResolutions].mWidth = dev_mode.dmPelsWidth; + mSupportedResolutions[mNumSupportedResolutions].mHeight = dev_mode.dmPelsHeight; + mNumSupportedResolutions++; + } + } + } + } + + num_resolutions = mNumSupportedResolutions; + return mSupportedResolutions; +} + + +F32 LLWindowWin32::getNativeAspectRatio() +{ + if (mOverrideAspectRatio > 0.f) + { + return mOverrideAspectRatio; + } + else if (mNativeAspectRatio > 0.f) + { + // we grabbed this value at startup, based on the user's desktop settings + return mNativeAspectRatio; + } + // RN: this hack presumes that the largest supported resolution is monitor-limited + // and that pixels in that mode are square, therefore defining the native aspect ratio + // of the monitor...this seems to work to a close approximation for most CRTs/LCDs + S32 num_resolutions; + LLWindowResolution* resolutions = getSupportedResolutions(num_resolutions); + + return ((F32)resolutions[num_resolutions - 1].mWidth / (F32)resolutions[num_resolutions - 1].mHeight); +} + +F32 LLWindowWin32::getPixelAspectRatio() +{ + F32 pixel_aspect = 1.f; + if (getFullscreen()) + { + LLCoordScreen screen_size; + getSize(&screen_size); + pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; + } + + return pixel_aspect; +} + +// Change display resolution. Returns true if successful. +// protected +bool LLWindowWin32::setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh) +{ + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + bool success = false; + + // Don't change anything if we don't have to + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == bits && + dev_mode.dmDisplayFrequency == refresh ) + { + // ...display mode identical, do nothing + return true; + } + } + + memset(&dev_mode, 0, sizeof(dev_mode)); + dev_mode.dmSize = sizeof(dev_mode); + dev_mode.dmPelsWidth = width; + dev_mode.dmPelsHeight = height; + dev_mode.dmBitsPerPel = bits; + dev_mode.dmDisplayFrequency = refresh; + dev_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; + + // CDS_FULLSCREEN indicates that this is a temporary change to the device mode. + LONG cds_result = ChangeDisplaySettings(&dev_mode, CDS_FULLSCREEN); + + success = (DISP_CHANGE_SUCCESSFUL == cds_result); + + if (!success) + { + LL_WARNS("Window") << "setDisplayResolution failed, " + << width << "x" << height << "x" << bits << " @ " << refresh << LL_ENDL; + } + + return success; +} + +// protected +bool LLWindowWin32::setFullscreenResolution() +{ + if (mFullscreen) + { + return setDisplayResolution( mFullscreenWidth, mFullscreenHeight, mFullscreenBits, mFullscreenRefresh); + } + else + { + return false; + } +} + +// protected +bool LLWindowWin32::resetDisplayResolution() +{ + LL_DEBUGS("Window") << "resetDisplayResolution START" << LL_ENDL; + + LONG cds_result = ChangeDisplaySettings(NULL, 0); + + bool success = (DISP_CHANGE_SUCCESSFUL == cds_result); + + if (!success) + { + LL_WARNS("Window") << "resetDisplayResolution failed" << LL_ENDL; + } + + LL_DEBUGS("Window") << "resetDisplayResolution END" << LL_ENDL; + + return success; +} + +void LLWindowWin32::swapBuffers() +{ + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + SwapBuffers(mhDC); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("GPU Collect"); + LL_PROFILER_GPU_COLLECT; + } +} + + +// +// LLSplashScreenImp +// +LLSplashScreenWin32::LLSplashScreenWin32() +: mWindow(NULL) +{ +} + +LLSplashScreenWin32::~LLSplashScreenWin32() +{ +} + +void LLSplashScreenWin32::showImpl() +{ + // This appears to work. ??? + HINSTANCE hinst = GetModuleHandle(NULL); + + mWindow = CreateDialog(hinst, + TEXT("SPLASHSCREEN"), + NULL, // no parent + (DLGPROC) LLSplashScreenWin32::windowProc); + ShowWindow(mWindow, SW_SHOW); + + // Should set taskbar text without creating a header for the window (caption) + SetWindowTextA(mWindow, "Second Life"); +} + + +void LLSplashScreenWin32::updateImpl(const std::string& mesg) +{ + if (!mWindow) return; + + int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); + if( output_str_len>1024 ) + return; + + WCHAR w_mesg[1025];//big enought to keep null terminatos + + MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); + + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 + w_mesg[output_str_len] = 0; + + SendDlgItemMessage(mWindow, + 666, // HACK: text id + WM_SETTEXT, + FALSE, + (LPARAM)w_mesg); +} + + +void LLSplashScreenWin32::hideImpl() +{ + if (mWindow) + { + if (!destroy_window_handler(mWindow)) + { + LL_WARNS("Window") << "Failed to properly close splash screen window!" << LL_ENDL; + } + mWindow = NULL; + } +} + + +// static +LRESULT CALLBACK LLSplashScreenWin32::windowProc(HWND h_wnd, UINT u_msg, + WPARAM w_param, LPARAM l_param) +{ + // Just give it to windows + return DefWindowProc(h_wnd, u_msg, w_param, l_param); +} + +// +// Helper Funcs +// + +S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type) +{ + UINT uType; + + switch(type) + { + case OSMB_OK: + uType = MB_OK; + break; + case OSMB_OKCANCEL: + uType = MB_OKCANCEL; + break; + case OSMB_YESNO: + uType = MB_YESNO; + break; + default: + uType = MB_OK; + break; + } + + int retval_win = MessageBoxW(NULL, // HWND + ll_convert_string_to_wide(text).c_str(), + ll_convert_string_to_wide(caption).c_str(), + uType); + S32 retval; + + switch(retval_win) + { + case IDYES: + retval = OSBTN_YES; + break; + case IDNO: + retval = OSBTN_NO; + break; + case IDOK: + retval = OSBTN_OK; + break; + case IDCANCEL: + retval = OSBTN_CANCEL; + break; + default: + retval = OSBTN_CANCEL; + break; + } + + return retval; +} + + +void LLWindowWin32::spawnWebBrowser(const std::string& escaped_url, bool async) +{ + bool found = false; + S32 i; + for (i = 0; i < gURLProtocolWhitelistCount; i++) + { + if (escaped_url.find(gURLProtocolWhitelist[i]) == 0) + { + found = true; + break; + } + } + + if (!found) + { + LL_WARNS("Window") << "spawn_web_browser() called for url with protocol not on whitelist: " << escaped_url << LL_ENDL; + return; + } + + LL_INFOS("Window") << "Opening URL " << escaped_url << LL_ENDL; + + // replaced ShellExecute code with ShellExecuteEx since ShellExecute doesn't work + // reliablly on Vista. + + // this is madness.. no, this is.. + LLWString url_wstring = utf8str_to_wstring( escaped_url ); + llutf16string url_utf16 = wstring_to_utf16str( url_wstring ); + + // let the OS decide what to use to open the URL + SHELLEXECUTEINFO sei = { sizeof( sei ) }; + // NOTE: this assumes that SL will stick around long enough to complete the DDE message exchange + // necessary for ShellExecuteEx to complete + if (async) + { + sei.fMask = SEE_MASK_ASYNCOK; + } + sei.nShow = SW_SHOWNORMAL; + sei.lpVerb = L"open"; + sei.lpFile = url_utf16.c_str(); + ShellExecuteEx( &sei ); +} + +/* + Make the raw keyboard data available - used to poke through to LLQtWebKit so + that Qt/Webkit has access to the virtual keycodes etc. that it needs +*/ +LLSD LLWindowWin32::getNativeKeyData() +{ + LLSD result = LLSD::emptyMap(); + + result["scan_code"] = (S32)mKeyScanCode; + result["virtual_key"] = (S32)mKeyVirtualKey; + result["msg"] = ll_sd_from_U32(mRawMsg); + result["w_param"] = ll_sd_from_U32(mRawWParam); + result["l_param"] = ll_sd_from_U32(mRawLParam); + + return result; +} + +bool LLWindowWin32::dialogColorPicker( F32 *r, F32 *g, F32 *b ) +{ + bool retval = false; + + static CHOOSECOLOR cc; + static COLORREF crCustColors[16]; + cc.lStructSize = sizeof(CHOOSECOLOR); + cc.hwndOwner = mWindowHandle; + cc.hInstance = NULL; + cc.rgbResult = RGB ((*r * 255.f),(*g *255.f),(*b * 255.f)); + //cc.rgbResult = RGB (0x80,0x80,0x80); + cc.lpCustColors = crCustColors; + cc.Flags = CC_RGBINIT | CC_FULLOPEN; + cc.lCustData = 0; + cc.lpfnHook = NULL; + cc.lpTemplateName = NULL; + + // This call is modal, so pause agent + //send_agent_pause(); // this is in newview and we don't want to set up a dependency + { + retval = ChooseColor(&cc); + } + //send_agent_resume(); // this is in newview and we don't want to set up a dependency + + *b = ((F32)((cc.rgbResult >> 16) & 0xff)) / 255.f; + + *g = ((F32)((cc.rgbResult >> 8) & 0xff)) / 255.f; + + *r = ((F32)(cc.rgbResult & 0xff)) / 255.f; + + return (retval); +} + +void *LLWindowWin32::getPlatformWindow() +{ + return (void*)mWindowHandle; +} + +void LLWindowWin32::bringToFront() +{ + mWindowThread->post([=]() + { + BringWindowToTop(mWindowHandle); + }); +} + +// set (OS) window focus back to the client +void LLWindowWin32::focusClient() +{ + mWindowThread->post([=]() + { + SetFocus(mWindowHandle); + }); +} + +void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, bool b) +{ + if (b == sLanguageTextInputAllowed || !LLWinImm::isAvailable()) + { + return; + } + + if (preeditor != mPreeditor && !b) + { + // This condition may occur with a call to + // setEnabled(bool) from LLTextEditor or LLLineEditor + // when the control is not focused. + // We need to silently ignore the case so that + // the language input status of the focused control + // is not disturbed. + return; + } + + // Take care of old and new preeditors. + if (preeditor != mPreeditor || !b) + { + if (sLanguageTextInputAllowed) + { + interruptLanguageTextInput(); + } + mPreeditor = (b ? preeditor : NULL); + } + + sLanguageTextInputAllowed = b; + + if (sLanguageTextInputAllowed) + { + mWindowThread->post([=]() + { + // Allowing: Restore the previous IME status, so that the user has a feeling that the previous + // text input continues naturally. Be careful, however, the IME status is meaningful only during the user keeps + // using same Input Locale (aka Keyboard Layout). + if (sWinIMEOpened && GetKeyboardLayout(0) == sWinInputLocale) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::setOpenStatus(himc, true); + LLWinImm::setConversionStatus(himc, sWinIMEConversionMode, sWinIMESentenceMode); + LLWinImm::releaseContext(mWindowHandle, himc); + } + }); + } + else + { + mWindowThread->post([=]() + { + // Disallowing: Turn off the IME so that succeeding key events bypass IME and come to us directly. + // However, do it after saving the current IME status. We need to restore the status when + // allowing language text input again. + sWinInputLocale = GetKeyboardLayout(0); + sWinIMEOpened = LLWinImm::isIME(sWinInputLocale); + if (sWinIMEOpened) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + sWinIMEOpened = LLWinImm::getOpenStatus(himc); + if (sWinIMEOpened) + { + LLWinImm::getConversionStatus(himc, &sWinIMEConversionMode, &sWinIMESentenceMode); + + // We need both ImmSetConversionStatus and ImmSetOpenStatus here to surely disable IME's + // keyboard hooking, because Some IME reacts only on the former and some other on the latter... + LLWinImm::setConversionStatus(himc, IME_CMODE_NOCONVERSION, sWinIMESentenceMode); + LLWinImm::setOpenStatus(himc, false); + } + LLWinImm::releaseContext(mWindowHandle, himc); + } + }); + } +} + +void LLWindowWin32::fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, + CANDIDATEFORM *form) +{ + LLCoordWindow caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + + memset(form, 0, sizeof(CANDIDATEFORM)); + form->dwStyle = CFS_EXCLUDE; + form->ptCurrentPos.x = caret_coord.mX; + form->ptCurrentPos.y = caret_coord.mY; + form->rcArea.left = top_left.mX; + form->rcArea.top = top_left.mY; + form->rcArea.right = bottom_right.mX; + form->rcArea.bottom = bottom_right.mY; +} + + +// Put the IME window at the right place (near current text input). Point coordinates should be the top of the current text line. +void LLWindowWin32::setLanguageTextInput( const LLCoordGL & position ) +{ + if (sLanguageTextInputAllowed && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + + LLCoordWindow win_pos; + convertCoords( position, &win_pos ); + + if ( win_pos.mX >= 0 && win_pos.mY >= 0 && + (win_pos.mX != sWinIMEWindowPosition.mX) || (win_pos.mY != sWinIMEWindowPosition.mY) ) + { + COMPOSITIONFORM ime_form; + memset( &ime_form, 0, sizeof(ime_form) ); + ime_form.dwStyle = CFS_POINT; + ime_form.ptCurrentPos.x = win_pos.mX; + ime_form.ptCurrentPos.y = win_pos.mY; + + LLWinImm::setCompositionWindow( himc, &ime_form ); + + sWinIMEWindowPosition = win_pos; + } + + LLWinImm::releaseContext(mWindowHandle, himc); + } +} + + +void LLWindowWin32::fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, + IMECHARPOSITION *char_position) +{ + LLCoordScreen caret_coord, top_left, bottom_right; + convertCoords(caret, &caret_coord); + convertCoords(LLCoordGL(bounds.mLeft, bounds.mTop), &top_left); + convertCoords(LLCoordGL(bounds.mRight, bounds.mBottom), &bottom_right); + + char_position->pt.x = caret_coord.mX; + char_position->pt.y = top_left.mY; // Windows wants the coordinate of upper left corner of a character... + char_position->cLineHeight = bottom_right.mY - top_left.mY; + char_position->rcDocument.left = top_left.mX; + char_position->rcDocument.top = top_left.mY; + char_position->rcDocument.right = bottom_right.mX; + char_position->rcDocument.bottom = bottom_right.mY; +} + +void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont) +{ + // Our font is a list of FreeType recognized font files that may + // not have a corresponding ones in Windows' fonts. Hence, we + // can't simply tell Windows which font we are using. We will + // notify a _standard_ font for a current input locale instead. + // We use a hard-coded knowledge about the Windows' standard + // configuration to do so... + + memset(logfont, 0, sizeof(LOGFONT)); + + const WORD lang_id = LOWORD(GetKeyboardLayout(0)); + switch (PRIMARYLANGID(lang_id)) + { + case LANG_CHINESE: + // We need to identify one of two Chinese fonts. + switch (SUBLANGID(lang_id)) + { + case SUBLANG_CHINESE_SIMPLIFIED: + case SUBLANG_CHINESE_SINGAPORE: + logfont->lfCharSet = GB2312_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("SimHei")); + break; + case SUBLANG_CHINESE_TRADITIONAL: + case SUBLANG_CHINESE_HONGKONG: + case SUBLANG_CHINESE_MACAU: + default: + logfont->lfCharSet = CHINESEBIG5_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MingLiU")); + break; + } + break; + case LANG_JAPANESE: + logfont->lfCharSet = SHIFTJIS_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("MS Gothic")); + break; + case LANG_KOREAN: + logfont->lfCharSet = HANGUL_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Gulim")); + break; + default: + logfont->lfCharSet = ANSI_CHARSET; + lstrcpy(logfont->lfFaceName, TEXT("Tahoma")); + break; + } + + logfont->lfHeight = mPreeditor->getPreeditFontSize(); + logfont->lfWeight = FW_NORMAL; +} + +U32 LLWindowWin32::fillReconvertString(const LLWString &text, + S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) +{ + const llutf16string text_utf16 = wstring_to_utf16str(text); + const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); + if (reconvert_string && reconvert_string->dwSize >= required_size) + { + const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); + const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); + + reconvert_string->dwVersion = 0; + reconvert_string->dwStrLen = text_utf16.length(); + reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); + reconvert_string->dwCompStrLen = focus_utf16_length; + reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); + reconvert_string->dwTargetStrLen = 0; + reconvert_string->dwTargetStrOffset = focus_utf16_at * sizeof(WCHAR); + + const LPWSTR text = (LPWSTR)((BYTE *)reconvert_string + sizeof(RECONVERTSTRING)); + memcpy(text, text_utf16.c_str(), (text_utf16.length() + 1) * sizeof(WCHAR)); + } + return required_size; +} + +void LLWindowWin32::updateLanguageTextInputArea() +{ + if (!mPreeditor || !LLWinImm::isAvailable()) + { + return; + } + + LLCoordGL caret_coord; + LLRect preedit_bounds; + if (mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL)) + { + mLanguageTextInputPointGL = caret_coord; + mLanguageTextInputAreaGL = preedit_bounds; + + CANDIDATEFORM candidate_form; + fillCandidateForm(caret_coord, preedit_bounds, &candidate_form); + + HIMC himc = LLWinImm::getContext(mWindowHandle); + // Win32 document says there may be up to 4 candidate windows. + // This magic number 4 appears only in the document, and + // there are no constant/macro for the value... + for (int i = 3; i >= 0; --i) + { + candidate_form.dwIndex = i; + LLWinImm::setCandidateWindow(himc, &candidate_form); + } + LLWinImm::releaseContext(mWindowHandle, himc); + } +} + +void LLWindowWin32::interruptLanguageTextInput() +{ + ASSERT_MAIN_THREAD(); + if (mPreeditor && LLWinImm::isAvailable()) + { + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::notifyIME(himc, NI_COMPOSITIONSTR, CPS_COMPLETE, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + } +} + +void LLWindowWin32::handleStartCompositionMessage() +{ + // Let IME know the font to use in feedback UI. + LOGFONT logfont; + fillCompositionLogfont(&logfont); + HIMC himc = LLWinImm::getContext(mWindowHandle); + LLWinImm::setCompositionFont(himc, &logfont); + LLWinImm::releaseContext(mWindowHandle, himc); +} + +// Handle WM_IME_COMPOSITION message. + +void LLWindowWin32::handleCompositionMessage(const U32 indexes) +{ + if (!mPreeditor) + { + return; + } + bool needs_update = false; + LLWString result_string; + LLWString preedit_string; + S32 preedit_string_utf16_length = 0; + LLPreeditor::segment_lengths_t preedit_segment_lengths; + LLPreeditor::standouts_t preedit_standouts; + + // Step I: Receive details of preedits from IME. + + HIMC himc = LLWinImm::getContext(mWindowHandle); + + if (indexes & GCS_RESULTSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_RESULTSTR, data, size); + if (size > 0) + { + result_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = true; + } + } + + if (indexes & GCS_COMPSTR) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, NULL, 0); + if (size >= 0) + { + const LPWSTR data = new WCHAR[size / sizeof(WCHAR) + 1]; + size = LLWinImm::getCompositionString(himc, GCS_COMPSTR, data, size); + if (size > 0) + { + preedit_string_utf16_length = size / sizeof(WCHAR); + preedit_string = utf16str_to_wstring(llutf16string(data, size / sizeof(WCHAR))); + } + delete[] data; + needs_update = true; + } + } + + if ((indexes & GCS_COMPCLAUSE) && preedit_string.length() > 0) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, NULL, 0); + if (size > 0) + { + const LPDWORD data = new DWORD[size / sizeof(DWORD)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPCLAUSE, data, size); + if (size >= sizeof(DWORD) * 2 + && data[0] == 0 && data[size / sizeof(DWORD) - 1] == preedit_string_utf16_length) + { + preedit_segment_lengths.resize(size / sizeof(DWORD) - 1); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + const S32 length = wstring_wstring_length_from_utf16_length(preedit_string, offset, data[i + 1] - data[i]); + preedit_segment_lengths[i] = length; + offset += length; + } + } + delete[] data; + } + } + + if ((indexes & GCS_COMPATTR) && preedit_segment_lengths.size() > 1) + { + LONG size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, NULL, 0); + if (size > 0) + { + const LPBYTE data = new BYTE[size / sizeof(BYTE)]; + size = LLWinImm::getCompositionString(himc, GCS_COMPATTR, data, size); + if (size == preedit_string_utf16_length) + { + preedit_standouts.assign(preedit_segment_lengths.size(), false); + S32 offset = 0; + for (U32 i = 0; i < preedit_segment_lengths.size(); i++) + { + if (ATTR_TARGET_CONVERTED == data[offset] || ATTR_TARGET_NOTCONVERTED == data[offset]) + { + preedit_standouts[i] = true; + } + offset += wstring_utf16_length(preedit_string, offset, preedit_segment_lengths[i]); + } + } + delete[] data; + } + } + + S32 caret_position = preedit_string.length(); + if (indexes & GCS_CURSORPOS) + { + const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); + if (caret_position_utf16 >= 0 && caret_position <= preedit_string_utf16_length) + { + caret_position = wstring_wstring_length_from_utf16_length(preedit_string, 0, caret_position_utf16); + } + } + + if (indexes == 0) + { + // I'm not sure this condition really happens, but + // Windows SDK document says it is an indication + // of "reset everything." + needs_update = true; + } + + LLWinImm::releaseContext(mWindowHandle, himc); + + // Step II: Update the active preeditor. + + if (needs_update) + { + if (preedit_string.length() != 0 || result_string.length() != 0) + { + mPreeditor->resetPreedit(); + } + + if (result_string.length() > 0) + { + for (LLWString::const_iterator i = result_string.begin(); i != result_string.end(); i++) + { + mPreeditor->handleUnicodeCharHere(*i); + } + } + + if (preedit_string.length() == 0) + { + preedit_segment_lengths.clear(); + preedit_standouts.clear(); + } + else + { + if (preedit_segment_lengths.size() == 0) + { + preedit_segment_lengths.assign(1, preedit_string.length()); + } + if (preedit_standouts.size() == 0) + { + preedit_standouts.assign(preedit_segment_lengths.size(), false); + } + } + mPreeditor->updatePreedit(preedit_string, preedit_segment_lengths, preedit_standouts, caret_position); + + // Some IME doesn't query char position after WM_IME_COMPOSITION, + // so we need to update them actively. + updateLanguageTextInputArea(); + } +} + +// Given a text and a focus range, find_context finds and returns a +// surrounding context of the focused subtext. A variable pointed +// to by offset receives the offset in llwchars of the beginning of +// the returned context string in the given wtext. + +static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_length, S32 *offset) +{ + static const S32 CONTEXT_EXCESS = 30; // This value is by experiences. + + const S32 e = llmin((S32) wtext.length(), focus + focus_length + CONTEXT_EXCESS); + S32 end = focus + focus_length; + while (end < e && '\n' != wtext[end]) + { + end++; + } + + const S32 s = llmax(0, focus - CONTEXT_EXCESS); + S32 start = focus; + while (start > s && '\n' != wtext[start - 1]) + { + --start; + } + + *offset = start; + return wtext.substr(start, end - start); +} + +// final stage of handling drop requests - both from WM_DROPFILES message +// for files and via IDropTarget interface requests. +LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ) +{ + ASSERT_MAIN_THREAD(); + return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); +} + +// Handle WM_IME_REQUEST message. +// If it handled the message, returns true. Otherwise, false. +// When it handled the message, the value to be returned from +// the Window Procedure is set to *result. + +bool LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *result) +{ + if ( mPreeditor ) + { + switch (request) + { + case IMR_CANDIDATEWINDOW: // http://msdn2.microsoft.com/en-us/library/ms776080.aspx + { + LLCoordGL caret_coord; + LLRect preedit_bounds; + mPreeditor->getPreeditLocation(-1, &caret_coord, &preedit_bounds, NULL); + + CANDIDATEFORM *const form = (CANDIDATEFORM *)param; + DWORD const dwIndex = form->dwIndex; + fillCandidateForm(caret_coord, preedit_bounds, form); + form->dwIndex = dwIndex; + + *result = 1; + return true; + } + case IMR_QUERYCHARPOSITION: + { + IMECHARPOSITION *const char_position = (IMECHARPOSITION *)param; + + // char_position->dwCharPos counts in number of + // WCHARs, i.e., UTF-16 encoding units, so we can't simply pass the + // number to getPreeditLocation. + + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + LLCoordGL caret_coord; + LLRect preedit_bounds, text_control; + const S32 position = wstring_wstring_length_from_utf16_length(wtext, preedit, char_position->dwCharPos); + + if (!mPreeditor->getPreeditLocation(position, &caret_coord, &preedit_bounds, &text_control)) + { + LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; + return false; + } + + fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); + + *result = 1; + return true; + } + case IMR_COMPOSITIONFONT: + { + fillCompositionLogfont((LOGFONT *)param); + + *result = 1; + return true; + } + case IMR_RECONVERTSTRING: + { + mPreeditor->resetPreedit(); + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 select, select_length; + mPreeditor->getSelectionRange(&select, &select_length); + + S32 context_offset; + const LLWString context = find_context(wtext, select, select_length, &context_offset); + + RECONVERTSTRING * const reconvert_string = (RECONVERTSTRING *)param; + const U32 size = fillReconvertString(context, select - context_offset, select_length, reconvert_string); + if (reconvert_string) + { + if (select_length == 0) + { + // Let the IME to decide the reconversion range, and + // adjust the reconvert_string structure accordingly. + HIMC himc = LLWinImm::getContext(mWindowHandle); + const bool adjusted = LLWinImm::setCompositionString(himc, + SCS_QUERYRECONVERTSTRING, reconvert_string, size, NULL, 0); + LLWinImm::releaseContext(mWindowHandle, himc); + if (adjusted) + { + const llutf16string & text_utf16 = wstring_to_utf16str(context); + const S32 new_preedit_start = reconvert_string->dwCompStrOffset / sizeof(WCHAR); + const S32 new_preedit_end = new_preedit_start + reconvert_string->dwCompStrLen; + select = utf16str_wstring_length(text_utf16, new_preedit_start); + select_length = utf16str_wstring_length(text_utf16, new_preedit_end) - select; + select += context_offset; + } + } + mPreeditor->markAsPreedit(select, select_length); + } + + *result = size; + return true; + } + case IMR_CONFIRMRECONVERTSTRING: + { + *result = 0; + return true; + } + case IMR_DOCUMENTFEED: + { + const LLWString & wtext = mPreeditor->getPreeditString(); + S32 preedit, preedit_length; + mPreeditor->getPreeditRange(&preedit, &preedit_length); + + S32 context_offset; + LLWString context = find_context(wtext, preedit, preedit_length, &context_offset); + preedit -= context_offset; + preedit_length = llmin(preedit_length, (S32)context.length() - preedit); + if (preedit_length > 0 && preedit >= 0) + { + // IMR_DOCUMENTFEED may be called when we have an active preedit. + // We should pass the context string *excluding* the preedit string. + // Otherwise, some IME are confused. + context.erase(preedit, preedit_length); + } + + RECONVERTSTRING *reconvert_string = (RECONVERTSTRING *)param; + *result = fillReconvertString(context, preedit, 0, reconvert_string); + return true; + } + default: + return false; + } + } + + return false; +} + +//static +void LLWindowWin32::setDPIAwareness() +{ + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + if (hShcore != NULL) + { + SetProcessDpiAwarenessType pSPDA; + pSPDA = (SetProcessDpiAwarenessType)GetProcAddress(hShcore, "SetProcessDpiAwareness"); + if (pSPDA) + { + + HRESULT hr = pSPDA(PROCESS_PER_MONITOR_DPI_AWARE); + if (hr != S_OK) + { + LL_WARNS() << "SetProcessDpiAwareness() function returned an error. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK. Will use legacy DPI awareness API of Win XP/7" << LL_ENDL; + } +} + +void* LLWindowWin32::getDirectInput8() +{ + return &gDirectInput8; +} + +bool LLWindowWin32::getInputDevices(U32 device_type_filter, + std::function osx_callback, + void * di8_devices_callback, + void* userdata) +{ + if (gDirectInput8 != NULL) + { + // Enumerate devices + HRESULT status = gDirectInput8->EnumDevices( + (DWORD) device_type_filter, // DWORD dwDevType, + (LPDIENUMDEVICESCALLBACK)di8_devices_callback, // LPDIENUMDEVICESCALLBACK lpCallback, // BOOL DIEnumDevicesCallback( LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef ) // BOOL CALLBACK DinputDevice::DevicesCallback + (LPVOID*)userdata, // LPVOID pvRef + DIEDFL_ATTACHEDONLY // DWORD dwFlags + ); + + return status == DI_OK; + } + return false; +} + +F32 LLWindowWin32::getSystemUISize() +{ + F32 scale_value = 1.f; + HWND hWnd = (HWND)getPlatformWindow(); + HDC hdc = GetDC(hWnd); + HMONITOR hMonitor; + HANDLE hProcess = GetCurrentProcess(); + PROCESS_DPI_AWARENESS dpi_awareness; + + HMODULE hShcore = LoadLibrary(L"shcore.dll"); + + if (hShcore != NULL) + { + GetProcessDpiAwarenessType pGPDA; + pGPDA = (GetProcessDpiAwarenessType)GetProcAddress(hShcore, "GetProcessDpiAwareness"); + GetDpiForMonitorType pGDFM; + pGDFM = (GetDpiForMonitorType)GetProcAddress(hShcore, "GetDpiForMonitor"); + if (pGPDA != NULL && pGDFM != NULL) + { + pGPDA(hProcess, &dpi_awareness); + if (dpi_awareness == PROCESS_PER_MONITOR_DPI_AWARE) + { + POINT pt; + UINT dpix = 0, dpiy = 0; + HRESULT hr = E_FAIL; + RECT rect; + + GetWindowRect(hWnd, &rect); + // Get the DPI for the monitor, on which the center of window is displayed and set the scaling factor + pt.x = (rect.left + rect.right) / 2; + pt.y = (rect.top + rect.bottom) / 2; + hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + hr = pGDFM(hMonitor, MDT_EFFECTIVE_DPI, &dpix, &dpiy); + if (hr == S_OK) + { + scale_value = F32(dpix) / F32(USER_DEFAULT_SCREEN_DPI); + } + else + { + LL_WARNS() << "Could not determine DPI for monitor. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + else + { + LL_WARNS() << "Process is not per-monitor DPI-aware. Setting scale to default 100 %" << LL_ENDL; + scale_value = 1.0f; + } + } + FreeLibrary(hShcore); + } + else + { + LL_WARNS() << "Could not load shcore.dll library (included by from Win 8.1 SDK). Using legacy DPI awareness API of Win XP/7" << LL_ENDL; + scale_value = F32(GetDeviceCaps(hdc, LOGPIXELSX)) / F32(USER_DEFAULT_SCREEN_DPI); + } + + ReleaseDC(hWnd, hdc); + return scale_value; +} + +//static +std::vector LLWindowWin32::getDisplaysResolutionList() +{ + return sMonitorInfo.getResolutionsList(); +} + +//static +std::vector LLWindowWin32::getDynamicFallbackFontList() +{ + // Fonts previously in getFontListSans() have moved to fonts.xml. + return std::vector(); +} + +void LLWindowWin32::setMaxVRAMMegabytes(U32 max_vram) +{ + if (mWindowThread) + { + mWindowThread->mMaxVRAM = max_vram; + } +} + +#endif // LL_WINDOWS + +inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() + : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/) +{ + LL::ThreadPool::start(); +} + +void LLWindowWin32::LLWindowWin32Thread::close() +{ + if (!mQueue->isClosed()) + { + LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL; + LL::ThreadPool::close(); + + // Workaround for SL-18721 in case window closes too early and abruptly + LLSplashScreen::show(); + LLSplashScreen::update("..."); // will be updated later + } +} + + +/** + * LogChange is to log changes in status while trying to avoid spamming the + * log with repeated messages, especially in a tight loop. It refuses to log + * a continuous run of identical messages, but logs every time the message + * changes. (It will happily spam when messages quickly bounce back and + * forth.) + */ +class LogChange +{ +public: + LogChange(const std::string& tag): + mTag(tag) + {} + + template + void always(Items&&... items) + { + // This odd construct ensures that the stringize() call is only + // executed if DEBUG logging is enabled for the passed tag. + LL_DEBUGS(mTag.c_str()); + log(LL_CONT, stringize(std::forward(items)...)); + LL_ENDL; + } + + template + void onChange(Items&&... items) + { + LL_DEBUGS(mTag.c_str()); + auto str = stringize(std::forward(items)...); + if (str != mPrev) + { + log(LL_CONT, str); + } + LL_ENDL; + } + +private: + void log(std::ostream& out, const std::string& message) + { + mPrev = message; + out << message; + } + std::string mTag; + std::string mPrev; +}; + +// Print hardware debug info about available graphics adapters in ordinal order +void debugEnumerateGraphicsAdapters() +{ + LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL; + + IDXGIFactory1* factory; + HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory); + if (FAILED(res) || !factory) + { + LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + UINT graphics_adapter_index = 0; + IDXGIAdapter3* dxgi_adapter; + while (true) + { + res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&dxgi_adapter)); + if (FAILED(res)) + { + if (graphics_adapter_index == 0) + { + LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL; + } + } + else + { + DXGI_ADAPTER_DESC desc; + dxgi_adapter->GetDesc(&desc); + std::wstring description_w((wchar_t*)desc.Description); + std::string description(description_w.begin(), description_w.end()); + LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", " + << "Description: " << description << ", " + << "DeviceId: " << desc.DeviceId << ", " + << "SubSysId: " << desc.SubSysId << ", " + << "AdapterLuid: " << desc.AdapterLuid.HighPart << "_" << desc.AdapterLuid.LowPart << ", " + << "DedicatedVideoMemory: " << desc.DedicatedVideoMemory / 1024 / 1024 << ", " + << "DedicatedSystemMemory: " << desc.DedicatedSystemMemory / 1024 / 1024 << ", " + << "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL; + } + + if (dxgi_adapter) + { + dxgi_adapter->Release(); + dxgi_adapter = NULL; + } + else + { + break; + } + + graphics_adapter_index++; + } + } + + if (factory) + { + factory->Release(); + } +} + +void LLWindowWin32::LLWindowWin32Thread::initDX() +{ + if (!mGLReady) { return; } + + if (mDXGIAdapter == NULL) + { + debugEnumerateGraphicsAdapters(); + + IDXGIFactory4* pFactory = nullptr; + + HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory); + + if (FAILED(res)) + { + LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + res = pFactory->EnumAdapters(0, reinterpret_cast(&mDXGIAdapter)); + if (FAILED(res)) + { + LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + LL_INFOS() << "EnumAdapters success" << LL_ENDL; + } + } + + if (pFactory) + { + pFactory->Release(); + } + } +} + +void LLWindowWin32::LLWindowWin32Thread::initD3D() +{ + if (!mGLReady) { return; } + + if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) + { + mD3D = Direct3DCreate9(D3D_SDK_VERSION); + + D3DPRESENT_PARAMETERS d3dpp; + + ZeroMemory(&d3dpp, sizeof(d3dpp)); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + + HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); + + if (FAILED(res)) + { + LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL; + } + } +} + +void LLWindowWin32::LLWindowWin32Thread::cleanupDX() +{ + //clean up DXGI/D3D resources + if (mDXGIAdapter) + { + mDXGIAdapter->Release(); + mDXGIAdapter = nullptr; + } + + if (mD3DDevice) + { + mD3DDevice->Release(); + mD3DDevice = nullptr; + } + + if (mD3D) + { + mD3D->Release(); + mD3D = nullptr; + } +} + +void LLWindowWin32::LLWindowWin32Thread::run() +{ + sWindowThreadId = std::this_thread::get_id(); + LogChange logger("Window"); + + //as good a place as any to up the MM timer resolution (see ms_sleep) + //attempt to set timer resolution to 1ms + TIMECAPS tc; + if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) == TIMERR_NOERROR) + { + timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax)); + } + + while (! getQueue().done()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + + // lazily call initD3D inside this loop to catch when mGLReady has been set to true + initDX(); + + if (mWindowHandleThrd != 0) + { + // lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true + // *TODO: Shutdown if this fails when mWindowHandle exists + initD3D(); + + MSG msg; + BOOL status; + if (mhDCThrd == 0) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage"); + logger.onChange("PeekMessage(", std::hex, mWindowHandleThrd, ")"); + status = PeekMessage(&msg, mWindowHandleThrd, 0, 0, PM_REMOVE); + } + else + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage"); + logger.always("GetMessage(", std::hex, mWindowHandleThrd, ")"); + status = GetMessage(&msg, NULL, 0, 0); + } + if (status > 0) + { + logger.always("got MSG (", std::hex, msg.hwnd, ", ", msg.message, + ", ", msg.wParam, ")"); + TranslateMessage(&msg); + DispatchMessage(&msg); + + mMessageQueue.pushFront(msg); + } + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue"); + logger.onChange("runPending()"); + //process any pending functions + getQueue().runPending(); + } + +#if 0 + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep"); + logger.always("sleep(1)"); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +#endif + } + + cleanupDX(); +} + +void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +{ + if (mQueue->isClosed()) + { + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; + return; + } + + // Make sure we don't leave a blank toolbar button. + // Also hiding window now prevents user from suspending it + // via some action (like dragging it around) + ShowWindow(mWindowHandleThrd, SW_HIDE); + + // Schedule destruction + HWND old_handle = mWindowHandleThrd; + post([this]() + { + if (IsWindow(mWindowHandleThrd)) + { + if (mhDCThrd) + { + if (!ReleaseDC(mWindowHandleThrd, mhDCThrd)) + { + LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL; + } + mhDCThrd = NULL; + } + + // This causes WM_DESTROY to be sent *immediately* + if (!destroy_window_handler(mWindowHandleThrd)) + { + LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL; + } + } + else + { + // Something killed the window while we were busy destroying gl or handle somehow got broken + LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; + } + mWindowHandleThrd = NULL; + mhDCThrd = NULL; + mGLReady = false; + }); + + LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL; + mQueue->close(); + + // Post a nonsense user message to wake up the thread in + // case it is waiting for a getMessage() + if (old_handle) + { + WPARAM wparam{ 0xB0B0 }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle + << ", " << WM_DUMMY_ + << ", " << wparam << ")" << std::dec << LL_ENDL; + PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); + } + + // There are cases where window will refuse to close, + // can't wait forever on join, check state instead + LLTimer timeout; + timeout.setTimerExpirySec(2.0); + while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd) + { + ms_sleep(100); + } + + if (getQueue().done() || mWindowHandleThrd == NULL) + { + // Window is closed, started closing or is cleaning up + // now wait for our single thread to die. + if (mWindowHandleThrd) + { + LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; + } + else + { + LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL; + } + for (auto& pair : mThreads) + { + pair.second.join(); + } + } + else + { + // Something suspended window thread, can't afford to wait forever + // so kill thread instead + // Ex: This can happen if user starts dragging window arround (if it + // was visible) or a modal notification pops up + LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL; + + for (auto& pair : mThreads) + { + // very unsafe + TerminateThread(pair.second.native_handle(), 0); + pair.second.detach(); + cleanupDX(); + } + } + LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; +} + +void LLWindowWin32::post(const std::function& func) +{ + mFunctionQueue.pushFront(func); +} + +void LLWindowWin32::postMouseButtonEvent(const std::function& func) +{ + mMouseQueue.pushFront(func); +} + +void LLWindowWin32::kickWindowThread(HWND windowHandle) +{ + if (! windowHandle) + windowHandle = mWindowHandle; + if (windowHandle) + { + // post a nonsense user message to wake up the Window Thread in + // case any functions are pending and no windows events came + // through this frame + WPARAM wparam{ 0xB0B0 }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle + << ", " << WM_DUMMY_ + << ", " << wparam << ")" << std::dec << LL_ENDL; + PostMessage(windowHandle, WM_DUMMY_, wparam, 0x1337); + } +} + +void LLWindowWin32::updateWindowRect() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + //called from window thread + RECT rect; + RECT client_rect; + + if (GetWindowRect(mWindowHandle, &rect) && + GetClientRect(mWindowHandle, &client_rect)) + { + post([=] + { + mRect = rect; + mClientRect = client_rect; + }); + } +} diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 8516b45393..82541ace6e 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -1,295 +1,295 @@ -/** - * @file llwindowwin32.h - * @brief Windows implementation of LLWindow class - * - * $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$ - */ - -#ifndef LL_LLWINDOWWIN32_H -#define LL_LLWINDOWWIN32_H - -// Limit Windows API to small and manageable set. -#include "llwin32headerslean.h" - -#include "llwindow.h" -#include "llwindowcallbacks.h" -#include "lldragdropwin32.h" -#include "llthread.h" -#include "llthreadsafequeue.h" -#include "llmutex.h" -#include "workqueue.h" - -// Hack for async host by name -#define LL_WM_HOST_RESOLVED (WM_APP + 1) -typedef void (*LLW32MsgCallback)(const MSG &msg); - -class LLWindowWin32 : public LLWindow -{ -public: - /*virtual*/ void show(); - /*virtual*/ void hide(); - /*virtual*/ void close(); - /*virtual*/ bool getVisible(); - /*virtual*/ bool getMinimized(); - /*virtual*/ bool getMaximized(); - /*virtual*/ bool maximize(); - /*virtual*/ void minimize(); - /*virtual*/ void restore(); - /*virtual*/ bool getFullscreen(); - /*virtual*/ bool getPosition(LLCoordScreen *position); - /*virtual*/ bool getSize(LLCoordScreen *size); - /*virtual*/ bool getSize(LLCoordWindow *size); - /*virtual*/ bool setPosition(LLCoordScreen position); - /*virtual*/ bool setSizeImpl(LLCoordScreen size); - /*virtual*/ bool setSizeImpl(LLCoordWindow size); - /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL); - /*virtual*/ void setTitle(const std::string title); - void* createSharedContext() override; - void makeContextCurrent(void* context) override; - void destroySharedContext(void* context) override; - /*virtual*/ void toggleVSync(bool enable_vsync); - /*virtual*/ bool setCursorPosition(LLCoordWindow position); - /*virtual*/ bool getCursorPosition(LLCoordWindow *position); - /*virtual*/ bool getCursorDelta(LLCoordCommon* delta); - /*virtual*/ void showCursor(); - /*virtual*/ void hideCursor(); - /*virtual*/ void showCursorFromMouseMove(); - /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ bool isCursorHidden(); - /*virtual*/ void updateCursor(); - /*virtual*/ ECursorType getCursor() const; - /*virtual*/ void captureMouse(); - /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( bool b ); - /*virtual*/ bool isClipboardTextAvailable(); - /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); - /*virtual*/ bool copyTextToClipboard(const LLWString &src); - /*virtual*/ void flashIcon(F32 seconds); - /*virtual*/ F32 getGamma(); - /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma - /*virtual*/ void setFSAASamples(const U32 fsaa_samples); - /*virtual*/ U32 getFSAASamples(); - /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) - /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput(); - /*virtual*/ void delayInputProcessing(); - /*virtual*/ void swapBuffers(); - /*virtual*/ void restoreGLContext() {}; - - // handy coordinate space conversion routines - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); - - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } - - /*virtual*/ void setMaxVRAMMegabytes(U32 max_vram) override; - - /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ); - - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront(); - /*virtual*/ void focusClient(); - - /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, bool b); - /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); - /*virtual*/ void updateLanguageTextInputArea(); - /*virtual*/ void interruptLanguageTextInput(); - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); - - /*virtual*/ F32 getSystemUISize(); - - LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); - - static std::vector getDisplaysResolutionList(); - static std::vector getDynamicFallbackFontList(); - static void setDPIAwareness(); - - /*virtual*/ void* getDirectInput8(); - /*virtual*/ bool getInputDevices(U32 device_type_filter, - std::function osx_callback, - void* win_callback, - void* userdata); - - U32 getRawWParam() { return mRawWParam; } - -protected: - LLWindowWin32(LLWindowCallbacks* callbacks, - const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, - bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); - ~LLWindowWin32(); - - void initCursors(); - void initInputDevices(); - HCURSOR loadColorCursor(LPCTSTR name); - bool isValid(); - void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); - virtual LLSD getNativeKeyData(); - - // Changes display resolution. Returns true if successful - bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); - - // Go back to last fullscreen display resolution. - bool setFullscreenResolution(); - - // Restore the display resolution to its value before we ran the app. - bool resetDisplayResolution(); - - bool shouldPostQuit() { return mPostQuit; } - - void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); - void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); - void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); - void fillCompositionLogfont(LOGFONT *logfont); - U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); - void handleStartCompositionMessage(); - void handleCompositionMessage(U32 indexes); - bool handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); - -protected: - // - // Platform specific methods - // - - bool getClientRectInScreenSpace(RECT* rectp); - void updateJoystick( ); - - static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); - static bool CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); - - - // - // Platform specific variables - // - WCHAR *mWindowTitle; - WCHAR *mWindowClassName; - - HWND mWindowHandle = 0; // window handle - HGLRC mhRC = 0; // OpenGL rendering context - HDC mhDC = 0; // Windows Device context handle - HINSTANCE mhInstance; // handle to application instance - RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() - WPARAM mLastSizeWParam; - F32 mOverrideAspectRatio; - F32 mNativeAspectRatio; - - HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors - LLCoordWindow mCursorPosition; // mouse cursor position, should only be mutated on main thread - LLMutex mRawMouseMutex; - RAWINPUTDEVICE mRawMouse; - LLCoordWindow mLastCursorPosition; // mouse cursor position from previous frame - LLCoordCommon mRawMouseDelta; // raw mouse delta according to window thread - LLCoordCommon mMouseFrameDelta; // how much the mouse moved between the last two calls to gatherInput - - MASK mMouseMask; - - static bool sIsClassRegistered; // has the window class been registered? - - F32 mCurrentGamma; - U32 mFSAASamples; - U32 mMaxCores; // for debugging only -- maximum number of CPU cores to use, or 0 for no limit - F32 mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6) - WORD mPrevGammaRamp[3][256]; - WORD mCurrentGammaRamp[3][256]; - bool mCustomGammaSet; - - LPWSTR mIconResource; - bool mInputProcessingPaused; - - // The following variables are for Language Text Input control. - // They are all static, since one context is shared by all LLWindowWin32 - // instances. - static bool sLanguageTextInputAllowed; - static bool sWinIMEOpened; - static HKL sWinInputLocale; - static DWORD sWinIMEConversionMode; - static DWORD sWinIMESentenceMode; - static LLCoordWindow sWinIMEWindowPosition; - LLCoordGL mLanguageTextInputPointGL; - LLRect mLanguageTextInputAreaGL; - - LLPreeditor *mPreeditor; - - LLDragDropWin32* mDragDrop; - - U32 mKeyCharCode; - U32 mKeyScanCode; - U32 mKeyVirtualKey; - U32 mRawMsg; - U32 mRawWParam; - U32 mRawLParam; - - bool mMouseVanish; - - // Cached values of GetWindowRect and GetClientRect to be used by app thread - void updateWindowRect(); - RECT mRect; - RECT mClientRect; - - struct LLWindowWin32Thread; - LLWindowWin32Thread* mWindowThread = nullptr; - LLThreadSafeQueue> mFunctionQueue; - LLThreadSafeQueue> mMouseQueue; - void post(const std::function& func); - void postMouseButtonEvent(const std::function& func); - void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); - void kickWindowThread(HWND windowHandle=0); - - friend class LLWindowManager; -}; - -class LLSplashScreenWin32 : public LLSplashScreen -{ -public: - LLSplashScreenWin32(); - virtual ~LLSplashScreenWin32(); - - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); - -#if LL_WINDOWS - static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, - WPARAM w_param, LPARAM l_param); -#endif - -private: -#if LL_WINDOWS - HWND mWindow; -#endif -}; - -extern LLW32MsgCallback gAsyncMsgCallback; -extern LPWSTR gIconResource; - -static void handleMessage( const MSG& msg ); - -S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type); - -#endif //LL_LLWINDOWWIN32_H +/** + * @file llwindowwin32.h + * @brief Windows implementation of LLWindow class + * + * $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$ + */ + +#ifndef LL_LLWINDOWWIN32_H +#define LL_LLWINDOWWIN32_H + +// Limit Windows API to small and manageable set. +#include "llwin32headerslean.h" + +#include "llwindow.h" +#include "llwindowcallbacks.h" +#include "lldragdropwin32.h" +#include "llthread.h" +#include "llthreadsafequeue.h" +#include "llmutex.h" +#include "workqueue.h" + +// Hack for async host by name +#define LL_WM_HOST_RESOLVED (WM_APP + 1) +typedef void (*LLW32MsgCallback)(const MSG &msg); + +class LLWindowWin32 : public LLWindow +{ +public: + /*virtual*/ void show(); + /*virtual*/ void hide(); + /*virtual*/ void close(); + /*virtual*/ bool getVisible(); + /*virtual*/ bool getMinimized(); + /*virtual*/ bool getMaximized(); + /*virtual*/ bool maximize(); + /*virtual*/ void minimize(); + /*virtual*/ void restore(); + /*virtual*/ bool getFullscreen(); + /*virtual*/ bool getPosition(LLCoordScreen *position); + /*virtual*/ bool getSize(LLCoordScreen *size); + /*virtual*/ bool getSize(LLCoordWindow *size); + /*virtual*/ bool setPosition(LLCoordScreen position); + /*virtual*/ bool setSizeImpl(LLCoordScreen size); + /*virtual*/ bool setSizeImpl(LLCoordWindow size); + /*virtual*/ bool switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ void setTitle(const std::string title); + void* createSharedContext() override; + void makeContextCurrent(void* context) override; + void destroySharedContext(void* context) override; + /*virtual*/ void toggleVSync(bool enable_vsync); + /*virtual*/ bool setCursorPosition(LLCoordWindow position); + /*virtual*/ bool getCursorPosition(LLCoordWindow *position); + /*virtual*/ bool getCursorDelta(LLCoordCommon* delta); + /*virtual*/ void showCursor(); + /*virtual*/ void hideCursor(); + /*virtual*/ void showCursorFromMouseMove(); + /*virtual*/ void hideCursorUntilMouseMove(); + /*virtual*/ bool isCursorHidden(); + /*virtual*/ void updateCursor(); + /*virtual*/ ECursorType getCursor() const; + /*virtual*/ void captureMouse(); + /*virtual*/ void releaseMouse(); + /*virtual*/ void setMouseClipping( bool b ); + /*virtual*/ bool isClipboardTextAvailable(); + /*virtual*/ bool pasteTextFromClipboard(LLWString &dst); + /*virtual*/ bool copyTextToClipboard(const LLWString &src); + /*virtual*/ void flashIcon(F32 seconds); + /*virtual*/ F32 getGamma(); + /*virtual*/ bool setGamma(const F32 gamma); // Set the gamma + /*virtual*/ void setFSAASamples(const U32 fsaa_samples); + /*virtual*/ U32 getFSAASamples(); + /*virtual*/ bool restoreGamma(); // Restore original gamma table (before updating gamma) + /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } + /*virtual*/ void gatherInput(); + /*virtual*/ void delayInputProcessing(); + /*virtual*/ void swapBuffers(); + /*virtual*/ void restoreGLContext() {}; + + // handy coordinate space conversion routines + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordScreen *to); + /*virtual*/ bool convertCoords(LLCoordWindow from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordWindow *to); + /*virtual*/ bool convertCoords(LLCoordScreen from, LLCoordGL *to); + /*virtual*/ bool convertCoords(LLCoordGL from, LLCoordScreen *to); + + /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); + /*virtual*/ F32 getNativeAspectRatio(); + /*virtual*/ F32 getPixelAspectRatio(); + /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + + /*virtual*/ void setMaxVRAMMegabytes(U32 max_vram) override; + + /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ); + + /*virtual*/ void *getPlatformWindow(); + /*virtual*/ void bringToFront(); + /*virtual*/ void focusClient(); + + /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, bool b); + /*virtual*/ void setLanguageTextInput( const LLCoordGL & pos ); + /*virtual*/ void updateLanguageTextInputArea(); + /*virtual*/ void interruptLanguageTextInput(); + /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); + + /*virtual*/ F32 getSystemUISize(); + + LLWindowCallbacks::DragNDropResult completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ); + + static std::vector getDisplaysResolutionList(); + static std::vector getDynamicFallbackFontList(); + static void setDPIAwareness(); + + /*virtual*/ void* getDirectInput8(); + /*virtual*/ bool getInputDevices(U32 device_type_filter, + std::function osx_callback, + void* win_callback, + void* userdata); + + U32 getRawWParam() { return mRawWParam; } + +protected: + LLWindowWin32(LLWindowCallbacks* callbacks, + const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, + bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); + ~LLWindowWin32(); + + void initCursors(); + void initInputDevices(); + HCURSOR loadColorCursor(LPCTSTR name); + bool isValid(); + void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); + virtual LLSD getNativeKeyData(); + + // Changes display resolution. Returns true if successful + bool setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); + + // Go back to last fullscreen display resolution. + bool setFullscreenResolution(); + + // Restore the display resolution to its value before we ran the app. + bool resetDisplayResolution(); + + bool shouldPostQuit() { return mPostQuit; } + + void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); + void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); + void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); + void fillCompositionLogfont(LOGFONT *logfont); + U32 fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string); + void handleStartCompositionMessage(); + void handleCompositionMessage(U32 indexes); + bool handleImeRequests(WPARAM request, LPARAM param, LRESULT *result); + +protected: + // + // Platform specific methods + // + + bool getClientRectInScreenSpace(RECT* rectp); + void updateJoystick( ); + + static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); + static bool CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); + + + // + // Platform specific variables + // + WCHAR *mWindowTitle; + WCHAR *mWindowClassName; + + HWND mWindowHandle = 0; // window handle + HGLRC mhRC = 0; // OpenGL rendering context + HDC mhDC = 0; // Windows Device context handle + HINSTANCE mhInstance; // handle to application instance + RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() + WPARAM mLastSizeWParam; + F32 mOverrideAspectRatio; + F32 mNativeAspectRatio; + + HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors + LLCoordWindow mCursorPosition; // mouse cursor position, should only be mutated on main thread + LLMutex mRawMouseMutex; + RAWINPUTDEVICE mRawMouse; + LLCoordWindow mLastCursorPosition; // mouse cursor position from previous frame + LLCoordCommon mRawMouseDelta; // raw mouse delta according to window thread + LLCoordCommon mMouseFrameDelta; // how much the mouse moved between the last two calls to gatherInput + + MASK mMouseMask; + + static bool sIsClassRegistered; // has the window class been registered? + + F32 mCurrentGamma; + U32 mFSAASamples; + U32 mMaxCores; // for debugging only -- maximum number of CPU cores to use, or 0 for no limit + F32 mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6) + WORD mPrevGammaRamp[3][256]; + WORD mCurrentGammaRamp[3][256]; + bool mCustomGammaSet; + + LPWSTR mIconResource; + bool mInputProcessingPaused; + + // The following variables are for Language Text Input control. + // They are all static, since one context is shared by all LLWindowWin32 + // instances. + static bool sLanguageTextInputAllowed; + static bool sWinIMEOpened; + static HKL sWinInputLocale; + static DWORD sWinIMEConversionMode; + static DWORD sWinIMESentenceMode; + static LLCoordWindow sWinIMEWindowPosition; + LLCoordGL mLanguageTextInputPointGL; + LLRect mLanguageTextInputAreaGL; + + LLPreeditor *mPreeditor; + + LLDragDropWin32* mDragDrop; + + U32 mKeyCharCode; + U32 mKeyScanCode; + U32 mKeyVirtualKey; + U32 mRawMsg; + U32 mRawWParam; + U32 mRawLParam; + + bool mMouseVanish; + + // Cached values of GetWindowRect and GetClientRect to be used by app thread + void updateWindowRect(); + RECT mRect; + RECT mClientRect; + + struct LLWindowWin32Thread; + LLWindowWin32Thread* mWindowThread = nullptr; + LLThreadSafeQueue> mFunctionQueue; + LLThreadSafeQueue> mMouseQueue; + void post(const std::function& func); + void postMouseButtonEvent(const std::function& func); + void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); + void kickWindowThread(HWND windowHandle=0); + + friend class LLWindowManager; +}; + +class LLSplashScreenWin32 : public LLSplashScreen +{ +public: + LLSplashScreenWin32(); + virtual ~LLSplashScreenWin32(); + + /*virtual*/ void showImpl(); + /*virtual*/ void updateImpl(const std::string& mesg); + /*virtual*/ void hideImpl(); + +#if LL_WINDOWS + static LRESULT CALLBACK windowProc(HWND h_wnd, UINT u_msg, + WPARAM w_param, LPARAM l_param); +#endif + +private: +#if LL_WINDOWS + HWND mWindow; +#endif +}; + +extern LLW32MsgCallback gAsyncMsgCallback; +extern LPWSTR gIconResource; + +static void handleMessage( const MSG& msg ); + +S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type); + +#endif //LL_LLWINDOWWIN32_H -- cgit v1.2.3 From b42f9d836b4c0f7fbd4bdae1734021e2a09fdbe8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Sat, 1 Jun 2024 15:49:26 +0200 Subject: Re-enable a lot of compiler warnings for MSVC and address the C4267 "possible loss of precision" warnings --- indra/llwindow/llwindowwin32.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 7ea53816cf..5326ed1d76 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -3634,13 +3634,13 @@ void LLSplashScreenWin32::updateImpl(const std::string& mesg) { if (!mWindow) return; - int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), mesg.length(), NULL, 0); + int output_str_len = MultiByteToWideChar(CP_UTF8, 0, mesg.c_str(), static_cast(mesg.length()), NULL, 0); if( output_str_len>1024 ) return; WCHAR w_mesg[1025];//big enought to keep null terminatos - MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), mesg.length(), w_mesg, output_str_len); + MultiByteToWideChar (CP_UTF8, 0, mesg.c_str(), static_cast(mesg.length()), w_mesg, output_str_len); //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858 w_mesg[output_str_len] = 0; @@ -4034,14 +4034,14 @@ U32 LLWindowWin32::fillReconvertString(const LLWString &text, S32 focus, S32 focus_length, RECONVERTSTRING *reconvert_string) { const llutf16string text_utf16 = wstring_to_utf16str(text); - const DWORD required_size = sizeof(RECONVERTSTRING) + (text_utf16.length() + 1) * sizeof(WCHAR); + const DWORD required_size = sizeof(RECONVERTSTRING) + (static_cast(text_utf16.length()) + 1) * sizeof(WCHAR); if (reconvert_string && reconvert_string->dwSize >= required_size) { const DWORD focus_utf16_at = wstring_utf16_length(text, 0, focus); const DWORD focus_utf16_length = wstring_utf16_length(text, focus, focus_length); reconvert_string->dwVersion = 0; - reconvert_string->dwStrLen = text_utf16.length(); + reconvert_string->dwStrLen = static_cast(text_utf16.length()); reconvert_string->dwStrOffset = sizeof(RECONVERTSTRING); reconvert_string->dwCompStrLen = focus_utf16_length; reconvert_string->dwCompStrOffset = focus_utf16_at * sizeof(WCHAR); @@ -4204,7 +4204,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) } } - S32 caret_position = preedit_string.length(); + S32 caret_position = static_cast(preedit_string.length()); if (indexes & GCS_CURSORPOS) { const S32 caret_position_utf16 = LLWinImm::getCompositionString(himc, GCS_CURSORPOS, NULL, 0); @@ -4250,7 +4250,7 @@ void LLWindowWin32::handleCompositionMessage(const U32 indexes) { if (preedit_segment_lengths.size() == 0) { - preedit_segment_lengths.assign(1, preedit_string.length()); + preedit_segment_lengths.assign(1, static_cast(preedit_string.length())); } if (preedit_standouts.size() == 0) { -- cgit v1.2.3 From 08c483c2693153f49cfacb8cf517cf6067f53205 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 30 May 2024 13:46:22 +0300 Subject: viewer#1583 [Win] Viewer fails to detect more than 4Gb of video memory --- indra/llwindow/llwindowwin32.cpp | 163 ++++++++++----------------------------- 1 file changed, 40 insertions(+), 123 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 7ea53816cf..92702b3ffa 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -361,14 +361,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool mGLReady = true; } - // initialzie DXGI adapter (for querying available VRAM) - void initDX(); - - // initialize D3D (if DXGI cannot be used) - void initD3D(); - - //clean up DXGI/D3D resources - void cleanupDX(); + // Use DXGI to check memory (because WMI doesn't report more than 4Gb) + void checkDXMem(); /// called by main thread to post work to this window thread template @@ -417,12 +411,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; + bool mGotGLBuffer = false; U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) - - IDXGIAdapter3* mDXGIAdapter = nullptr; - LPDIRECT3D9 mD3D = nullptr; - LPDIRECT3DDEVICE9 mD3DDevice = nullptr; }; @@ -4631,39 +4622,55 @@ private: std::string mPrev; }; -// Print hardware debug info about available graphics adapters in ordinal order -void debugEnumerateGraphicsAdapters() +void LLWindowWin32::LLWindowWin32Thread::checkDXMem() { - LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL; + if (!mGLReady || mGotGLBuffer) { return; } + + IDXGIFactory4* p_factory = nullptr; + + HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory); - IDXGIFactory1* factory; - HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory); - if (FAILED(res) || !factory) + if (FAILED(res)) { LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; } else { + IDXGIAdapter3* p_dxgi_adapter = nullptr; UINT graphics_adapter_index = 0; - IDXGIAdapter3* dxgi_adapter; while (true) { - res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&dxgi_adapter)); + res = p_factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&p_dxgi_adapter)); if (FAILED(res)) { if (graphics_adapter_index == 0) { LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; } - else - { - LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL; - } } else { + if (graphics_adapter_index == 0) // Should it check largest one isntead of first? + { + DXGI_QUERY_VIDEO_MEMORY_INFO info; + p_dxgi_adapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info); + + // Alternatively use GetDesc from below to get adapter's memory + UINT64 budget_mb = info.Budget / (1024 * 1024); + if (gGLManager.mVRAM < (S32)budget_mb) + { + gGLManager.mVRAM = (S32)budget_mb; + LL_INFOS("RenderInit") << "New VRAM Budget (DX9): " << gGLManager.mVRAM << " MB" << LL_ENDL; + } + else + { + LL_INFOS("RenderInit") << "VRAM Budget (DX9): " << budget_mb + << " MB, current (WMI): " << gGLManager.mVRAM << " MB" << LL_ENDL; + } + } + DXGI_ADAPTER_DESC desc; - dxgi_adapter->GetDesc(&desc); + p_dxgi_adapter->GetDesc(&desc); std::wstring description_w((wchar_t*)desc.Description); std::string description(description_w.begin(), description_w.end()); LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", " @@ -4676,10 +4683,10 @@ void debugEnumerateGraphicsAdapters() << "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL; } - if (dxgi_adapter) + if (p_dxgi_adapter) { - dxgi_adapter->Release(); - dxgi_adapter = NULL; + p_dxgi_adapter->Release(); + p_dxgi_adapter = NULL; } else { @@ -4690,95 +4697,12 @@ void debugEnumerateGraphicsAdapters() } } - if (factory) + if (p_factory) { - factory->Release(); + p_factory->Release(); } -} - -void LLWindowWin32::LLWindowWin32Thread::initDX() -{ - if (!mGLReady) { return; } - - if (mDXGIAdapter == NULL) - { - debugEnumerateGraphicsAdapters(); - IDXGIFactory4* pFactory = nullptr; - - HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory); - - if (FAILED(res)) - { - LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - res = pFactory->EnumAdapters(0, reinterpret_cast(&mDXGIAdapter)); - if (FAILED(res)) - { - LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - LL_INFOS() << "EnumAdapters success" << LL_ENDL; - } - } - - if (pFactory) - { - pFactory->Release(); - } - } -} - -void LLWindowWin32::LLWindowWin32Thread::initD3D() -{ - if (!mGLReady) { return; } - - if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) - { - mD3D = Direct3DCreate9(D3D_SDK_VERSION); - - D3DPRESENT_PARAMETERS d3dpp; - - ZeroMemory(&d3dpp, sizeof(d3dpp)); - d3dpp.Windowed = TRUE; - d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - - HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); - - if (FAILED(res)) - { - LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL; - } - else - { - LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL; - } - } -} - -void LLWindowWin32::LLWindowWin32Thread::cleanupDX() -{ - //clean up DXGI/D3D resources - if (mDXGIAdapter) - { - mDXGIAdapter->Release(); - mDXGIAdapter = nullptr; - } - - if (mD3DDevice) - { - mD3DDevice->Release(); - mD3DDevice = nullptr; - } - - if (mD3D) - { - mD3D->Release(); - mD3D = nullptr; - } + mGotGLBuffer = true; } void LLWindowWin32::LLWindowWin32Thread::run() @@ -4798,15 +4722,11 @@ void LLWindowWin32::LLWindowWin32Thread::run() { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - // lazily call initD3D inside this loop to catch when mGLReady has been set to true - initDX(); + // Check memory budget using DirectX + checkDXMem(); if (mWindowHandleThrd != 0) { - // lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true - // *TODO: Shutdown if this fails when mWindowHandle exists - initD3D(); - MSG msg; BOOL status; if (mhDCThrd == 0) @@ -4847,8 +4767,6 @@ void LLWindowWin32::LLWindowWin32Thread::run() } #endif } - - cleanupDX(); } void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() @@ -4948,7 +4866,6 @@ void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() // very unsafe TerminateThread(pair.second.native_handle(), 0); pair.second.detach(); - cleanupDX(); } } LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; -- cgit v1.2.3 From c0fad3028fd55c2067ce6a0ae4382cffe1014284 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 16:42:43 +0200 Subject: Re-enable compiler warnings C4018, C4100, C4231 and C4506 --- indra/llwindow/lldxhardware.cpp | 2 +- indra/llwindow/lldxhardware.h | 2 +- indra/llwindow/llwindowwin32.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index 0830dc9528..cba820fcab 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -216,7 +216,7 @@ HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) } //static -S32 LLDXHardware::getMBVideoMemoryViaWMI() +U32 LLDXHardware::getMBVideoMemoryViaWMI() { DWORD vram = 0; if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram))) diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index aaefc6ae8c..2b879e021c 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -104,7 +104,7 @@ public: // Will get memory of best GPU in MB, return memory on sucsess, 0 on failure // Note: WMI is not accurate in some cases - static S32 getMBVideoMemoryViaWMI(); + static U32 getMBVideoMemoryViaWMI(); // Find a particular device that matches the following specs. // Empty strings indicate that you don't care. diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index c57258fbce..3d349b2080 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -446,7 +446,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mMaxCores = llmin(mMaxCores, (U32) 64); DWORD_PTR mask = 0; - for (int i = 0; i < mMaxCores; ++i) + for (U32 i = 0; i < mMaxCores; ++i) { mask |= ((DWORD_PTR) 1) << i; } -- cgit v1.2.3 From 9f6b8484dfb7dfa981d8a8ac3693d3f68e32bc12 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 10 Jun 2024 23:43:50 +0200 Subject: Re-enable compiler warnings C4127, C4512 & C4706 Disable particular CRT and WinSock API warnings for functions Microsoft considers unsafe/deprecated --- indra/llwindow/lldxhardware.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index cba820fcab..d916d95713 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -454,10 +454,10 @@ void get_wstring(IDxDiagContainer* containerp, WCHAR* wszPropName, WCHAR* wszPro switch( var.vt ) { case VT_UI4: - swprintf( wszPropValue, L"%d", var.ulVal ); /* Flawfinder: ignore */ + swprintf( wszPropValue, outputSize, L"%d", var.ulVal ); /* Flawfinder: ignore */ break; case VT_I4: - swprintf( wszPropValue, L"%d", var.lVal ); /* Flawfinder: ignore */ + swprintf( wszPropValue, outputSize, L"%d", var.lVal ); /* Flawfinder: ignore */ break; case VT_BOOL: wcscpy( wszPropValue, (var.boolVal) ? L"true" : L"false" ); /* Flawfinder: ignore */ -- cgit v1.2.3 From ea83746cdab7225b070d0244bafbabdc7ac9eea3 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Mon, 17 Jun 2024 15:42:06 +0200 Subject: Remove orphaned VRAM handling code --- indra/llwindow/llwindow.cpp | 5 ++--- indra/llwindow/llwindow.h | 19 +++++++------------ indra/llwindow/llwindowheadless.h | 2 -- indra/llwindow/llwindowmacosx.cpp | 3 +-- indra/llwindow/llwindowmacosx.h | 5 +---- indra/llwindow/llwindowwin32.cpp | 14 -------------- indra/llwindow/llwindowwin32.h | 10 +--------- 7 files changed, 12 insertions(+), 46 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 964b173e74..56c393be0f 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -409,7 +409,6 @@ LLWindow* LLWindowManager::createWindow( bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, - U32 max_vram, F32 max_gl_version) { LLWindow* new_window; @@ -427,11 +426,11 @@ LLWindow* LLWindowManager::createWindow( #elif LL_WINDOWS new_window = new LLWindowWin32(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_vram, max_gl_version); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_gl_version); #elif LL_DARWIN new_window = new LLWindowMacOSX(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_vram); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); #endif } else diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index b7bb426654..5e06e665f3 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -164,8 +164,6 @@ public: virtual F32 getPixelAspectRatio() = 0; virtual void setNativeAspectRatio(F32 aspect) = 0; - virtual void setMaxVRAMMegabytes(U32 max_vram) = 0; - virtual void beforeDialog() {}; // prepare to put up an OS dialog (if special measures are required, such as in fullscreen mode) virtual void afterDialog() {}; // undo whatever was done in beforeDialog() @@ -286,14 +284,14 @@ protected: // Platform-neutral for accessing the platform specific message box S32 OSMessageBox(const std::string& text, const std::string& caption, U32 type); -const U32 OSMB_OK = 0; -const U32 OSMB_OKCANCEL = 1; -const U32 OSMB_YESNO = 2; +constexpr U32 OSMB_OK = 0; +constexpr U32 OSMB_OKCANCEL = 1; +constexpr U32 OSMB_YESNO = 2; -const S32 OSBTN_YES = 0; -const S32 OSBTN_NO = 1; -const S32 OSBTN_OK = 2; -const S32 OSBTN_CANCEL = 3; +constexpr S32 OSBTN_YES = 0; +constexpr S32 OSBTN_NO = 1; +constexpr S32 OSBTN_OK = 2; +constexpr S32 OSBTN_CANCEL = 3; // // LLWindowManager @@ -313,7 +311,6 @@ public: bool ignore_pixel_depth = false, U32 fsaa_samples = 0, U32 max_cores = 0, - U32 max_vram = 0, F32 max_gl_version = 4.6f); static bool destroyWindow(LLWindow* window); static bool isWindowValid(LLWindow *window); @@ -329,6 +326,4 @@ extern const S32 gURLProtocolWhitelistCount; extern const std::string gURLProtocolWhitelist[]; //extern const std::string gURLProtocolWhitelistHandler[]; -void simpleEscapeString ( std::string& stringIn ); - #endif // _LL_window_h_ diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index 32c12b0d47..5696b69a59 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -101,8 +101,6 @@ public: /*virtual*/ F32 getPixelAspectRatio() override { return 1.0f; } /*virtual*/ void setNativeAspectRatio(F32 ratio) override {} - void setMaxVRAMMegabytes(U32 max_vram) override {} - /*virtual*/ void *getPlatformWindow() override { return 0; } /*virtual*/ void bringToFront() override {} diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index cd00f4d33c..80001b14ee 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -122,8 +122,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_vram) + U32 fsaa_samples) : LLWindow(NULL, fullscreen, flags) { // *HACK: During window construction we get lots of OS events for window diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index 3be89c255a..f5b6441746 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -100,8 +100,6 @@ public: F32 getPixelAspectRatio() override; void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - virtual void setMaxVRAMMegabytes(U32 max_vram) override {} - void beforeDialog() override; void afterDialog() override; @@ -154,8 +152,7 @@ protected: const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, bool ignore_pixel_depth, - U32 fsaa_samples, - U32 max_vram); + U32 fsaa_samples); ~LLWindowMacOSX(); void initCursors(); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3d349b2080..f0f7e03691 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -404,7 +404,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool using FuncType = std::function; // call GetMessage() and pull enqueue messages for later processing - void gatherInput(); HWND mWindowHandleThrd = NULL; HDC mhDCThrd = 0; @@ -412,8 +411,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; bool mGotGLBuffer = false; - - U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage) }; @@ -425,7 +422,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, - U32 max_vram, F32 max_gl_version) : LLWindow(callbacks, fullscreen, flags), @@ -434,7 +430,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, { sMainThreadId = LLThread::currentID(); mWindowThread = new LLWindowWin32Thread(); - mWindowThread->mMaxVRAM = max_vram; //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways LoadLibrary(L"opengl32.dll"); @@ -4545,15 +4540,6 @@ std::vector LLWindowWin32::getDynamicFallbackFontList() // Fonts previously in getFontListSans() have moved to fonts.xml. return std::vector(); } - -void LLWindowWin32::setMaxVRAMMegabytes(U32 max_vram) -{ - if (mWindowThread) - { - mWindowThread->mMaxVRAM = max_vram; - } -} - #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 82541ace6e..287402faa0 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -108,8 +108,6 @@ public: /*virtual*/ F32 getPixelAspectRatio(); /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } - /*virtual*/ void setMaxVRAMMegabytes(U32 max_vram) override; - /*virtual*/ bool dialogColorPicker(F32 *r, F32 *g, F32 *b ); /*virtual*/ void *getPlatformWindow(); @@ -142,11 +140,10 @@ protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, bool fullscreen, bool clearBg, bool enable_vsync, bool use_gl, - bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version); + bool ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, F32 max_gl_version); ~LLWindowWin32(); void initCursors(); - void initInputDevices(); HCURSOR loadColorCursor(LPCTSTR name); bool isValid(); void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); @@ -163,7 +160,6 @@ protected: bool shouldPostQuit() { return mPostQuit; } - void fillCompositionForm(const LLRect& bounds, COMPOSITIONFORM *form); void fillCandidateForm(const LLCoordGL& caret, const LLRect& bounds, CANDIDATEFORM *form); void fillCharPosition(const LLCoordGL& caret, const LLRect& bounds, const LLRect& control, IMECHARPOSITION *char_position); void fillCompositionLogfont(LOGFONT *logfont); @@ -178,10 +174,8 @@ protected: // bool getClientRectInScreenSpace(RECT* rectp); - void updateJoystick( ); static LRESULT CALLBACK mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param); - static bool CALLBACK enumChildWindows(HWND h_wnd, LPARAM l_param); // @@ -288,8 +282,6 @@ private: extern LLW32MsgCallback gAsyncMsgCallback; extern LPWSTR gIconResource; -static void handleMessage( const MSG& msg ); - S32 OSMessageBoxWin32(const std::string& text, const std::string& caption, U32 type); #endif //LL_LLWINDOWWIN32_H -- cgit v1.2.3