summaryrefslogtreecommitdiff
path: root/indra/llwindow
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llwindow')
-rw-r--r--indra/llwindow/llwindowsdl.cpp524
-rw-r--r--indra/llwindow/llwindowsdl.h96
2 files changed, 300 insertions, 320 deletions
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);