summaryrefslogtreecommitdiffstats
path: root/widget/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'widget/gtk')
-rw-r--r--widget/gtk/CompositorWidgetChild.cpp10
-rw-r--r--widget/gtk/CompositorWidgetChild.h5
-rw-r--r--widget/gtk/CompositorWidgetParent.cpp8
-rw-r--r--widget/gtk/CompositorWidgetParent.h6
-rw-r--r--widget/gtk/GtkCompositorWidget.cpp50
-rw-r--r--widget/gtk/GtkCompositorWidget.h21
-rw-r--r--widget/gtk/MPRISServiceHandler.cpp6
-rw-r--r--widget/gtk/MozContainer.cpp11
-rw-r--r--widget/gtk/MozContainerWayland.cpp15
-rw-r--r--widget/gtk/PCompositorWidget.ipdl4
-rw-r--r--widget/gtk/ScreenHelperGTK.cpp2
-rw-r--r--widget/gtk/WindowSurfaceProvider.cpp30
-rw-r--r--widget/gtk/WindowSurfaceProvider.h9
-rw-r--r--widget/gtk/nsDragService.cpp55
-rw-r--r--widget/gtk/nsLookAndFeel.cpp4
-rw-r--r--widget/gtk/nsNativeThemeGTK.cpp16
-rw-r--r--widget/gtk/nsWindow.cpp493
-rw-r--r--widget/gtk/nsWindow.h29
18 files changed, 396 insertions, 378 deletions
diff --git a/widget/gtk/CompositorWidgetChild.cpp b/widget/gtk/CompositorWidgetChild.cpp
index b7908a43d4..3b6af872ed 100644
--- a/widget/gtk/CompositorWidgetChild.cpp
+++ b/widget/gtk/CompositorWidgetChild.cpp
@@ -38,13 +38,13 @@ void CompositorWidgetChild::NotifyClientSizeChanged(
Unused << SendNotifyClientSizeChanged(aClientSize);
}
-void CompositorWidgetChild::DisableRendering() {
- Unused << SendDisableRendering();
+void CompositorWidgetChild::CleanupResources() {
+ Unused << SendCleanupResources();
}
-void CompositorWidgetChild::EnableRendering(const uintptr_t aXWindow,
- const bool aShaped) {
- Unused << SendEnableRendering(aXWindow, aShaped);
+void CompositorWidgetChild::SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) {
+ Unused << SendSetRenderingSurface(aXWindow, aShaped);
}
} // namespace widget
diff --git a/widget/gtk/CompositorWidgetChild.h b/widget/gtk/CompositorWidgetChild.h
index b1cad75da3..f46cf63bfb 100644
--- a/widget/gtk/CompositorWidgetChild.h
+++ b/widget/gtk/CompositorWidgetChild.h
@@ -27,8 +27,9 @@ class CompositorWidgetChild final : public PCompositorWidgetChild,
mozilla::ipc::IPCResult RecvUnobserveVsync() override;
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
- void DisableRendering() override;
- void EnableRendering(const uintptr_t aXWindow, const bool aShaped) override;
+ void CleanupResources() override;
+ void SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) override;
private:
RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;
diff --git a/widget/gtk/CompositorWidgetParent.cpp b/widget/gtk/CompositorWidgetParent.cpp
index 998614622e..7f576f35e7 100644
--- a/widget/gtk/CompositorWidgetParent.cpp
+++ b/widget/gtk/CompositorWidgetParent.cpp
@@ -40,14 +40,14 @@ mozilla::ipc::IPCResult CompositorWidgetParent::RecvNotifyClientSizeChanged(
return IPC_OK();
}
-mozilla::ipc::IPCResult CompositorWidgetParent::RecvDisableRendering() {
- DisableRendering();
+mozilla::ipc::IPCResult CompositorWidgetParent::RecvCleanupResources() {
+ CleanupResources();
return IPC_OK();
}
-mozilla::ipc::IPCResult CompositorWidgetParent::RecvEnableRendering(
+mozilla::ipc::IPCResult CompositorWidgetParent::RecvSetRenderingSurface(
const uintptr_t& aXWindow, const bool& aShaped) {
- EnableRendering(aXWindow, aShaped);
+ SetRenderingSurface(aXWindow, aShaped);
return IPC_OK();
}
diff --git a/widget/gtk/CompositorWidgetParent.h b/widget/gtk/CompositorWidgetParent.h
index 2bbc70af3e..8c0a6e8c26 100644
--- a/widget/gtk/CompositorWidgetParent.h
+++ b/widget/gtk/CompositorWidgetParent.h
@@ -28,9 +28,9 @@ class CompositorWidgetParent final : public PCompositorWidgetParent,
mozilla::ipc::IPCResult RecvNotifyClientSizeChanged(
const LayoutDeviceIntSize& aClientSize) override;
- mozilla::ipc::IPCResult RecvDisableRendering() override;
- mozilla::ipc::IPCResult RecvEnableRendering(const uintptr_t& aXWindow,
- const bool& aShaped) override;
+ mozilla::ipc::IPCResult RecvCleanupResources() override;
+ mozilla::ipc::IPCResult RecvSetRenderingSurface(const uintptr_t& aXWindow,
+ const bool& aShaped) override;
private:
RefPtr<VsyncObserver> mVsyncObserver;
diff --git a/widget/gtk/GtkCompositorWidget.cpp b/widget/gtk/GtkCompositorWidget.cpp
index 36559cfd54..073ad5248f 100644
--- a/widget/gtk/GtkCompositorWidget.cpp
+++ b/widget/gtk/GtkCompositorWidget.cpp
@@ -7,6 +7,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/WidgetUtilsGtk.h"
#include "mozilla/widget/InProcessCompositorWidget.h"
#include "mozilla/widget/PlatformWidgetTypes.h"
#include "nsWindow.h"
@@ -40,25 +41,22 @@ GtkCompositorWidget::GtkCompositorWidget(
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
ConfigureX11Backend((Window)aInitData.XWindow(), aInitData.Shaped());
- LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p "
- "mIsRenderingSuspended %d\n",
- (void*)mWidget.get(), (void*)aInitData.XWindow(),
- !!mIsRenderingSuspended);
+ LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mXWindow %p\n",
+ (void*)mWidget.get(), (void*)aInitData.XWindow());
}
#endif
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
ConfigureWaylandBackend();
- LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mWidget %p "
- "mIsRenderingSuspended %d\n",
- (void*)mWidget.get(), (void*)mWidget, !!mIsRenderingSuspended);
+ LOG("GtkCompositorWidget::GtkCompositorWidget() [%p] mWidget %p\n",
+ (void*)mWidget.get(), (void*)mWidget);
}
#endif
}
GtkCompositorWidget::~GtkCompositorWidget() {
LOG("GtkCompositorWidget::~GtkCompositorWidget [%p]\n", (void*)mWidget.get());
- DisableRendering();
+ CleanupResources();
RefPtr<nsIWidget> widget = mWidget.forget();
NS_ReleaseOnMainThread("GtkCompositorWidget::mWidget", widget.forget());
}
@@ -169,57 +167,47 @@ GtkCompositorWidget::GetNativeLayerRoot() {
}
#endif
-void GtkCompositorWidget::DisableRendering() {
- LOG("GtkCompositorWidget::DisableRendering [%p]\n", (void*)mWidget.get());
- mIsRenderingSuspended = true;
+void GtkCompositorWidget::CleanupResources() {
+ LOG("GtkCompositorWidget::CleanupResources [%p]\n", (void*)mWidget.get());
mProvider.CleanupResources();
}
#if defined(MOZ_WAYLAND)
-bool GtkCompositorWidget::ConfigureWaylandBackend() {
+void GtkCompositorWidget::ConfigureWaylandBackend() {
mProvider.Initialize(this);
- return true;
}
#endif
#if defined(MOZ_X11)
-bool GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
+void GtkCompositorWidget::ConfigureX11Backend(Window aXWindow, bool aShaped) {
// We don't have X window yet.
if (!aXWindow) {
- mIsRenderingSuspended = true;
- return false;
+ mProvider.CleanupResources();
+ return;
}
// Initialize the window surface provider
- return mProvider.Initialize(aXWindow, aShaped);
+ mProvider.Initialize(aXWindow, aShaped);
}
#endif
-void GtkCompositorWidget::EnableRendering(const uintptr_t aXWindow,
- const bool aShaped) {
- LOG("GtkCompositorWidget::EnableRendering() [%p]\n", mWidget.get());
+void GtkCompositorWidget::SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) {
+ LOG("GtkCompositorWidget::SetRenderingSurface() [%p]\n", mWidget.get());
- if (!mIsRenderingSuspended) {
- LOG(" quit, mIsRenderingSuspended = false\n");
- return;
- }
#if defined(MOZ_WAYLAND)
if (GdkIsWaylandDisplay()) {
LOG(" configure widget %p\n", mWidget.get());
- if (!ConfigureWaylandBackend()) {
- return;
- }
+ ConfigureWaylandBackend();
}
#endif
#if defined(MOZ_X11)
if (GdkIsX11Display()) {
LOG(" configure XWindow %p shaped %d\n", (void*)aXWindow, aShaped);
- if (!ConfigureX11Backend((Window)aXWindow, aShaped)) {
- return;
- }
+ ConfigureX11Backend((Window)aXWindow, aShaped);
}
#endif
- mIsRenderingSuspended = false;
}
+
#ifdef MOZ_LOGGING
bool GtkCompositorWidget::IsPopup() {
return mWidget ? mWidget->IsPopup() : false;
diff --git a/widget/gtk/GtkCompositorWidget.h b/widget/gtk/GtkCompositorWidget.h
index bde88bde6c..d4834247f1 100644
--- a/widget/gtk/GtkCompositorWidget.h
+++ b/widget/gtk/GtkCompositorWidget.h
@@ -28,9 +28,9 @@ class PlatformCompositorWidgetDelegate : public CompositorWidgetDelegate {
const LayoutDeviceIntSize& aClientSize) = 0;
virtual GtkCompositorWidget* AsGtkCompositorWidget() { return nullptr; };
- virtual void DisableRendering() = 0;
- virtual void EnableRendering(const uintptr_t aXWindow,
- const bool aShaped) = 0;
+ virtual void CleanupResources() = 0;
+ virtual void SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) = 0;
// CompositorWidgetDelegate Overrides
@@ -74,10 +74,11 @@ class GtkCompositorWidget : public CompositorWidget,
// Suspend rendering of this remote widget and clear all resources.
// Can be used when underlying window is hidden/unmapped.
- void DisableRendering() override;
+ void CleanupResources() override;
// Resume rendering with to given aXWindow (X11) or nsWindow (Wayland).
- void EnableRendering(const uintptr_t aXWindow, const bool aShaped) override;
+ void SetRenderingSurface(const uintptr_t aXWindow,
+ const bool aShaped) override;
// If we fail to set window size (due to different screen scale or so)
// we can't paint the frame by compositor.
@@ -90,11 +91,6 @@ class GtkCompositorWidget : public CompositorWidget,
RefPtr<mozilla::layers::NativeLayerRoot> GetNativeLayerRoot() override;
#endif
- bool PreRender(WidgetRenderingContext* aContext) override {
- return !mIsRenderingSuspended;
- }
- bool IsHidden() const override { return mIsRenderingSuspended; }
-
// PlatformCompositorWidgetDelegate Overrides
void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
@@ -102,10 +98,10 @@ class GtkCompositorWidget : public CompositorWidget,
private:
#if defined(MOZ_WAYLAND)
- bool ConfigureWaylandBackend();
+ void ConfigureWaylandBackend();
#endif
#if defined(MOZ_X11)
- bool ConfigureX11Backend(Window aXWindow, bool aShaped);
+ void ConfigureX11Backend(Window aXWindow, bool aShaped);
#endif
#ifdef MOZ_LOGGING
bool IsPopup();
@@ -129,7 +125,6 @@ class GtkCompositorWidget : public CompositorWidget,
#ifdef MOZ_WAYLAND
RefPtr<mozilla::layers::NativeLayerRootWayland> mNativeLayerRoot;
#endif
- Atomic<bool> mIsRenderingSuspended{true};
};
} // namespace widget
diff --git a/widget/gtk/MPRISServiceHandler.cpp b/widget/gtk/MPRISServiceHandler.cpp
index ae1ef8654d..847bf3d78d 100644
--- a/widget/gtk/MPRISServiceHandler.cpp
+++ b/widget/gtk/MPRISServiceHandler.cpp
@@ -439,10 +439,10 @@ const char* MPRISServiceHandler::DesktopEntry() const {
bool MPRISServiceHandler::PressKey(dom::MediaControlKey aKey) const {
MOZ_ASSERT(mInitialized);
if (!IsMediaKeySupported(aKey)) {
- LOGMPRIS("%s is not supported", ToMediaControlKeyStr(aKey));
+ LOGMPRIS("%s is not supported", dom::GetEnumString(aKey).get());
return false;
}
- LOGMPRIS("Press %s", ToMediaControlKeyStr(aKey));
+ LOGMPRIS("Press %s", dom::GetEnumString(aKey).get());
EmitEvent(aKey);
return true;
}
@@ -861,7 +861,7 @@ bool MPRISServiceHandler::EmitSupportedKeyChanged(dom::MediaControlKey aKey,
bool aSupported) const {
auto it = gKeyProperty.find(aKey);
if (it == gKeyProperty.end()) {
- LOGMPRIS("No property for %s", ToMediaControlKeyStr(aKey));
+ LOGMPRIS("No property for %s", dom::GetEnumString(aKey).get());
return false;
}
diff --git a/widget/gtk/MozContainer.cpp b/widget/gtk/MozContainer.cpp
index 775ae0488f..446dc97a66 100644
--- a/widget/gtk/MozContainer.cpp
+++ b/widget/gtk/MozContainer.cpp
@@ -87,19 +87,18 @@ void moz_container_class_init(MozContainerClass* klass) {
GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); */
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+ widget_class->map = moz_container_map;
widget_class->realize = moz_container_realize;
widget_class->unrealize = moz_container_unrealize;
widget_class->destroy = moz_container_destroy;
#ifdef MOZ_WAYLAND
if (mozilla::widget::GdkIsWaylandDisplay()) {
- widget_class->map = moz_container_wayland_map;
widget_class->size_allocate = moz_container_wayland_size_allocate;
widget_class->map_event = moz_container_wayland_map_event;
widget_class->unmap = moz_container_wayland_unmap;
} else {
#endif
- widget_class->map = moz_container_map;
widget_class->size_allocate = moz_container_size_allocate;
widget_class->unmap = moz_container_unmap;
#ifdef MOZ_WAYLAND
@@ -130,6 +129,10 @@ void moz_container_map(GtkWidget* widget) {
if (gtk_widget_get_has_window(widget)) {
gdk_window_show(gtk_widget_get_window(widget));
}
+
+ // Enable rendering to nsWindow/MozContainer
+ nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget));
+ window->OnMap();
}
void moz_container_unmap(GtkWidget* widget) {
@@ -138,9 +141,9 @@ void moz_container_unmap(GtkWidget* widget) {
LOGCONTAINER(("moz_container_unmap() [%p]",
(void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget))));
- // Disable rendering to MozContainer before we unmap it.
+ // Disable rendering to nsWindow/MozContainer before we really unmap it.
nsWindow* window = moz_container_get_nsWindow(MOZ_CONTAINER(widget));
- window->DisableRendering();
+ window->OnUnmap();
gtk_widget_set_mapped(widget, FALSE);
diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp
index 8490f25599..39e8a48390 100644
--- a/widget/gtk/MozContainerWayland.cpp
+++ b/widget/gtk/MozContainerWayland.cpp
@@ -419,21 +419,6 @@ gboolean moz_container_wayland_map_event(GtkWidget* widget,
return FALSE;
}
-void moz_container_wayland_map(GtkWidget* widget) {
- LOGCONTAINER("%s [%p]\n", __FUNCTION__,
- (void*)moz_container_get_nsWindow(MOZ_CONTAINER(widget)));
-
- g_return_if_fail(IS_MOZ_CONTAINER(widget));
-
- // We need to mark MozContainer as mapped to make sure
- // moz_container_wayland_unmap() is called on hide/withdraw.
- gtk_widget_set_mapped(widget, TRUE);
-
- if (gtk_widget_get_has_window(widget)) {
- gdk_window_show(gtk_widget_get_window(widget));
- }
-}
-
void moz_container_wayland_size_allocate(GtkWidget* widget,
GtkAllocation* allocation) {
GtkAllocation tmp_allocation;
diff --git a/widget/gtk/PCompositorWidget.ipdl b/widget/gtk/PCompositorWidget.ipdl
index d554a33144..e083e8d4ef 100644
--- a/widget/gtk/PCompositorWidget.ipdl
+++ b/widget/gtk/PCompositorWidget.ipdl
@@ -22,8 +22,8 @@ parent:
async __delete__();
async NotifyClientSizeChanged(LayoutDeviceIntSize aClientSize);
- async DisableRendering();
- async EnableRendering(uintptr_t aXWindow, bool aShaped);
+ async CleanupResources();
+ async SetRenderingSurface(uintptr_t aXWindow, bool aShaped);
child:
diff --git a/widget/gtk/ScreenHelperGTK.cpp b/widget/gtk/ScreenHelperGTK.cpp
index 60be234c60..313bf54b1e 100644
--- a/widget/gtk/ScreenHelperGTK.cpp
+++ b/widget/gtk/ScreenHelperGTK.cpp
@@ -269,7 +269,7 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen,
contentsScale.scale, defaultCssScale.scale, dpi, refreshRate);
return MakeAndAddRef<Screen>(rect, availRect, pixelDepth, pixelDepth,
refreshRate, contentsScale, defaultCssScale, dpi,
- Screen::IsPseudoDisplay::No);
+ Screen::IsPseudoDisplay::No, Screen::IsHDR::No);
}
void ScreenGetterGtk::RefreshScreens() {
diff --git a/widget/gtk/WindowSurfaceProvider.cpp b/widget/gtk/WindowSurfaceProvider.cpp
index 82f9029315..c8b2c5a7d6 100644
--- a/widget/gtk/WindowSurfaceProvider.cpp
+++ b/widget/gtk/WindowSurfaceProvider.cpp
@@ -11,6 +11,7 @@
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsWindow.h"
+#include "mozilla/ScopeExit.h"
#ifdef MOZ_WAYLAND
# include "mozilla/StaticPrefs_widget.h"
@@ -129,13 +130,13 @@ RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
// 2. XPutImage
# ifdef MOZ_HAVE_SHMIMAGE
if (!mIsShaped && nsShmImage::UseShm()) {
- LOG(("Drawing to Window 0x%lx will use MIT-SHM\n", mXWindow));
+ 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", mXWindow));
+ LOG(("Drawing to Window 0x%lx will use XPutImage\n", (Window)mXWindow));
return MakeRefPtr<WindowSurfaceX11Image>(DefaultXDisplay(), mXWindow,
mXVisual, mXDepth, mIsShaped);
}
@@ -143,6 +144,11 @@ RefPtr<WindowSurface> WindowSurfaceProvider::CreateWindowSurface() {
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,
@@ -151,7 +157,13 @@ WindowSurfaceProvider::StartRemoteDrawingInRegion(
return nullptr;
}
- MutexAutoLock lock(mMutex);
+ // 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;
@@ -178,12 +190,20 @@ WindowSurfaceProvider::StartRemoteDrawingInRegion(
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) {
- MutexAutoLock lock(mMutex);
+ // 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;
@@ -218,5 +238,7 @@ void WindowSurfaceProvider::EndRemoteDrawingInRegion(
mWindowSurface->Commit(aInvalidRegion);
}
+MOZ_POP_THREAD_SAFETY
+
} // namespace widget
} // namespace mozilla
diff --git a/widget/gtk/WindowSurfaceProvider.h b/widget/gtk/WindowSurfaceProvider.h
index 6aaf50e2da..44a0d78ec6 100644
--- a/widget/gtk/WindowSurfaceProvider.h
+++ b/widget/gtk/WindowSurfaceProvider.h
@@ -81,7 +81,7 @@ class WindowSurfaceProvider final {
*/
mozilla::Mutex mMutex MOZ_UNANNOTATED;
// WindowSurface needs to be re-created as underlying window was changed.
- mozilla::Atomic<bool> mWindowSurfaceValid;
+ bool mWindowSurfaceValid;
#ifdef MOZ_WAYLAND
RefPtr<nsWindow> mWidget;
// WindowSurfaceProvider is owned by GtkCompositorWidget so we don't need
@@ -91,7 +91,12 @@ class WindowSurfaceProvider final {
#ifdef MOZ_X11
bool mIsShaped;
int mXDepth;
- Window mXWindow;
+ // Make mXWindow atomic to allow it read from different threads
+ // and make tsan happy.
+ // We don't care much about actual mXWindow value (it may be valid XWindow or
+ // nullptr) because we invalidate mXWindow at compositor/renderer thread
+ // before it's release in unmap handler.
+ Atomic<Window, Relaxed> mXWindow;
Visual* mXVisual;
#endif
};
diff --git a/widget/gtk/nsDragService.cpp b/widget/gtk/nsDragService.cpp
index 0135f97a4e..f435cdf2a0 100644
--- a/widget/gtk/nsDragService.cpp
+++ b/widget/gtk/nsDragService.cpp
@@ -607,6 +607,14 @@ nsDragService::EndDragSession(bool aDoneDrag, uint32_t aKeyModifiers) {
mTargetDragContextForRemote = nullptr;
mTargetWindow = nullptr;
mPendingWindow = nullptr;
+ mPendingDragContext = nullptr;
+ mPendingWindowPoint = {};
+ mScheduledTask = eDragTaskNone;
+ if (mTaskSource) {
+ g_source_remove(mTaskSource);
+ mTaskSource = 0;
+ }
+ mPendingTime = 0;
mCachedDragContext = 0;
return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
@@ -1208,19 +1216,57 @@ void nsDragService::TargetDataReceived(GtkWidget* aWidget,
GdkAtom target = gtk_selection_data_get_target(aSelectionData);
GUniquePtr<gchar> name(gdk_atom_name(target));
nsDependentCString flavor(name.get());
-
if (gtk_targets_include_uri(&target, 1)) {
- GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
+ // For the vnd.portal.filetransfer and vnd.portal.files we receive numeric
+ // id when it's a local file. The numeric id is then used by
+ // gtk_selection_data_get_uris implementation to get the actual file
+ // available in the flatpak environment.
+ //
+ // However due to GTK implementation also for example the uris like https
+ // are also provided by the vnd.portal.filetransfer target. In this case the
+ // call gtk_selection_data_get_uris fails. This is a bug in the gtk.
+ // To workaround it we try to create the valid uri and only if we fail
+ // we try to use the gtk_selection_data_get_uris. We ignore the valid uris
+ // for the vnd.portal.file* targets.
+ // See: https://gitlab.gnome.org/GNOME/gtk/-/issues/6563
+ if (flavor.Equals(gPortalFile) || flavor.Equals(gPortalFileTransfer)) {
+ const guchar* data = gtk_selection_data_get_data(aSelectionData);
+ if (!data || data[0] == '\0') {
+ LOGDRAGSERVICE(" Empty data!\n");
+ return;
+ }
+ nsCOMPtr<nsIURI> sourceURI;
+ nsresult rv =
+ NS_NewURI(getter_AddRefs(sourceURI), (const gchar*)data, nullptr);
+ if (NS_FAILED(rv)) {
+ // We're unable to get the URI, we'll use the
+ // gtk_selection_data_get_uris to get the actual file location
+ // accessible from the Firefox runtime.
+ GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
+ uris.swap(mTargetDragUris);
+ } else {
+ LOGDRAGSERVICE(
+ " got valid uri for MIME %s - this is bug in GTK - expected "
+ "numeric value for portal, got %s\n",
+ flavor.get(), data);
+ return;
+ }
+
+ } else {
+ GUniquePtr<gchar*> uris(gtk_selection_data_get_uris(aSelectionData));
+ uris.swap(mTargetDragUris);
+ }
#ifdef MOZ_LOGGING
if (MOZ_LOG_TEST(gWidgetDragLog, mozilla::LogLevel::Debug)) {
- gchar** uri = uris.get();
+ gchar** uri = mTargetDragUris.get();
while (uri && *uri) {
LOGDRAGSERVICE(" got uri %s, MIME %s", *uri, flavor.get());
uri++;
}
}
+
#endif
- uris.swap(mTargetDragUris);
+
if (mTargetDragUris) {
mCachedUris.InsertOrUpdate(
flavor, GUniquePtr<gchar*>(g_strdupv(mTargetDragUris.get())));
@@ -2557,6 +2603,7 @@ gboolean nsDragService::RunScheduledTask() {
// Nothing more to do
// Returning false removes the task source from the event loop.
mTaskSource = 0;
+ mPendingDragContext = nullptr;
return FALSE;
}
diff --git a/widget/gtk/nsLookAndFeel.cpp b/widget/gtk/nsLookAndFeel.cpp
index 040d942cdf..8702c154d6 100644
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -800,6 +800,7 @@ nsresult nsLookAndFeel::PerThemeData::GetColor(ColorID aID,
case ColorID::SpellCheckerUnderline:
case ColorID::Mark:
case ColorID::Marktext:
+ case ColorID::MozAutofillBackground:
aColor = GetStandinForNativeColor(
aID, mIsDark ? ColorScheme::Dark : ColorScheme::Light);
break;
@@ -863,9 +864,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
case IntID::CaretWidth:
aResult = 1;
break;
- case IntID::ShowCaretDuringSelection:
- aResult = 0;
- break;
case IntID::SelectTextfieldsOnKeyFocus: {
GtkSettings* settings;
gboolean select_on_focus;
diff --git a/widget/gtk/nsNativeThemeGTK.cpp b/widget/gtk/nsNativeThemeGTK.cpp
index 16945349bb..78d4e925fe 100644
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -167,9 +167,6 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
ElementState elementState = GetContentState(aFrame, aAppearance);
if (aState) {
memset(aState, 0, sizeof(GtkWidgetState));
-
- // For XUL checkboxes and radio buttons, the state of the parent
- // determines our state.
if (aWidgetFlags) {
if (elementState.HasState(ElementState::CHECKED)) {
*aWidgetFlags |= MOZ_GTK_WIDGET_CHECKED;
@@ -241,7 +238,8 @@ bool nsNativeThemeGTK::GetGtkWidgetAndState(StyleAppearance aAppearance,
aAppearance == StyleAppearance::MozWindowButtonMinimize ||
aAppearance == StyleAppearance::MozWindowButtonMaximize ||
aAppearance == StyleAppearance::MozWindowButtonRestore) {
- aState->backdrop = !nsWindow::GetTopLevelWindowActiveState(aFrame);
+ aState->backdrop = aFrame->PresContext()->Document()->State().HasState(
+ dom::DocumentState::WINDOW_INACTIVE);
}
}
@@ -884,11 +882,6 @@ LayoutDeviceIntMargin nsNativeThemeGTK::GetWidgetBorder(
CSSIntMargin result;
GtkTextDirection direction = GetTextDirection(aFrame);
switch (aAppearance) {
- case StyleAppearance::Toolbox:
- // gtk has no toolbox equivalent. So, although we map toolbox to
- // gtk's 'toolbar' for purposes of painting the widget background,
- // we don't use the toolbar border for toolbox.
- break;
case StyleAppearance::Dualbutton:
// TOOLBAR_DUAL_BUTTON is an interesting case. We want a border to draw
// around the entire button + dropdown, and also an inner border if you're
@@ -1169,9 +1162,7 @@ nsNativeThemeGTK::WidgetStateChanged(nsIFrame* aFrame,
}
// Some widget types just never change state.
- if (aAppearance == StyleAppearance::Toolbox ||
- aAppearance == StyleAppearance::Toolbar ||
- aAppearance == StyleAppearance::Progresschunk ||
+ if (aAppearance == StyleAppearance::Progresschunk ||
aAppearance == StyleAppearance::ProgressBar ||
aAppearance == StyleAppearance::Tooltip ||
aAppearance == StyleAppearance::MozWindowDecorations) {
@@ -1244,7 +1235,6 @@ nsNativeThemeGTK::ThemeSupportsWidget(nsPresContext* aPresContext,
case StyleAppearance::Button:
case StyleAppearance::Radio:
case StyleAppearance::Checkbox:
- case StyleAppearance::Toolbox: // N/A
case StyleAppearance::Toolbarbutton:
case StyleAppearance::Dualbutton: // so we can override the border with 0
case StyleAppearance::ToolbarbuttonDropdown:
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
index e84044990c..0a78d0c8ec 100644
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -187,8 +187,6 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor);
/* callbacks from widgets */
static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
static gboolean configure_event_cb(GtkWidget* widget, GdkEventConfigure* event);
-static void widget_map_cb(GtkWidget* widget);
-static void widget_unmap_cb(GtkWidget* widget);
static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation);
static void toplevel_window_size_allocate_cb(GtkWidget* widget,
GtkAllocation* allocation);
@@ -392,11 +390,11 @@ static void GtkWindowSetTransientFor(GtkWindow* aWindow, GtkWindow* aParent) {
nsWindow::nsWindow()
: mTitlebarRectMutex("nsWindow::mTitlebarRectMutex"),
- mDestroyMutex("nsWindow::mDestroyMutex"),
+ mWindowVisibilityMutex("nsWindow::mWindowVisibilityMutex"),
+ mIsMapped(false),
mIsDestroyed(false),
mIsShown(false),
mNeedsShow(false),
- mIsMapped(false),
mEnabled(true),
mCreated(false),
mHandleTouchEvent(false),
@@ -581,7 +579,6 @@ void nsWindow::Destroy() {
LOG("nsWindow::Destroy\n");
- MutexAutoLock lock(mDestroyMutex);
mIsDestroyed = true;
mCreated = false;
@@ -612,6 +609,9 @@ void nsWindow::Destroy() {
NativeShow(false);
+ MOZ_ASSERT(!gtk_widget_get_mapped(mShell));
+ MOZ_ASSERT(!gtk_widget_get_mapped(GTK_WIDGET(mContainer)));
+
ClearTransparencyBitmap();
DestroyLayerManager();
@@ -3165,23 +3165,34 @@ void nsWindow::SetFocus(Raise aRaise, mozilla::dom::CallerType aCallerType) {
LOG(" widget now has focus in SetFocus()");
}
+void nsWindow::ResetScreenBounds() {
+ mGdkWindowOrigin.reset();
+ mGdkWindowRootOrigin.reset();
+}
+
LayoutDeviceIntRect nsWindow::GetScreenBounds() {
if (!mGdkWindow) {
return mBounds;
}
const LayoutDeviceIntPoint origin = [&] {
- gint x, y;
- gdk_window_get_root_origin(mGdkWindow, &x, &y);
+ GdkPoint origin;
+
+ if (mGdkWindowRootOrigin.isSome()) {
+ origin = mGdkWindowRootOrigin.value();
+ } else {
+ gdk_window_get_root_origin(mGdkWindow, &origin.x, &origin.y);
+ mGdkWindowRootOrigin = Some(origin);
+ }
// Workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4820
// Bug 1775017 Gtk < 3.24.35 returns scaled values for
// override redirected window on X11.
if (gtk_check_version(3, 24, 35) != nullptr && GdkIsX11Display() &&
gdk_window_get_window_type(mGdkWindow) == GDK_WINDOW_TEMP) {
- return LayoutDeviceIntPoint(x, y);
+ return LayoutDeviceIntPoint(origin.x, origin.y);
}
- return GdkPointToDevicePixels({x, y});
+ return GdkPointToDevicePixels(origin);
}();
// mBounds.Size() is the window bounds, not the window-manager frame
@@ -3237,6 +3248,7 @@ void nsWindow::RecomputeClientOffset(bool aNotify) {
gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget,
GdkEventProperty* aEvent) {
if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) {
+ ResetScreenBounds();
RecomputeClientOffset(/* aNotify = */ true);
return FALSE;
}
@@ -3395,40 +3407,37 @@ void* nsWindow::GetNativeData(uint32_t aDataType) {
case NS_NATIVE_OPENGL_CONTEXT:
return nullptr;
case NS_NATIVE_EGL_WINDOW: {
+ // On X11 we call it:
+ // 1) If window is mapped on OnMap() by nsWindow::ResumeCompositorImpl(),
+ // new EGLSurface/XWindow is created.
+ // 2) If window is hidden on OnUnmap(), we replace EGLSurface/XWindow
+ // by offline surface and release XWindow.
+
+ // On Wayland it:
+ // 1) If window is mapped on OnMap(), we request frame callback
+ // at MozContainer. If we get frame callback at MozContainer,
+ // nsWindow::ResumeCompositorImpl() is called from it
+ // and EGLSurface/wl_surface is created.
+ // 2) If window is hidden on OnUnmap(), we replace EGLSurface/wl_surface
+ // by offline surface and release XWindow.
+
+ // If nsWindow is already destroyed, don't try to get EGL window at all,
+ // we're going to be deleted anyway.
+ MutexAutoLock lock(mWindowVisibilityMutex);
void* eglWindow = nullptr;
-
- // We can't block on mutex here as it leads to a deadlock:
- // 1) mutex is taken at nsWindow::Destroy()
- // 2) NS_NATIVE_EGL_WINDOW is called from compositor/rendering thread,
- // blocking on mutex.
- // 3) DestroyCompositor() is called by nsWindow::Destroy(). As a sync
- // call it waits to compositor/rendering threads,
- // but they're blocked at 2).
- // It's fine if we return null EGL window during DestroyCompositor(),
- // in such case compositor painting is skipped.
- if (mDestroyMutex.TryLock()) {
- if (mGdkWindow && !mIsDestroyed) {
+ if (mIsMapped && !mIsDestroyed) {
#ifdef MOZ_X11
- if (GdkIsX11Display()) {
- eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow);
- }
+ if (GdkIsX11Display()) {
+ eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow);
+ }
#endif
#ifdef MOZ_WAYLAND
- if (GdkIsWaylandDisplay()) {
- bool hiddenWindow =
- mCompositorWidgetDelegate &&
- mCompositorWidgetDelegate->AsGtkCompositorWidget() &&
- mCompositorWidgetDelegate->AsGtkCompositorWidget()->IsHidden();
- if (!hiddenWindow) {
- eglWindow = moz_container_wayland_get_egl_window(
- mContainer, FractionalScaleFactor());
- }
- }
-#endif
+ if (GdkIsWaylandDisplay()) {
+ eglWindow = moz_container_wayland_get_egl_window(
+ mContainer, FractionalScaleFactor());
}
- mDestroyMutex.Unlock();
+#endif
}
-
LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p",
mGdkWindow, eglWindow);
return eglWindow;
@@ -3556,11 +3565,16 @@ LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
if (IsWaylandPopup() && !mPopupUseMoveToRect) {
return mBounds.TopLeft();
}
- nsIntPoint origin(0, 0);
- if (mGdkWindow) {
- gdk_window_get_origin(mGdkWindow, &origin.x.value, &origin.y.value);
+
+ GdkPoint origin{};
+ if (mGdkWindowOrigin.isSome()) {
+ origin = mGdkWindowOrigin.value();
+ } else if (mGdkWindow) {
+ gdk_window_get_origin(mGdkWindow, &origin.x, &origin.y);
+ mGdkWindowOrigin = Some(origin);
}
- return GdkPointToDevicePixels({origin.x, origin.y});
+
+ return GdkPointToDevicePixels(origin);
}
void nsWindow::CaptureRollupEvents(bool aDoCapture) {
@@ -3749,6 +3763,8 @@ void nsWindow::RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion) {
KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
if (knowsCompositor && layerManager && mCompositorSession) {
+ LOG("nsWindow::RequestRepaint()");
+
if (!mConfiguredClearColor && !IsPopup()) {
layerManager->WrBridge()->SendSetDefaultClearColor(LookAndFeel::Color(
LookAndFeel::ColorID::Window, PreferenceSheet::ColorSchemeForChrome(),
@@ -3764,9 +3780,13 @@ void nsWindow::RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion) {
}
gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
+ LOG("nsWindow::OnExposeEvent GdkWindow [%p] XID [0x%lx]", mGdkWindow,
+ GetX11Window());
+
// This might destroy us.
NotifyOcclusionState(OcclusionState::VISIBLE);
if (mIsDestroyed) {
+ LOG("destroyed after NotifyOcclusionState()");
return FALSE;
}
@@ -3774,26 +3794,27 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
// May run event loop and destroy us.
MaybeDispatchResized();
if (mIsDestroyed) {
+ LOG("destroyed after MaybeDispatchResized()");
return FALSE;
}
// Windows that are not visible will be painted after they become visible.
if (!mGdkWindow || !mHasMappedToplevel) {
+ LOG("quit, !mGdkWindow || !mHasMappedToplevel");
return FALSE;
}
#ifdef MOZ_WAYLAND
if (GdkIsWaylandDisplay() && !moz_container_wayland_can_draw(mContainer)) {
+ LOG("quit, !moz_container_wayland_can_draw()");
return FALSE;
}
#endif
if (!GetListener()) {
+ LOG("quit, !GetListener()");
return FALSE;
}
- LOG("nsWindow::OnExposeEvent GdkWindow [%p] XID [0x%lx]", mGdkWindow,
- GetX11Window());
-
LayoutDeviceIntRegion exposeRegion;
if (!ExtractExposeRegion(exposeRegion, cr)) {
LOG(" no rects, quit");
@@ -3816,19 +3837,24 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
// If the window has been destroyed during the will paint notification,
// there is nothing left to do.
if (!mGdkWindow || mIsDestroyed) {
+ LOG("quit, !mGdkWindow || mIsDestroyed");
return TRUE;
}
// Re-get all rendering components since the will paint notification
// might have killed it.
nsIWidgetListener* listener = GetListener();
- if (!listener) return FALSE;
+ if (!listener) {
+ LOG("quit, !listener");
+ return FALSE;
+ }
WindowRenderer* renderer = GetWindowRenderer();
WebRenderLayerManager* layerManager = renderer->AsWebRender();
KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
if (knowsCompositor && layerManager && layerManager->NeedsComposite()) {
+ LOG("needs composite, ScheduleComposite() call");
layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
layerManager->SetNeedsComposite(false);
}
@@ -3859,11 +3885,13 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
}
if (region.IsEmpty()) {
+ LOG("quit, region.IsEmpty()");
return TRUE;
}
// If this widget uses OMTC...
if (renderer->GetBackendType() == LayersBackend::LAYERS_WR) {
+ LOG("redirect painting to OMTC rendering...");
listener->PaintWindow(this, region);
// Re-get the listener since the will paint notification might have
@@ -4048,6 +4076,8 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
mPendingConfigures--;
}
+ ResetScreenBounds();
+
// Don't fire configure event for scale changes, we handle that
// OnScaleChanged event. Skip that for toplevel windows only.
if (mGdkWindow && IsTopLevelWindowType()) {
@@ -4103,45 +4133,12 @@ gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
return FALSE;
}
-void nsWindow::OnMap() {
- LOG("nsWindow::OnMap");
- // Gtk mapped widget to screen. Configure underlying GdkWindow properly
- // as our rendering target.
- // This call means we have X11 (or Wayland) window we can render to by GL
- // so we need to notify compositor about it.
- mIsMapped = true;
- ConfigureGdkWindow();
-}
-
-void nsWindow::OnUnmap() {
- LOG("nsWindow::OnUnmap");
-
- mIsMapped = false;
-
- if (mSourceDragContext) {
- static auto sGtkDragCancel =
- (void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
- if (sGtkDragCancel) {
- sGtkDragCancel(mSourceDragContext);
- mSourceDragContext = nullptr;
- }
- }
-
- // We don't have valid XWindow any more,
- // so clear stored ones at GtkCompositorWidget() for OMTC rendering
- // and mSurfaceProvider for legacy rendering.
- if (GdkIsX11Display()) {
- mSurfaceProvider.CleanupResources();
- if (mCompositorWidgetDelegate) {
- mCompositorWidgetDelegate->DisableRendering();
- }
- }
-}
-
void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) {
LOG("nsWindow::OnSizeAllocate %d,%d -> %d x %d\n", aAllocation->x,
aAllocation->y, aAllocation->width, aAllocation->height);
+ ResetScreenBounds();
+
// Client offset are updated by _NET_FRAME_EXTENTS on X11 when system titlebar
// is enabled. In either cases (Wayland or system titlebar is off on X11)
// we don't get _NET_FRAME_EXTENTS X11 property notification so we derive
@@ -4650,9 +4647,16 @@ bool nsWindow::DoTitlebarAction(LookAndFeel::TitlebarEvent aEvent,
LOG(" action menu");
TryToShowNativeWindowMenu(aButtonEvent);
break;
- // Lower is part of gtk_surface1 protocol which we can't support
- // as Gtk keeps it private. So emulate it by minimize.
case LookAndFeel::TitlebarAction::WindowLower:
+ LOG(" action lower");
+ // Lower is part of gtk_surface1 protocol which we can't support
+ // as Gtk keeps it private. So emulate it by minimize.
+ if (GdkIsWaylandDisplay()) {
+ SetSizeMode(nsSizeMode_Minimized);
+ } else {
+ gdk_window_lower(GetToplevelGdkWindow());
+ }
+ break;
case LookAndFeel::TitlebarAction::WindowMinimize:
LOG(" action minimize");
SetSizeMode(nsSizeMode_Minimized);
@@ -5425,8 +5429,8 @@ void nsWindow::OnScaleChanged(bool aNotify) {
NotifyAPZOfDPIChange();
- LOG("OnScaleChanged %d, %f -> %d, %f\n", int(mCeiledScaleFactor),
- mFractionalScaleFactor, newCeiled, newFractional);
+ LOG("OnScaleChanged %d, %f -> %d, %f Notify %d\n", int(mCeiledScaleFactor),
+ mFractionalScaleFactor, newCeiled, newFractional, aNotify);
mCeiledScaleFactor = newCeiled;
mFractionalScaleFactor = newFractional;
@@ -5822,8 +5826,8 @@ bool nsWindow::GetShapedState() {
}
void nsWindow::ConfigureCompositor() {
- MOZ_DIAGNOSTIC_ASSERT(mCompositorState == COMPOSITOR_ENABLED);
MOZ_DIAGNOSTIC_ASSERT(mIsMapped);
+ MOZ_DIAGNOSTIC_ASSERT(mCompositorState == COMPOSITOR_ENABLED);
LOG("nsWindow::ConfigureCompositor()");
auto startCompositing = [self = RefPtr{this}, this]() -> void {
@@ -5833,7 +5837,7 @@ void nsWindow::ConfigureCompositor() {
// too late
if (mIsDestroyed || !mIsMapped) {
LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed,
- mIsMapped);
+ !!mIsMapped);
return;
}
// Compositor will be resumed later by ResumeCompositorFlickering().
@@ -5860,73 +5864,6 @@ void nsWindow::ConfigureCompositor() {
}
}
-void nsWindow::ConfigureGdkWindow() {
- LOG("nsWindow::ConfigureGdkWindow()");
-
- EnsureGdkWindow();
- OnScaleChanged(/* aNotify = */ false);
-
- if (mIsAlert) {
- gdk_window_set_override_redirect(mGdkWindow, TRUE);
- }
-
-#ifdef MOZ_X11
- if (GdkIsX11Display()) {
- mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
-
- // Set window manager hint to keep fullscreen windows composited.
- //
- // If the window were to get unredirected, there could be visible
- // tearing because Gecko does not align its framebuffer updates with
- // vblank.
- SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
- }
-#endif
-#ifdef MOZ_WAYLAND
- if (GdkIsWaylandDisplay()) {
- mSurfaceProvider.Initialize(this);
- }
-#endif
-
- if (mIsDragPopup) {
- if (GdkIsWaylandDisplay()) {
- // Disable painting to the widget on Wayland as we paint directly to the
- // widget. Wayland compositors does not paint wl_subsurface
- // of D&D widget.
- if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
- GtkWidgetDisableUpdates(parent);
- }
- GtkWidgetDisableUpdates(mShell);
- GtkWidgetDisableUpdates(GTK_WIDGET(mContainer));
- } else {
- // Disable rendering of parent container on X11 to avoid flickering.
- if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
- gtk_widget_set_opacity(parent, 0.0);
- }
- }
- }
-
- if (mWindowType == WindowType::Popup) {
- if (mNoAutoHide) {
- gint wmd = ConvertBorderStyles(mBorderStyle);
- if (wmd != -1) {
- gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
- }
- }
- // If the popup ignores mouse events, set an empty input shape.
- SetInputRegion(mInputRegion);
- }
-
- RefreshWindowClass();
-
- // We're not mapped yet but we have already created compositor.
- if (mCompositorWidgetDelegate) {
- ConfigureCompositor();
- }
-
- LOG(" finished, new GdkWindow %p XID 0x%lx\n", mGdkWindow, GetX11Window());
-}
-
nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
widget::InitData* aInitData) {
@@ -6355,8 +6292,6 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
G_CALLBACK(settings_xft_dpi_changed_cb), this);
// Widget signals
- g_signal_connect(mContainer, "map", G_CALLBACK(widget_map_cb), nullptr);
- g_signal_connect(mContainer, "unmap", G_CALLBACK(widget_unmap_cb), nullptr);
g_signal_connect_after(mContainer, "size_allocate",
G_CALLBACK(size_allocate_cb), nullptr);
g_signal_connect(mContainer, "hierarchy-changed",
@@ -6567,6 +6502,10 @@ void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
LOG("nsWindow::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n",
aMoved, aResized, topLeft.x, topLeft.y, size.width, size.height);
+ if (aMoved) {
+ ResetScreenBounds();
+ }
+
if (aResized && !AreBoundsSane()) {
LOG(" bounds are insane, hidding the window");
// We have been resized but to incorrect size.
@@ -6648,8 +6587,8 @@ void nsWindow::PauseCompositorFlickering() {
CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
if (remoteRenderer) {
- remoteRenderer->SendPause();
mCompositorState = COMPOSITOR_PAUSED_FLICKERING;
+ remoteRenderer->SendPause();
mCompositorPauseTimeoutID = (int)g_timeout_add(
COMPOSITOR_PAUSE_TIMEOUT,
[](void* data) -> gint {
@@ -6703,7 +6642,8 @@ void nsWindow::ResumeCompositorImpl() {
LOG("nsWindow::ResumeCompositorImpl()\n");
MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate);
- mCompositorWidgetDelegate->EnableRendering(GetX11Window(), GetShapedState());
+ mCompositorWidgetDelegate->SetRenderingSurface(GetX11Window(),
+ GetShapedState());
// As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
// time to start it.
@@ -8287,25 +8227,6 @@ static gboolean configure_event_cb(GtkWidget* widget,
return window->OnConfigureEvent(widget, event);
}
-// Some Gtk widget code may call gtk_widget_unrealize() which destroys
-// mGdkWindow. We need to listen on this signal and re-create
-// mGdkWindow when we're already mapped.
-static void widget_map_cb(GtkWidget* widget) {
- RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
- if (!window) {
- return;
- }
- window->OnMap();
-}
-
-static void widget_unmap_cb(GtkWidget* widget) {
- RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
- if (!window) {
- return;
- }
- window->OnUnmap();
-}
-
static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
if (!window) {
@@ -9124,7 +9045,7 @@ void nsWindow::DidGetNonBlankPaint() {
void nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) {
LOG("nsWindow::SetCompositorWidgetDelegate %p mIsMapped %d "
"mCompositorWidgetDelegate %p\n",
- delegate, mIsMapped, mCompositorWidgetDelegate);
+ delegate, !!mIsMapped, mCompositorWidgetDelegate);
MOZ_RELEASE_ASSERT(NS_IsMainThread());
if (delegate) {
@@ -9962,26 +9883,6 @@ void nsWindow::UnlockNativePointer() {
}
#endif
-bool nsWindow::GetTopLevelWindowActiveState(nsIFrame* aFrame) {
- // Used by window frame and button box rendering. We can end up in here in
- // the content process when rendering one of these moz styles freely in a
- // page. Fail in this case, there is no applicable window focus state.
- if (!XRE_IsParentProcess()) {
- return false;
- }
- // All headless windows are considered active so they are painted.
- if (gfxPlatform::IsHeadless()) {
- return true;
- }
- // Get the widget. nsIFrame's GetNearestWidget walks up the view chain
- // until it finds a real window.
- nsWindow* window = static_cast<nsWindow*>(aFrame->GetNearestWidget());
- if (!window) {
- return false;
- }
- return !window->mTitlebarBackdropState;
-}
-
static nsIFrame* FindTitlebarFrame(nsIFrame* aFrame) {
for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
StyleAppearance appearance =
@@ -10072,41 +9973,34 @@ nsWindow* nsWindow::GetFocusedWindow() { return gFocusWindow; }
#ifdef MOZ_WAYLAND
bool nsWindow::SetEGLNativeWindowSize(
const LayoutDeviceIntSize& aEGLWindowSize) {
- if (!GdkIsWaylandDisplay()) {
+ if (!GdkIsWaylandDisplay() || !mIsMapped) {
return true;
}
- // SetEGLNativeWindowSize() is called from renderer/compositor thread,
- // make sure nsWindow is not destroyed.
- bool paint = false;
+ if (mCompositorState == COMPOSITOR_PAUSED_FLICKERING) {
+ LOG("nsWindow::SetEGLNativeWindowSize() return, "
+ "COMPOSITOR_PAUSED_FLICKERING is set");
+ return false;
+ }
- // See NS_NATIVE_EGL_WINDOW why we can't block here.
- if (mDestroyMutex.TryLock()) {
- if (!mIsDestroyed) {
- gint scale = GdkCeiledScaleFactor();
+ gint scale = GdkCeiledScaleFactor();
# ifdef MOZ_LOGGING
- if (LOG_ENABLED()) {
- static uintptr_t lastSizeLog = 0;
- uintptr_t sizeLog = uintptr_t(this) + aEGLWindowSize.width +
- aEGLWindowSize.height + scale +
- aEGLWindowSize.width / scale +
- aEGLWindowSize.height / scale;
- if (lastSizeLog != sizeLog) {
- lastSizeLog = sizeLog;
- LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
- "%d x "
- "%d)",
- aEGLWindowSize.width, aEGLWindowSize.height, scale,
- aEGLWindowSize.width / scale, aEGLWindowSize.height / scale);
- }
- }
-# endif
- paint = moz_container_wayland_egl_window_set_size(
- mContainer, aEGLWindowSize.ToUnknownSize(), scale);
+ if (LOG_ENABLED()) {
+ static uintptr_t lastSizeLog = 0;
+ uintptr_t sizeLog =
+ uintptr_t(this) + aEGLWindowSize.width + aEGLWindowSize.height + scale +
+ aEGLWindowSize.width / scale + aEGLWindowSize.height / scale;
+ if (lastSizeLog != sizeLog) {
+ lastSizeLog = sizeLog;
+ LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
+ "%d x %d)",
+ aEGLWindowSize.width, aEGLWindowSize.height, scale,
+ aEGLWindowSize.width / scale, aEGLWindowSize.height / scale);
}
- mDestroyMutex.Unlock();
}
- return paint;
+# endif
+ return moz_container_wayland_egl_window_set_size(
+ mContainer, aEGLWindowSize.ToUnknownSize(), scale);
}
#endif
@@ -10123,45 +10017,138 @@ void nsWindow::ClearRenderingQueue() {
DestroyLayerManager();
}
-void nsWindow::DisableRendering() {
- LOG("nsWindow::DisableRendering()");
+// nsWindow::OnMap() / nsWindow::OnUnmap() is called from map/unmap mContainer
+// handlers directly as we paint to mContainer.
+void nsWindow::OnMap() {
+ LOG("nsWindow::OnMap");
- if (mGdkWindow) {
- g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
- mGdkWindow = nullptr;
+ {
+ MutexAutoLock lock(mWindowVisibilityMutex);
+ mIsMapped = true;
+
+ EnsureGdkWindow();
+ OnScaleChanged(/* aNotify = */ false);
+
+ if (mIsAlert) {
+ gdk_window_set_override_redirect(mGdkWindow, TRUE);
+ }
+
+#ifdef MOZ_X11
+ if (GdkIsX11Display()) {
+ mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
+
+ // Set window manager hint to keep fullscreen windows composited.
+ //
+ // If the window were to get unredirected, there could be visible
+ // tearing because Gecko does not align its framebuffer updates with
+ // vblank.
+ SetCompositorHint(GTK_WIDGET_COMPOSITED_ENABLED);
+ }
+#endif
+#ifdef MOZ_WAYLAND
+ if (GdkIsWaylandDisplay()) {
+ mSurfaceProvider.Initialize(this);
+ }
+#endif
+ }
+
+ if (mIsDragPopup) {
+ if (GdkIsWaylandDisplay()) {
+ // Disable painting to the widget on Wayland as we paint directly to the
+ // widget. Wayland compositors does not paint wl_subsurface
+ // of D&D widget.
+ if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
+ GtkWidgetDisableUpdates(parent);
+ }
+ GtkWidgetDisableUpdates(mShell);
+ GtkWidgetDisableUpdates(GTK_WIDGET(mContainer));
+ } else {
+ // Disable rendering of parent container on X11 to avoid flickering.
+ if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
+ gtk_widget_set_opacity(parent, 0.0);
+ }
+ }
+ }
+
+ if (mWindowType == WindowType::Popup) {
+ if (mNoAutoHide) {
+ gint wmd = ConvertBorderStyles(mBorderStyle);
+ if (wmd != -1) {
+ gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
+ }
+ }
+ // If the popup ignores mouse events, set an empty input shape.
+ SetInputRegion(mInputRegion);
+ }
+
+ RefreshWindowClass();
+
+ // We're not mapped yet but we have already created compositor.
+ if (mCompositorWidgetDelegate) {
+ ConfigureCompositor();
+ }
+
+ LOG(" finished, new GdkWindow %p XID 0x%lx\n", mGdkWindow, GetX11Window());
+}
+
+void nsWindow::OnUnmap() {
+ LOG("nsWindow::OnUnmap");
+
+ {
+ MutexAutoLock lock(mWindowVisibilityMutex);
+ mIsMapped = false;
+
+ if (mSourceDragContext) {
+ static auto sGtkDragCancel =
+ (void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT, "gtk_drag_cancel");
+ if (sGtkDragCancel) {
+ sGtkDragCancel(mSourceDragContext);
+ mSourceDragContext = nullptr;
+ }
+ }
+
+ if (mGdkWindow) {
+ g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
+ mGdkWindow = nullptr;
+ }
+
+ // Clear resources (mainly XWindow) stored at GtkCompositorWidget.
+ // It makes sure we don't paint to it when nsWindow becomes hiden/deleted
+ // and XWindow is released.
+ if (mCompositorWidgetDelegate) {
+ mCompositorWidgetDelegate->CleanupResources();
+ }
+
+ // Clear nsWindow resources used for old (in-thread) rendering.
+ mSurfaceProvider.CleanupResources();
}
// Until Bug 1654938 is fixed we delete layer manager for hidden popups,
// otherwise it can easily hold 1GB+ memory for long time.
if (mWindowType == WindowType::Popup) {
DestroyLayerManager();
- mSurfaceProvider.CleanupResources();
} else {
-#ifdef MOZ_WAYLAND
- // Widget is backed by OpenGL EGLSurface created over wl_surface
- // owned by mContainer.
- // RenderCompositorEGL::Resume() deletes recent EGLSurface based on
- // wl_surface owned by mContainer and creates a new fallback EGLSurface.
- // Then we can delete wl_surface in moz_container_wayland_unmap().
+ // Widget is backed by OpenGL EGLSurface created over wl_surface/XWindow.
+ //
+ // RenderCompositorEGL::Resume() deletes recent EGLSurface,
+ // calls nsWindow::GetNativeData(NS_NATIVE_EGL_WINDOW) from compositor
+ // thread to get new native rendering surface.
+ //
+ // For hidden/unmapped windows we return nullptr NS_NATIVE_EGL_WINDOW at
+ // nsWindow::GetNativeData() so RenderCompositorEGL::Resume() creates
+ // offscreen fallback EGLSurface to avoid compositor pause.
+ //
// We don't want to pause compositor as it may lead to whole
// browser freeze (Bug 1777664).
- ///
- // We don't need to do such operation for SW backend as
- // WindowSurfaceWaylandMB::Commit() gets wl_surface from
- // MozContainer every commit.
- if (moz_container_wayland_has_egl_window(mContainer) &&
- mCompositorWidgetDelegate) {
- if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
- // Call DisableRendering() to make GtkCompositorWidget hidden.
- // Then SendResume() will create fallback EGLSurface, see
- // GLContextEGL::CreateEGLSurfaceForCompositorWidget().
- mCompositorWidgetDelegate->DisableRendering();
- remoteRenderer->SendResume();
- mCompositorWidgetDelegate->EnableRendering(GetX11Window(),
- GetShapedState());
- }
+ //
+ // If RenderCompositorSWGL compositor is used (SW fallback)
+ // RenderCompositorSWGL::Resume() only requests full render for next paint
+ // as wl_surface/XWindow is managed by WindowSurfaceProvider owned
+ // directly by GtkCompositorWidget and that's covered by
+ // mCompositorWidgetDelegate->CleanupResources() call above.
+ if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
+ remoteRenderer->SendResume();
}
-#endif
}
}
diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h
index f8fe344f09..25d68129d8 100644
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -175,6 +175,7 @@ class nsWindow final : public nsBaseWidget {
void MoveToWorkspace(const nsAString& workspaceID) override;
void Enable(bool aState) override;
void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
+ void ResetScreenBounds();
LayoutDeviceIntRect GetScreenBounds() override;
LayoutDeviceIntRect GetClientBounds() override;
LayoutDeviceIntSize GetClientSize() override;
@@ -411,7 +412,6 @@ class nsWindow final : public nsBaseWidget {
*/
static GtkWindowDecoration GetSystemGtkWindowDecoration();
- static bool GetTopLevelWindowActiveState(nsIFrame* aFrame);
static bool TitlebarUseShapeMask();
bool IsRemoteContent() { return HasRemoteContent(); }
void NativeMoveResizeWaylandPopupCallback(const GdkRectangle* aFinalSize,
@@ -461,8 +461,6 @@ class nsWindow final : public nsBaseWidget {
// rendering queue blocking (see Bug 1782948).
void ClearRenderingQueue();
- void DisableRendering();
-
bool ApplyEnterLeaveMutterWorkaround();
void NotifyOcclusionState(mozilla::widget::OcclusionState aState) override;
@@ -553,6 +551,9 @@ class nsWindow final : public nsBaseWidget {
GtkWidget* mShell = nullptr;
MozContainer* mContainer = nullptr;
GdkWindow* mGdkWindow = nullptr;
+ mozilla::Maybe<GdkPoint> mGdkWindowOrigin;
+ mozilla::Maybe<GdkPoint> mGdkWindowRootOrigin;
+
PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate = nullptr;
mozilla::Atomic<WindowCompositorState, mozilla::Relaxed> mCompositorState{
COMPOSITOR_ENABLED};
@@ -633,10 +634,14 @@ class nsWindow final : public nsBaseWidget {
mozilla::Mutex mTitlebarRectMutex;
LayoutDeviceIntRect mTitlebarRect MOZ_GUARDED_BY(mTitlebarRectMutex);
- mozilla::Mutex mDestroyMutex;
+ // This mutex protect window visibility changes.
+ mozilla::Mutex mWindowVisibilityMutex;
+ // This track real window visibility from OS perspective.
+ // It's set by OnMap/OnUnmap which is based on Gtk events.
+ mozilla::Atomic<bool, mozilla::Relaxed> mIsMapped;
// Has this widget been destroyed yet?
- bool mIsDestroyed : 1;
+ mozilla::Atomic<bool, mozilla::Relaxed> mIsDestroyed;
// mIsShown tracks requested visible status from browser perspective, i.e.
// if the window should be visible or now.
bool mIsShown : 1;
@@ -646,9 +651,6 @@ class nsWindow final : public nsBaseWidget {
// that the window is not actually visible but we report to browser that
// it is visible (mIsShown == true).
bool mNeedsShow : 1;
- // This track real window visibility from OS perspective.
- // It's set by OnMap/OnUnmap which is based on Gtk events.
- bool mIsMapped : 1;
// is this widget enabled?
bool mEnabled : 1;
// has the native window for this been created yet?
@@ -802,11 +804,6 @@ class nsWindow final : public nsBaseWidget {
void DispatchMissedButtonReleases(GdkEventCrossing* aGdkEvent);
- // When window widget gets mapped/unmapped we need to configure
- // underlying GdkWindow properly. Otherwise we'll end up with
- // rendering to released window.
- void ConfigureGdkWindow();
- void ReleaseGdkWindow();
void ConfigureCompositor();
bool IsAlwaysUndecoratedWindow() const;
@@ -996,9 +993,9 @@ class nsWindow final : public nsBaseWidget {
void RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion);
#ifdef MOZ_X11
- typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
- GTK_WIDGET_COMPOSIDED_DISABLED = 1,
- GTK_WIDGET_COMPOSIDED_ENABLED = 2} WindowComposeRequest;
+ typedef enum {GTK_WIDGET_COMPOSITED_DEFAULT = 0,
+ GTK_WIDGET_COMPOSITED_DISABLED = 1,
+ GTK_WIDGET_COMPOSITED_ENABLED = 2} WindowComposeRequest;
void SetCompositorHint(WindowComposeRequest aState);
bool ConfigureX11GLVisual();
#endif