diff options
Diffstat (limited to 'indra/llwindow/llwindowsdl.cpp')
-rw-r--r-- | indra/llwindow/llwindowsdl.cpp | 1937 |
1 files changed, 542 insertions, 1395 deletions
diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index 8c90f917b8..8fddbf05e2 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -37,6 +37,7 @@ #include "llstring.h" #include "lldir.h" #include "llfindlocale.h" +#include "llgamecontrol.h" #ifdef LL_GLIB #include <glib.h> @@ -49,397 +50,209 @@ extern "C" { #if LL_LINUX || __FreeBSD__ // not necessarily available on random SDL platforms, so #if LL_LINUX // for execv(), waitpid(), fork() -# include <unistd.h> -# include <sys/types.h> -# include <sys/wait.h> -# define GLX_GLXEXT_PROTOTYPES 1 -# include <GL/glx.h> -# include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdio.h> #endif // LL_LINUX extern bool gDebugWindowProc; const S32 MAX_NUM_RESOLUTIONS = 200; -// static variable for ATI mouse cursor crash work-around: -static bool ATIbug = false; - -#if LL_DARWIN - -#include <OpenGL/OpenGL.h> -#include <CoreGraphics/CGDirectDisplay.h> -#include <CoreServices/CoreServices.h> - -bool gHiDPISupport = true; - -namespace -{ - struct NativeKeyEventData { - enum EventType { - KEYUNKNOWN, - KEYUP, - KEYDOWN, - KEYCHAR - }; - - EventType mKeyEvent = KEYUNKNOWN; - uint32_t mEventType = 0; - uint32_t mEventModifiers = 0; - uint32_t mEventKeyCode = 0; - uint32_t mEventChars = 0; - uint32_t mEventUnmodChars = 0; - bool mEventRepeat = false; - } *mRawKeyEvent = NULL; -} -// -// LLWindowMacOSX -// - -bool LLWindowSDL::sUseMultGL = false; - -#endif - -bool hasHIDPI = 0; - // // LLWindowSDL // -#if LL_X11 -# include <X11/Xutil.h> -#endif //LL_X11 +#include <X11/Xutil.h> // TOFU HACK -- (*exactly* the same hack as LLWindowMacOSX for a similar // set of reasons): Stash a pointer to the LLWindowSDL object here and // maintain in the constructor and destructor. This assumes that there will // be only one object of this class at any time. Currently this is true. -static LLWindowSDL *gWindowImplementation = NULL; - +static LLWindowSDL *gWindowImplementation = nullptr; void maybe_lock_display(void) { - if (gWindowImplementation && gWindowImplementation->Lock_Display) { + if (gWindowImplementation && gWindowImplementation->Lock_Display) gWindowImplementation->Lock_Display(); - } } - void maybe_unlock_display(void) { - if (gWindowImplementation && gWindowImplementation->Unlock_Display) { + if (gWindowImplementation && gWindowImplementation->Unlock_Display) gWindowImplementation->Unlock_Display(); - } } -#if LL_X11 -// static Window LLWindowSDL::get_SDL_XWindowID(void) { - if (gWindowImplementation) { - return gWindowImplementation->mSDL_XWindowID; - } + if (gWindowImplementation) + return gWindowImplementation->mX11Data.mXWindowID; return None; } -//static Display* LLWindowSDL::get_SDL_Display(void) { - if (gWindowImplementation) { - return gWindowImplementation->mSDL_Display; - } - return NULL; + if (gWindowImplementation) + return gWindowImplementation->mX11Data.mDisplay; + return nullptr; } -#endif // LL_X11 -#if LL_X11 - -// Clipboard handing via native X11, base on the implementation in Cool VL by Henri Beauchamp +/* + * In wayland a window does not have a state of "minimized" or gets messages that it got minimized [1] + * There's two ways to approach this challenge: + * 1) Ignore it, this would mean even if minimized/not visible the viewer will always fun at full fps + * 2) Try to detect something like "minimized", the best way I found so far is to as for frame_done events. Those will + * only happen if parts of the viewer are visible. As such it is not the same a "minimized" but rather "this window + * is not fully hidden behind another window or minimized". That's (I guess) still better than nothing and running + * full tilt even if hidden. + * + * [1] As of 2024-09, maybe in the future we get nice things +*/ +#ifdef LL_WAYLAND +#include <wayland-client-protocol.h> +#include <dlfcn.h> -namespace +bool LLWindowSDL::isWaylandWindowNotDrawing() const { - 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; + if( Wayland != mServerProtocol || mWaylandData.mLastFrameEvent == 0 ) + return false; - maybe_lock_display(); + auto currentTime = LLTimer::getTotalTime(); + if( (currentTime - mWaylandData.mLastFrameEvent) > 250000 ) + return true; - XDeleteProperty(display, window, PVT_PASTE_BUFFER); - XFlush(display); + return false; +} - XConvertSelection(display, selection, target, PVT_PASTE_BUFFER, window, CurrentTime); +uint32_t (*ll_wl_proxy_get_version)(struct wl_proxy *proxy); +void (*ll_wl_proxy_destroy)(struct wl_proxy *proxy); +int (*ll_wl_proxy_add_listener)(struct wl_proxy *proxy, void (**implementation)(void), void *data); - // Unlock the connection so that the SDL event loop may function - maybe_unlock_display(); +wl_interface *ll_wl_callback_interface; - const auto start{ SDL_GetTicks() }; - const auto end{ start + 1000 }; +int ll_wl_callback_add_listener(struct wl_callback *wl_callback, + const struct wl_callback_listener *listener, void *data) +{ + return ll_wl_proxy_add_listener((struct wl_proxy *) wl_callback, + (void (**)(void)) listener, data); +} - XEvent xevent {}; - bool response = false; +struct wl_proxy* (*ll_wl_proxy_marshal_flags)(struct wl_proxy *proxy, uint32_t opcode, + const struct wl_interface *interface, + uint32_t version, + uint32_t flags, ...); - do - { - SDL_Event event {}; - // Wait for an event - SDL_WaitEvent(&event); +bool loadWaylandClient() +{ + auto *pSO = dlopen( "libwayland-client.so.0", RTLD_NOW); + if( !pSO ) + return false; - // 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 ); + ll_wl_callback_interface = (wl_interface*)dlsym(pSO, "wl_callback_interface"); + *(void**)&ll_wl_proxy_marshal_flags = dlsym(pSO, "wl_proxy_marshal_flags"); + *(void**)&ll_wl_proxy_get_version = dlsym(pSO, "wl_proxy_get_version"); + *(void**)&ll_wl_proxy_destroy = dlsym(pSO, "wl_proxy_destroy"); + *(void**)&ll_wl_proxy_add_listener = dlsym(pSO, "wl_proxy_add_listener"); - return response && xevent.xselection.property != None; - } + return ll_wl_callback_interface != nullptr && ll_wl_proxy_marshal_flags != nullptr && + ll_wl_proxy_get_version != nullptr && ll_wl_proxy_destroy != nullptr && + ll_wl_proxy_add_listener != nullptr; } -void LLWindowSDL::initialiseX11Clipboard() +struct wl_callback* ll_wl_surface_frame(struct wl_surface *wl_surface) { - 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); + auto version = ll_wl_proxy_get_version((struct wl_proxy *) wl_surface); - gSupportedAtoms[0] = XInternAtom(mSDL_Display, "UTF8_STRING", False); - gSupportedAtoms[1] = XInternAtom(mSDL_Display, "COMPOUND_TEXT", False); - gSupportedAtoms[2] = XA_STRING; + auto callback = ll_wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_FRAME, ll_wl_callback_interface, version, + 0, nullptr); - // 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(); + return (struct wl_callback *) callback; } -bool LLWindowSDL::getSelectionText( Atom aSelection, Atom aType, LLWString &text ) +void ll_wl_callback_destroy(struct wl_callback *wl_callback) { - 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; + ll_wl_proxy_destroy((struct wl_proxy *) wl_callback); } -bool LLWindowSDL::getSelectionText(Atom selection, LLWString& text) +void LLWindowSDL::waylandFrameDoneCB(void *data, struct wl_callback *cb, uint32_t time) { - if (!mSDL_Display) - return false; + static uint32_t frame_count {0}; + static F64SecondsImplicit lastInfo{0}; - maybe_lock_display(); + ++frame_count; + + ll_wl_callback_destroy(cb); + auto pThis = reinterpret_cast<LLWindowSDL*>(data); + pThis->mWaylandData.mLastFrameEvent = LLTimer::getTotalTime(); - Window owner = XGetSelectionOwner(mSDL_Display, selection); - if (owner == None) + auto now = LLTimer::getElapsedSeconds(); + if( lastInfo > 0) { - if (selection == XA_PRIMARY) + auto diff = now.value() - lastInfo.value(); + constexpr double FPS_INFO_INTERVAL = 60.f * 5.f; + if( diff >= FPS_INFO_INTERVAL) { - owner = DefaultRootWindow(mSDL_Display); - selection = XA_CUT_BUFFER0; - } - else - { - maybe_unlock_display(); - return false; + double fFPS = frame_count; + fFPS /= diff; + LL_INFOS() << "Wayland: FPS " << fFPS << " fps, " << frame_count << " #frames time " << (diff) << LL_ENDL; + frame_count = 0; + lastInfo = now; } } + else + lastInfo = now; - maybe_unlock_display(); - - for( Atom atom : gSupportedAtoms ) - { - if(getSelectionText(selection, atom, text ) ) - return true; - } - - return false; + pThis->setupWaylandFrameCallback(); // ask for a new frame } -bool LLWindowSDL::setSelectionText(Atom selection, const LLWString& text) +void LLWindowSDL::setupWaylandFrameCallback() { - 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); + static wl_callback_listener frame_listener { nullptr }; + frame_listener.done = &LLWindowSDL::waylandFrameDoneCB; - maybe_unlock_display(); - - return owner == mSDL_XWindowID; + auto cb = ll_wl_surface_frame(mWaylandData.mSurface); + ll_wl_callback_add_listener(cb, &frame_listener, this); } - -Display* LLWindowSDL::getSDLDisplay() +#else +bool LLWindowSDL::isWaylandWindowNotDrawing() { - if (gWindowImplementation) - return gWindowImplementation->mSDL_Display; - return nullptr; + return false; +} +void LLWindowSDL::setupWaylandFrameCallback() +{ + LL_WARNS() << "Viewer is running under Wayland, but was not compiled with full wayland support!" << LL_ENDL; } - #endif - LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, - const std::string& title, S32 x, S32 y, S32 width, + const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, bool fullscreen, bool clearBg, - bool disable_vsync, bool use_gl, + bool enable_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) + Lock_Display(nullptr), + Unlock_Display(nullptr), 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 - -#if LL_DARWIN - hasHIDPI = gHiDPISupport; -#endif - - // 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; -#endif // LL_X11 // Assume 4:3 aspect ratio until we know better mOriginalAspectRatio = 1024.0 / 768.0; if (title.empty()) - mWindowTitle = "SDL Window"; // *FIX: (?) + mWindowTitle = "Second Life"; 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)) + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) { gGLManager.initGL(); @@ -453,13 +266,8 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, // Stash an object pointer for OSMessageBox() gWindowImplementation = this; -#if LL_X11 mFlashing = false; - initialiseX11Clipboard(); -#endif // LL_X11 - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -478,145 +286,6 @@ static SDL_Surface *Load_BMP_Resource(const char *basename) return SDL_LoadBMP(path_buffer); } -#if LL_X11 -// This is an XFree86/XOrg-specific hack for detecting the amount of Video RAM -// on this machine. It works by searching /var/log/var/log/Xorg.?.log or -// /var/log/XFree86.?.log for a ': (VideoRAM ?|Memory): (%d+) kB' regex, where -// '?' is the X11 display number derived from $DISPLAY -static int x11_detect_VRAM_kb_fp(FILE *fp, const char *prefix_str) -{ - const int line_buf_size = 1000; - char line_buf[line_buf_size]; - while (fgets(line_buf, line_buf_size, fp)) - { - //LL_DEBUGS() << "XLOG: " << line_buf << LL_ENDL; - - // Why the ad-hoc parser instead of using a regex? Our - // favourite regex implementation - libboost_regex - is - // quite a heavy and troublesome dependency for the client, so - // it seems a shame to introduce it for such a simple task. - // *FIXME: libboost_regex is a dependency now anyway, so we may - // as well use it instead of this hand-rolled nonsense. - const char *part1_template = prefix_str; - const char part2_template[] = " kB"; - char *part1 = strstr(line_buf, part1_template); - if (part1) // found start of matching line - { - part1 = &part1[strlen(part1_template)]; // -> after - char *part2 = strstr(part1, part2_template); - if (part2) // found end of matching line - { - // now everything between part1 and part2 is - // supposed to be numeric, describing the - // number of kB of Video RAM supported - int rtn = 0; - for (; part1 < part2; ++part1) - { - if (*part1 < '0' || *part1 > '9') - { - // unexpected char, abort parse - rtn = 0; - break; - } - rtn *= 10; - rtn += (*part1) - '0'; - } - if (rtn > 0) - { - // got the kB number. return it now. - return rtn; - } - } - } - } - return 0; // 'could not detect' -} - -static int x11_detect_VRAM_kb() -{ - std::string x_log_location("/var/log/"); - std::string fname; - int rtn = 0; // 'could not detect' - int display_num = 0; - FILE *fp; - char *display_env = getenv("DISPLAY"); // e.g. :0 or :0.0 or :1.0 etc - // parse DISPLAY number so we can go grab the right log file - if (display_env[0] == ':' && - display_env[1] >= '0' && display_env[1] <= '9') - { - display_num = display_env[1] - '0'; - } - - // *TODO: we could be smarter and see which of Xorg/XFree86 has the - // freshest time-stamp. - - // Try Xorg log first - fname = x_log_location; - fname += "Xorg."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Video RAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - // Try old XFree86 log otherwise - fname = x_log_location; - fname += "XFree86."; - fname += ('0' + display_num); - fname += ".log"; - fp = fopen(fname.c_str(), "r"); - if (fp) - { - LL_INFOS() << "Looking in " << fname - << " for VRAM info..." << LL_ENDL; - rtn = x11_detect_VRAM_kb_fp(fp, ": VideoRAM: "); - fclose(fp); - if (0 == rtn) - { - fp = fopen(fname.c_str(), "r"); - if (fp) - { - rtn = x11_detect_VRAM_kb_fp(fp, ": Memory: "); - fclose(fp); - } - } - } - else - { - LL_INFOS() << "Could not open " << fname - << " - skipped." << LL_ENDL; - } - } - return rtn; -} -#endif // LL_X11 - void LLWindowSDL::setTitle(const std::string title) { SDL_SetWindowTitle( mWindow, title.c_str() ); @@ -627,7 +296,7 @@ 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)) + if(width == 0 || height == 0) { // Scan through the list of modes, looking for one which has: // height between 700 and 800 @@ -635,16 +304,15 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) S32 resolutionCount = 0; LLWindowResolution *resolutionList = getSupportedResolutions(resolutionCount); - if(resolutionList != NULL) + if(resolutionList != nullptr) { 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++) + for(S32 i=0; i < resolutionCount; i++) { F32 aspect = (F32)resolutionList[i].mWidth / (F32)resolutionList[i].mHeight; @@ -667,7 +335,7 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) } } - if((width == 0) || (height == 0)) + if(width == 0 || height == 0) { // Mode search failed for some reason. Use the old-school default. width = 1024; @@ -675,142 +343,84 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) } } -bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool disable_vsync) +bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { - //bool glneedsinit = false; - - LL_INFOS() << "createContext, fullscreen=" << fullscreen << - " size=" << width << "x" << height << LL_ENDL; + 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"}, - {SDL_HINT_IME_INTERNAL_EDITING,"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; + if (x == 0) + x = SDL_WINDOWPOS_UNDEFINED; + if (y == 0) + y = SDL_WINDOWPOS_UNDEFINED; mFullscreen = fullscreen; - int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - - if( mFullscreen ) - { - sdlflags |= SDL_WINDOW_FULLSCREEN; - tryFindFullscreenSize( width, height ); - } - - if(hasHIDPI) sdlflags = sdlflags | SDL_WINDOW_ALLOW_HIGHDPI; - - mSDLFlags = sdlflags; + // Setup default backing colors GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; + GLint depthBits{24}, stencilBits{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_CONTEXT_MAJOR_VERSION, 4); -#if LL_DARWIN - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); -#else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6); -#endif - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, alphaBits); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, depthBits); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, stencilBits); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - if (mFSAASamples > 0) + U32 context_flags = 0; + if (gDebugGL) { - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, mFSAASamples); + context_flags |= SDL_GL_CONTEXT_DEBUG_FLAG; } - + SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); 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 ) + int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + + if( mFullscreen ) + { + sdlflags |= SDL_WINDOW_FULLSCREEN; + tryFindFullscreenSize( width, height ); + } + + mWindow = SDL_CreateWindow( mWindowTitle.c_str(), x, y, width, height, sdlflags ); + if (mWindow == nullptr) { - mContext = SDL_GL_CreateContext( mWindow ); + LL_WARNS() << "Window creation failure. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("Window creation error", "Error", OSMB_OK); + } - 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); + // Create the context + mContext = SDL_GL_CreateContext(mWindow); + if(!mContext) + { + LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context creation error", "Error", OSMB_OK); } + if (SDL_GL_MakeCurrent(mWindow, mContext) != 0) + { + LL_WARNS() << "Failed to make context current. SDL: " << SDL_GetError() << LL_ENDL; + setupFailure("GL Context failed to set current failure", "Error", OSMB_OK); + } - if( mFullscreen ) + mSurface = SDL_GetWindowSurface(mWindow); + if(mFullscreen) { - if (mWindow) + if (mSurface) { mFullscreen = true; - /* mFullscreenWidth = mSurface->w; mFullscreenHeight = mSurface->h; mFullscreenBits = mSurface->format->BitsPerPixel; - */ - SDL_GetWindowSize(mWindow, &mFullscreenWidth, &mFullscreenHeight); mFullscreenRefresh = -1; LL_INFOS() << "Running at " << mFullscreenWidth @@ -822,7 +432,7 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b else { LL_WARNS() << "createContext: fullscreen creation failure. SDL: " << SDL_GetError() << LL_ENDL; - // No fullscreen support + mFullscreen = false; mFullscreenWidth = -1; mFullscreenHeight = -1; @@ -830,8 +440,7 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b 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; + setupFailure( error, "Error", OSMB_OK ); } } else @@ -840,73 +449,8 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b { LL_WARNS() << "createContext: window creation failure. SDL: " << SDL_GetError() << LL_ENDL; setupFailure("Window creation error", "Error", OSMB_OK); - return false; - } - } - - // 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 - { - PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC queryInteger; - queryInteger = (PFNGLXQUERYCURRENTRENDERERINTEGERMESAPROC) - glXGetProcAddressARB((const GLubyte *)"glXQueryCurrentRendererIntegerMESA"); - unsigned int vram_megabytes = 0; - queryInteger(GLX_RENDERER_VIDEO_MEMORY_MESA, &vram_megabytes); - if (!vram_megabytes) { - glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, (int *)&vram_megabytes); - vram_megabytes /= 1024; - } - if (!vram_megabytes) { - glGetIntegerv(GL_VBO_FREE_MEMORY_ATI, (int *)&vram_megabytes); - vram_megabytes /= 1024; - } - gGLManager.mVRAM = vram_megabytes; - } -#elif LL_DARWIN - CGLRendererInfoObj info = 0; - GLint vram_megabytes = 0; - int num_renderers = 0; - auto err = CGLQueryRendererInfo(CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay), - &info, &num_renderers); - if (!err) { - CGLDescribeRenderer(info, 0, kCGLRPVideoMemoryMegabytes, &vram_megabytes); - CGLDestroyRendererInfo(info); - } else - vram_megabytes = 256; - gGLManager.mVRAM = vram_megabytes; -# 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 = 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); @@ -929,7 +473,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b // relaxed about if we have to. if (colorBits < 32) { -#if 0 close(); setupFailure( "Second Life requires True Color (32-bit) to run in a window.\n" @@ -939,11 +482,22 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b "will automatically adjust the screen each time it runs.", "Error", OSMB_OK); - return false; -#endif } -#if LL_X11 + LL_PROFILER_GPU_CONTEXT; + + // Enable vertical sync + toggleVSync(enable_vsync); + + // Set the application icon. + SDL_Surface* bmpsurface = Load_BMP_Resource("ll_icon.BMP"); + if (bmpsurface) + { + SDL_SetWindowIcon(mWindow, bmpsurface); + SDL_FreeSurface(bmpsurface); + bmpsurface = nullptr; + } + /* Grab the window manager specific information */ SDL_SysWMinfo info; SDL_VERSION(&info.version); @@ -952,22 +506,46 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b /* Save the information for later use */ if ( info.subsystem == SDL_SYSWM_X11 ) { - mSDL_Display = info.info.x11.display; - mSDL_XWindowID = info.info.x11.window; + SDL_SetHint(SDL_HINT_VIDEODRIVER, "x11"); + mX11Data.mDisplay = info.info.x11.display; + mX11Data.mXWindowID = info.info.x11.window; + mServerProtocol = X11; + LL_INFOS() << "Running under X11" << LL_ENDL; + } + else if ( info.subsystem == SDL_SYSWM_WAYLAND ) + { +#ifdef LL_WAYLAND + if( !loadWaylandClient() ) { + SDL_SetHint(SDL_HINT_VIDEODRIVER, "x11"); + LL_ERRS() << "Failed to load wayland-client.so or grab required functions" << LL_ENDL; + } else { + SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland"); + } + + mWaylandData.mSurface = info.info.wl.surface; + mServerProtocol = Wayland; + setupWaylandFrameCallback(); + + // If set (XWayland) remove DISPLAY, this will prompt dullahan to also use Wayland + if( getenv("DISPLAY") ) + unsetenv("DISPLAY"); + + LL_INFOS() << "Running under Wayland" << LL_ENDL; + LL_WARNS() << "Be aware that with at least SDL2 the window will not receive minimizing events, thus minimized state can only be estimated." + "also setting the application icon via SDL_SetWindowIcon does not work." << LL_ENDL; +#else + setupFailure("Viewer is running under Wayland, but was not compiled with full wayland support!\nYou can compile the viewer with wayland prelimiary support using COMPILE_WAYLAND_SUPPORT", "Error", OSMB_OK); +#endif } else { - LL_WARNS() << "We're not running under X11? Wild." - << LL_ENDL; + LL_WARNS() << "We're not running under X11 or Wayland? Wild." << LL_ENDL; } } else { - LL_WARNS() << "We're not running under any known WM. Wild." - << LL_ENDL; + LL_WARNS() << "We're not running under any known WM. Wild." << LL_ENDL; } -#endif // LL_X11 - SDL_StartTextInput(); //make sure multisampling is disabled by default @@ -979,9 +557,46 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b return true; } +void* LLWindowSDL::createSharedContext() +{ + SDL_GLContext pContext = SDL_GL_CreateContext(mWindow); + if (pContext) + { + 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) +{ + SDL_GL_MakeCurrent(mWindow, contextPtr); + LL_PROFILER_GPU_CONTEXT; +} + +void LLWindowSDL::destroySharedContext(void* contextPtr) +{ + SDL_GL_DeleteContext(contextPtr); +} + +void LLWindowSDL::toggleVSync(bool enable_vsync) +{ + if (!enable_vsync) + { + LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(0); + } + else + { + LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; + SDL_GL_SetSwapInterval(1); + } +} // 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) +bool LLWindowSDL::switchContext(bool fullscreen, const LLCoordScreen &size, bool enable_vsync, const LLCoordScreen * const posp) { const bool needsRebuild = true; // Just nuke the context and start over. bool result = true; @@ -991,7 +606,7 @@ bool LLWindowSDL::switchContext(bool fullscreen, const LLCoordScreen &size, bool if(needsRebuild) { destroyContext(); - result = createContext(0, 0, size.mX, size.mY, 0, fullscreen, disable_vsync); + result = createContext(0, 0, size.mX, size.mY, 32, fullscreen, enable_vsync); if (result) { gGLManager.initGL(); @@ -1011,40 +626,61 @@ void LLWindowSDL::destroyContext() { LL_INFOS() << "destroyContext begins" << LL_ENDL; + // Stop unicode input SDL_StopTextInput(); -#if LL_X11 - 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(); + + mX11Data.mDisplay = nullptr; + mX11Data.mXWindowID = None; + Lock_Display = nullptr; + Unlock_Display = nullptr; + mServerProtocol = Unknown; + + LL_INFOS() << "Destroying SDL cursors" << LL_ENDL; + quitCursors(); + + if (mContext) + { + LL_INFOS() << "Destroying SDL GL Context" << LL_ENDL; + SDL_GL_DeleteContext(mContext); + mContext = nullptr; + } + else + { + LL_INFOS() << "SDL GL Context already destroyed" << LL_ENDL; + } + + if (mWindow) + { + LL_INFOS() << "Destroying SDL Window" << LL_ENDL; + SDL_DestroyWindow(mWindow); + mWindow = nullptr; + } + else + { + LL_INFOS() << "SDL Window already destroyed" << LL_ENDL; + } + LL_INFOS() << "destroyContext end" << LL_ENDL; + LL_INFOS() << "SDL_QuitSS/VID begins" << LL_ENDL; SDL_QuitSubSystem(SDL_INIT_VIDEO); // *FIX: this might be risky... - - mWindow = NULL; } LLWindowSDL::~LLWindowSDL() { - quitCursors(); destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + delete []mSupportedResolutions; - gWindowImplementation = NULL; + gWindowImplementation = nullptr; } void LLWindowSDL::show() { - // *FIX: What to do with SDL? if (mWindow) { SDL_ShowWindow(mWindow); @@ -1053,44 +689,32 @@ void LLWindowSDL::show() void LLWindowSDL::hide() { - // *FIX: What to do with SDL? if (mWindow) { SDL_HideWindow(mWindow); } } -//virtual void LLWindowSDL::minimize() { - // *FIX: What to do with SDL? if (mWindow) { SDL_MinimizeWindow(mWindow); } } -//virtual void LLWindowSDL::restore() { - // *FIX: What to do with SDL? if (mWindow) { SDL_RestoreWindow(mWindow); } } - // close() destroys all OS-specific code associated with a window. // Usually called from LLWindowManager::destroyWindow() void LLWindowSDL::close() { - // Is window is already closed? - // if (!mWindow) - // { - // return; - // } - // Make sure cursor is visible and we haven't mangled the clipping state. setMouseClipping(false); showCursor(); @@ -1100,120 +724,108 @@ void LLWindowSDL::close() bool LLWindowSDL::isValid() { - return (mWindow != NULL); + return mWindow != nullptr; } -bool LLWindowSDL::getVisible() +bool LLWindowSDL::getVisible() const { bool result = false; - - // *FIX: This isn't really right... - // Then what is? if (mWindow) { - if( SDL_GetWindowFlags(mWindow) & SDL_WINDOW_SHOWN ) result = true; + Uint32 flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_SHOWN) + { + result = true; + } } - - return(result); + return result; } -bool LLWindowSDL::getMinimized() +bool LLWindowSDL::getMinimized() const { - bool result = false; + if( isWaylandWindowNotDrawing() ) + return true; - if (mWindow/*&& (1 == mIsMinimized)*/) + bool result = false; + if (mWindow) { - if( SDL_GetWindowFlags(mWindow) & SDL_WINDOW_MINIMIZED ) result = true; + Uint32 flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_MINIMIZED) + { + result = true; + } } - - mIsMinimized = result; - return(result); + return result; } -bool LLWindowSDL::getMaximized() +bool LLWindowSDL::getMaximized() const { bool result = false; - if (mWindow) { - // TODO - if( SDL_GetWindowFlags(mWindow) & SDL_WINDOW_MAXIMIZED ) result = true; - else result = false; + Uint32 flags = SDL_GetWindowFlags(mWindow); + if (flags & SDL_WINDOW_MAXIMIZED) + { + result = true; + } } - return(result); + return result; } bool LLWindowSDL::maximize() { - // TODO - bool result = false; - if (mWindow) { SDL_MaximizeWindow(mWindow); - result = true; + return true; } - - return result; -} - -bool LLWindowSDL::getFullscreen() -{ - return mFullscreen; + return false; } -bool LLWindowSDL::getPosition(LLCoordScreen *position) +bool LLWindowSDL::getPosition(LLCoordScreen *position) const { - // *FIX: can anything be done with this? - position->mX = 0; - position->mY = 0; - return true; + if (mWindow) + { + SDL_GetWindowPosition(mWindow, &position->mX, &position->mY); + return true; + } + return false; } -bool LLWindowSDL::getSize(LLCoordScreen *size) +bool LLWindowSDL::getSize(LLCoordScreen *size) const { - if (mWindow) + if (mSurface) { - /* - if(hasHIDPI) - SDL_GL_GetDrawableSize(mWindow, &size->mX, &size->mY); - else - */ - SDL_GetWindowSize(mWindow, &size->mX, &size->mY); - return (true); + size->mX = mSurface->w; + size->mY = mSurface->h; + return true; } - return (false); + return false; } -bool LLWindowSDL::getSize(LLCoordWindow *size) +bool LLWindowSDL::getSize(LLCoordWindow *size) const { - if (mWindow) + if (mSurface) { - if(hasHIDPI) - SDL_GL_GetDrawableSize(mWindow, &size->mX, &size->mY); - else - SDL_GetWindowSize(mWindow, &size->mX, &size->mY); - return (true); + size->mX = mSurface->w; + size->mY = mSurface->h; + return true; } - return (false); + return false; } bool LLWindowSDL::setPosition(const LLCoordScreen position) { - bool result = false; - - if(mWindow) + if (mWindow) { - // *FIX: (?) - //MacMoveWindow(mWindow, position.mX, position.mY, false); SDL_SetWindowPosition(mWindow, position.mX, position.mY); - result = true; + return true; } - return result; + return false; } template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) @@ -1226,7 +838,6 @@ template< typename T > bool setSizeImpl( const T& newSize, SDL_Window *pWin ) if( nFlags & SDL_WINDOW_MAXIMIZED ) SDL_RestoreWindow( pWin ); - SDL_SetWindowSize( pWin, newSize.mX, newSize.mY ); SDL_Event event; event.type = SDL_WINDOWEVENT; @@ -1254,11 +865,12 @@ void LLWindowSDL::swapBuffers() { if (mWindow) { - SDL_GL_SwapWindow( mWindow ); + SDL_GL_SwapWindow(mWindow); } + LL_PROFILER_GPU_COLLECT; } -U32 LLWindowSDL::getFSAASamples() +U32 LLWindowSDL::getFSAASamples() const { return mFSAASamples; } @@ -1268,30 +880,36 @@ void LLWindowSDL::setFSAASamples(const U32 samples) mFSAASamples = samples; } -F32 LLWindowSDL::getGamma() +F32 LLWindowSDL::getGamma() const { - return 1/mGamma; + return 1.f / mGamma; } bool LLWindowSDL::restoreGamma() { - //CGDisplayRestoreColorSyncSettings(); - // SDL_SetGamma(1.0f, 1.0f, 1.0f); - Uint16 ramp; - SDL_CalculateGammaRamp(1.0f, &ramp); - SDL_SetWindowGammaRamp(mWindow, &ramp, &ramp, &ramp); + if (mWindow) + { + Uint16 ramp[256]; + SDL_CalculateGammaRamp(1.f, ramp); + SDL_SetWindowGammaRamp(mWindow, ramp, ramp, ramp); + } return true; } bool LLWindowSDL::setGamma(const F32 gamma) { - mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; - mGamma = 1/mGamma; - // SDL_SetGamma(mGamma, mGamma, mGamma); - Uint16 ramp; - SDL_CalculateGammaRamp(mGamma, &ramp); - SDL_SetWindowGammaRamp(mWindow, &ramp, &ramp, &ramp); + if (mWindow) + { + Uint16 ramp[256]; + + mGamma = gamma; + if (mGamma == 0) + mGamma = 0.1f; + mGamma = 1.f / mGamma; + + SDL_CalculateGammaRamp(mGamma, ramp); + SDL_SetWindowGammaRamp(mWindow, ramp, ramp, ramp); + } return true; } @@ -1300,12 +918,11 @@ bool LLWindowSDL::isCursorHidden() return mCursorHidden; } - - // Constrains the mouse to the window. -void LLWindowSDL::setMouseClipping( bool b ) +void LLWindowSDL::setMouseClipping(bool b) { - //SDL_WM_GrabInput(b ? SDL_GRAB_ON : SDL_GRAB_OFF); + if( mWindow ) + SDL_SetWindowGrab( mWindow, b?SDL_TRUE:SDL_FALSE ); } // virtual @@ -1313,18 +930,10 @@ void LLWindowSDL::setMinSize(U32 min_width, U32 min_height, bool enforce_immedia { LLWindow::setMinSize(min_width, min_height, enforce_immediately); -#if LL_X11 - // Set the minimum size limits for X11 window - // so the window manager doesn't allow resizing below those limits. - XSizeHints* hints = XAllocSizeHints(); - hints->flags |= PMinSize; - hints->min_width = mMinWindowWidth; - hints->min_height = mMinWindowHeight; - - XSetWMNormalHints(mSDL_Display, mSDL_XWindowID, hints); - - XFree(hints); -#endif + if (mWindow && min_width > 0 && min_height > 0) + { + SDL_SetWindowMinimumSize(mWindow, mMinWindowWidth, mMinWindowHeight); + } } bool LLWindowSDL::setCursorPosition(const LLCoordWindow position) @@ -1333,24 +942,11 @@ bool LLWindowSDL::setCursorPosition(const LLCoordWindow position) LLCoordScreen screen_pos; if (!convertCoords(position, &screen_pos)) - { return false; - } - - //LL_INFOS() << "setCursorPosition(" << screen_pos.mX << ", " << screen_pos.mY << ")" << LL_ENDL; // do the actual forced cursor move. - - if (mFullscreen) - { - SDL_WarpMouseGlobal(screen_pos.mX, screen_pos.mY); - return result; - } - SDL_WarpMouseInWindow(mWindow, screen_pos.mX, screen_pos.mY); - //LL_INFOS() << llformat("llcw %d,%d -> scr %d,%d", position.mX, position.mY, screen_pos.mX, screen_pos.mY) << LL_ENDL; - return result; } @@ -1359,7 +955,6 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) //Point cursor_point; LLCoordScreen screen_pos; - //GetMouse(&cursor_point); int x, y; SDL_GetMouseState(&x, &y); @@ -1369,12 +964,6 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) return convertCoords(screen_pos, position); } -F32 LLWindowSDL::getSystemUISize() -{ - if(hasHIDPI) return 2.0f; - else return 1.f; -} - F32 LLWindowSDL::getNativeAspectRatio() { // MBW -- there are a couple of bad assumptions here. One is that the display list won't include @@ -1395,9 +984,7 @@ F32 LLWindowSDL::getNativeAspectRatio() // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. if (mOverrideAspectRatio > 0.f) - { return mOverrideAspectRatio; - } return mOriginalAspectRatio; } @@ -1409,9 +996,7 @@ F32 LLWindowSDL::getPixelAspectRatio() { LLCoordScreen screen_size; if (getSize(&screen_size)) - { pixel_aspect = getNativeAspectRatio() * (F32)screen_size.mY / (F32)screen_size.mX; - } } return pixel_aspect; @@ -1422,173 +1007,109 @@ F32 LLWindowSDL::getPixelAspectRatio() // dialogs are still usable in fullscreen. void LLWindowSDL::beforeDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::beforeDialog()" << LL_ENDL; if (SDLReallyCaptureInput(false)) // must ungrab input so popup works! { - if (mFullscreen) - { - // need to temporarily go non-fullscreen; bless SDL - // for providing a SDL_WM_ToggleFullScreen() - though - // it only works in X11 - if (running_x11 && mWindow) - { - SDL_SetWindowFullscreen( mWindow, 0 ); - } - } + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } -#if LL_X11 - if (mSDL_Display) + if (mServerProtocol == X11 && mX11Data.mDisplay) { // Everything that we/SDL asked for should happen before we // potentially hand control over to GTK. maybe_lock_display(); - XSync(mSDL_Display, False); + XSync(mX11Data.mDisplay, False); maybe_unlock_display(); } -#endif // LL_X11 maybe_lock_display(); } void LLWindowSDL::afterDialog() { - bool running_x11 = false; -#if LL_X11 - running_x11 = (mSDL_XWindowID != None); -#endif //LL_X11 - LL_INFOS() << "LLWindowSDL::afterDialog()" << LL_ENDL; maybe_unlock_display(); - if (mFullscreen) - { - // need to restore fullscreen mode after dialog - only works - // in X11 - if (running_x11 && mWindow) - { - SDL_SetWindowFullscreen( mWindow, 0 ); - } - } + if (mFullscreen && mWindow ) + SDL_SetWindowFullscreen( mWindow, 0 ); } - -#if LL_X11 -// set/reset the XWMHints flag for 'urgency' that usually makes the icon flash -void LLWindowSDL::x11_set_urgent(bool urgent) +void LLWindowSDL::flashIcon(F32 seconds) { - if (mSDL_Display && !mFullscreen) - { - XWMHints *wm_hints; + LL_INFOS() << "LLWindowSDL::flashIcon(" << seconds << ")" << LL_ENDL; - LL_INFOS() << "X11 hint for urgency, " << urgent << LL_ENDL; + F32 remaining_time = mFlashTimer.getRemainingTimeF32(); + if (remaining_time < seconds) + remaining_time = seconds; + mFlashTimer.reset(); + mFlashTimer.setTimerExpirySec(remaining_time); - maybe_lock_display(); - wm_hints = XGetWMHints(mSDL_Display, mSDL_XWindowID); - if (!wm_hints) - wm_hints = XAllocWMHints(); - - if (urgent) - wm_hints->flags |= XUrgencyHint; - else - wm_hints->flags &= ~XUrgencyHint; - - XSetWMHints(mSDL_Display, mSDL_XWindowID, wm_hints); - XFree(wm_hints); - XSync(mSDL_Display, False); - maybe_unlock_display(); - } + SDL_FlashWindow(mWindow, SDL_FLASH_UNTIL_FOCUSED); + mFlashing = true; } -#endif // LL_X11 -void LLWindowSDL::flashIcon(F32 seconds) +void LLWindowSDL::maybeStopFlashIcon() { - if (getMinimized()) + if (mFlashing && mFlashTimer.hasExpired()) { -#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 + mFlashing = false; + SDL_FlashWindow( mWindow, SDL_FLASH_CANCEL ); } } bool LLWindowSDL::isClipboardTextAvailable() { -#if LL_X11 - return mSDL_Display && XGetSelectionOwner(mSDL_Display, XA_CLIPBOARD) != None; -#else - return SDL_HasClipboardText(); -#endif + return SDL_HasClipboardText() == SDL_TRUE; } bool LLWindowSDL::pasteTextFromClipboard(LLWString &dst) { -#if LL_X11 - return getSelectionText(XA_CLIPBOARD, dst); -#else - auto data = SDL_GetClipboardText(); - if (data) + if (isClipboardTextAvailable()) { - dst = LLWString(utf8str_to_wstring(data)); - SDL_free(data); - return true; + char* data = SDL_GetClipboardText(); + if (data) + { + dst = LLWString(utf8str_to_wstring(data)); + SDL_free(data); + return true; + } } return false; -#endif } -bool LLWindowSDL::copyTextToClipboard(const LLWString &s) +bool LLWindowSDL::copyTextToClipboard(const LLWString& text) { -#if LL_X11 - return setSelectionText(XA_CLIPBOARD, s); -#else - return !SDL_SetClipboardText(wstring_to_utf8str(s).c_str()); -#endif + const std::string utf8 = wstring_to_utf8str(text); + return SDL_SetClipboardText(utf8.c_str()) == 0; // success == 0 } bool LLWindowSDL::isPrimaryTextAvailable() { -#if LL_X11 - LLWString text; - return getSelectionText(XA_PRIMARY, text) && !text.empty(); -#else - return false; // unsupported -#endif + return SDL_HasPrimarySelectionText() == SDL_TRUE; } bool LLWindowSDL::pasteTextFromPrimary(LLWString &dst) { -#if LL_X11 - return getSelectionText(XA_PRIMARY, dst); -#else - return false; // unsupported -#endif + if (isPrimaryTextAvailable()) + { + char* data = SDL_GetPrimarySelectionText(); + if (data) + { + dst = LLWString(utf8str_to_wstring(data)); + SDL_free(data); + return true; + } + } + return false; } -bool LLWindowSDL::copyTextToPrimary(const LLWString &s) +bool LLWindowSDL::copyTextToPrimary(const LLWString& text) { -#if LL_X11 - return setSelectionText(XA_PRIMARY, s); -#else - return false; // unsupported -#endif + const std::string utf8 = wstring_to_utf8str(text); + return SDL_SetPrimarySelectionText(utf8.c_str()) == 0; // success == 0 } LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_resolutions) @@ -1606,9 +1127,7 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso { SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 }; if (SDL_GetDisplayMode( 0 , i, &mode) != 0) - { continue; - } int w = mode.w; int h = mode.h; @@ -1631,33 +1150,29 @@ LLWindow::LLWindowResolution* LLWindowSDL::getSupportedResolutions(S32 &num_reso return mSupportedResolutions; } -bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) +bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordWindow *to) const { if (!to) return false; to->mX = from.mX; - int h; - SDL_GetWindowSize(mWindow, nullptr, &h); - to->mY = h - from.mY - 1; + to->mY = mSurface->h - from.mY - 1; return true; } -bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) +bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordGL* to) const { if (!to) return false; to->mX = from.mX; - int h; - SDL_GetWindowSize(mWindow, nullptr, &h); - to->mY = h - from.mY - 1; + to->mY = mSurface->h - from.mY - 1; return true; } -bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) +bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) const { if (!to) return false; @@ -1665,10 +1180,10 @@ bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } -bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) +bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) const { if (!to) return false; @@ -1676,103 +1191,39 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) // In the fullscreen case, window and screen coordinates are the same. to->mX = from.mX; to->mY = from.mY; - return (true); + return true; } -bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) +bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordGL *to) const { 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) +bool LLWindowSDL::convertCoords(LLCoordGL from, LLCoordScreen *to) const { LLCoordWindow window_coord; - return(convertCoords(from, &window_coord) && convertCoords(window_coord, to)); + return convertCoords(from, &window_coord) && convertCoords(window_coord, to); } - - - void LLWindowSDL::setupFailure(const std::string& text, const std::string& caption, U32 type) { destroyContext(); OSMessageBox(text, caption, type); + + // This is so catastrophic > bail as fast as possible. Otherwise the viewer can be stuck in a perpetual state of startup pain + std::terminate(); } 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 (!mFullscreen && mWindow ) /* only bother if we're windowed anyway */ + SDL_SetWindowGrab( mWindow, capture?SDL_TRUE:SDL_FALSE); - 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 (!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 - // return boolean success for whether we ended up in the desired state - return capture == newGrab; + return capture; } U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain) @@ -1819,7 +1270,6 @@ U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain) 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"); @@ -1834,7 +1284,7 @@ void check_vm_bloat() ssize_t res; size_t dummy; - char *ptr = NULL; + char *ptr = nullptr; for (int i=0; i<22; ++i) // parse past the values we don't want { res = getdelim(&ptr, &dummy, ' ', fp); @@ -1844,7 +1294,7 @@ void check_vm_bloat() goto finally; } free(ptr); - ptr = NULL; + ptr = nullptr; } // 23rd space-delimited entry is vsize res = getdelim(&ptr, &dummy, ' ', fp); @@ -1856,7 +1306,7 @@ void check_vm_bloat() } this_vm_size = atoll(ptr); free(ptr); - ptr = NULL; + ptr = nullptr; // 24th space-delimited entry is RSS res = getdelim(&ptr, &dummy, ' ', fp); llassert(ptr); @@ -1867,12 +1317,11 @@ void check_vm_bloat() } this_rss_size = getpagesize() * atoll(ptr); free(ptr); - ptr = NULL; + ptr = nullptr; 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 (llabs(last_vm_size - this_vm_size) > significant_vm_difference) { if (this_vm_size > last_vm_size) { @@ -1884,8 +1333,7 @@ void check_vm_bloat() } } - if (llabs(last_rss_size - this_rss_size) > - significant_rss_difference) + if (llabs(last_rss_size - this_rss_size) > significant_rss_difference) { if (this_rss_size > last_rss_size) { @@ -1900,22 +1348,17 @@ void check_vm_bloat() last_rss_size = this_rss_size; last_vm_size = this_vm_size; - finally: - if (NULL != ptr) - { +finally: + if (ptr) free(ptr); - ptr = NULL; - } fclose(fp); } -#endif // LL_LINUX } // virtual void LLWindowSDL::processMiscNativeEvents() { -#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; @@ -1925,22 +1368,14 @@ void LLWindowSDL::processMiscNativeEvents() { 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(); - } } -void LLWindowSDL::gatherInput() +void LLWindowSDL::gatherInput(bool app_has_focus) { - const Uint32 CLICK_THRESHOLD = 300; // milliseconds - static int leftClick = 0; - static int rightClick = 0; - static Uint32 lastLeftDown = 0; - static Uint32 lastRightDown = 0; SDL_Event event; // Handle all outstanding SDL events @@ -1949,21 +1384,23 @@ void LLWindowSDL::gatherInput() switch (event.type) { case SDL_MOUSEWHEEL: + { if( event.wheel.y != 0 ) + { mCallbacks->handleScrollWheel(this, -event.wheel.y); + } + if (event.wheel.x != 0) + { + mCallbacks->handleScrollHWheel(this, -event.wheel.x); + } break; + } case SDL_MOUSEMOTION: { - LLCoordWindow winCoord(event.button.x, event.button.y); + LLCoordWindow winCoord(event.motion.x, event.motion.y); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - - openGlCoord.mX = openGlCoord.mX * getSystemUISize(); - openGlCoord.mY = openGlCoord.mY * getSystemUISize(); - - //LL_INFOS() << "SDL_MOUSEMOTION " << event.button.x << " " << event.button.y << " gl " << openGlCoord.mX << " " << openGlCoord.mY << LL_ENDL; - MASK mask = gKeyboard->currentMask(true); mCallbacks->handleMouseMove(this, openGlCoord, mask); break; @@ -1973,7 +1410,7 @@ void LLWindowSDL::gatherInput() { auto string = utf8str_to_utf16str( event.text.text ); mKeyModifiers = gKeyboard->currentMask( false ); - mInputType = "textinput"; + for( auto key: string ) { mKeyVirtualKey = key; @@ -1989,13 +1426,10 @@ void LLWindowSDL::gatherInput() case SDL_KEYDOWN: 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 ); @@ -2018,13 +1452,10 @@ void LLWindowSDL::gatherInput() case SDL_KEYUP: 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(mKeyVirtualKey, false) == 0) SDLReallyCaptureInput(false); // part of the fix for SL-13243 @@ -2034,68 +1465,30 @@ void LLWindowSDL::gatherInput() case SDL_MOUSEBUTTONDOWN: { - bool isDoubleClick = false; LLCoordWindow winCoord(event.button.x, event.button.y); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - - openGlCoord.mX *= getSystemUISize(); - openGlCoord.mY *= getSystemUISize(); - MASK mask = gKeyboard->currentMask(true); - if (event.button.button == SDL_BUTTON_LEFT) // SDL doesn't manage double clicking... - { - Uint32 now = SDL_GetTicks(); - if ((now - lastLeftDown) > CLICK_THRESHOLD) - leftClick = 1; - else - { - if (++leftClick >= 2) - { - leftClick = 0; - isDoubleClick = true; - } - } - lastLeftDown = now; - } - else if (event.button.button == SDL_BUTTON_RIGHT) - { - Uint32 now = SDL_GetTicks(); - if ((now - lastRightDown) > CLICK_THRESHOLD) - rightClick = 1; - else - { - if (++rightClick >= 2) - { - rightClick = 0; - isDoubleClick = true; - } - } - lastRightDown = now; - } - if (event.button.button == SDL_BUTTON_LEFT) // left { - if (isDoubleClick) + if (event.button.clicks >= 2) mCallbacks->handleDoubleClick(this, openGlCoord, mask); else mCallbacks->handleMouseDown(this, openGlCoord, mask); } - - else if (event.button.button == SDL_BUTTON_RIGHT) // right + else if (event.button.button == SDL_BUTTON_RIGHT) { mCallbacks->handleRightMouseDown(this, openGlCoord, mask); } - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle { mCallbacks->handleMiddleMouseDown(this, openGlCoord, mask); } - else if (event.button.button == 4) // mousewheel up...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, -1); - else if (event.button.button == 5) // mousewheel down...thanks to X11 for making SDL consider these "buttons". - mCallbacks->handleScrollWheel(this, 1); + else + { + mCallbacks->handleOtherMouseDown(this, openGlCoord, mask, event.button.button); + } break; } @@ -2105,106 +1498,68 @@ void LLWindowSDL::gatherInput() LLCoordWindow winCoord(event.button.x, event.button.y); LLCoordGL openGlCoord; convertCoords(winCoord, &openGlCoord); - - openGlCoord.mX *= getSystemUISize(); - openGlCoord.mY *= getSystemUISize(); - MASK mask = gKeyboard->currentMask(true); if (event.button.button == SDL_BUTTON_LEFT) // left - mCallbacks->handleMouseUp(this, openGlCoord, mask); - else if (event.button.button == SDL_BUTTON_RIGHT) // right - mCallbacks->handleRightMouseUp(this, openGlCoord, mask); - else if (event.button.button == SDL_BUTTON_MIDDLE) // middle - mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); - // don't handle mousewheel here... - - break; - } - - case SDL_WINDOWEVENT: // *FIX: handle this? - { - 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; - - S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); - S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); - - // *FIX: I'm not sure this is necessary! - // <FS:ND> I think is is not - // SDL_SetWindowSize(mWindow, width, height); - // - - mCallbacks->handleResize(this, width * getSystemUISize(), height * getSystemUISize()); - } - else if(event.window.event == SDL_WINDOWEVENT_ENTER) - { - LL_INFOS() << "SDL_WINDOWEVENT_ENTER" << LL_ENDL; - if(!mHaveInputFocus) mCallbacks->handleFocus(this); - mHaveInputFocus = true; + mCallbacks->handleMouseUp(this, openGlCoord, mask); } - else if(event.window.event == SDL_WINDOWEVENT_LEAVE) + else if (event.button.button == SDL_BUTTON_RIGHT) // right { - LL_INFOS() << "SDL_WINDOWEVENT_LEAVE" << LL_ENDL; - if(mHaveInputFocus) mCallbacks->handleFocusLost(this); - mHaveInputFocus = false; + mCallbacks->handleRightMouseUp(this, openGlCoord, mask); } - else if( event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED ) // <FS:ND> What about SDL_WINDOWEVENT_ENTER (mouse focus) + else if (event.button.button == SDL_BUTTON_MIDDLE) // middle { - // 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); + mCallbacks->handleMiddleMouseUp(this, openGlCoord, mask); } - else if( event.window.event == SDL_WINDOWEVENT_FOCUS_LOST ) // <FS:ND> What about SDL_WINDOWEVENT_LEAVE (mouse focus) + else { - // 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); + mCallbacks->handleOtherMouseUp(this, openGlCoord, mask, event.button.button); } - /* - Bug : the app remains inactive when maximized .. + break; + } - else if(event.window.event == SDL_WINDOWEVENT_MINIMIZED) - { - LL_INFOS() << "SDL_WINDOWEVENT_MINIMIZED" << LL_ENDL; - if(!mIsMinimized) mCallbacks->handleActivate(this,false); - mIsMinimized = true; - } - else if(event.window.event == SDL_WINDOWEVENT_MAXIMIZED) - { - LL_INFOS() << "SDL_WINDOWEVENT_MAXIMIZED" << LL_ENDL; - if(mIsMinimized) mCallbacks->handleActivate(this,true); - mIsMinimized = false; - } - */ - else if (event.window.event == SDL_WINDOWEVENT_EXPOSED) + case SDL_WINDOWEVENT: + { + switch(event.window.event) { - int w, h; - SDL_GL_GetDrawableSize(mWindow, &w, &h); + //case SDL_WINDOWEVENT_SIZE_CHANGED: <FS:ND> SDL_WINDOWEVENT_SIZE_CHANGED is followed by SDL_WINDOWEVENT_RESIZED, so handling one shall be enough + case SDL_WINDOWEVENT_RESIZED: + { + LL_INFOS() << "Handling a resize event: " << event.window.data1 << "x" << event.window.data2 << LL_ENDL; + S32 width = llmax(event.window.data1, (S32)mMinWindowWidth); + S32 height = llmax(event.window.data2, (S32)mMinWindowHeight); - mCallbacks->handlePaint(this, 0, 0, w, h); - } - 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); + mSurface = SDL_GetWindowSurface(mWindow); + mCallbacks->handleResize(this, width, height); + break; + } + case SDL_WINDOWEVENT_LEAVE: + mCallbacks->handleMouseLeave(this); + break; + case SDL_WINDOWEVENT_FOCUS_GAINED: + mCallbacks->handleFocus(this); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + mCallbacks->handleFocusLost(this); + break; + case SDL_WINDOWEVENT_EXPOSED: + case SDL_WINDOWEVENT_SHOWN: + case SDL_WINDOWEVENT_HIDDEN: + case SDL_WINDOWEVENT_MINIMIZED: + case SDL_WINDOWEVENT_MAXIMIZED: + case SDL_WINDOWEVENT_RESTORED: + { + Uint32 flags = SDL_GetWindowFlags(mWindow); + bool minimized = (flags & SDL_WINDOW_MINIMIZED); + bool hidden = (flags & SDL_WINDOW_HIDDEN); - mCallbacks->handleActivate(this, !mIsMinimized); - LL_INFOS() << "SDL deiconification state switched to " << mIsMinimized << LL_ENDL; + mCallbacks->handleActivate(this, !minimized || !hidden); + LL_INFOS() << "SDL deiconification state switched to " << minimized << LL_ENDL; + break; + } } - break; } case SDL_QUIT: @@ -2216,27 +1571,25 @@ void LLWindowSDL::gatherInput() } break; default: - //LL_INFOS() << "Unhandled SDL event type " << event.type << LL_ENDL; + LLGameControl::handleEvent(event, app_has_focus); break; } } updateCursor(); -#if LL_X11 // This is a good time to stop flashing the icon if our mFlashTimer has // expired. if (mFlashing && mFlashTimer.hasExpired()) { - x11_set_urgent(false); + SDL_FlashWindow(mWindow, SDL_FLASH_CANCEL); mFlashing = false; } -#endif // LL_X11 } static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty) { - SDL_Cursor *sdlcursor = NULL; + SDL_Cursor *sdlcursor = nullptr; SDL_Surface *bmpsurface; // Load cursor pixel data from BMP file @@ -2254,12 +1607,12 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty SDL_SwapLE32(0xFF00U), SDL_SwapLE32(0xFF0000U), SDL_SwapLE32(0xFF000000U)); - SDL_FillRect(cursurface, NULL, SDL_SwapLE32(0x00000000U)); + SDL_FillRect(cursurface, nullptr, 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)) + if (0 == SDL_BlitSurface(bmpsurface, nullptr, + cursurface, nullptr)) { // n.b. we already checked that width is a multiple of 8. const int bitmap_bytes = (cursurface->w * cursurface->h) / 8; @@ -2310,12 +1663,6 @@ static SDL_Cursor *makeSDLCursorFromBMP(const char *filename, int hotx, int hoty 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) @@ -2327,37 +1674,38 @@ void LLWindowSDL::updateCursor() sdlcursor = mSDLCursors[UI_CURSOR_ARROW]; if (sdlcursor) SDL_SetCursor(sdlcursor); - } else { + + mCurrentCursor = mNextCursor; + } + 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; - } + for ( int i=0; i<UI_CURSOR_COUNT; ++i) + mSDLCursors[i] = nullptr; + // 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_ARROW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); + mSDLCursors[UI_CURSOR_WAIT] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); + mSDLCursors[UI_CURSOR_HAND] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); + mSDLCursors[UI_CURSOR_IBEAM] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); + mSDLCursors[UI_CURSOR_CROSS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR); + mSDLCursors[UI_CURSOR_SIZENWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); + mSDLCursors[UI_CURSOR_SIZENESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); + mSDLCursors[UI_CURSOR_SIZEWE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); + mSDLCursors[UI_CURSOR_SIZENS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); + mSDLCursors[UI_CURSOR_SIZEALL] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); + mSDLCursors[UI_CURSOR_NO] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); + mSDLCursors[UI_CURSOR_WORKING] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAITARROW); 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); @@ -2390,32 +1738,28 @@ void LLWindowSDL::initCursors() 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) + for (int i=0; i<UI_CURSOR_COUNT; ++i) { if (mSDLCursors[i]) { SDL_FreeCursor(mSDLCursors[i]); - mSDLCursors[i] = NULL; + mSDLCursors[i] = nullptr; } } - } else { + } + 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; + for (int i=0; i<UI_CURSOR_COUNT; ++i) + mSDLCursors[i] = nullptr; } } @@ -2444,7 +1788,7 @@ void LLWindowSDL::hideCursor() // LL_INFOS() << "hideCursor: hiding" << LL_ENDL; mCursorHidden = true; mHideCursorPermanent = true; - SDL_ShowCursor(0); + SDL_ShowCursor(SDL_DISABLE); } else { @@ -2459,7 +1803,7 @@ void LLWindowSDL::showCursor() // LL_INFOS() << "showCursor: showing" << LL_ENDL; mCursorHidden = false; mHideCursorPermanent = false; - SDL_ShowCursor(1); + SDL_ShowCursor(SDL_ENABLE); } else { @@ -2543,34 +1887,14 @@ S32 OSMessageBoxSDL(const std::string& text, const std::string& caption, U32 typ bool LLWindowSDL::dialogColorPicker( F32 *r, F32 *g, F32 *b) { - return (false); + return false; } -#if LL_DARWIN -LLSD LLWindowSDL::getNativeKeyData() -{ - LLSD result = LLSD::emptyMap(); - - if(mRawKeyEvent) - { - result["event_type"] = LLSD::Integer(mRawKeyEvent->mEventType); - result["event_modifiers"] = LLSD::Integer(mRawKeyEvent->mEventModifiers); - result["event_keycode"] = LLSD::Integer(mRawKeyEvent->mEventKeyCode); - result["event_chars"] = (mRawKeyEvent->mEventChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventChars)) : LLSD(); - result["event_umodchars"] = (mRawKeyEvent->mEventUnmodChars) ? LLSD(LLSD::Integer(mRawKeyEvent->mEventUnmodChars)) : LLSD(); - result["event_isrepeat"] = LLSD::Boolean(mRawKeyEvent->mEventRepeat); - } - - LL_DEBUGS() << "native key data is: " << result << LL_ENDL; - - return result; -} -#else /* 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 LLWindowSDL::getNativeKeyData() const { LLSD result = LLSD::emptyMap(); @@ -2593,66 +1917,8 @@ LLSD LLWindowSDL::getNativeKeyData() 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_DARWIN - -#if LL_LINUX || LL_SOLARIS || __FreeBSD__ -// 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); - // <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 // Open a URL with the user's default web browser. // Must begin with protocol identifier. @@ -2677,78 +1943,17 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) LL_INFOS() << "spawn_web_browser: " << escaped_url << LL_ENDL; -#if LL_LINUX || __FreeBSD__ -# if LL_X11 - if (mSDL_Display) - { - maybe_lock_display(); - // Just in case - before forking. - XSync(mSDL_Display, False); - maybe_unlock_display(); - } -# endif // LL_X11 - - std::string cmd, arg; -#ifdef LL_USESYSTEMLIBS - cmd = gDirUtilp->getExecutableDir(); -#else - cmd = gDirUtilp->getAppRODataDir(); - cmd += gDirUtilp->getDirDelimiter(); - cmd += "etc"; -#endif - cmd += gDirUtilp->getDirDelimiter(); - cmd += "launch_url.sh"; - arg = escaped_url; - exec_cmd(cmd, arg); - -#elif LL_DARWIN - - S32 result = 0; - CFURLRef urlRef = NULL; - - LL_INFOS() << "Opening URL " << escaped_url << LL_ENDL; - - CFStringRef stringRef = CFStringCreateWithCString(NULL, escaped_url.c_str(), kCFStringEncodingUTF8); - if (stringRef) + if (SDL_OpenURL(escaped_url.c_str()) != 0) { - // This will succeed if the string is a full URL, including the http:// - // Note that URLs specified this way need to be properly percent-escaped. - urlRef = CFURLCreateWithString(NULL, stringRef, NULL); - - // Don't use CRURLCreateWithFileSystemPath -- only want valid URLs - - CFRelease(stringRef); + LL_WARNS() << "spawn_web_browser failed with error: " << SDL_GetError() << LL_ENDL; } - if (urlRef) - { - result = LSOpenCFURLRef(urlRef, NULL); - - if (result != noErr) - { - LL_INFOS() << "Error " << result << " on open." << LL_ENDL; - } - - CFRelease(urlRef); - } - else - { - LL_INFOS() << "Error: couldn't create URL." << LL_ENDL; - } - -#endif // LL_LINUX - LL_INFOS() << "spawn_web_browser returning." << LL_ENDL; } -void LLWindowSDL::openFile(const std::string& file_name) -{ - spawnWebBrowser("file://"+file_name,true); -} - void *LLWindowSDL::getPlatformWindow() { - return NULL; + return nullptr; } void LLWindowSDL::bringToFront() @@ -2756,15 +1961,10 @@ void LLWindowSDL::bringToFront() // This is currently used when we are 'launched' to a specific // map position externally. LL_INFOS() << "bringToFront" << LL_ENDL; -#if LL_X11 - if (mSDL_Display && !mFullscreen) + if (mWindow && !mFullscreen) { - maybe_lock_display(); - XRaiseWindow(mSDL_Display, mSDL_XWindowID); - XSync(mSDL_Display, False); - maybe_unlock_display(); + SDL_RaiseWindow(mWindow); } -#endif // LL_X11 } //static @@ -2787,8 +1987,8 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() // 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; + FcFontSet *fs = nullptr; + FcPattern *sortpat = nullptr; LL_INFOS() << "Getting system font list from FontConfig..." << LL_ENDL; @@ -2797,7 +1997,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() // 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_Locale *locale = nullptr; FL_Success success = FL_FindLocale(&locale, FL_MESSAGES); if (success != 0) { @@ -2828,8 +2028,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() { // Sort the list of system fonts from most-to-least-desirable. FcResult result; - fs = FcFontSort(NULL, sortpat, elide_unicode_coverage, - NULL, &result); + fs = FcFontSort(nullptr, sortpat, elide_unicode_coverage, nullptr, &result); FcPatternDestroy(sortpat); } @@ -2842,10 +2041,7 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() for (int i=0; i<fs->nfont; ++i) { FcChar8 *filename; - if (FcResultMatch == FcPatternGetString(fs->fonts[i], - FC_FILE, 0, - &filename) - && 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) @@ -2856,66 +2052,17 @@ std::vector<std::string> LLWindowSDL::getDynamicFallbackFontList() } LL_DEBUGS() << "Using font list: " << LL_ENDL; - for (std::vector<std::string>::iterator it = rtns.begin(); - it != rtns.end(); - ++it) + for (auto 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) -{ - if( !enable_vsync) - { - SDL_GL_SetSwapInterval(0); - SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC,"0",SDL_HINT_OVERRIDE); - } - else - { - SDL_GL_SetSwapInterval(1); - SDL_SetHintWithPriority(SDL_HINT_RENDER_VSYNC,"1",SDL_HINT_OVERRIDE); - } -} - void LLWindowSDL::setLanguageTextInput(const LLCoordGL& position) { LLCoordWindow win_pos; |