226 lines
6.2 KiB
C++
226 lines
6.2 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "WindowSurfaceProvider.h"
|
|
|
|
#include "gfxPlatformGtk.h"
|
|
#include "GtkCompositorWidget.h"
|
|
#include "mozilla/gfx/Logging.h"
|
|
#include "mozilla/layers/LayersTypes.h"
|
|
#include "nsWindow.h"
|
|
#include "mozilla/ScopeExit.h"
|
|
#include "WidgetUtilsGtk.h"
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
# include "mozilla/StaticPrefs_widget.h"
|
|
# include "WindowSurfaceCairo.h"
|
|
# include "WindowSurfaceWaylandMultiBuffer.h"
|
|
#endif
|
|
#ifdef MOZ_X11
|
|
# include "mozilla/X11Util.h"
|
|
# include "WindowSurfaceX11Image.h"
|
|
# include "WindowSurfaceX11SHM.h"
|
|
#endif
|
|
|
|
#undef LOG
|
|
#ifdef MOZ_LOGGING
|
|
# include "mozilla/Logging.h"
|
|
# include "nsTArray.h"
|
|
# include "Units.h"
|
|
extern mozilla::LazyLogModule gWidgetLog;
|
|
# define LOG(args) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, args)
|
|
#else
|
|
# define LOG(args)
|
|
#endif /* MOZ_LOGGING */
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
using namespace mozilla::layers;
|
|
|
|
WindowSurfaceProvider::WindowSurfaceProvider()
|
|
: mWindowSurface(nullptr),
|
|
mMutex("WindowSurfaceProvider"),
|
|
mWindowSurfaceValid(false)
|
|
#ifdef MOZ_X11
|
|
,
|
|
mXDepth(0),
|
|
mXWindow(0),
|
|
mXVisual(nullptr)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
WindowSurfaceProvider::~WindowSurfaceProvider() {
|
|
#ifdef MOZ_WAYLAND
|
|
MOZ_DIAGNOSTIC_ASSERT(!mWidget,
|
|
"nsWindow reference is still live, we're leaking it!");
|
|
#endif
|
|
#ifdef MOZ_X11
|
|
MOZ_DIAGNOSTIC_ASSERT(!mXWindow, "mXWindow should be released on quit!");
|
|
#endif
|
|
}
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
bool WindowSurfaceProvider::Initialize(RefPtr<nsWindow> aWidget) {
|
|
mWindowSurfaceValid = false;
|
|
mWidget = std::move(aWidget);
|
|
return true;
|
|
}
|
|
bool WindowSurfaceProvider::Initialize(GtkCompositorWidget* aCompositorWidget) {
|
|
mWindowSurfaceValid = false;
|
|
mCompositorWidget = aCompositorWidget;
|
|
mWidget = static_cast<nsWindow*>(aCompositorWidget->RealWidget());
|
|
return true;
|
|
}
|
|
#endif
|
|
#ifdef MOZ_X11
|
|
bool WindowSurfaceProvider::Initialize(Window aWindow) {
|
|
mWindowSurfaceValid = false;
|
|
|
|
// Grab the window's visual and depth
|
|
XWindowAttributes windowAttrs;
|
|
if (!XGetWindowAttributes(DefaultXDisplay(), aWindow, &windowAttrs)) {
|
|
NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
|
|
return false;
|
|
}
|
|
|
|
mXWindow = aWindow;
|
|
mXVisual = windowAttrs.visual;
|
|
mXDepth = windowAttrs.depth;
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void WindowSurfaceProvider::CleanupResources() {
|
|
MutexAutoLock lock(mMutex);
|
|
mWindowSurfaceValid = false;
|
|
#ifdef MOZ_WAYLAND
|
|
mWidget = nullptr;
|
|
#endif
|
|
#ifdef MOZ_X11
|
|
mXWindow = 0;
|
|
mXVisual = 0;
|
|
mXDepth = 0;
|
|
#endif
|
|
}
|
|
|
|
RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
|
|
#ifdef MOZ_WAYLAND
|
|
if (GdkIsWaylandDisplay()) {
|
|
// We're called too early or we're unmapped.
|
|
if (!mWidget) {
|
|
return nullptr;
|
|
}
|
|
if (mWidget->IsDragPopup()) {
|
|
return MakeRefPtr<WindowSurfaceCairo>(mWidget);
|
|
}
|
|
return MakeRefPtr<WindowSurfaceWaylandMB>(mWidget, mCompositorWidget);
|
|
}
|
|
#endif
|
|
#ifdef MOZ_X11
|
|
if (GdkIsX11Display()) {
|
|
// We're called too early or we're unmapped.
|
|
if (!mXWindow) {
|
|
return nullptr;
|
|
}
|
|
// Blit to the window with the following priority:
|
|
// 1. MIT-SHM
|
|
// 2. XPutImage
|
|
# ifdef MOZ_HAVE_SHMIMAGE
|
|
if (nsShmImage::UseShm()) {
|
|
LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", (Window)mXWindow));
|
|
return MakeRefPtr<WindowSurfaceX11SHM>(DefaultXDisplay(), mXWindow,
|
|
mXVisual, mXDepth);
|
|
}
|
|
# endif // MOZ_HAVE_SHMIMAGE
|
|
|
|
LOG(("Drawing to Window 0x%lx will use XPutImage\n", (Window)mXWindow));
|
|
return MakeRefPtr<WindowSurfaceX11Image>(DefaultXDisplay(), mXWindow,
|
|
mXVisual, mXDepth);
|
|
}
|
|
#endif
|
|
MOZ_RELEASE_ASSERT(false);
|
|
}
|
|
|
|
// We need to ignore thread safety checks here. We need to hold mMutex
|
|
// between StartRemoteDrawingInRegion()/EndRemoteDrawingInRegion() calls
|
|
// which confuses it.
|
|
MOZ_PUSH_IGNORE_THREAD_SAFETY
|
|
|
|
already_AddRefed<gfx::DrawTarget>
|
|
WindowSurfaceProvider::StartRemoteDrawingInRegion(
|
|
const LayoutDeviceIntRegion& aInvalidRegion) {
|
|
if (aInvalidRegion.IsEmpty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
// We return a reference to mWindowSurface inside draw target so we need to
|
|
// hold the mutex untill EndRemoteDrawingInRegion() call where draw target
|
|
// is returned.
|
|
// If we return null dt, EndRemoteDrawingInRegion() won't be called to
|
|
// release mutex.
|
|
mMutex.Lock();
|
|
auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
|
|
|
|
if (!mWindowSurfaceValid) {
|
|
mWindowSurface = nullptr;
|
|
mWindowSurfaceValid = true;
|
|
}
|
|
|
|
if (!mWindowSurface) {
|
|
mWindowSurface = CreateWindowSurface();
|
|
if (!mWindowSurface) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
RefPtr<gfx::DrawTarget> dt = mWindowSurface->Lock(aInvalidRegion);
|
|
#ifdef MOZ_X11
|
|
if (!dt && GdkIsX11Display() && !mWindowSurface->IsFallback()) {
|
|
// We can't use WindowSurfaceX11Image fallback on Wayland but
|
|
// Lock() call on WindowSurfaceWayland should never fail.
|
|
gfxWarningOnce()
|
|
<< "Failed to lock WindowSurface, falling back to XPutImage backend.";
|
|
mWindowSurface = MakeRefPtr<WindowSurfaceX11Image>(
|
|
DefaultXDisplay(), mXWindow, mXVisual, mXDepth);
|
|
dt = mWindowSurface->Lock(aInvalidRegion);
|
|
}
|
|
#endif
|
|
if (dt) {
|
|
// We have valid dt, mutex will be released in EndRemoteDrawingInRegion().
|
|
unlockMutex.release();
|
|
}
|
|
|
|
return dt.forget();
|
|
}
|
|
|
|
void WindowSurfaceProvider::EndRemoteDrawingInRegion(
|
|
gfx::DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
|
|
// Unlock mutex from StartRemoteDrawingInRegion().
|
|
mMutex.AssertCurrentThreadOwns();
|
|
auto unlockMutex = MakeScopeExit([&] { mMutex.Unlock(); });
|
|
|
|
// Commit to mWindowSurface only if we have a valid one.
|
|
if (!mWindowSurface || !mWindowSurfaceValid) {
|
|
return;
|
|
}
|
|
#if defined(MOZ_WAYLAND)
|
|
if (GdkIsWaylandDisplay()) {
|
|
// We're called too early or we're unmapped.
|
|
// Don't draw anything.
|
|
if (!mWidget || !mWidget->IsMapped()) {
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
mWindowSurface->Commit(aInvalidRegion);
|
|
}
|
|
|
|
MOZ_POP_THREAD_SAFETY
|
|
|
|
} // namespace widget
|
|
} // namespace mozilla
|