diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/cmake/UI.cmake | 9 | ||||
-rw-r--r-- | indra/llrender/llgl.cpp | 5 | ||||
-rw-r--r-- | indra/llwindow/llwindowsdl.cpp | 524 | ||||
-rw-r--r-- | indra/llwindow/llwindowsdl.h | 96 |
4 files changed, 313 insertions, 321 deletions
diff --git a/indra/cmake/UI.cmake b/indra/cmake/UI.cmake index ae039b4a47..a407f68db3 100644 --- a/indra/cmake/UI.cmake +++ b/indra/cmake/UI.cmake @@ -13,6 +13,15 @@ if (LINUX) return() endif() + include(FindPkgConfig) + pkg_check_modules(WAYLAND_CLIENT wayland-client) + + if( WAYLAND_CLIENT_FOUND ) + target_compile_definitions( ll::uilibraries INTERFACE LL_WAYLAND=1) + else() + message("pkgconfig could not find wayland client, compiling without full wayland support") + endif() + target_link_libraries( ll::uilibraries INTERFACE fltk Xrender diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 798b605f08..9209cdcb51 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -1433,7 +1433,10 @@ void LLGLManager::initExtensions() mHasDebugOutput = mGLVersion >= 4.29f; #if LL_WINDOWS || LL_LINUX - mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); + if( gGLHExts.mSysExts ) + mHasNVXGpuMemoryInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); + else + LL_WARNS() << "gGLHExts.mSysExts is not set.?" << LL_ENDL; #endif // Misc diff --git a/indra/llwindow/llwindowsdl.cpp b/indra/llwindow/llwindowsdl.cpp index ea95a5aa2e..f87a00c34b 100644 --- a/indra/llwindow/llwindowsdl.cpp +++ b/indra/llwindow/llwindowsdl.cpp @@ -50,10 +50,10 @@ extern "C" { #if LL_LINUX // 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> -# include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdio.h> #endif // LL_LINUX extern bool gDebugWindowProc; @@ -64,52 +64,170 @@ const S32 MAX_NUM_RESOLUTIONS = 200; // 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; + if (gWindowImplementation) + return gWindowImplementation->mX11Data.mDisplay; + return nullptr; +} + +/* + * 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> + +bool LLWindowSDL::isWaylandWindowNotDrawing() const +{ + if( Wayland != mServerProtocol || mWaylandData.mLastFrameEvent == 0 ) + return false; + + auto currentTime = LLTimer::getTotalTime(); + if( (currentTime - mWaylandData.mLastFrameEvent) > 250000 ) + return true; + + return false; +} + +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); + +wl_interface *ll_wl_callback_interface; + +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); +} + +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, ...); + + +bool loadWaylandClient() +{ + auto *pSO = dlopen( "libwayland-client.so", RTLD_NOW); + if( !pSO ) + return false; + + + 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 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; +} + +struct wl_callback* ll_wl_surface_frame(struct wl_surface *wl_surface) +{ + auto version = ll_wl_proxy_get_version((struct wl_proxy *) wl_surface); + + auto callback = ll_wl_proxy_marshal_flags((struct wl_proxy *) wl_surface, + WL_SURFACE_FRAME, ll_wl_callback_interface, version, + 0, nullptr); + + return (struct wl_callback *) callback; +} + +void ll_wl_callback_destroy(struct wl_callback *wl_callback) +{ + ll_wl_proxy_destroy((struct wl_proxy *) wl_callback); +} + +void LLWindowSDL::waylandFrameDoneCB(void *data, struct wl_callback *cb, uint32_t time) +{ + static uint32_t frame_count {0}; + static F64SecondsImplicit lastInfo{0}; + + ++frame_count; + + ll_wl_callback_destroy(cb); + auto pThis = reinterpret_cast<LLWindowSDL*>(data); + pThis->mWaylandData.mLastFrameEvent = LLTimer::getTotalTime(); + + auto now = LLTimer::getElapsedSeconds(); + if( lastInfo > 0) + { + auto diff = now.value() - lastInfo.value(); + constexpr double FPS_INFO_INTERVAL = 60.f * 5.f; + if( diff >= FPS_INFO_INTERVAL) + { + double fFPS = frame_count; + fFPS /= diff; + LL_INFOS() << "Wayland: FPS " << fFPS << " fps, " << frame_count << " #frames time " << (diff) << LL_ENDL; + frame_count = 0; + lastInfo = now; + } } - return NULL; + else + lastInfo = now; + + pThis->setupWaylandFrameCallback(); // ask for a new frame } -#endif // LL_X11 + +void LLWindowSDL::setupWaylandFrameCallback() +{ + static wl_callback_listener frame_listener { nullptr }; + frame_listener.done = &LLWindowSDL::waylandFrameDoneCB; + + auto cb = ll_wl_surface_frame(mWaylandData.mSurface); + ll_wl_callback_add_listener(cb, &frame_listener, this); +} +#else +bool LLWindowSDL::isWaylandWindowNotDrawing() +{ + 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, const std::string& name, S32 x, S32 y, S32 width, @@ -118,29 +236,12 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, 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) + 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 - - // 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 = nullptr; -#endif // LL_X11 // Assume 4:3 aspect ratio until we know better mOriginalAspectRatio = 1024.0 / 768.0; @@ -167,8 +268,6 @@ LLWindowSDL::LLWindowSDL(LLWindowCallbacks* callbacks, mFlashing = false; - mKeyVirtualKey = 0; - mKeyModifiers = KMOD_NONE; } static SDL_Surface *Load_BMP_Resource(const char *basename) @@ -197,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 @@ -205,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; @@ -237,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; @@ -247,16 +345,10 @@ void LLWindowSDL::tryFindFullscreenSize( int &width, int &height ) bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync) { - if (width == 0) - width = 1024; - if (height == 0) - width = 768; - 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; if (width == 0) width = 1024; @@ -269,15 +361,6 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b mFullscreen = fullscreen; - int sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - - if( mFullscreen ) - { - sdlflags |= SDL_WINDOW_FULLSCREEN; - tryFindFullscreenSize( width, height ); - } - - mSDLFlags = sdlflags; // Setup default backing colors GLint redBits{8}, greenBits{8}, blueBits{8}, alphaBits{8}; @@ -300,13 +383,19 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, context_flags); SDL_GL_SetAttribute(SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1); - // Create the window - mWindow = SDL_CreateWindow(mWindowTitle.c_str(), x, y, width, height, mSDLFlags); + 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) { LL_WARNS() << "Window creation failure. SDL: " << SDL_GetError() << LL_ENDL; setupFailure("Window creation error", "Error", OSMB_OK); - return false; } // Create the context @@ -315,14 +404,12 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b { LL_WARNS() << "Cannot create GL context " << SDL_GetError() << LL_ENDL; setupFailure("GL Context creation error", "Error", OSMB_OK); - return false; } 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); - return false; } mSurface = SDL_GetWindowSurface(mWindow); @@ -345,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; @@ -353,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 @@ -363,7 +449,6 @@ 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; } } @@ -397,7 +482,6 @@ 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; } LL_PROFILER_GPU_CONTEXT; @@ -411,10 +495,9 @@ bool LLWindowSDL::createContext(int x, int y, int width, int height, int bits, b { SDL_SetWindowIcon(mWindow, bmpsurface); SDL_FreeSurface(bmpsurface); - bmpsurface = NULL; + bmpsurface = nullptr; } -#if LL_X11 /* Grab the window manager specific information */ SDL_SysWMinfo info; SDL_VERSION(&info.version); @@ -423,21 +506,41 @@ 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; + 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() ) + LL_ERRS() << "Failed to load wayland-client.so or grab required functions" << LL_ENDL; + + 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 @@ -523,12 +626,11 @@ void LLWindowSDL::destroyContext() LL_INFOS() << "shutdownGL begins" << LL_ENDL; gGLManager.shutdownGL(); -#if LL_X11 - mSDL_Display = NULL; - mSDL_XWindowID = None; - Lock_Display = NULL; - Unlock_Display = NULL; -#endif // LL_X11 + mX11Data.mDisplay = nullptr; + mX11Data.mXWindowID = None; + Lock_Display = nullptr; + Unlock_Display = nullptr; + mServerProtocol = Unknown; LL_INFOS() << "Destroying SDL cursors" << LL_ENDL; quitCursors(); @@ -564,12 +666,9 @@ LLWindowSDL::~LLWindowSDL() { destroyContext(); - if(mSupportedResolutions != NULL) - { - delete []mSupportedResolutions; - } + delete []mSupportedResolutions; - gWindowImplementation = NULL; + gWindowImplementation = nullptr; } @@ -589,7 +688,6 @@ void LLWindowSDL::hide() } } -//virtual void LLWindowSDL::minimize() { if (mWindow) @@ -598,7 +696,6 @@ void LLWindowSDL::minimize() } } -//virtual void LLWindowSDL::restore() { if (mWindow) @@ -611,12 +708,6 @@ void LLWindowSDL::restore() // 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(); @@ -626,7 +717,7 @@ void LLWindowSDL::close() bool LLWindowSDL::isValid() { - return (mWindow != NULL); + return mWindow != nullptr; } bool LLWindowSDL::getVisible() const @@ -645,6 +736,9 @@ bool LLWindowSDL::getVisible() const bool LLWindowSDL::getMinimized() const { + if( isWaylandWindowNotDrawing() ) + return true; + bool result = false; if (mWindow) { @@ -698,10 +792,10 @@ bool LLWindowSDL::getSize(LLCoordScreen *size) const { size->mX = mSurface->w; size->mY = mSurface->h; - return (true); + return true; } - return (false); + return false; } bool LLWindowSDL::getSize(LLCoordWindow *size) const @@ -710,10 +804,10 @@ bool LLWindowSDL::getSize(LLCoordWindow *size) const { size->mX = mSurface->w; size->mY = mSurface->h; - return (true); + return true; } - return (false); + return false; } bool LLWindowSDL::setPosition(const LLCoordScreen position) @@ -737,7 +831,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; @@ -803,7 +896,8 @@ bool LLWindowSDL::setGamma(const F32 gamma) Uint16 ramp[256]; mGamma = gamma; - if (mGamma == 0) mGamma = 0.1f; + if (mGamma == 0) + mGamma = 0.1f; mGamma = 1.f / mGamma; SDL_CalculateGammaRamp(mGamma, ramp); @@ -820,7 +914,8 @@ bool LLWindowSDL::isCursorHidden() // Constrains the mouse to the window. 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 @@ -840,17 +935,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. 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; } @@ -868,7 +957,6 @@ bool LLWindowSDL::getCursorPosition(LLCoordWindow *position) return convertCoords(screen_pos, position); } - F32 LLWindowSDL::getNativeAspectRatio() { // MBW -- there are a couple of bad assumptions here. One is that the display list won't include @@ -889,9 +977,7 @@ F32 LLWindowSDL::getNativeAspectRatio() // switching, and stashes it in mOriginalAspectRatio. Here, we just return it. if (mOverrideAspectRatio > 0.f) - { return mOverrideAspectRatio; - } return mOriginalAspectRatio; } @@ -903,9 +989,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; @@ -916,61 +1000,34 @@ 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 ); } void LLWindowSDL::flashIcon(F32 seconds) @@ -987,6 +1044,15 @@ void LLWindowSDL::flashIcon(F32 seconds) mFlashing = true; } +void LLWindowSDL::maybeStopFlashIcon() +{ + if (mFlashing && mFlashTimer.hasExpired()) + { + mFlashing = false; + SDL_FlashWindow( mWindow, SDL_FLASH_CANCEL ); + } +} + bool LLWindowSDL::isClipboardTextAvailable() { return SDL_HasClipboardText() == SDL_TRUE; @@ -1054,9 +1120,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; @@ -1109,7 +1173,7 @@ bool LLWindowSDL::convertCoords(LLCoordScreen from, LLCoordWindow* to) const // 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) const @@ -1120,21 +1184,21 @@ bool LLWindowSDL::convertCoords(LLCoordWindow from, LLCoordScreen *to) const // 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) 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) 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) @@ -1142,55 +1206,17 @@ void LLWindowSDL::setupFailure(const std::string& text, const std::string& capti 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 (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 (!mFullscreen && mWindow ) /* only bother if we're windowed anyway */ + SDL_SetWindowGrab( mWindow, capture?SDL_TRUE:SDL_FALSE); - if (!mFullscreen) /* only bother if we're windowed anyway */ - { - int result; - if (wantGrab == true) - { - result = SDL_CaptureMouse(SDL_TRUE); - if (0 == result) - newGrab = true; - else - newGrab = false; - } - else - { - newGrab = false; - result = SDL_CaptureMouse(SDL_FALSE); - } - } - - // return boolean success for whether we ended up in the desired state - return capture == newGrab; + return capture; } U32 LLWindowSDL::SDLCheckGrabbyKeys(U32 keysym, bool gain) @@ -1237,7 +1263,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"); @@ -1252,7 +1277,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); @@ -1262,7 +1287,7 @@ void check_vm_bloat() goto finally; } free(ptr); - ptr = NULL; + ptr = nullptr; } // 23rd space-delimited entry is vsize res = getdelim(&ptr, &dummy, ' ', fp); @@ -1274,7 +1299,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); @@ -1285,12 +1310,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) { @@ -1302,8 +1326,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) { @@ -1319,21 +1342,16 @@ void check_vm_bloat() last_vm_size = this_vm_size; finally: - if (NULL != ptr) - { + 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; @@ -1343,18 +1361,15 @@ 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(bool app_has_focus) { - SDL_Event event; + SDL_Event event; // Handle all outstanding SDL events while (SDL_PollEvent(&event)) @@ -1388,7 +1403,7 @@ void LLWindowSDL::gatherInput(bool app_has_focus) { auto string = utf8str_to_utf16str( event.text.text ); mKeyModifiers = gKeyboard->currentMask( false ); - mInputType = "textinput"; + for( auto key: string ) { mKeyVirtualKey = key; @@ -1404,13 +1419,10 @@ void LLWindowSDL::gatherInput(bool app_has_focus) 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 ); @@ -1433,13 +1445,10 @@ void LLWindowSDL::gatherInput(bool app_has_focus) 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 @@ -1461,7 +1470,7 @@ void LLWindowSDL::gatherInput(bool app_has_focus) 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); } @@ -1591,12 +1600,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; @@ -1670,12 +1679,10 @@ void LLWindowSDL::updateCursor() void LLWindowSDL::initCursors() { - int i; // Blank the cursor pointer array for those we may miss. - for (i=0; i<UI_CURSOR_COUNT; ++i) - { + 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. @@ -1728,23 +1735,24 @@ void LLWindowSDL::initCursors() 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; } } @@ -1872,7 +1880,7 @@ 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; } /* @@ -1902,7 +1910,6 @@ LLSD LLWindowSDL::getNativeKeyData() const result["virtual_key"] = (S32)mKeyVirtualKey; result["virtual_key_win"] = (S32)LLKeyboardSDL::mapSDL2toWin( mKeyVirtualKey ); result["modifiers"] = (S32)modifiers; - result["input_type"] = mInputType; return result; } @@ -1939,7 +1946,7 @@ void LLWindowSDL::spawnWebBrowser(const std::string& escaped_url, bool async) void *LLWindowSDL::getPlatformWindow() { - return NULL; + return nullptr; } void LLWindowSDL::bringToFront() @@ -1973,8 +1980,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; @@ -1983,7 +1990,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) { @@ -2014,8 +2021,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); } @@ -2028,10 +2034,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) @@ -2042,12 +2045,11 @@ 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); diff --git a/indra/llwindow/llwindowsdl.h b/indra/llwindow/llwindowsdl.h index a85b7c11e7..974ba69b61 100644 --- a/indra/llwindow/llwindowsdl.h +++ b/indra/llwindow/llwindowsdl.h @@ -11,7 +11,6 @@ * 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. @@ -36,10 +35,8 @@ #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 "SDL2/SDL_syswm.h" -#endif // AssertMacros.h does bad things. #include "fix_macros.h" @@ -50,8 +47,8 @@ class LLWindowSDL : public LLWindow { public: void show() override; - void hide() override; + void restore() override; void close() override; @@ -62,11 +59,8 @@ public: bool getMaximized() const override; bool maximize() override; - void minimize() override; - void restore() override; - bool getPosition(LLCoordScreen *position) const override; bool getSize(LLCoordScreen *size) const override; @@ -87,49 +81,38 @@ public: bool getCursorPosition(LLCoordWindow *position) override; void showCursor() override; - void hideCursor() override; + bool isCursorHidden() 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; + 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; + void maybeStopFlashIcon(); F32 getGamma() const override; - bool setGamma(const F32 gamma) override; // Set the gamma + bool restoreGamma() override; // Restore original gamma table (before updating gamma) U32 getFSAASamples() const override; - void setFSAASamples(const U32 samples) override; - bool restoreGamma() override; // Restore original gamma table (before updating gamma) - void processMiscNativeEvents() override; void gatherInput(bool app_has_focus) override; @@ -162,7 +145,6 @@ public: void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } void beforeDialog() override; - void afterDialog() override; bool dialogColorPicker(F32 *r, F32 *g, F32 *b) override; @@ -179,31 +161,15 @@ public: 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; -#endif - - void (*Lock_Display)(void); - - void (*Unlock_Display)(void); - -#if LL_X11 + void (*Lock_Display)(void) = nullptr; + void (*Unlock_Display)(void) = nullptr; 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; protected: @@ -219,7 +185,6 @@ protected: LLSD getNativeKeyData() const override; void initCursors(); - void quitCursors(); void moveWindow(const LLCoordScreen &position, const LLCoordScreen &size); @@ -239,7 +204,6 @@ protected: // create or re-create the GL context/window. Called from the constructor and switchContext(). bool createContext(int x, int y, int width, int height, int bits, bool fullscreen, bool enable_vsync); - void destroyContext(); void setupFailure(const std::string &text, const std::string &caption, U32 type); @@ -251,36 +215,50 @@ protected: // // Platform specific variables // - U32 mGrabbyKeyFlags; - int mReallyCapturedCount; + U32 mGrabbyKeyFlags = 0; - SDL_Window *mWindow; + SDL_Window *mWindow = nullptr; 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. + double mOriginalAspectRatio = 1.0f; + bool mNeedsResize = false; // Constructor figured out the window is too big, it needs a resize. LLCoordScreen mNeedsResizeSize; - F32 mOverrideAspectRatio; - F32 mGamma; - U32 mFSAASamples; + F32 mOverrideAspectRatio = 0.0f; + F32 mGamma = 0.0f; + U32 mFSAASamples = 0; - int mSDLFlags; - - int mHaveInputFocus; /* 0=no, 1=yes, else unknown */ - int mIsMinimized; /* 0=no, 1=yes, else unknown */ + int mHaveInputFocus = -1; /* 0=no, 1=yes, else unknown */ friend class LLWindowManager; private: - bool mFlashing; + bool mFlashing = false; LLTimer mFlashTimer; - U32 mKeyVirtualKey; - U32 mKeyModifiers; - std::string mInputType; + U32 mKeyVirtualKey = 0; + U32 mKeyModifiers = KMOD_NONE; + + enum EServerProtocol{ X11, Wayland, Unknown }; + EServerProtocol mServerProtocol = Unknown; + struct { + Window mXWindowID = None; + Display *mDisplay = nullptr; + } mX11Data; + + // Wayland + struct { + wl_surface *mSurface = nullptr; + uint64_t mLastFrameEvent = 0; + } mWaylandData; + + bool isWaylandWindowNotDrawing() const; + + void setupWaylandFrameCallback(); + static void waylandFrameDoneCB(void *data, struct wl_callback *cb, uint32_t time); + // private: void tryFindFullscreenSize(int &aWidth, int &aHeight); |