diff options
| author | Nicky Dasmijn <nicky.dasmijn@posteo.nl> | 2024-04-05 19:25:02 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-05 20:25:02 +0300 | 
| commit | 57d423745fd1d3d0ea6a0c69b869a20c27e27fc5 (patch) | |
| tree | f590e086983c7277e4b05fcd54c3eebf6b12f43a /indra/llwindow | |
| parent | cc8d71c18c124138e76e85e663498d2ee9776b3c (diff) | |
Linux viewer (ReleaseOS) resurrection (#1099)
Co-authored-by: AiraYumi <aira.youme@airanyumi.net>
Diffstat (limited to 'indra/llwindow')
| -rw-r--r-- | indra/llwindow/CMakeLists.txt | 8 | ||||
| -rw-r--r-- | indra/llwindow/llkeyboard.cpp | 40 | ||||
| -rw-r--r-- | indra/llwindow/llkeyboard.h | 36 | ||||
| -rw-r--r-- | indra/llwindow/llkeyboardheadless.cpp | 4 | ||||
| -rw-r--r-- | indra/llwindow/llkeyboardheadless.h | 9 | ||||
| -rw-r--r-- | indra/llwindow/llkeyboardsdl.cpp | 837 | ||||
| -rw-r--r-- | indra/llwindow/llkeyboardsdl.h | 50 | ||||
| -rw-r--r-- | indra/llwindow/llwindowsdl.cpp | 3864 | ||||
| -rw-r--r-- | indra/llwindow/llwindowsdl.h | 433 | 
9 files changed, 2828 insertions, 2453 deletions
| diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt index 7b1430c67c..9ebd6ef0b0 100644 --- a/indra/llwindow/CMakeLists.txt +++ b/indra/llwindow/CMakeLists.txt @@ -59,11 +59,12 @@ set(llwindow_LINK_LIBRARIES          ll::uilibraries          ll::SDL          ) +  # Libraries on which this library depends, needed for Linux builds  # Sort by high-level to low-level  if (LINUX) -  list(APPEND viewer_SOURCE_FILES  -       llkeyboardsdl.cpp  +  list(APPEND viewer_SOURCE_FILES +       llkeyboardsdl.cpp         llwindowsdl.cpp         )    list(APPEND viewer_HEADER_FILES @@ -83,7 +84,6 @@ if (LINUX)          fontconfig          # For FCInit and other FC* functions.          )    endif (BUILD_HEADLESS) -  endif (LINUX)  if (DARWIN) @@ -179,7 +179,7 @@ endif (SDL_FOUND)    target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES})    target_include_directories(llwindow INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) -   +  if (DARWIN)    include(CMakeFindFrameworks)    find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llwindow/llkeyboard.cpp b/indra/llwindow/llkeyboard.cpp index 34720ff64e..f55e0a0819 100644 --- a/indra/llwindow/llkeyboard.cpp +++ b/indra/llwindow/llkeyboard.cpp @@ -1,25 +1,25 @@ -/**  +/**   * @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$   */ @@ -41,7 +41,6 @@ std::map<KEY,std::string> LLKeyboard::sKeysToNames;  std::map<std::string,KEY> LLKeyboard::sNamesToKeys;  LLKeyStringTranslatorFunc*	LLKeyboard::mStringTranslator = NULL;	// Used for l10n + PC/Mac/Linux accelerator labeling -  //  // Class Implementation  // @@ -122,7 +121,7 @@ LLKeyboard::LLKeyboard() : mCallbacks(NULL)  	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" ); @@ -195,12 +194,11 @@ void LLKeyboard::resetKeys()  } -BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key) +BOOL LLKeyboard::translateKey(const NATIVE_KEY_TYPE os_key, KEY *out_key)  { -	std::map<U16, KEY>::iterator iter;  	// Only translate keys in the map, ignore all other keys for now -	iter = mTranslateKeyMap.find(os_key); +	auto iter = mTranslateKeyMap.find(os_key);  	if (iter == mTranslateKeyMap.end())  	{  		//LL_WARNS() << "Unknown virtual key " << os_key << LL_ENDL; @@ -214,11 +212,9 @@ BOOL LLKeyboard::translateKey(const U16 os_key, KEY *out_key)  	}  } - -U16 LLKeyboard::inverseTranslateKey(const KEY translated_key) +LLKeyboard::NATIVE_KEY_TYPE LLKeyboard::inverseTranslateKey(const KEY translated_key)  { -	std::map<KEY, U16>::iterator iter; -	iter = mInvTranslateKeyMap.find(translated_key); +	auto iter = mInvTranslateKeyMap.find(translated_key);  	if (iter == mInvTranslateKeyMap.end())  	{  		return 0; @@ -250,7 +246,7 @@ BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask  		repeated = TRUE;  		mKeyRepeated[translated_key] = TRUE;  	} -	 +  	mKeyDown[translated_key] = TRUE;  	mCurTranslatedKey = (KEY)translated_key;  	handled = mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask, repeated); @@ -259,12 +255,12 @@ BOOL LLKeyboard::handleTranslatedKeyDown(KEY translated_key, U32 translated_mask  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 @@ -273,7 +269,7 @@ BOOL LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask)  		mKeyUp[translated_key] = TRUE;  		handled = mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask);  	} -	 +  	LL_DEBUGS("UserInput") << "keyup -" << translated_key << "-" << LL_ENDL;  	return handled; @@ -451,13 +447,13 @@ std::string LLKeyboard::stringFromAccelerator(MASK accel_mask)  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) && @@ -468,7 +464,7 @@ std::string LLKeyboard::stringFromAccelerator( MASK accel_mask, KEY key )  	std::string keystr = stringFromKey( key );  	res.append( keystr ); -	 +  	return res;  } @@ -529,7 +525,7 @@ BOOL LLKeyboard::maskFromString(const std::string& str, MASK *mask)  		*mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT;  		return TRUE;  	} -	else  +	else  	{  		return FALSE;  	} diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index dad150e3c1..2c96df3b5b 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -1,25 +1,25 @@ -/**  +/**   * @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$   */ @@ -34,7 +34,7 @@  #include "lltimer.h"  #include "indra_constants.h" -enum EKeystate  +enum EKeystate  {  	KEYSTATE_DOWN,  	KEYSTATE_LEVEL, @@ -43,7 +43,7 @@ enum EKeystate  typedef boost::function<bool(EKeystate keystate)> LLKeyFunc;  typedef std::string (LLKeyStringTranslatorFunc)(const char *label); -	 +  enum EKeyboardInsertMode  {  	LL_KIM_INSERT, @@ -55,6 +55,11 @@ class LLWindowCallbacks;  class LLKeyboard  {  public: +#ifndef LL_SDL +    typedef U16 NATIVE_KEY_TYPE; +#else +    typedef U32 NATIVE_KEY_TYPE; +#endif  	LLKeyboard();  	virtual ~LLKeyboard(); @@ -67,15 +72,14 @@ public:  	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			translateKey(const NATIVE_KEY_TYPE os_key, KEY *translated_key); +    NATIVE_KEY_TYPE		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 NATIVE_KEY_TYPE key, MASK mask) = 0; +	virtual BOOL	handleKeyDown(const NATIVE_KEY_TYPE 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 OS X.  	virtual void	handleModifier(MASK mask) = 0; @@ -106,13 +110,13 @@ public:  	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<U16, KEY>	mTranslateKeyMap;		// Map of translations from OS keys to Linden KEYs -	std::map<KEY, U16>	mInvTranslateKeyMap;	// Map of translations from Linden KEYs to OS keys +	std::map<NATIVE_KEY_TYPE, KEY>	mTranslateKeyMap;		// Map of translations from OS keys to Linden KEYs +	std::map<KEY, NATIVE_KEY_TYPE>	mInvTranslateKeyMap;	// Map of translations from Linden KEYs to OS keys  	LLWindowCallbacks *mCallbacks;  	LLTimer			mKeyLevelTimer[KEY_COUNT];	// Time since level was set @@ -125,7 +129,7 @@ protected:  	KEY				mCurScanKey;		// Used during the scanKeyboard()  	static LLKeyStringTranslatorFunc*	mStringTranslator;	// Used for l10n + PC/Mac/Linux accelerator labeling -	 +  	EKeyboardInsertMode mInsertMode;  	static std::map<KEY,std::string> sKeysToNames; diff --git a/indra/llwindow/llkeyboardheadless.cpp b/indra/llwindow/llkeyboardheadless.cpp index a1b6b294e0..0785410357 100644 --- a/indra/llwindow/llkeyboardheadless.cpp +++ b/indra/llwindow/llkeyboardheadless.cpp @@ -35,12 +35,8 @@ 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; } diff --git a/indra/llwindow/llkeyboardheadless.h b/indra/llwindow/llkeyboardheadless.h index 8ed28ace90..79c276fdbb 100644 --- a/indra/llwindow/llkeyboardheadless.h +++ b/indra/llwindow/llkeyboardheadless.h @@ -35,8 +35,13 @@ public:  	LLKeyboardHeadless();  	/*virtual*/ ~LLKeyboardHeadless() {}; -	/*virtual*/ BOOL	handleKeyUp(const U16 key, MASK mask); -	/*virtual*/ BOOL	handleKeyDown(const U16 key, MASK mask); +#ifndef LL_SDL +	/*virtual*/ BOOL	handleKeyUp(const U16 key, MASK mask) { return FALSE; } +	/*virtual*/ BOOL	handleKeyDown(const U16 key, MASK mask) { return FALSE; } +#else +    /*virtual*/ BOOL	handleKeyUp(const U32 key, MASK mask) { return FALSE; } +    /*virtual*/ BOOL	handleKeyDown(const U32 key, MASK mask) { return FALSE; } +#endif  	/*virtual*/ void	resetMaskKeys();  	/*virtual*/ MASK	currentMask(BOOL for_mouse_event);  	/*virtual*/ void	scanKeyboard(); diff --git a/indra/llwindow/llkeyboardsdl.cpp b/indra/llwindow/llkeyboardsdl.cpp index 7c9aa1d340..b29b832011 100644 --- a/indra/llwindow/llkeyboardsdl.cpp +++ b/indra/llwindow/llkeyboardsdl.cpp @@ -1,324 +1,661 @@ -/**  - * @file llkeyboardsdl.cpp - * @brief Handler for assignable key bindings +/** + * @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 "llkeyboardsdl.h"  #include "llwindowcallbacks.h" -#include "SDL/SDL.h" +#include "SDL2/SDL.h" +#include "SDL2/SDL_keycode.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<U16, KEY>::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; -	} +    // 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... + +    // <FS:ND> Looks like we need to map those despite of SDL_TEXTINPUT handling most of this, but without +    // the translation lower->upper here accelerators will not work. + +    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] = ' '; 	// <FS:ND/> Those are handled by SDL2 via text input, do not map them +    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_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]   = '='; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_COMMA]  = ','; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_MINUS]  = '-'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_PERIOD] = '.'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_BACKQUOTE] = '`'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_SLASH] = KEY_DIVIDE; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_SEMICOLON] = ';'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_LEFTBRACKET] = '['; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_BACKSLASH] = '\\'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_RIGHTBRACKET] = ']'; // <FS:ND/> Those are handled by SDL2 via text input, do not map them +    mTranslateKeyMap[SDLK_QUOTE] = '\''; // <FS:ND/> Those are handled by SDL2 via text input, do not map them + +    // Build inverse map +    for (auto iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) +    { +        mInvTranslateKeyMap[iter->second] = iter->first; +    } + +    // numpad map +    mTranslateNumpadMap[SDLK_KP_0] = KEY_PAD_INS; +    mTranslateNumpadMap[SDLK_KP_1] = KEY_PAD_END; +    mTranslateNumpadMap[SDLK_KP_2] = KEY_PAD_DOWN; +    mTranslateNumpadMap[SDLK_KP_3] = KEY_PAD_PGDN; +    mTranslateNumpadMap[SDLK_KP_4] = KEY_PAD_LEFT; +    mTranslateNumpadMap[SDLK_KP_5] = KEY_PAD_CENTER; +    mTranslateNumpadMap[SDLK_KP_6] = KEY_PAD_RIGHT; +    mTranslateNumpadMap[SDLK_KP_7] = KEY_PAD_HOME; +    mTranslateNumpadMap[SDLK_KP_8] = KEY_PAD_UP; +    mTranslateNumpadMap[SDLK_KP_9] = KEY_PAD_PGUP; +    mTranslateNumpadMap[SDLK_KP_PERIOD] = KEY_PAD_DEL; + +    // build inverse numpad map +    for (auto 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; -	} +    SDL_Keymod 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; +    // translate the mask +    MASK out_mask = MASK_NONE; -	if(mask & KMOD_SHIFT) -	{ -		out_mask |= MASK_SHIFT; -	} +    if(mask & KMOD_SHIFT) +    { +        out_mask |= MASK_SHIFT; +    } -	if(mask & KMOD_CTRL) -	{ -		out_mask |= MASK_CONTROL; -	} +    if(mask & KMOD_CTRL) +    { +        out_mask |= MASK_CONTROL; +    } -	if(mask & KMOD_ALT) -	{ -		out_mask |= MASK_ALT; -	} +    if(mask & KMOD_ALT) +    { +        out_mask |= MASK_ALT; +    } -	return out_mask; +    return out_mask;  } -static U16 adjustNativekeyFromUnhandledMask(const U16 key, const U32 mask) +static U32 adjustNativekeyFromUnhandledMask(const U32 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; +    // SDL doesn't automatically adjust the keysym according to +    // whether NUMLOCK is engaged, so we massage the keysym manually. +    U32 rtn = key; +    if (!(mask & KMOD_NUM)) +    { +        switch (key) +        { +            case SDLK_KP_PERIOD: rtn = SDLK_DELETE; break; +            case SDLK_KP_0: rtn = SDLK_INSERT; break; +            case SDLK_KP_1: rtn = SDLK_END; break; +            case SDLK_KP_2: rtn = SDLK_DOWN; break; +            case SDLK_KP_3: rtn = SDLK_PAGEDOWN; break; +            case SDLK_KP_4: rtn = SDLK_LEFT; break; +            case SDLK_KP_6: rtn = SDLK_RIGHT; break; +            case SDLK_KP_7: rtn = SDLK_HOME; break; +            case SDLK_KP_8: rtn = SDLK_UP; break; +            case SDLK_KP_9: rtn = SDLK_PAGEUP; break; +        } +    } +    return rtn;  } -BOOL LLKeyboardSDL::handleKeyDown(const U16 key, const U32 mask) +BOOL LLKeyboardSDL::handleKeyDown(const U32 key, const U32 mask)  { -	U16     adjusted_nativekey; -	KEY	translated_key = 0; -	U32	translated_mask = MASK_NONE; -	BOOL	handled = FALSE; +    U32 adjusted_nativekey; +    KEY	translated_key = 0; +    U32	translated_mask = MASK_NONE; +    BOOL handled = FALSE; + +    adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); -	adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); +    translated_mask = updateModifiers(mask); -	translated_mask = updateModifiers(mask); -	 -	if(translateNumpadKey(adjusted_nativekey, &translated_key)) -	{ -		handled = handleTranslatedKeyDown(translated_key, translated_mask); -	} +    if(translateNumpadKey(adjusted_nativekey, &translated_key)) +    { +        handled = handleTranslatedKeyDown(translated_key, translated_mask); +    } -	return handled; +    return handled;  } -BOOL LLKeyboardSDL::handleKeyUp(const U16 key, const U32 mask) +BOOL LLKeyboardSDL::handleKeyUp(const U32 key, const U32 mask)  { -	U16     adjusted_nativekey; -	KEY	translated_key = 0; -	U32	translated_mask = MASK_NONE; -	BOOL	handled = FALSE; +    U32 adjusted_nativekey; +    KEY	translated_key = 0; +    U32	translated_mask = MASK_NONE; +    BOOL handled = FALSE; -	adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); +    adjusted_nativekey = adjustNativekeyFromUnhandledMask(key, mask); -	translated_mask = updateModifiers(mask); +    translated_mask = updateModifiers(mask); -	if(translateNumpadKey(adjusted_nativekey, &translated_key)) -	{ -		handled = handleTranslatedKeyUp(translated_key, translated_mask); -	} +    if(translateNumpadKey(adjusted_nativekey, &translated_key)) +    { +        handled = handleTranslatedKeyUp(translated_key, translated_mask); +    } -	return handled; +    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; +    MASK result = MASK_NONE; +    SDL_Keymod 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_GUI) +            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]++; -		} -	} +    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) + +BOOL LLKeyboardSDL::translateNumpadKey( const U32 os_key, KEY *translated_key)  { -	return translateKey(os_key, translated_key);	 +    return translateKey(os_key, translated_key);  }  U16 LLKeyboardSDL::inverseTranslateNumpadKey(const KEY translated_key)  { -	return inverseTranslateKey(translated_key); +    return inverseTranslateKey(translated_key);  } -#endif - +enum class WindowsVK : U32 +{ +    VK_UNKNOWN = 0, +    VK_CANCEL = 0x03, +    VK_BACK = 0x08, +    VK_TAB = 0x09, +    VK_CLEAR = 0x0C, +    VK_RETURN = 0x0D, +    VK_SHIFT = 0x10, +    VK_CONTROL = 0x11, +    VK_MENU = 0x12, +    VK_PAUSE = 0x13, +    VK_CAPITAL = 0x14, +    VK_KANA = 0x15, +    VK_HANGUL = 0x15, +    VK_JUNJA = 0x17, +    VK_FINAL = 0x18, +    VK_HANJA = 0x19, +    VK_KANJI = 0x19, +    VK_ESCAPE = 0x1B, +    VK_CONVERT = 0x1C, +    VK_NONCONVERT = 0x1D, +    VK_ACCEPT = 0x1E, +    VK_MODECHANGE = 0x1F, +    VK_SPACE = 0x20, +    VK_PRIOR = 0x21, +    VK_NEXT = 0x22, +    VK_END = 0x23, +    VK_HOME = 0x24, +    VK_LEFT = 0x25, +    VK_UP = 0x26, +    VK_RIGHT = 0x27, +    VK_DOWN = 0x28, +    VK_SELECT = 0x29, +    VK_PRINT = 0x2A, +    VK_EXECUTE = 0x2B, +    VK_SNAPSHOT = 0x2C, +    VK_INSERT = 0x2D, +    VK_DELETE = 0x2E, +    VK_HELP = 0x2F, +    VK_0 = 0x30, +    VK_1 = 0x31, +    VK_2 = 0x32, +    VK_3 = 0x33, +    VK_4 = 0x34, +    VK_5 = 0x35, +    VK_6 = 0x36, +    VK_7 = 0x37, +    VK_8 = 0x38, +    VK_9 = 0x39, +    VK_A = 0x41, +    VK_B = 0x42, +    VK_C = 0x43, +    VK_D = 0x44, +    VK_E = 0x45, +    VK_F = 0x46, +    VK_G = 0x47, +    VK_H = 0x48, +    VK_I = 0x49, +    VK_J = 0x4A, +    VK_K = 0x4B, +    VK_L = 0x4C, +    VK_M = 0x4D, +    VK_N = 0x4E, +    VK_O = 0x4F, +    VK_P = 0x50, +    VK_Q = 0x51, +    VK_R = 0x52, +    VK_S = 0x53, +    VK_T = 0x54, +    VK_U = 0x55, +    VK_V = 0x56, +    VK_W = 0x57, +    VK_X = 0x58, +    VK_Y = 0x59, +    VK_Z = 0x5A, +    VK_LWIN = 0x5B, +    VK_RWIN = 0x5C, +    VK_APPS = 0x5D, +    VK_SLEEP = 0x5F, +    VK_NUMPAD0 = 0x60, +    VK_NUMPAD1 = 0x61, +    VK_NUMPAD2 = 0x62, +    VK_NUMPAD3 = 0x63, +    VK_NUMPAD4 = 0x64, +    VK_NUMPAD5 = 0x65, +    VK_NUMPAD6 = 0x66, +    VK_NUMPAD7 = 0x67, +    VK_NUMPAD8 = 0x68, +    VK_NUMPAD9 = 0x69, +    VK_MULTIPLY = 0x6A, +    VK_ADD = 0x6B, +    VK_SEPARATOR = 0x6C, +    VK_SUBTRACT = 0x6D, +    VK_DECIMAL = 0x6E, +    VK_DIVIDE = 0x6F, +    VK_F1 = 0x70, +    VK_F2 = 0x71, +    VK_F3 = 0x72, +    VK_F4 = 0x73, +    VK_F5 = 0x74, +    VK_F6 = 0x75, +    VK_F7 = 0x76, +    VK_F8 = 0x77, +    VK_F9 = 0x78, +    VK_F10 = 0x79, +    VK_F11 = 0x7A, +    VK_F12 = 0x7B, +    VK_F13 = 0x7C, +    VK_F14 = 0x7D, +    VK_F15 = 0x7E, +    VK_F16 = 0x7F, +    VK_F17 = 0x80, +    VK_F18 = 0x81, +    VK_F19 = 0x82, +    VK_F20 = 0x83, +    VK_F21 = 0x84, +    VK_F22 = 0x85, +    VK_F23 = 0x86, +    VK_F24 = 0x87, +    VK_NUMLOCK = 0x90, +    VK_SCROLL = 0x91, +    VK_LSHIFT = 0xA0, +    VK_RSHIFT = 0xA1, +    VK_LCONTROL = 0xA2, +    VK_RCONTROL = 0xA3, +    VK_LMENU = 0xA4, +    VK_RMENU = 0xA5, +    VK_BROWSER_BACK = 0xA6, +    VK_BROWSER_FORWARD = 0xA7, +    VK_BROWSER_REFRESH = 0xA8, +    VK_BROWSER_STOP = 0xA9, +    VK_BROWSER_SEARCH = 0xAA, +    VK_BROWSER_FAVORITES = 0xAB, +    VK_BROWSER_HOME = 0xAC, +    VK_VOLUME_MUTE = 0xAD, +    VK_VOLUME_DOWN = 0xAE, +    VK_VOLUME_UP = 0xAF, +    VK_MEDIA_NEXT_TRACK = 0xB0, +    VK_MEDIA_PREV_TRACK = 0xB1, +    VK_MEDIA_STOP = 0xB2, +    VK_MEDIA_PLAY_PAUSE = 0xB3, +    VK_MEDIA_LAUNCH_MAIL = 0xB4, +    VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5, +    VK_MEDIA_LAUNCH_APP1 = 0xB6, +    VK_MEDIA_LAUNCH_APP2 = 0xB7, +    VK_OEM_1 = 0xBA, +    VK_OEM_PLUS = 0xBB, +    VK_OEM_COMMA = 0xBC, +    VK_OEM_MINUS = 0xBD, +    VK_OEM_PERIOD = 0xBE, +    VK_OEM_2 = 0xBF, +    VK_OEM_3 = 0xC0, +    VK_OEM_4 = 0xDB, +    VK_OEM_5 = 0xDC, +    VK_OEM_6 = 0xDD, +    VK_OEM_7 = 0xDE, +    VK_OEM_8 = 0xDF, +    VK_OEM_102 = 0xE2, +    VK_PROCESSKEY = 0xE5, +    VK_PACKET = 0xE7, +    VK_ATTN = 0xF6, +    VK_CRSEL = 0xF7, +    VK_EXSEL = 0xF8, +    VK_EREOF = 0xF9, +    VK_PLAY = 0xFA, +    VK_ZOOM = 0xFB, +    VK_NONAME = 0xFC, +    VK_PA1 = 0xFD, +    VK_OEM_CLEAR = 0xFE, +}; + +std::map< U32, U32 > mSDL2_to_Win; +std::set< U32 > mIgnoreSDL2Keys; + +U32 LLKeyboardSDL::mapSDL2toWin( U32 aSymbol ) +{ +    // <FS:ND> Map SDLK_ virtual keys to Windows VK_ virtual keys. +    // Text is handled via unicode input (SDL_TEXTINPUT event) and does not need to be translated into VK_ values as those match already. +    if( mSDL2_to_Win.empty() ) +    { + +        mSDL2_to_Win[ SDLK_BACKSPACE ] = (U32)WindowsVK::VK_BACK; +        mSDL2_to_Win[ SDLK_TAB ] = (U32)WindowsVK::VK_TAB; +        mSDL2_to_Win[ 12 ] = (U32)WindowsVK::VK_CLEAR; +        mSDL2_to_Win[ SDLK_RETURN ] = (U32)WindowsVK::VK_RETURN; +        mSDL2_to_Win[ 19 ] = (U32)WindowsVK::VK_PAUSE; +        mSDL2_to_Win[ SDLK_ESCAPE ] = (U32)WindowsVK::VK_ESCAPE; +        mSDL2_to_Win[ SDLK_SPACE ] = (U32)WindowsVK::VK_SPACE; +        mSDL2_to_Win[ SDLK_QUOTE ] = (U32)WindowsVK::VK_OEM_7; +        mSDL2_to_Win[ SDLK_COMMA ] = (U32)WindowsVK::VK_OEM_COMMA; +        mSDL2_to_Win[ SDLK_MINUS ] = (U32)WindowsVK::VK_OEM_MINUS; +        mSDL2_to_Win[ SDLK_PERIOD ] = (U32)WindowsVK::VK_OEM_PERIOD; +        mSDL2_to_Win[ SDLK_SLASH ] = (U32)WindowsVK::VK_OEM_2; + +        mSDL2_to_Win[ SDLK_0 ] = (U32)WindowsVK::VK_0; +        mSDL2_to_Win[ SDLK_1 ] = (U32)WindowsVK::VK_1; +        mSDL2_to_Win[ SDLK_2 ] = (U32)WindowsVK::VK_2; +        mSDL2_to_Win[ SDLK_3 ] = (U32)WindowsVK::VK_3; +        mSDL2_to_Win[ SDLK_4 ] = (U32)WindowsVK::VK_4; +        mSDL2_to_Win[ SDLK_5 ] = (U32)WindowsVK::VK_5; +        mSDL2_to_Win[ SDLK_6 ] = (U32)WindowsVK::VK_6; +        mSDL2_to_Win[ SDLK_7 ] = (U32)WindowsVK::VK_7; +        mSDL2_to_Win[ SDLK_8 ] = (U32)WindowsVK::VK_8; +        mSDL2_to_Win[ SDLK_9 ] = (U32)WindowsVK::VK_9; + +        mSDL2_to_Win[ SDLK_SEMICOLON ] = (U32)WindowsVK::VK_OEM_1; +        mSDL2_to_Win[ SDLK_LESS ] = (U32)WindowsVK::VK_OEM_102; +        mSDL2_to_Win[ SDLK_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; +        mSDL2_to_Win[ SDLK_KP_EQUALS ] = (U32)WindowsVK::VK_OEM_PLUS; + +        mSDL2_to_Win[ SDLK_LEFTBRACKET ] = (U32)WindowsVK::VK_OEM_4; +        mSDL2_to_Win[ SDLK_BACKSLASH ] = (U32)WindowsVK::VK_OEM_5; +        mSDL2_to_Win[ SDLK_RIGHTBRACKET ] = (U32)WindowsVK::VK_OEM_6; +        mSDL2_to_Win[ SDLK_BACKQUOTE ] = (U32)WindowsVK::VK_OEM_8; + +        mSDL2_to_Win[ SDLK_a ] = (U32)WindowsVK::VK_A; +        mSDL2_to_Win[ SDLK_b ] = (U32)WindowsVK::VK_B; +        mSDL2_to_Win[ SDLK_c ] = (U32)WindowsVK::VK_C; +        mSDL2_to_Win[ SDLK_d ] = (U32)WindowsVK::VK_D; +        mSDL2_to_Win[ SDLK_e ] = (U32)WindowsVK::VK_E; +        mSDL2_to_Win[ SDLK_f ] = (U32)WindowsVK::VK_F; +        mSDL2_to_Win[ SDLK_g ] = (U32)WindowsVK::VK_G; +        mSDL2_to_Win[ SDLK_h ] = (U32)WindowsVK::VK_H; +        mSDL2_to_Win[ SDLK_i ] = (U32)WindowsVK::VK_I; +        mSDL2_to_Win[ SDLK_j ] = (U32)WindowsVK::VK_J; +        mSDL2_to_Win[ SDLK_k ] = (U32)WindowsVK::VK_K; +        mSDL2_to_Win[ SDLK_l ] = (U32)WindowsVK::VK_L; +        mSDL2_to_Win[ SDLK_m ] = (U32)WindowsVK::VK_M; +        mSDL2_to_Win[ SDLK_n ] = (U32)WindowsVK::VK_N; +        mSDL2_to_Win[ SDLK_o ] = (U32)WindowsVK::VK_O; +        mSDL2_to_Win[ SDLK_p ] = (U32)WindowsVK::VK_P; +        mSDL2_to_Win[ SDLK_q ] = (U32)WindowsVK::VK_Q; +        mSDL2_to_Win[ SDLK_r ] = (U32)WindowsVK::VK_R; +        mSDL2_to_Win[ SDLK_s ] = (U32)WindowsVK::VK_S; +        mSDL2_to_Win[ SDLK_t ] = (U32)WindowsVK::VK_T; +        mSDL2_to_Win[ SDLK_u ] = (U32)WindowsVK::VK_U; +        mSDL2_to_Win[ SDLK_v ] = (U32)WindowsVK::VK_V; +        mSDL2_to_Win[ SDLK_w ] = (U32)WindowsVK::VK_W; +        mSDL2_to_Win[ SDLK_x ] = (U32)WindowsVK::VK_X; +        mSDL2_to_Win[ SDLK_y ] = (U32)WindowsVK::VK_Y; +        mSDL2_to_Win[ SDLK_z ] = (U32)WindowsVK::VK_Z; + +        mSDL2_to_Win[ SDLK_DELETE ] = (U32)WindowsVK::VK_DELETE; + + +        mSDL2_to_Win[ SDLK_NUMLOCKCLEAR ] = (U32)WindowsVK::VK_NUMLOCK; +        mSDL2_to_Win[ SDLK_SCROLLLOCK ] = (U32)WindowsVK::VK_SCROLL; + +        mSDL2_to_Win[ SDLK_HELP ] = (U32)WindowsVK::VK_HELP; +        mSDL2_to_Win[ SDLK_PRINTSCREEN ] = (U32)WindowsVK::VK_SNAPSHOT; +        mSDL2_to_Win[ SDLK_CANCEL ] = (U32)WindowsVK::VK_CANCEL; +        mSDL2_to_Win[ SDLK_APPLICATION ] = (U32)WindowsVK::VK_APPS; + +        mSDL2_to_Win[ SDLK_UNKNOWN    ] = (U32)WindowsVK::VK_UNKNOWN; +        mSDL2_to_Win[ SDLK_BACKSPACE  ] = (U32)WindowsVK::VK_BACK; +        mSDL2_to_Win[ SDLK_TAB        ] = (U32)WindowsVK::VK_TAB; +        mSDL2_to_Win[ SDLK_CLEAR      ] = (U32)WindowsVK::VK_CLEAR; +        mSDL2_to_Win[ SDLK_RETURN     ] = (U32)WindowsVK::VK_RETURN; +        mSDL2_to_Win[ SDLK_PAUSE      ] = (U32)WindowsVK::VK_PAUSE; +        mSDL2_to_Win[ SDLK_ESCAPE     ] = (U32)WindowsVK::VK_ESCAPE; +        mSDL2_to_Win[ SDLK_DELETE     ] = (U32)WindowsVK::VK_DELETE; + +        mSDL2_to_Win[ SDLK_KP_PERIOD  ] = (U32)WindowsVK::VK_OEM_PERIOD; // VK_DECIMAL? +        mSDL2_to_Win[ SDLK_KP_DIVIDE  ] = (U32)WindowsVK::VK_DIVIDE; +        mSDL2_to_Win[ SDLK_KP_MULTIPLY] = (U32)WindowsVK::VK_MULTIPLY; +        mSDL2_to_Win[ SDLK_KP_MINUS   ] = (U32)WindowsVK::VK_OEM_MINUS; // VK_SUBSTRACT? +        mSDL2_to_Win[ SDLK_KP_PLUS    ] = (U32)WindowsVK::VK_OEM_PLUS;  // VK_ADD? +        mSDL2_to_Win[ SDLK_KP_ENTER   ] = (U32)WindowsVK::VK_RETURN; +        mSDL2_to_Win[ SDLK_KP_0 ] = (U32)WindowsVK::VK_NUMPAD0; +        mSDL2_to_Win[ SDLK_KP_1 ] = (U32)WindowsVK::VK_NUMPAD1; +        mSDL2_to_Win[ SDLK_KP_2 ] = (U32)WindowsVK::VK_NUMPAD2; +        mSDL2_to_Win[ SDLK_KP_3 ] = (U32)WindowsVK::VK_NUMPAD3; +        mSDL2_to_Win[ SDLK_KP_4 ] = (U32)WindowsVK::VK_NUMPAD4; +        mSDL2_to_Win[ SDLK_KP_5 ] = (U32)WindowsVK::VK_NUMPAD5; +        mSDL2_to_Win[ SDLK_KP_6 ] = (U32)WindowsVK::VK_NUMPAD6; +        mSDL2_to_Win[ SDLK_KP_7 ] = (U32)WindowsVK::VK_NUMPAD7; +        mSDL2_to_Win[ SDLK_KP_8 ] = (U32)WindowsVK::VK_NUMPAD8; +        mSDL2_to_Win[ SDLK_KP_9 ] = (U32)WindowsVK::VK_NUMPAD9; + +        // ? + +        mSDL2_to_Win[ SDLK_UP         ] = (U32)WindowsVK::VK_UP; +        mSDL2_to_Win[ SDLK_DOWN       ] = (U32)WindowsVK::VK_DOWN; +        mSDL2_to_Win[ SDLK_RIGHT      ] = (U32)WindowsVK::VK_RIGHT; +        mSDL2_to_Win[ SDLK_LEFT       ] = (U32)WindowsVK::VK_LEFT; +        mSDL2_to_Win[ SDLK_INSERT     ] = (U32)WindowsVK::VK_INSERT; +        mSDL2_to_Win[ SDLK_HOME       ] = (U32)WindowsVK::VK_HOME; +        mSDL2_to_Win[ SDLK_END        ] = (U32)WindowsVK::VK_END; +        mSDL2_to_Win[ SDLK_PAGEUP     ] = (U32)WindowsVK::VK_PRIOR; +        mSDL2_to_Win[ SDLK_PAGEDOWN   ] = (U32)WindowsVK::VK_NEXT; +        mSDL2_to_Win[ SDLK_F1         ] = (U32)WindowsVK::VK_F1; +        mSDL2_to_Win[ SDLK_F2         ] = (U32)WindowsVK::VK_F2; +        mSDL2_to_Win[ SDLK_F3         ] = (U32)WindowsVK::VK_F3; +        mSDL2_to_Win[ SDLK_F4         ] = (U32)WindowsVK::VK_F4; +        mSDL2_to_Win[ SDLK_F5         ] = (U32)WindowsVK::VK_F5; +        mSDL2_to_Win[ SDLK_F6         ] = (U32)WindowsVK::VK_F6; +        mSDL2_to_Win[ SDLK_F7         ] = (U32)WindowsVK::VK_F7; +        mSDL2_to_Win[ SDLK_F8         ] = (U32)WindowsVK::VK_F8; +        mSDL2_to_Win[ SDLK_F9         ] = (U32)WindowsVK::VK_F9; +        mSDL2_to_Win[ SDLK_F10        ] = (U32)WindowsVK::VK_F10; +        mSDL2_to_Win[ SDLK_F11        ] = (U32)WindowsVK::VK_F11; +        mSDL2_to_Win[ SDLK_F12        ] = (U32)WindowsVK::VK_F12; +        mSDL2_to_Win[ SDLK_F13        ] = (U32)WindowsVK::VK_F13; +        mSDL2_to_Win[ SDLK_F14        ] = (U32)WindowsVK::VK_F14; +        mSDL2_to_Win[ SDLK_F15        ] = (U32)WindowsVK::VK_F15; +        mSDL2_to_Win[ SDLK_CAPSLOCK   ] = (U32)WindowsVK::VK_CAPITAL; +        mSDL2_to_Win[ SDLK_RSHIFT     ] = (U32)WindowsVK::VK_SHIFT; +        mSDL2_to_Win[ SDLK_LSHIFT     ] = (U32)WindowsVK::VK_SHIFT; +        mSDL2_to_Win[ SDLK_RCTRL      ] = (U32)WindowsVK::VK_CONTROL; +        mSDL2_to_Win[ SDLK_LCTRL      ] = (U32)WindowsVK::VK_CONTROL; +        mSDL2_to_Win[ SDLK_RALT       ] = (U32)WindowsVK::VK_MENU; +        mSDL2_to_Win[ SDLK_LALT       ] = (U32)WindowsVK::VK_MENU; + +        mSDL2_to_Win[ SDLK_MENU       ] = (U32)WindowsVK::VK_MENU; + +        // VK_MODECHANGE ? +        // mSDL2_to_Win[ SDLK_MODE       ] = (U32)WindowsVK::VK_MODE; + +        // ? +        // mSDL2_to_Win[ SDLK_SYSREQ     ] = (U32)WindowsVK::VK_SYSREQ; +        // mSDL2_to_Win[ SDLK_POWER      ] = (U32)WindowsVK::VK_POWER; +        // mSDL2_to_Win[ SDLK_UNDO       ] = (U32)WindowsVK::VK_UNDO; +        // mSDL2_to_Win[ SDLK_KP_EQUALS  ] = (U32)WindowsVK::VK_EQUALS; +        // mSDL2_to_Win[ 311 ] = (U32)WindowsVK::VK_LWIN; +        // mSDL2_to_Win[ 312 ] = (U32)WindowsVK::VK_RWIN; +        // mSDL2_to_Win[ SDLK_COLON ] = ? +    } + +    auto itr = mSDL2_to_Win.find( aSymbol ); +    if( itr != mSDL2_to_Win.end() ) +        return itr->second; + +    return aSymbol; +} diff --git a/indra/llwindow/llkeyboardsdl.h b/indra/llwindow/llkeyboardsdl.h index 02a71425f1..4453e15adc 100644 --- a/indra/llwindow/llkeyboardsdl.h +++ b/indra/llwindow/llkeyboardsdl.h @@ -1,55 +1,57 @@ -/**  - * @file llkeyboardsdl.h - * @brief Handler for assignable key bindings +/** + * @author This module has many fathers, and it shows.   * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * $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_LLKEYBOARDSDL_H -#define LL_LLKEYBOARDSDL_H +#ifndef LL_LLKEYBOARDSDL2_H +#define LL_LLKEYBOARDSDL2_H  #include "llkeyboard.h" -#include "SDL/SDL.h" +#include "SDL2/SDL.h"  class LLKeyboardSDL : public LLKeyboard  {  public: -	LLKeyboardSDL(); -	/*virtual*/ ~LLKeyboardSDL() {}; +    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(); +    /*virtual*/ BOOL	handleKeyUp(const U32 key, MASK mask); +    /*virtual*/ BOOL	handleKeyDown(const U32 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); +    MASK	updateModifiers(const U32 mask); +    void	setModifierKeyLevel( KEY key, BOOL new_state ); +    BOOL	translateNumpadKey( const U32 os_key, KEY *translated_key ); +    U16	inverseTranslateNumpadKey(const KEY translated_key);  private: -	std::map<U16, KEY> mTranslateNumpadMap;  // special map for translating OS keys to numpad keys -	std::map<KEY, U16> mInvTranslateNumpadMap; // inverse of the above +    std::map<U32, KEY> mTranslateNumpadMap;  // special map for translating OS keys to numpad keys +    std::map<KEY, U32> mInvTranslateNumpadMap; // inverse of the above + +public: +    static U32 mapSDL2toWin( U32 );  };  #endif diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 7ea87f5884..b8b502508b 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -1,4 +1,4 @@ -/**  +/**   * @file llwindowsdl.cpp   * @brief SDL implementation of LLWindow class   * @author This module has many fathers, and it shows. @@ -6,27 +6,25 @@   * $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" @@ -40,12 +38,9 @@  #include "lldir.h"  #include "llfindlocale.h" -#if LL_GTK -extern "C" { -# include "gtk/gtk.h" -} -#include <locale.h> -#endif // LL_GTK +#ifdef LL_GLIB +#include <glib.h> +#endif  extern "C" {  # include "fontconfig/fontconfig.h" @@ -57,6 +52,7 @@ extern "C" {  # include <unistd.h>  # include <sys/types.h>  # include <sys/wait.h> +# include <stdio.h>  #endif // LL_LINUX  extern BOOL gDebugWindowProc; @@ -64,7 +60,7 @@ extern BOOL gDebugWindowProc;  const S32 MAX_NUM_RESOLUTIONS = 200;  // static variable for ATI mouse cursor crash work-around: -static bool ATIbug = false;  +static bool ATIbug = false;  //  // LLWindowSDL @@ -83,188 +79,360 @@ static LLWindowSDL *gWindowImplementation = NULL;  void maybe_lock_display(void)  { -	if (gWindowImplementation && gWindowImplementation->Lock_Display) { -		gWindowImplementation->Lock_Display(); -	} +    if (gWindowImplementation && gWindowImplementation->Lock_Display) { +        gWindowImplementation->Lock_Display(); +    }  }  void maybe_unlock_display(void)  { -	if (gWindowImplementation && gWindowImplementation->Unlock_Display) { -		gWindowImplementation->Unlock_Display(); -	} +    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; +    if (gWindowImplementation) { +        return gWindowImplementation->mSDL_XWindowID; +    } +    return None;  }  //static  Display* LLWindowSDL::get_SDL_Display(void)  { -	if (gWindowImplementation) { -		return gWindowImplementation->mSDL_Display; -	} -	return NULL; +    if (gWindowImplementation) { +        return gWindowImplementation->mSDL_Display; +    } +    return NULL;  }  #endif // LL_X11 +#if LL_X11 + +// Clipboard handing via native X11, base on the implementation in Cool VL by Henri Beauchamp + +namespace +{ +    std::array<Atom, 3> gSupportedAtoms; + +    Atom XA_CLIPBOARD; +    Atom XA_TARGETS; +    Atom PVT_PASTE_BUFFER; +    long const MAX_PASTE_BUFFER_SIZE = 16383; + +    void filterSelectionRequest( XEvent aEvent ) +    { +        auto *display = LLWindowSDL::getSDLDisplay(); +        auto &request = aEvent.xselectionrequest; + +        XSelectionEvent reply { SelectionNotify, aEvent.xany.serial, aEvent.xany.send_event, display, +                                request.requestor, request.selection, request.target, +                                request.property,request.time }; + +        if (request.target == XA_TARGETS) +        { +            XChangeProperty(display, request.requestor, request.property, +                            XA_ATOM, 32, PropModeReplace, +                            (unsigned char *) &gSupportedAtoms.front(), gSupportedAtoms.size()); +        } +        else if (std::find(gSupportedAtoms.begin(), gSupportedAtoms.end(), request.target) != +                 gSupportedAtoms.end()) +        { +            std::string utf8; +            if (request.selection == XA_PRIMARY) +                utf8 = wstring_to_utf8str(gWindowImplementation->getPrimaryText()); +            else +                utf8 = wstring_to_utf8str(gWindowImplementation->getSecondaryText()); + +            XChangeProperty(display, request.requestor, request.property, +                            request.target, 8, PropModeReplace, +                            (unsigned char *) utf8.c_str(), utf8.length()); +        } +        else if (request.selection == XA_CLIPBOARD) +        { +            // Did not have what they wanted, so no property set +            reply.property = None; +        } +        else +            return; + +        XSendEvent(request.display, request.requestor, False, NoEventMask, (XEvent *) &reply); +        XSync(display, False); +    } + +    void filterSelectionClearRequest( XEvent aEvent ) +    { +        auto &request = aEvent.xselectionrequest; +        if (request.selection == XA_PRIMARY) +            gWindowImplementation->clearPrimaryText(); +        else if (request.selection == XA_CLIPBOARD) +            gWindowImplementation->clearSecondaryText(); +    } + +    int x11_clipboard_filter(void*, SDL_Event *evt) +    { +        Display *display = LLWindowSDL::getSDLDisplay(); +        if (!display) +            return 1; + +        if (evt->type != SDL_SYSWMEVENT) +            return 1; + +        auto xevent = evt->syswm.msg->msg.x11.event; + +        if (xevent.type == SelectionRequest) +            filterSelectionRequest( xevent ); +        else if (xevent.type == SelectionClear) +            filterSelectionClearRequest( xevent ); +        return 1; +    } + +    bool grab_property(Display* display, Window window, Atom selection, Atom target) +    { +        if( !display ) +            return false; + +        maybe_lock_display(); + +        XDeleteProperty(display, window, PVT_PASTE_BUFFER); +        XFlush(display); + +        XConvertSelection(display, selection, target, PVT_PASTE_BUFFER, window,  CurrentTime); + +        // Unlock the connection so that the SDL event loop may function +        maybe_unlock_display(); + +        const auto start{ SDL_GetTicks() }; +        const auto end{ start + 1000 }; + +        XEvent xevent {}; +        bool response = false; + +        do +        { +            SDL_Event event {}; + +            // Wait for an event +            SDL_WaitEvent(&event); + +            // If the event is a window manager event +            if (event.type == SDL_SYSWMEVENT) +            { +                xevent = event.syswm.msg->msg.x11.event; + +                if (xevent.type == SelectionNotify && xevent.xselection.requestor == window) +                    response = true; +            } +        } while (!response && SDL_GetTicks() < end ); + +        return response && xevent.xselection.property != None; +    } +} + +void LLWindowSDL::initialiseX11Clipboard() +{ +    if (!mSDL_Display) +        return; + +    SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); +    SDL_SetEventFilter(x11_clipboard_filter, nullptr); + +    maybe_lock_display(); + +    XA_CLIPBOARD = XInternAtom(mSDL_Display, "CLIPBOARD", False); + +    gSupportedAtoms[0] = XInternAtom(mSDL_Display, "UTF8_STRING", False); +    gSupportedAtoms[1] = XInternAtom(mSDL_Display, "COMPOUND_TEXT", False); +    gSupportedAtoms[2] = XA_STRING; + +    // TARGETS atom +    XA_TARGETS = XInternAtom(mSDL_Display, "TARGETS", False); + +    // SL_PASTE_BUFFER atom +    PVT_PASTE_BUFFER = XInternAtom(mSDL_Display, "FS_PASTE_BUFFER", False); + +    maybe_unlock_display(); +} + +bool LLWindowSDL::getSelectionText( Atom aSelection, Atom aType, LLWString &text ) +{ +    if( !mSDL_Display ) +        return false; + +    if( !grab_property(mSDL_Display, mSDL_XWindowID, aSelection,aType ) ) +        return false; + +    maybe_lock_display(); + +    Atom type; +    int format{}; +    unsigned long len{},remaining {}; +    unsigned char* data = nullptr; +    int res = XGetWindowProperty(mSDL_Display, mSDL_XWindowID, +                                 PVT_PASTE_BUFFER, 0, MAX_PASTE_BUFFER_SIZE, False, +                                 AnyPropertyType, &type, &format, &len, +                                 &remaining, &data); +    if (data && len) +    { +        text = LLWString( +                utf8str_to_wstring(reinterpret_cast< char const *>( data ) ) +        ); +        XFree(data); +    } + +    maybe_unlock_display(); +    return res == Success; +} + +bool LLWindowSDL::getSelectionText(Atom selection, LLWString& text) +{ +    if (!mSDL_Display) +        return false; + +    maybe_lock_display(); + +    Window owner = XGetSelectionOwner(mSDL_Display, selection); +    if (owner == None) +    { +        if (selection == XA_PRIMARY) +        { +            owner = DefaultRootWindow(mSDL_Display); +            selection = XA_CUT_BUFFER0; +        } +        else +        { +            maybe_unlock_display(); +            return false; +        } +    } + +    maybe_unlock_display(); + +    for( Atom atom : gSupportedAtoms ) +    { +        if(getSelectionText(selection, atom, text ) ) +            return true; +    } + +    return false; +} + +bool LLWindowSDL::setSelectionText(Atom selection, const LLWString& text) +{ +    maybe_lock_display(); + +    if (selection == XA_PRIMARY) +    { +        std::string utf8 = wstring_to_utf8str(text); +        XStoreBytes(mSDL_Display, utf8.c_str(), utf8.length() + 1); +        mPrimaryClipboard = text; +    } +    else +        mSecondaryClipboard = text; + +    XSetSelectionOwner(mSDL_Display, selection, mSDL_XWindowID, CurrentTime); + +    auto owner = XGetSelectionOwner(mSDL_Display, selection); + +    maybe_unlock_display(); + +    return owner == mSDL_XWindowID; +} + +Display* LLWindowSDL::getSDLDisplay() +{ +    if (gWindowImplementation) +        return gWindowImplementation->mSDL_Display; +    return nullptr; +} + +#endif +  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; +                         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) +        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; +    mContext = {}; +    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; +    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; +    // Assume 4:3 aspect ratio until we know better +    mOriginalAspectRatio = 1024.0 / 768.0; -	if (title.empty()) -		mWindowTitle = "SDL Window";  // *FIX: (?) -	else -		mWindowTitle = title; +    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(); +    // 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 ); -	} +        //start with arrow cursor +        initCursors(); +        setCursor( UI_CURSOR_ARROW ); +    } -	stop_glerror(); +    stop_glerror(); -	// Stash an object pointer for OSMessageBox() -	gWindowImplementation = this; +    // Stash an object pointer for OSMessageBox() +    gWindowImplementation = this;  #if LL_X11 -	mFlashing = FALSE; +    mFlashing = FALSE; +    initialiseX11Clipboard();  #endif // LL_X11 -	mKeyScanCode = 0; -	mKeyVirtualKey = 0; -	mKeyModifiers = KMOD_NONE; +    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); +    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 @@ -274,520 +442,513 @@ static SDL_Surface *Load_BMP_Resource(const char *basename)  // '?' 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' +    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; +    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 +void LLWindowSDL::setTitle(const std::string title) +{ +    SDL_SetWindowTitle( mWindow, title.c_str() ); +} + +void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) +{ +    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; +    } +} +  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. +    //bool			glneedsinit = false; + +    LL_INFOS() << "createContext, fullscreen=" << fullscreen << +               " size=" << width << "x" << height << LL_ENDL; + +    // captures don't survive contexts +    mGrabbyKeyFlags = 0; +    mReallyCapturedCount = 0; + +    std::initializer_list<std::tuple< char const*, char const * > > hintList = +            { +                    {SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR,"0"}, +                    {SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,"1"}, +            }; + +    for( auto hint: hintList ) +    { +        SDL_SetHint( std::get<0>(hint), std::get<1>(hint)); +    } + +    std::initializer_list<std::tuple<uint32_t, char const*, bool>> initList= +            { {SDL_INIT_VIDEO,"SDL_INIT_VIDEO", true}, +              {SDL_INIT_AUDIO,"SDL_INIT_AUDIO", false}, +              {SDL_INIT_GAMECONTROLLER,"SDL_INIT_GAMECONTROLLER", false}, +              {SDL_INIT_SENSOR,"SDL_INIT_SENSOR", false} +            }; + +    for( auto subSystem : initList) +    { +        if( SDL_InitSubSystem( std::get<0>(subSystem) ) < 0 ) +        { +            LL_WARNS() << "SDL_InitSubSystem for " << std::get<1>(subSystem) << " failed " << SDL_GetError() << LL_ENDL; + +            if( std::get<2>(subSystem)) +                setupFailure("SDL_Init() failure", "error", OSMB_OK); + +        } +    } + +    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; +    SDL_version r_sdl_version; +    SDL_GetVersion(&r_sdl_version); +    LL_INFOS() << " Running against SDL " +               << int(r_sdl_version.major) << "." +               << int(r_sdl_version.minor) << "." +               << int(r_sdl_version.patch) << LL_ENDL; + +    if (width == 0) +        width = 1024; +    if (height == 0) +        width = 768; + +    mFullscreen = fullscreen; + +    int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + +    if( mFullscreen ) +    { +        sdlflags |= SDL_WINDOW_FULLSCREEN; +        tryFindFullscreenSize( width, height ); +    } + +    mSDLFlags = sdlflags; + +    GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; + +    GLint depthBits{(bits <= 16) ? 16 : 24}, stencilBits{8}; + +    if (getenv("LL_GL_NO_STENCIL")) +        stencilBits = 0; + +    SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, alphaBits); +    SDL_GL_SetAttribute(SDL_GL_RED_SIZE,   redBits); +    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, greenBits); +    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE,  blueBits); +    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits ); + +    // We need stencil support for a few (minor) things. +    if (stencilBits) +        SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); +    // *FIX: try to toggle vsync here? + +    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + +    if (mFSAASamples > 0) +    { +        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); +        SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); +    } + +    SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); +    mWindow = SDL_CreateWindow( mWindowTitle.c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, mSDLFlags ); + +    if( mWindow ) +    { +        mContext = SDL_GL_CreateContext( mWindow ); + +        if( mContext == 0 ) +        { +            LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; +            setupFailure("GL Context creation error creation error", "Error", OSMB_OK); +            return FALSE; +        } +        // SDL_GL_SetSwapInterval(1); +        mSurface = SDL_GetWindowSurface( mWindow ); +    } + + +    if( mFullscreen ) +    { +        if (mSurface) +        { +            mFullscreen = TRUE; +            mFullscreenWidth = mSurface->w; +            mFullscreenHeight = mSurface->h; +            mFullscreenBits    = mSurface->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); +            return FALSE; +        } +    } +    else +    { +        if (!mWindow) +        { +            LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; +            setupFailure("Window creation error", "Error", OSMB_OK); +            return FALSE; +        } +    } + +    // Set the application icon. +    SDL_Surface *bmpsurface; +    bmpsurface = Load_BMP_Resource("ll_icon.BMP"); +    if (bmpsurface) +    { +        SDL_SetWindowIcon(mWindow, bmpsurface); +        SDL_FreeSurface(bmpsurface); +        bmpsurface = NULL; +    } + +    // 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 +    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 +    { +        // 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 = 0; +        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); + +    SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &redBits); +    SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &greenBits); +    SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &blueBits); +    SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alphaBits); +    SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depthBits); +    SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &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 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; -	} +    /* Grab the window manager specific information */ +    SDL_SysWMinfo info; +    SDL_VERSION(&info.version); +    if ( SDL_GetWindowWMInfo(mWindow, &info) ) +    { +        /* Save the information for later use */ +        if ( info.subsystem == SDL_SYSWM_X11 ) +        { +            mSDL_Display = info.info.x11.display; +            mSDL_XWindowID = info.info.x11.window; +        } +        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() <<LL_ENDL; +    SDL_StartTextInput(); +    //make sure multisampling is disabled by default +    glDisable(GL_MULTISAMPLE_ARB); -	// Don't need to get the current gamma, since there's a call that restores it to the system defaults. -	return TRUE; +    // Don't need to get the current gamma, since there's a call that restores it to the system defaults. +    return TRUE;  }  // changing fullscreen resolution, or switching between windowed and fullscreen mode.  BOOL LLWindowSDL::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp)  { -	const BOOL needsRebuild = TRUE;  // Just nuke the context and start over. -	BOOL result = true; +    const BOOL needsRebuild = TRUE;  // Just nuke the context and start over. +    BOOL result = true; -	LL_INFOS() << "switchContext, fullscreen=" << fullscreen << LL_ENDL; -	stop_glerror(); -	if(needsRebuild) -	{ -		destroyContext(); -		result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); -		if (result) -		{ -			gGLManager.initGL(); +    LL_INFOS() << "switchContext, fullscreen=" << fullscreen << LL_ENDL; +    stop_glerror(); +    if(needsRebuild) +    { +        destroyContext(); +        result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); +        if (result) +        { +            gGLManager.initGL(); -			//start with arrow cursor -			initCursors(); -			setCursor( UI_CURSOR_ARROW ); -		} -	} +            //start with arrow cursor +            initCursors(); +            setCursor( UI_CURSOR_ARROW ); +        } +    } -	stop_glerror(); +    stop_glerror(); -	return result; +    return result;  }  void LLWindowSDL::destroyContext()  { -	LL_INFOS() << "destroyContext begins" << LL_ENDL; +    LL_INFOS() << "destroyContext begins" << LL_ENDL; +    SDL_StopTextInput();  #if LL_X11 -	mSDL_Display = NULL; -	mSDL_XWindowID = None; -	Lock_Display = NULL; -	Unlock_Display = NULL; +    mSDL_Display = NULL; +    mSDL_XWindowID = None; +    Lock_Display = NULL; +    Unlock_Display = NULL;  #endif // LL_X11 -	// Clean up remaining GL state before blowing away window -	LL_INFOS() << "shutdownGL begins" << LL_ENDL; -	gGLManager.shutdownGL(); -	LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; -	SDL_QuitSubSystem(SDL_INIT_VIDEO);  // *FIX: this might be risky... +    // Clean up remaining GL state before blowing away window +    LL_INFOS() << "shutdownGL begins" << LL_ENDL; +    gGLManager.shutdownGL(); +    LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; +    SDL_QuitSubSystem(SDL_INIT_VIDEO);  // *FIX: this might be risky... -	mWindow = NULL; +    mWindow = NULL;  }  LLWindowSDL::~LLWindowSDL()  { -	quitCursors(); -	destroyContext(); +    quitCursors(); +    destroyContext(); -	if(mSupportedResolutions != NULL) -	{ -		delete []mSupportedResolutions; -	} +    if(mSupportedResolutions != NULL) +    { +        delete []mSupportedResolutions; +    } -	gWindowImplementation = NULL; +    gWindowImplementation = NULL;  } @@ -818,87 +979,87 @@ void LLWindowSDL::restore()  // Usually called from LLWindowManager::destroyWindow()  void LLWindowSDL::close()  { -	// Is window is already closed? -	//	if (!mWindow) -	//	{ -	//		return; -	//	} +    // Is window is already closed? +    //	if (!mWindow) +    //	{ +    //		return; +    //	} -	// Make sure cursor is visible and we haven't mangled the clipping state. -	setMouseClipping(FALSE); -	showCursor(); +    // Make sure cursor is visible and we haven't mangled the clipping state. +    setMouseClipping(FALSE); +    showCursor(); -	destroyContext(); +    destroyContext();  }  BOOL LLWindowSDL::isValid()  { -	return (mWindow != NULL); +    return (mWindow != NULL);  }  BOOL LLWindowSDL::getVisible()  { -	BOOL result = FALSE; +    BOOL result = FALSE;      // *FIX: This isn't really right... -	// Then what is? -	if (mWindow) -	{ -		result = TRUE; -	} +    // Then what is? +    if (mWindow) +    { +        result = TRUE; +    } -	return(result); +    return(result);  }  BOOL LLWindowSDL::getMinimized()  { -	BOOL result = FALSE; +    BOOL result = FALSE; -	if (mWindow && (1 == mIsMinimized)) -	{ -		result = TRUE; -	} -	return(result); +    if (mWindow && (1 == mIsMinimized)) +    { +        result = TRUE; +    } +    return(result);  }  BOOL LLWindowSDL::getMaximized()  { -	BOOL result = FALSE; +    BOOL result = FALSE; -	if (mWindow) -	{ -		// TODO -	} +    if (mWindow) +    { +        // TODO +    } -	return(result); +    return(result);  }  BOOL LLWindowSDL::maximize()  { -	// TODO -	return FALSE; +    // TODO +    return FALSE;  }  BOOL LLWindowSDL::getFullscreen()  { -	return mFullscreen; +    return mFullscreen;  }  BOOL LLWindowSDL::getPosition(LLCoordScreen *position)  {      // *FIX: can anything be done with this? -	position->mX = 0; -	position->mY = 0; +    position->mX = 0; +    position->mY = 0;      return TRUE;  }  BOOL LLWindowSDL::getSize(LLCoordScreen *size)  { -    if (mWindow) +    if (mSurface)      { -        size->mX = mWindow->w; -        size->mY = mWindow->h; -	return (TRUE); +        size->mX = mSurface->w; +        size->mY = mSurface->h; +        return (TRUE);      }      return (FALSE); @@ -906,11 +1067,11 @@ BOOL LLWindowSDL::getSize(LLCoordScreen *size)  BOOL LLWindowSDL::getSize(LLCoordWindow *size)  { -    if (mWindow) +    if (mSurface)      { -        size->mX = mWindow->w; -        size->mY = mWindow->h; -	return (TRUE); +        size->mX = mSurface->w; +        size->mY = mSurface->h; +        return (TRUE);      }      return (FALSE); @@ -918,94 +1079,91 @@ BOOL LLWindowSDL::getSize(LLCoordWindow *size)  BOOL LLWindowSDL::setPosition(const LLCoordScreen position)  { -	if(mWindow) -	{ +    if(mWindow) +    {          // *FIX: (?) -		//MacMoveWindow(mWindow, position.mX, position.mY, false); -	} +        //MacMoveWindow(mWindow, position.mX, position.mY, false); +    } -	return TRUE; +    return TRUE;  } -BOOL LLWindowSDL::setSizeImpl(const LLCoordScreen size) +template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin )  { -	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 +    if( !pWin ) +        return false; + +    auto nFlags = SDL_GetWindowFlags( pWin ); -		return TRUE; -	} -		 -	return FALSE; +    if( nFlags & SDL_WINDOW_MAXIMIZED ) +        SDL_RestoreWindow( pWin ); + + +    SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); +    SDL_Event event; +    event.type = SDL_WINDOWEVENT; +    event.window.event = SDL_WINDOWEVENT_RESIZED; +    event.window.windowID = SDL_GetWindowID( pWin ); +    event.window.data1 = newSize.mX; +    event.window.data2 = newSize.mY; +    SDL_PushEvent( &event ); + +    return true;  } -BOOL LLWindowSDL::setSizeImpl(const LLCoordWindow size) +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 ::setSizeImpl( size, mWindow ); +} -	return FALSE; +BOOL LLWindowSDL::setSizeImpl(const LLCoordWindow size) +{ +    return ::setSizeImpl( size, mWindow );  }  void LLWindowSDL::swapBuffers()  { -	if (mWindow) -	{	 -		SDL_GL_SwapBuffers(); -	} +    if (mWindow) +    { +        SDL_GL_SwapWindow( mWindow ); +    }  }  U32 LLWindowSDL::getFSAASamples()  { -	return mFSAASamples; +    return mFSAASamples;  }  void LLWindowSDL::setFSAASamples(const U32 samples)  { -	mFSAASamples = samples; +    mFSAASamples = samples;  }  F32 LLWindowSDL::getGamma()  { -	return 1/mGamma; +    return 1/mGamma;  }  BOOL LLWindowSDL::restoreGamma()  { -	//CGDisplayRestoreColorSyncSettings(); -    SDL_SetGamma(1.0f, 1.0f, 1.0f); -	return true; +    //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; +    mGamma = gamma; +    if (mGamma == 0) mGamma = 0.1f; +    mGamma = 1/mGamma; +    // SDL_SetGamma(mGamma, mGamma, mGamma); +    return true;  }  BOOL LLWindowSDL::isCursorHidden()  { -	return mCursorHidden; +    return mCursorHidden;  } @@ -1019,110 +1177,98 @@ void LLWindowSDL::setMouseClipping( BOOL b )  // virtual  void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immediately)  { -	LLWindow::setMinSize(min_width, min_height, 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; +    // 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); +    XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); -	XFree(hints); +    XFree(hints);  #endif  }  BOOL LLWindowSDL::setCursorPosition(const LLCoordWindow position)  { -	BOOL result = TRUE; -	LLCoordScreen screen_pos; +    BOOL result = TRUE; +    LLCoordScreen screen_pos; -	if (!convertCoords(position, &screen_pos)) -	{ -		return FALSE; -	} +    if (!convertCoords(position, &screen_pos)) +    { +        return FALSE; +    } -	//LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; +    //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; +    // do the actual forced cursor move. +    SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); -	return result; +    //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; +    //Point cursor_point; +    LLCoordScreen screen_pos; -	//GetMouse(&cursor_point); +    //GetMouse(&cursor_point);      int x, y;      SDL_GetMouseState(&x, &y); -	screen_pos.mX = x; -	screen_pos.mY = y; +    screen_pos.mX = x; +    screen_pos.mY = y; -	return convertCoords(screen_pos, position); +    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); - +    // 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. -	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. +    // 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 +    //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. +    // 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; -	} +    if (mOverrideAspectRatio > 0.f) +    { +        return mOverrideAspectRatio; +    } -	return mOriginalAspectRatio; +    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; -		} -	} +    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; +    return pixel_aspect;  } @@ -1130,67 +1276,61 @@ F32 LLWindowSDL::getPixelAspectRatio()  // dialogs are still usable in fullscreen.  void LLWindowSDL::beforeDialog()  { -	bool running_x11 = false; +    bool running_x11 = false;  #if LL_X11 -	running_x11 = (mSDL_XWindowID != None); +    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); -			} -		} -	} +    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_SetWindowFullscreen( mWindow, 0 ); +            } +        } +    }  #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(); -	} +    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(); +    maybe_lock_display();  }  void LLWindowSDL::afterDialog()  { -	bool running_x11 = false; +    bool running_x11 = false;  #if LL_X11 -	running_x11 = (mSDL_XWindowID != None); +    running_x11 = (mSDL_XWindowID != None);  #endif //LL_X11 -	LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; +    LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; -	maybe_unlock_display(); +    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 (mFullscreen) +    { +        // need to restore fullscreen mode after dialog - only works +        // in X11 +        if (running_x11 && mWindow) +        { +            SDL_SetWindowFullscreen( mWindow, 0 ); +        } +    }  } @@ -1198,210 +1338,120 @@ void LLWindowSDL::afterDialog()  // 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; +    if (mSDL_Display && !mFullscreen) +    { +        XWMHints *wm_hints; -		maybe_lock_display(); -		wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); -		if (!wm_hints) -			wm_hints = XAllocWMHints(); +        LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; -		if (urgent) -			wm_hints->flags |= XUrgencyHint; -		else -			wm_hints->flags &= ~XUrgencyHint; +        maybe_lock_display(); +        wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); +        if (!wm_hints) +            wm_hints = XAllocWMHints(); -		XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); -		XFree(wm_hints); -		XSync(mSDL_Display, False); -		maybe_unlock_display(); -	} +        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 (getMinimized()) +    {  #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 -} +        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); -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 +        x11_set_urgent(TRUE); +        mFlashing = TRUE; +#endif // LL_X11 +    }  } -#else -  BOOL LLWindowSDL::isClipboardTextAvailable()  { -	return FALSE; // unsupported +    return mSDL_Display && XGetSelectionOwner(mSDL_Display, XA_CLIPBOARD) != None;  }  BOOL LLWindowSDL::pasteTextFromClipboard(LLWString &dst)  { -	return FALSE; // unsupported +    return getSelectionText(XA_CLIPBOARD, dst);  }  BOOL LLWindowSDL::copyTextToClipboard(const LLWString &s)  { -	return FALSE;  // unsupported +    return setSelectionText(XA_CLIPBOARD, s);  }  BOOL LLWindowSDL::isPrimaryTextAvailable()  { -	return FALSE; // unsupported +    LLWString text; +    return getSelectionText(XA_PRIMARY, text) && !text.empty();  }  BOOL LLWindowSDL::pasteTextFromPrimary(LLWString &dst)  { -	return FALSE; // unsupported +    return getSelectionText(XA_PRIMARY, dst);  }  BOOL LLWindowSDL::copyTextToPrimary(const LLWString &s)  { -	return FALSE;  // unsupported +    return setSelectionText(XA_PRIMARY, s);  } -#endif // LL_GTK -  LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions)  { -	if (!mSupportedResolutions) -	{ -		mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; -		mNumSupportedResolutions = 0; +    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)) ) +        // <FS:ND> Use display no from mWindow/mSurface here? +        int max = SDL_GetNumDisplayModes(0); +        max = llclamp( max, 0, MAX_NUM_RESOLUTIONS ); + +        for( int i =0; i < max; ++i )          { -            int count = 0; -            while (*modes && count<MAX_NUM_RESOLUTIONS)  // they're sorted biggest to smallest, so find end... +            SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; +            if (SDL_GetDisplayMode( 0 , i, &mode) != 0)              { -                modes++; -                count++; +                continue;              } -            while (count--) +            int w = mode.w; +            int h = mode.h; +            if ((w >= 800) && (h >= 600))              { -                modes--; -                SDL_Rect *r = *modes; -                int w = r->w; -                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)) )                  { -                    // 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++; -                    } +                    mSupportedResolutions[mNumSupportedResolutions].mWidth = w; +                    mSupportedResolutions[mNumSupportedResolutions].mHeight = h; +                    mNumSupportedResolutions++;                  }              }          } -	} +    } -	num_resolutions = mNumSupportedResolutions; -	return mSupportedResolutions; +    num_resolutions = mNumSupportedResolutions; +    return mSupportedResolutions;  }  BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) @@ -1409,10 +1459,10 @@ BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to)      if (!to)          return FALSE; -	to->mX = from.mX; -	to->mY = mWindow->h - from.mY - 1; +    to->mX = from.mX; +    to->mY = mSurface->h - from.mY - 1; -	return TRUE; +    return TRUE;  }  BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) @@ -1420,46 +1470,46 @@ BOOL LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to)      if (!to)          return FALSE; -	to->mX = from.mX; -	to->mY = mWindow->h - from.mY - 1; +    to->mX = from.mX; +    to->mY = mSurface->h - from.mY - 1; -	return TRUE; +    return TRUE;  }  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; +    // 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; +        return FALSE; -	// In the fullscreen case, window and screen coordinates are the same. -	to->mX = from.mX; -	to->mY = from.mY; +    // 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; +    LLCoordWindow window_coord; -	return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +    return(convertCoords(from, &window_coord) && convertCoords(window_coord, to));  }  BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to)  { -	LLCoordWindow window_coord; +    LLCoordWindow window_coord; -	return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); +    return(convertCoords(from, &window_coord) && convertCoords(window_coord, to));  } @@ -1467,226 +1517,216 @@ BOOL LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to)  void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type)  { -	destroyContext(); +    destroyContext(); -	OSMessageBox(text, caption, type); +    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 */ -	{ +    // 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; + +    bool wantGrab; +    if (mReallyCapturedCount <= 0) // uncapture +    { +        wantGrab = false; +    } else // capture +    { +        wantGrab = true; +    } + +    if (mReallyCapturedCount < 0) // yuck, imbalance. +    { +        mReallyCapturedCount = 0; +        LL_WARNS() << "ReallyCapture count was < 0" << LL_ENDL; +    } + +    bool newGrab = wantGrab; +  #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; +    if (!mFullscreen) /* only bother if we're windowed anyway */ +    { +        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 (wantGrab == true) +            { +                maybe_lock_display(); +                result = XGrabPointer(mSDL_Display, mSDL_XWindowID, +                                      True, 0, GrabModeAsync, +                                      GrabModeAsync, +                                      None, None, CurrentTime); +                maybe_unlock_display(); +                if (GrabSuccess == result) +                    newGrab = true; +                else +                    newGrab = false; +            } +            else +            { +                newGrab = false; + +                maybe_lock_display(); +                XUngrabPointer(mSDL_Display, CurrentTime); +                // Make sure the ungrab happens RIGHT NOW. +                XSync(mSDL_Display, False); +                maybe_unlock_display(); +            } +        } +    }  #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; +    // return boolean success for whether we ended up in the desired state +    return capture == newGrab; +} + +U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 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); -	} +    // 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  } @@ -1694,38 +1734,22 @@ finally:  // 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 +#if LL_GLIB +    // 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 +    { +        g_main_context_iteration(g_main_context_default(), FALSE); +    } while( g_main_context_pending(g_main_context_default()) && !pump_timer.hasExpired()); +#endif      // hack - doesn't belong here - but this is just for debugging      if (getenv("LL_DEBUG_BLOAT"))      { -	    check_vm_bloat(); +        check_vm_bloat();      }  } @@ -1743,43 +1767,83 @@ void LLWindowSDL::gatherInput()      {          switch (event.type)          { +            case SDL_MOUSEWHEEL: +                if( event.wheel.y != 0 ) +                    mCallbacks->handleScrollWheel(this, -event.wheel.y); +                break; +              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); +                MASK mask = gKeyboard->currentMask(TRUE); +                mCallbacks->handleMouseMove(this, openGlCoord, mask); +                break; +            } + +            case SDL_TEXTINPUT: +            { +                auto string = utf8str_to_utf16str( event.text.text ); +                mKeyModifiers = gKeyboard->currentMask( FALSE ); +                mInputType = "textinput"; +                for( auto key: string ) +                { +                    mKeyVirtualKey = key; + +                    if( (MASK_CONTROL|MASK_ALT)&mKeyModifiers ) +                        gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); +                    else +                        handleUnicodeUTF16( key, mKeyModifiers ); +                }                  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)); -		    } +                mKeyVirtualKey = event.key.keysym.sym; +                mKeyModifiers = event.key.keysym.mod; +                mInputType = "keydown"; + +                // treat all possible Enter/Return keys the same +                if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) +                { +                    mKeyVirtualKey = SDLK_RETURN; +                } + +                gKeyboard->handleKeyDown(mKeyVirtualKey, mKeyModifiers ); + +                // <FS:ND> Slightly hacky :| To make the viewer honor enter (eg to accept form input) we've to not only send handleKeyDown but also send a +                // invoke handleUnicodeUTF16 in case the user hits return. +                // Note that we cannot blindly use handleUnicodeUTF16 for each SDL_KEYDOWN. Doing so will create bogus keyboard input (like % for cursor left). +                if( mKeyVirtualKey == SDLK_RETURN ) +                { +                    // fix return key not working when capslock, scrolllock or numlock are enabled +                    mKeyModifiers &= (~(KMOD_NUM | KMOD_CAPS | KMOD_MODE | KMOD_SCROLL)); +                    handleUnicodeUTF16( mKeyVirtualKey, mKeyModifiers ); +                } + +                // part of the fix for SL-13243 +                if (SDLCheckGrabbyKeys(event.key.keysym.sym, TRUE) != 0) +                    SDLReallyCaptureInput(TRUE); +                  break;              case SDL_KEYUP: -		    mKeyScanCode = event.key.keysym.scancode; -		    mKeyVirtualKey = event.key.keysym.unicode; -		    mKeyModifiers = event.key.keysym.mod; +                mKeyVirtualKey = event.key.keysym.sym; +                mKeyModifiers = event.key.keysym.mod; +                mInputType = "keyup"; + +                // treat all possible Enter/Return keys the same +                if (mKeyVirtualKey == SDLK_RETURN2 || mKeyVirtualKey == SDLK_KP_ENTER) +                { +                    mKeyVirtualKey = SDLK_RETURN; +                } -		    if (SDLCheckGrabbyKeys(event.key.keysym.sym, FALSE) == 0) -			    SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 +                if (SDLCheckGrabbyKeys(mKeyVirtualKey, FALSE) == 0) +                    SDLReallyCaptureInput(FALSE); // part of the fix for SL-13243 -		    gKeyboard->handleKeyUp(event.key.keysym.sym, event.key.keysym.mod); -		    break; +                gKeyboard->handleKeyUp(mKeyVirtualKey,mKeyModifiers); +                break;              case SDL_MOUSEBUTTONDOWN:              { @@ -1787,7 +1851,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...                  { @@ -1799,7 +1863,7 @@ void LLWindowSDL::gatherInput()                          if (++leftClick >= 2)                          {                              leftClick = 0; -			    isDoubleClick = true; +                            isDoubleClick = true;                          }                      }                      lastLeftDown = now; @@ -1814,7 +1878,7 @@ void LLWindowSDL::gatherInput()                          if (++rightClick >= 2)                          {                              rightClick = 0; -    					    isDoubleClick = true; +                            isDoubleClick = true;                          }                      }                      lastRightDown = now; @@ -1823,24 +1887,24 @@ void LLWindowSDL::gatherInput()                  if (event.button.button == SDL_BUTTON_LEFT)  // left                  {                      if (isDoubleClick) -				        mCallbacks->handleDoubleClick(this, openGlCoord, mask); +                        mCallbacks->handleDoubleClick(this, openGlCoord, mask);                      else -    				    mCallbacks->handleMouseDown(this, openGlCoord, mask); +                        mCallbacks->handleMouseDown(this, openGlCoord, mask);                  }                  else if (event.button.button == SDL_BUTTON_RIGHT)  // right                  { -			mCallbacks->handleRightMouseDown(this, openGlCoord, mask); +                    mCallbacks->handleRightMouseDown(this, openGlCoord, mask);                  }                  else if (event.button.button == SDL_BUTTON_MIDDLE)  // middle -				{ -				    mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); -				} +                { +                    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); +                    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); +                    mCallbacks->handleScrollWheel(this, 1);                  break;              } @@ -1850,365 +1914,346 @@ 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); +                    mCallbacks->handleMouseUp(this, openGlCoord, mask);                  else if (event.button.button == SDL_BUTTON_RIGHT)  // right -			mCallbacks->handleRightMouseUp(this, openGlCoord, mask); +                    mCallbacks->handleRightMouseUp(this, openGlCoord, mask);                  else if (event.button.button == SDL_BUTTON_MIDDLE)  // middle -			mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); +                    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? +            case SDL_WINDOWEVENT:  // *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; -		} +                if( event.window.event == SDL_WINDOWEVENT_RESIZED +                    /* || event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED*/ ) // <FS:ND> SDL_WINDOWEVENT_SIZE_CHANGED is followed by SDL_WINDOWEVENT_RESIZED, so handling one shall be enough +                { +                    LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; -		mCallbacks->handleResize(this, width, height); -                break; -            } -            case SDL_ACTIVEEVENT: -                if (event.active.state & SDL_APPINPUTFOCUS) +                    S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); +                    S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); +                    mSurface = SDL_GetWindowSurface( mWindow ); + +                    // *FIX: I'm not sure this is necessary! +                    // <FS:ND> I think is is not +                    // SDL_SetWindowSize(mWindow, width, height); +                    // + +                    mCallbacks->handleResize(this, width, height); +                } +                else if( event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ) // <FS:ND> What about SDL_WINDOWEVENT_ENTER (mouse focus)                  { -			// 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); -			} +                    // 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]. +                    mHaveInputFocus = true; + +                    mCallbacks->handleFocus(this);                  } -                if (event.active.state & SDL_APPACTIVE) +                else if( event.window.event == SDL_WINDOWEVENT_FOCUS_LOST ) // <FS:ND> What about SDL_WINDOWEVENT_LEAVE (mouse focus)                  { -			// 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; -			} +                    // 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]. +                    mHaveInputFocus = false; + +                    mCallbacks->handleFocusLost(this);                  } -                break; +                else if( event.window.event == SDL_WINDOWEVENT_MINIMIZED || +                         event.window.event == SDL_WINDOWEVENT_MAXIMIZED || +                         event.window.event == SDL_WINDOWEVENT_RESTORED || +                         event.window.event == SDL_WINDOWEVENT_EXPOSED || +                         event.window.event == SDL_WINDOWEVENT_SHOWN ) +                { +                    mIsMinimized = (event.window.event == SDL_WINDOWEVENT_MINIMIZED); +                    mCallbacks->handleActivate(this, !mIsMinimized); +                    LL_INFOS() << "SDL deiconification state switched to " << mIsMinimized << 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 -    			} +                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; -	default: -		//LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; -		break;          }      } -	 -	updateCursor(); + +    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; +        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; i<cursurface->h; ++i) { -				for (j=0; j<cursurface->w; ++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; +    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; i<cursurface->h; ++i) { +                for (j=0; j<cursurface->w; ++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; -	} +    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; i<UI_CURSOR_COUNT; ++i) -	{ -		mSDLCursors[i] = NULL; -	} -	// Pre-make an SDL cursor for each of the known cursor types. -	// We hardcode the hotspots - to avoid that we'd have to write -	// a .cur file loader. -	// NOTE: SDL doesn't load RLE-compressed BMP files. -	mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0); -	mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15); -	mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10); -	mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16); -	mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14); -	mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17); -	mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17); -	mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14); -	mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16); +    int i; +    // Blank the cursor pointer array for those we may miss. +    for (i=0; i<UI_CURSOR_COUNT; ++i) +    { +        mSDLCursors[i] = NULL; +    } +    // Pre-make an SDL cursor for each of the known cursor types. +    // We hardcode the hotspots - to avoid that we'd have to write +    // a .cur file loader. +    // NOTE: SDL doesn't load RLE-compressed BMP files. +    mSDLCursors[UI_CURSOR_ARROW] = makeSDLCursorFromBMP("llarrow.BMP",0,0); +    mSDLCursors[UI_CURSOR_WAIT] = makeSDLCursorFromBMP("wait.BMP",12,15); +    mSDLCursors[UI_CURSOR_HAND] = makeSDLCursorFromBMP("hand.BMP",7,10); +    mSDLCursors[UI_CURSOR_IBEAM] = makeSDLCursorFromBMP("ibeam.BMP",15,16); +    mSDLCursors[UI_CURSOR_CROSS] = makeSDLCursorFromBMP("cross.BMP",16,14); +    mSDLCursors[UI_CURSOR_SIZENWSE] = makeSDLCursorFromBMP("sizenwse.BMP",14,17); +    mSDLCursors[UI_CURSOR_SIZENESW] = makeSDLCursorFromBMP("sizenesw.BMP",17,17); +    mSDLCursors[UI_CURSOR_SIZEWE] = makeSDLCursorFromBMP("sizewe.BMP",16,14); +    mSDLCursors[UI_CURSOR_SIZENS] = makeSDLCursorFromBMP("sizens.BMP",17,16);      mSDLCursors[UI_CURSOR_SIZEALL] = makeSDLCursorFromBMP("sizeall.BMP", 17, 17); -	mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8); -	mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15); -	mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13); -	mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6); -	mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5); -	mSDLCursors[UI_CURSOR_TOOLCREATE] = makeSDLCursorFromBMP("lltoolcreate.BMP",7,7); -	mSDLCursors[UI_CURSOR_ARROWDRAG] = makeSDLCursorFromBMP("arrowdrag.BMP",0,0); -	mSDLCursors[UI_CURSOR_ARROWCOPY] = makeSDLCursorFromBMP("arrowcop.BMP",0,0); -	mSDLCursors[UI_CURSOR_ARROWDRAGMULTI] = makeSDLCursorFromBMP("llarrowdragmulti.BMP",0,0); -	mSDLCursors[UI_CURSOR_ARROWCOPYMULTI] = makeSDLCursorFromBMP("arrowcopmulti.BMP",0,0); -	mSDLCursors[UI_CURSOR_NOLOCKED] = makeSDLCursorFromBMP("llnolocked.BMP",8,8); -	mSDLCursors[UI_CURSOR_ARROWLOCKED] = makeSDLCursorFromBMP("llarrowlocked.BMP",0,0); -	mSDLCursors[UI_CURSOR_GRABLOCKED] = makeSDLCursorFromBMP("llgrablocked.BMP",2,13); -	mSDLCursors[UI_CURSOR_TOOLTRANSLATE] = makeSDLCursorFromBMP("lltooltranslate.BMP",0,0); -	mSDLCursors[UI_CURSOR_TOOLROTATE] = makeSDLCursorFromBMP("lltoolrotate.BMP",0,0); -	mSDLCursors[UI_CURSOR_TOOLSCALE] = makeSDLCursorFromBMP("lltoolscale.BMP",0,0); -	mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5); -	mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5); -	mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5); +    mSDLCursors[UI_CURSOR_NO] = makeSDLCursorFromBMP("llno.BMP",8,8); +    mSDLCursors[UI_CURSOR_WORKING] = makeSDLCursorFromBMP("working.BMP",12,15); +    mSDLCursors[UI_CURSOR_TOOLGRAB] = makeSDLCursorFromBMP("lltoolgrab.BMP",2,13); +    mSDLCursors[UI_CURSOR_TOOLLAND] = makeSDLCursorFromBMP("lltoolland.BMP",1,6); +    mSDLCursors[UI_CURSOR_TOOLFOCUS] = makeSDLCursorFromBMP("lltoolfocus.BMP",8,5); +    mSDLCursors[UI_CURSOR_TOOLCREATE] = makeSDLCursorFromBMP("lltoolcreate.BMP",7,7); +    mSDLCursors[UI_CURSOR_ARROWDRAG] = makeSDLCursorFromBMP("arrowdrag.BMP",0,0); +    mSDLCursors[UI_CURSOR_ARROWCOPY] = makeSDLCursorFromBMP("arrowcop.BMP",0,0); +    mSDLCursors[UI_CURSOR_ARROWDRAGMULTI] = makeSDLCursorFromBMP("llarrowdragmulti.BMP",0,0); +    mSDLCursors[UI_CURSOR_ARROWCOPYMULTI] = makeSDLCursorFromBMP("arrowcopmulti.BMP",0,0); +    mSDLCursors[UI_CURSOR_NOLOCKED] = makeSDLCursorFromBMP("llnolocked.BMP",8,8); +    mSDLCursors[UI_CURSOR_ARROWLOCKED] = makeSDLCursorFromBMP("llarrowlocked.BMP",0,0); +    mSDLCursors[UI_CURSOR_GRABLOCKED] = makeSDLCursorFromBMP("llgrablocked.BMP",2,13); +    mSDLCursors[UI_CURSOR_TOOLTRANSLATE] = makeSDLCursorFromBMP("lltooltranslate.BMP",0,0); +    mSDLCursors[UI_CURSOR_TOOLROTATE] = makeSDLCursorFromBMP("lltoolrotate.BMP",0,0); +    mSDLCursors[UI_CURSOR_TOOLSCALE] = makeSDLCursorFromBMP("lltoolscale.BMP",0,0); +    mSDLCursors[UI_CURSOR_TOOLCAMERA] = makeSDLCursorFromBMP("lltoolcamera.BMP",7,5); +    mSDLCursors[UI_CURSOR_TOOLPAN] = makeSDLCursorFromBMP("lltoolpan.BMP",7,5); +    mSDLCursors[UI_CURSOR_TOOLZOOMIN] = makeSDLCursorFromBMP("lltoolzoomin.BMP",7,5);      mSDLCursors[UI_CURSOR_TOOLZOOMOUT] = makeSDLCursorFromBMP("lltoolzoomout.BMP", 7, 5); -	mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0); -	mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0); -	mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0); -	mSDLCursors[UI_CURSOR_TOOLMEDIAOPEN] = makeSDLCursorFromBMP("toolmediaopen.BMP",0,0); -	mSDLCursors[UI_CURSOR_PIPETTE] = makeSDLCursorFromBMP("lltoolpipette.BMP",2,28); -	mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",20,15); -	mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); -	mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",20,15); -	mSDLCursors[UI_CURSOR_TOOLPATHFINDING] = makeSDLCursorFromBMP("lltoolpathfinding.BMP", 16, 16); -	mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START] = makeSDLCursorFromBMP("lltoolpathfindingpathstart.BMP", 16, 16); -	mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathstartadd.BMP", 16, 16); -	mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END] = makeSDLCursorFromBMP("lltoolpathfindingpathend.BMP", 16, 16); -	mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathendadd.BMP", 16, 16); -	mSDLCursors[UI_CURSOR_TOOLNO] = makeSDLCursorFromBMP("llno.BMP",8,8); - -	if (getenv("LL_ATI_MOUSE_CURSOR_BUG") != NULL) { -		LL_INFOS() << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << LL_ENDL; -		ATIbug = true; -	} +    mSDLCursors[UI_CURSOR_TOOLPICKOBJECT3] = makeSDLCursorFromBMP("toolpickobject3.BMP",0,0); +    mSDLCursors[UI_CURSOR_TOOLPLAY] = makeSDLCursorFromBMP("toolplay.BMP",0,0); +    mSDLCursors[UI_CURSOR_TOOLPAUSE] = makeSDLCursorFromBMP("toolpause.BMP",0,0); +    mSDLCursors[UI_CURSOR_TOOLMEDIAOPEN] = makeSDLCursorFromBMP("toolmediaopen.BMP",0,0); +    mSDLCursors[UI_CURSOR_PIPETTE] = makeSDLCursorFromBMP("lltoolpipette.BMP",2,28); +    mSDLCursors[UI_CURSOR_TOOLSIT] = makeSDLCursorFromBMP("toolsit.BMP",20,15); +    mSDLCursors[UI_CURSOR_TOOLBUY] = makeSDLCursorFromBMP("toolbuy.BMP",20,15); +    mSDLCursors[UI_CURSOR_TOOLOPEN] = makeSDLCursorFromBMP("toolopen.BMP",20,15); +    mSDLCursors[UI_CURSOR_TOOLPATHFINDING] = makeSDLCursorFromBMP("lltoolpathfinding.BMP", 16, 16); +    mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START] = makeSDLCursorFromBMP("lltoolpathfindingpathstart.BMP", 16, 16); +    mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathstartadd.BMP", 16, 16); +    mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END] = makeSDLCursorFromBMP("lltoolpathfindingpathend.BMP", 16, 16); +    mSDLCursors[UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD] = makeSDLCursorFromBMP("lltoolpathfindingpathendadd.BMP", 16, 16); +    mSDLCursors[UI_CURSOR_TOOLNO] = makeSDLCursorFromBMP("llno.BMP",8,8); + +    if (getenv("LL_ATI_MOUSE_CURSOR_BUG") != NULL) { +        LL_INFOS() << "Disabling cursor updating due to LL_ATI_MOUSE_CURSOR_BUG" << LL_ENDL; +        ATIbug = true; +    }  }  void LLWindowSDL::quitCursors()  { -	int i; -	if (mWindow) -	{ -		for (i=0; i<UI_CURSOR_COUNT; ++i) -		{ -			if (mSDLCursors[i]) -			{ -				SDL_FreeCursor(mSDLCursors[i]); -				mSDLCursors[i] = NULL; -			} -		} -	} else { -		// SDL doesn't refcount cursors, so if the window has -		// already been destroyed then the cursors have gone with it. -		LL_INFOS() << "Skipping quitCursors: mWindow already gone." << LL_ENDL; -		for (i=0; i<UI_CURSOR_COUNT; ++i) -			mSDLCursors[i] = NULL; -	} +    int i; +    if (mWindow) +    { +        for (i=0; i<UI_CURSOR_COUNT; ++i) +        { +            if (mSDLCursors[i]) +            { +                SDL_FreeCursor(mSDLCursors[i]); +                mSDLCursors[i] = NULL; +            } +        } +    } else { +        // SDL doesn't refcount cursors, so if the window has +        // already been destroyed then the cursors have gone with it. +        LL_INFOS() << "Skipping quitCursors: mWindow already gone." << LL_ENDL; +        for (i=0; i<UI_CURSOR_COUNT; ++i) +            mSDLCursors[i] = NULL; +    }  }  void LLWindowSDL::captureMouse()  { -	// SDL already enforces the semantics that captureMouse is -	// used for, i.e. that we continue to get mouse events as long -	// as a button is down regardless of whether we left the -	// window, and in a less obnoxious way than SDL_WM_GrabInput	 -	// which would confine the cursor to the window too. +    // SDL already enforces the semantics that captureMouse is +    // used for, i.e. that we continue to get mouse events as long +    // as a button is down regardless of whether we left the +    // window, and in a less obnoxious way than SDL_WM_GrabInput +    // which would confine the cursor to the window too. -	LL_DEBUGS() << "LLWindowSDL::captureMouse" << LL_ENDL; +    LL_DEBUGS() << "LLWindowSDL::captureMouse" << LL_ENDL;  }  void LLWindowSDL::releaseMouse()  { -	// see LWindowSDL::captureMouse() -	 -	LL_DEBUGS() << "LLWindowSDL::releaseMouse" << LL_ENDL; +    // see LWindowSDL::captureMouse() + +    LL_DEBUGS() << "LLWindowSDL::releaseMouse" << LL_ENDL;  }  void LLWindowSDL::hideCursor()  { -	if(!mCursorHidden) -	{ -		// LL_INFOS() << "hideCursor: hiding" << LL_ENDL; -		mCursorHidden = TRUE; -		mHideCursorPermanent = TRUE; -		SDL_ShowCursor(0); -	} -	else -	{ -		// LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; -	} +    if(!mCursorHidden) +    { +        // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; +        mCursorHidden = TRUE; +        mHideCursorPermanent = TRUE; +        SDL_ShowCursor(0); +    } +    else +    { +        // LL_INFOS() << "hideCursor: already hidden" << LL_ENDL; +    }  }  void LLWindowSDL::showCursor()  { -	if(mCursorHidden) -	{ -		// LL_INFOS() << "showCursor: showing" << LL_ENDL; -		mCursorHidden = FALSE; -		mHideCursorPermanent = FALSE; -		SDL_ShowCursor(1); -	} -	else -	{ -		// LL_INFOS() << "showCursor: already visible" << LL_ENDL; -	} +    if(mCursorHidden) +    { +        // LL_INFOS() << "showCursor: showing" << LL_ENDL; +        mCursorHidden = FALSE; +        mHideCursorPermanent = FALSE; +        SDL_ShowCursor(1); +    } +    else +    { +        // LL_INFOS() << "showCursor: already visible" << LL_ENDL; +    }  }  void LLWindowSDL::showCursorFromMouseMove()  { -	if (!mHideCursorPermanent) -	{ -		showCursor(); -	} +    if (!mHideCursorPermanent) +    { +        showCursor(); +    }  }  void LLWindowSDL::hideCursorUntilMouseMove()  { -	if (!mHideCursorPermanent) -	{ -		hideCursor(); -		mHideCursorPermanent = FALSE; -	} +    if (!mHideCursorPermanent) +    { +        hideCursor(); +        mHideCursorPermanent = FALSE; +    }  } - -  //  // LLSplashScreenSDL - I don't think we'll bother to implement this; it's  // fairly obsolete at this point. @@ -2233,272 +2278,128 @@ void LLSplashScreenSDL::hideImpl()  {  } +S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) +{ +    SDL_MessageBoxData oData = { SDL_MESSAGEBOX_INFORMATION, nullptr, caption.c_str(), text.c_str(), 0, nullptr, nullptr }; +    SDL_MessageBoxButtonData btnOk[] = {{SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_OK, "OK" }}; +    SDL_MessageBoxButtonData btnOkCancel [] =  {{SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_OK, "OK" }, {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, OSBTN_CANCEL, "Cancel"} }; +    SDL_MessageBoxButtonData btnYesNo[] = { {SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, OSBTN_YES, "Yes" }, {SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, OSBTN_NO, "No"} }; +    switch (type) +    { +        default: +        case OSMB_OK: +            oData.flags = SDL_MESSAGEBOX_WARNING; +            oData.buttons = btnOk; +            oData.numbuttons = 1; +            break; +        case OSMB_OKCANCEL: +            oData.flags = SDL_MESSAGEBOX_INFORMATION; +            oData.buttons = btnOkCancel; +            oData.numbuttons = 2; +            break; +        case OSMB_YESNO: +            oData.flags = SDL_MESSAGEBOX_INFORMATION; +            oData.buttons = btnYesNo; +            oData.numbuttons = 2; +            break; +    } -#if LL_GTK -static void response_callback (GtkDialog *dialog, -			       gint       arg1, -			       gpointer   user_data) -{ -	gint *response = (gint*)user_data; -	*response = arg1; -	gtk_widget_destroy(GTK_WIDGET(dialog)); -	gtk_main_quit(); +    int btn{0}; +    if( 0 == SDL_ShowMessageBox( &oData, &btn ) ) +        return btn; +    return OSBTN_CANCEL;  } -S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type) +BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b)  { -	S32 rtn = OSBTN_CANCEL; - -	if(gWindowImplementation != NULL) -		gWindowImplementation->beforeDialog(); - -	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); +    return (FALSE);  } -  /*          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(); +    LLSD result = LLSD::emptyMap(); -	if (ll_try_gtk_init()) -	{ -		GtkWidget *win = NULL; +    U32 modifiers = 0; // pretend-native modifiers... oh what a tangled web we weave! -		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; -} +    // 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). -BOOL LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) -{ -	return (FALSE); +    result["virtual_key"] = (S32)mKeyVirtualKey; +    result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey ); +    result["modifiers"] = (S32)modifiers; +    result["input_type"] = mInputType; +    return result;  } -#endif // LL_GTK -#if LL_LINUX +#if LL_LINUX || LL_SOLARIS  // 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; -		} -	} +    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); +        // <FS:TS> Reopen stdin, stdout, and stderr to /dev/null. +        //         It's good practice to always have those file +        //         descriptors open to something, lest the exec'd +        //         program actually try to use them. +        FILE *result; +        result = freopen("/dev/null","r",stdin); +        if (result == NULL) +        { +            LL_WARNS() << "Error reopening stdin for web browser: " +                       << strerror(errno) << LL_ENDL; +        } +        result = freopen("/dev/null","w",stdout); +        if (result == NULL) +        { +            LL_WARNS() << "Error reopening stdout for web browser: " +                       << strerror(errno) << LL_ENDL; +        } +        result = freopen("/dev/null","w",stderr); +        if (result == NULL) +        { +            LL_WARNS() << "Error reopening stderr for web browser: " +                       << strerror(errno) << LL_ENDL; +        } +        // 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 @@ -2506,192 +2407,215 @@ void exec_cmd(const std::string& cmd, const std::string& arg)  // 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; -	 +    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(); -	} +    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); +    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; +    LL_INFOS() << "spawn_web_browser returning." << LL_ENDL;  } +void LLWindowSDL::openFile(const std::string& file_name) +{ +    spawnWebBrowser("file://"+file_name,TRUE); +}  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; +    return NULL;  }  void LLWindowSDL::bringToFront()  { -	// This is currently used when we are 'launched' to a specific -	// map position externally. -	LL_INFOS() << "bringToFront" << LL_ENDL; +    // 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(); -	} +    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<std::string> 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<std::string> 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; i<fs->nfont; ++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<std::string>::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 +    // 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<std::string> 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; i<fs->nfont; ++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<std::string>::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; +} + + +void* LLWindowSDL::createSharedContext() +{ +    auto *pContext = SDL_GL_CreateContext(mWindow); +    if ( pContext) +    { +        SDL_GL_SetSwapInterval(0); +        SDL_GL_MakeCurrent(mWindow, mContext); + +        LLCoordScreen size; +        if (getSize(&size)) +            setSize(size); + +        LL_DEBUGS() << "Creating shared OpenGL context successful!" << LL_ENDL; + +        return (void*)pContext; +    } + +    LL_WARNS() << "Creating shared OpenGL context failed!" << LL_ENDL; + +    return nullptr; +} + +void LLWindowSDL::makeContextCurrent(void* contextPtr) +{ +    LL_PROFILER_GPU_CONTEXT; +    SDL_GL_MakeCurrent( mWindow, contextPtr ); +} + +void LLWindowSDL::destroySharedContext(void* contextPtr) +{ +    SDL_GL_DeleteContext( contextPtr ); +} + +void LLWindowSDL::toggleVSync(bool enable_vsync) +{ +} + +U32 LLWindowSDL::getAvailableVRAMMegabytes() +{ +    return 4096; +} diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index 7193e6f45a..74b9ff026c 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -1,43 +1,43 @@ -/**  +/**   * @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 +#ifndef LL_LLWINDOWSDL2_H +#define LL_LLWINDOWSDL2_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" +#include "SDL2/SDL.h" +#include "SDL2/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" +#include "SDL2/SDL_syswm.h"  #endif  // AssertMacros.h does bad things. @@ -46,184 +46,295 @@  #undef require -class LLWindowSDL : public LLWindow -{ +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<std::string> 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. +    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 disable_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; + +    void captureMouse() override; + +    void releaseMouse() override; + +    void setMouseClipping(BOOL b) override; + +       void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true) override; + +    BOOL isClipboardTextAvailable() override; + +    BOOL pasteTextFromClipboard(LLWString &dst) override; + +    BOOL copyTextToClipboard(const LLWString &src) override; + +    BOOL isPrimaryTextAvailable() override; + +    BOOL pasteTextFromPrimary(LLWString &dst) override; + +    BOOL copyTextToPrimary(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 samples) override; + +    BOOL restoreGamma() override;            // Restore original gamma table (before updating gamma) +    ESwapMethod getSwapMethod()  override { return mSwapMethod; } + +    void processMiscNativeEvents() override; + +    void gatherInput() override; + +    void swapBuffers() override; + +    void restoreGLContext() {}; + +    void delayInputProcessing()  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; } + +    void beforeDialog() override; + +    void afterDialog() override; + +    BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; + +    void *getPlatformWindow() override; + +    void bringToFront() override; + +    void spawnWebBrowser(const std::string &escaped_url, bool async) override; + +    void openFile(const std::string &file_name); + +    void setTitle(const std::string title) override; + +    static std::vector<std::string> 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; +    Window mSDL_XWindowID; +    Display *mSDL_Display;  #endif -	void (*Lock_Display)(void); -	void (*Unlock_Display)(void); + +    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); +    // 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	 + +    static Window get_SDL_XWindowID(void); + +    static Display *get_SDL_Display(void); + +#endif // LL_X11 + +    void *createSharedContext() override; + +    void makeContextCurrent(void *context) override; + +    void destroySharedContext(void *context) override; + +    void toggleVSync(bool enable_vsync) override; + +    U32 getAvailableVRAMMegabytes() override;  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(); +    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(); +    BOOL isValid() override; -	void	initCursors(); -	void	quitCursors(); -	void	moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); +    LLSD getNativeKeyData() override; -	// Changes display resolution. Returns true if successful -	BOOL	setDisplayResolution(S32 width, S32 height, S32 bits, S32 refresh); +    void initCursors(); -	// Go back to last fullscreen display resolution. -	BOOL	setFullscreenResolution(); +    void quitCursors(); -	BOOL	shouldPostQuit() { return mPostQuit; } +    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; +    // +    // 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(U32 keysym, BOOL gain); + +    BOOL SDLReallyCaptureInput(BOOL capture); + +    // +    // Platform specific variables +    // +    U32 mGrabbyKeyFlags; +    int mReallyCapturedCount; + +    SDL_Window *mWindow; +    SDL_Surface *mSurface; +    SDL_GLContext mContext; +    SDL_Cursor *mSDLCursors[UI_CURSOR_COUNT]; + +    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; + +    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; + +    void x11_set_urgent(BOOL urgent); + +    BOOL mFlashing; +    LLTimer mFlashTimer;  #endif //LL_X11 -	 -	U32 mKeyScanCode; -        U32 mKeyVirtualKey; -	SDLMod mKeyModifiers; -}; +    U32 mKeyVirtualKey; +    U32 mKeyModifiers; +    std::string mInputType; + +public: +#if LL_X11 + +    static Display *getSDLDisplay(); + +    LLWString const &getPrimaryText() const { return mPrimaryClipboard; } + +    LLWString const &getSecondaryText() const { return mSecondaryClipboard; } + +    void clearPrimaryText() { mPrimaryClipboard.clear(); } + +    void clearSecondaryText() { mSecondaryClipboard.clear(); } + +private: +    void tryFindFullscreenSize(int &aWidth, int &aHeight); + +    void initialiseX11Clipboard(); + +    bool getSelectionText(Atom selection, LLWString &text); + +    bool getSelectionText(Atom selection, Atom type, LLWString &text); + +    bool setSelectionText(Atom selection, const LLWString &text); + +#endif +    LLWString mPrimaryClipboard; +    LLWString mSecondaryClipboard; +};  class LLSplashScreenSDL : public LLSplashScreen  {  public: -	LLSplashScreenSDL(); -	virtual ~LLSplashScreenSDL(); +    LLSplashScreenSDL(); +    virtual ~LLSplashScreenSDL(); -	/*virtual*/ void showImpl(); -	/*virtual*/ void updateImpl(const std::string& mesg); -	/*virtual*/ void hideImpl(); +    void showImpl(); +    void updateImpl(const std::string& mesg); +    void hideImpl();  };  S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 type); | 
