diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -11,11 +11,11 @@ #include #include #include "CompositorWidget.h" #include "MozContainer.h" -#include "MozContainerSurfaceLock.h" +#include "WaylandSurfaceLock.h" #include "VsyncSource.h" #include "mozilla/EventForwards.h" #include "mozilla/Maybe.h" #include "mozilla/RefPtr.h" #include "mozilla/TouchEvents.h" @@ -45,10 +45,13 @@ # include "nsClipboardWayland.h" #endif #ifdef MOZ_LOGGING +# undef LOG +# undef LOGVERBOSE + # include "mozilla/Logging.h" # include "nsTArray.h" # include "Units.h" extern mozilla::LazyLogModule gWidgetLog; @@ -59,26 +62,32 @@ # define LOG(str, ...) \ MOZ_LOG(IsPopup() ? gWidgetPopupLog : gWidgetLog, \ mozilla::LogLevel::Debug, \ ("%s: " str, GetDebugTag().get(), ##__VA_ARGS__)) +# define LOGVERBOSE(str, ...) \ + MOZ_LOG(IsPopup() ? gWidgetPopupLog : gWidgetLog, \ + mozilla::LogLevel::Verbose, \ + ("%s: " str, GetDebugTag().get(), ##__VA_ARGS__)) # define LOGW(...) MOZ_LOG(gWidgetLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) # define LOGDRAG(...) \ MOZ_LOG(gWidgetDragLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) # define LOG_POPUP(...) \ MOZ_LOG(gWidgetPopupLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -# define LOG_VSYNC(...) \ - MOZ_LOG(gWidgetVsync, mozilla::LogLevel::Debug, (__VA_ARGS__)) +# define LOG_VSYNC(str, ...) \ + MOZ_LOG(gWidgetVsync, mozilla::LogLevel::Debug, \ + ("%s: " str, GetDebugTag().get(), ##__VA_ARGS__)) # define LOG_ENABLED() \ (MOZ_LOG_TEST(gWidgetPopupLog, mozilla::LogLevel::Debug) || \ MOZ_LOG_TEST(gWidgetLog, mozilla::LogLevel::Debug)) # define LOG_WAYLAND(...) \ MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) #else # define LOG(...) +# define LOGVERBOSE(...) # define LOGW(...) # define LOGDRAG(...) # define LOG_POPUP(...) # define LOG_ENABLED() false @@ -131,10 +140,12 @@ #endif namespace widget { class DBusMenuBar; class Screen; +class WaylandSurface; +class WaylandSurfaceLock; } // namespace widget } // namespace mozilla class nsWindow final : public nsBaseWidget { public: @@ -294,12 +305,20 @@ bool SynchronouslyRepaintOnResize() override; void OnDPIChanged(); void OnCheckResize(); void OnCompositedChanged(); - void OnScaleChanged(bool aNotify); void DispatchResized(); + void OnScaleEvent(); + + // Load new scale from system. + + // aRefreshScreen means notify layout that scale was changed and + // it should load correct values. + // Set aRefreshScreen to false if we operate on hidden window + // or if we're going to repaint. + void RefreshScale(bool aRefreshScreen); static guint32 sLastButtonPressTime; MozContainer* GetMozContainer() { return mContainer; } GdkWindow* GetGdkWindow() const { return mGdkWindow; }; @@ -426,11 +445,11 @@ bool aFlippedX, bool aFlippedY); static bool IsToplevelWindowTransparent(); static nsWindow* GetFocusedWindow(); - mozilla::UniquePtr LockSurface(); + mozilla::UniquePtr LockSurface(); #ifdef MOZ_WAYLAND // Use xdg-activation protocol to transfer focus from gFocusWindow to aWindow. static void TransferFocusToWaylandWindow(nsWindow* aWindow); void FocusWaylandWindow(const char* aTokenID); @@ -494,13 +513,10 @@ void MaybeDispatchResized(); void DispatchPanGesture(mozilla::PanGestureInput& aPanInput); void RegisterTouchWindow() override; - mozilla::Atomic mCeiledScaleFactor{1}; - double mFractionalScaleFactor = 0.0; - void NativeMoveResize(bool aMoved, bool aResized); void NativeShow(bool aAction); void SetHasMappedToplevel(bool aState); LayoutDeviceIntSize GetSafeWindowSize(LayoutDeviceIntSize aSize); @@ -562,10 +578,13 @@ void RefreshWindowClass(); GtkWidget* mShell = nullptr; MozContainer* mContainer = nullptr; GdkWindow* mGdkWindow = nullptr; +#ifdef MOZ_WAYLAND + RefPtr mSurface; +#endif mozilla::Maybe mGdkWindowOrigin; mozilla::Maybe mGdkWindowRootOrigin; PlatformCompositorWidgetDelegate* mCompositorWidgetDelegate = nullptr; mozilla::Atomic mCompositorState{ @@ -584,10 +603,14 @@ float mAspectRatio = 0.0f; float mAspectRatioSaved = 0.0f; mozilla::Maybe mAspectResizer; LayoutDeviceIntPoint mLastResizePoint; + // Keep in sync with WaylandSurface::sNoScale + constexpr static const int sNoScale = -1; + int mCeiledScaleFactor = sNoScale; + // The size requested, which might not be reflected in mBounds. Used in // WaylandPopupSetDirectPosition() to remember intended size for popup // positioning, in LockAspect() to remember the intended aspect ratio, and // to remember a size requested while waiting for moved-to-rect when // OnSizeAllocate() might change mBounds.Size(). @@ -1015,14 +1038,10 @@ // An activation token from our environment (see handling of the // XDG_ACTIVATION_TOKEN/DESKTOP_STARTUP_ID) env vars. nsCString mWindowActivationTokenFromEnv; mozilla::widget::WindowSurfaceProvider mSurfaceProvider; GdkDragContext* mSourceDragContext = nullptr; -#if MOZ_LOGGING - LayoutDeviceIntRect mLastLoggedBoundSize; - int mLastLoggedScale = -1; -#endif mozilla::Sides mResizableEdges{mozilla::SideBits::eAll}; // Running in kiosk mode and requested to stay on specified monitor. // If monitor is removed minimize the window. mozilla::Maybe mKioskMonitor; LayoutDeviceIntRegion mOpaqueRegion MOZ_GUARDED_BY(mOpaqueRegionLock); diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -588,10 +588,11 @@ MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove); #ifdef MOZ_WAYLAND // Shut down our local vsync source + // Also drops reference to nsWindow::mSurface. if (mWaylandVsyncSource) { mWaylandVsyncSource->Shutdown(); mWaylandVsyncSource = nullptr; } mWaylandVsyncDispatcher = nullptr; @@ -655,10 +656,13 @@ } gtk_widget_destroy(mShell); mShell = nullptr; mContainer = nullptr; +#ifdef MOZ_WAYLAND + mSurface = nullptr; +#endif MOZ_ASSERT(!mGdkWindow, "mGdkWindow should be NULL when mContainer is destroyed"); #ifdef ACCESSIBILITY @@ -3179,18 +3183,16 @@ // with Resize. const LayoutDeviceIntRect rect(origin, mBounds.Size()); #if MOZ_LOGGING if (MOZ_LOG_TEST(IsPopup() ? gWidgetPopupLog : gWidgetLog, LogLevel::Verbose)) { - gint scale = GdkCeiledScaleFactor(); - if (mLastLoggedScale != scale || !(mLastLoggedBoundSize == rect)) { - mLastLoggedScale = scale; - mLastLoggedBoundSize = rect; - LOG("GetScreenBounds %d,%d -> %d x %d, unscaled %d,%d -> %d x %d\n", - rect.x, rect.y, rect.width, rect.height, rect.x / scale, - rect.y / scale, rect.width / scale, rect.height / scale); - } + double scale = FractionalScaleFactor(); + LOGVERBOSE( + "GetScreenBounds [%d,%d] -> [%d x %d], unscaled [%f,%f] -> [%f x %f] " + "ceiled scale %f", + rect.x, rect.y, rect.width, rect.height, rect.x / scale, rect.y / scale, + rect.width / scale, rect.height / scale, scale); } #endif return rect; } @@ -3407,12 +3409,11 @@ eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow); } #endif #ifdef MOZ_WAYLAND if (GdkIsWaylandDisplay()) { - eglWindow = moz_container_wayland_get_egl_window( - mContainer, FractionalScaleFactor()); + eglWindow = moz_container_wayland_get_egl_window(mContainer); } #endif } LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p", mGdkWindow, eglWindow); @@ -3966,11 +3967,11 @@ } ResetScreenBounds(); // Don't fire configure event for scale changes, we handle that - // OnScaleChanged event. Skip that for toplevel windows only. + // OnScaleEvent event. Skip that for toplevel windows only. if (mGdkWindow && IsTopLevelWidget()) { if (mCeiledScaleFactor != gdk_window_get_scale_factor(mGdkWindow)) { LOG(" scale factor changed to %d,return early", gdk_window_get_scale_factor(mGdkWindow)); return FALSE; @@ -5325,41 +5326,67 @@ // system metrics, not other theme shenanigans. NotifyThemeChanged(ThemeChangeKind::MediaQueriesOnly); mCompositedScreen = gdk_screen_is_composited(gdk_screen_get_default()); } -void nsWindow::OnScaleChanged(bool aNotify) { - if (!IsTopLevelWidget()) { +// X11(XWayland) and Wayland handles screen scale differently. +// If there are more monitors with different scale factor (say 2 and 3), +// XWayland sends scale 3 to all application windows and downscales +// applications on monitor with scale 2. +// If scale is changed system wide in settings, OnScaleEvent() is send +// to all application windows. +// +// Wayland sends actual scale to each window according to its position +// and also sends OnScaleEvent is scale changes for particular window. +// So we can have toplevel window with scale 3 and its child popup with scale 2 +// (because toplevel it's located on more than one screen). +// +// But right now gecko code (or widget/gtk?) expects that toplevel and its +// popup use the same scale factor (which may be actually different). +// We see various rendering/sizing/position errors otherwise, +// maybe we get scale from wrong windows or so. +// +// Let's follow the working scenario for now to avoid complexity +// and maybe fix that later. +void nsWindow::OnScaleEvent() { + if (!mGdkWindow || !IsTopLevelWidget()) { return; } - if (!mGdkWindow) { - return; // We'll get there again when we configure the window. + + LOG("nsWindow::OnScaleEvent() GdkWindow scale %d", + gdk_window_get_scale_factor(mGdkWindow)); + + RefreshScale(/* aRefreshScreen */ true); +} + +void nsWindow::RefreshScale(bool aRefreshScreen) { + if (!IsTopLevelWidget()) { + return; } - gint newCeiled = gdk_window_get_scale_factor(mGdkWindow); - double newFractional = [&] { + + LOG("nsWindow::RefreshScale() GdkWindow scale %d refresh %d", + gdk_window_get_scale_factor(mGdkWindow), aRefreshScreen); + #ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { - return moz_container_wayland_get_fractional_scale(mContainer); - } + if (GdkIsWaylandDisplay()) { + WaylandSurfaceLock lock(mSurface); + mSurface->SetCeiledScaleLocked(lock, + gdk_window_get_scale_factor(mGdkWindow)); + } #endif - return 0.0; - }(); - if (mCeiledScaleFactor == newCeiled && - mFractionalScaleFactor == newFractional) { + MOZ_DIAGNOSTIC_ASSERT(mIsMapped && mGdkWindow); + int ceiledScale = gdk_window_get_scale_factor(mGdkWindow); + bool scaleChanged = (mCeiledScaleFactor != ceiledScale); + if (!scaleChanged) { return; } + mCeiledScaleFactor = ceiledScale; NotifyAPZOfDPIChange(); - LOG("OnScaleChanged %d, %f -> %d, %f Notify %d\n", int(mCeiledScaleFactor), - mFractionalScaleFactor, newCeiled, newFractional, aNotify); - - mCeiledScaleFactor = newCeiled; - mFractionalScaleFactor = newFractional; - - if (!aNotify) { + if (!aRefreshScreen) { return; } // We pause compositor to avoid rendering of obsoleted remote content which // produces flickering. @@ -5372,11 +5399,12 @@ LayoutDeviceIntSize size = GdkRectToDevicePixels(allocation).Size(); mBounds.SizeTo(size); // Check mBounds size if (mCompositorSession && !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) { - gfxCriticalNoteOnce << "Invalid mBounds in OnScaleChanged " << mBounds; + gfxCriticalNoteOnce << "Invalid mBounds in PropagateScaleChange() " + << mBounds; } if (mWidgetListener) { if (PresShell* presShell = mWidgetListener->GetPresShell()) { presShell->BackingScaleFactorChanged(); @@ -5807,12 +5835,10 @@ } } nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, widget::InitData* aInitData) { - LOG("nsWindow::Create\n"); - MOZ_DIAGNOSTIC_ASSERT(!aInitData || aInitData->mWindowType != WindowType::Invisible); #ifdef ACCESSIBILITY // Send a DBus message to check whether a11y is enabled @@ -5831,10 +5857,12 @@ nsGTKToolkit::GetToolkit(); // initialize all the common bits of this class BaseCreate(aParent, aInitData); + LOG("nsWindow::Create()"); + // save our bounds mBounds = aRect; LOG(" mBounds: x:%d y:%d w:%d h:%d\n", mBounds.x, mBounds.y, mBounds.width, mBounds.height); @@ -5845,16 +5873,17 @@ mWindowType == WindowType::Popup && aInitData && aInitData->mTransparencyMode == TransparencyMode::Transparent; // Figure out our parent window - only used for WindowType::Child auto* parentnsWindow = static_cast(aParent); + LOG(" parent window [%p]", parentnsWindow); if (mWindowType == WindowType::Child) { // We don't support WindowType::Child directly but emulate it by popup // windows. mWindowType = WindowType::Popup; mIsChildWindow = true; - LOG(" child widget, switch to popup. parent nsWindow %p", parentnsWindow); + LOG(" child widget, switch to popup"); } MOZ_ASSERT_IF(mWindowType == WindowType::Popup, parentnsWindow); if (mWindowType != WindowType::Dialog && mWindowType != WindowType::Popup && @@ -5892,26 +5921,21 @@ // It is important that this happens before the realize() call below, so that // we don't get bogus CSD margins on Wayland, see bug 1794577. mUndecorated = IsAlwaysUndecoratedWindow(); if (mUndecorated) { - LOG(" Is undecorated Window\n"); + LOG(" Is undecorated Window\n"); gtk_window_set_titlebar(GTK_WINDOW(mShell), gtk_fixed_new()); gtk_window_set_decorated(GTK_WINDOW(mShell), false); } // Ensure gfxPlatform is initialized, since that is what initializes // gfxVars, used below. Unused << gfxPlatform::GetPlatform(); if (IsTopLevelWidget()) { mGtkWindowDecoration = GetSystemGtkWindowDecoration(); - // Inherit initial scale from our parent, or use the default monitor scale - // otherwise. - mCeiledScaleFactor = parentnsWindow - ? int32_t(parentnsWindow->mCeiledScaleFactor) - : ScreenHelperGTK::GetGTKMonitorScaleFactor(); } // Don't use transparency for PictureInPicture windows. bool toplevelNeedsAlphaVisual = false; if (mWindowType == WindowType::TopLevel && !mIsPIPWindow) { @@ -5952,38 +5976,38 @@ // We only move a general managed toplevel window if someone has // actually placed the window somewhere. If no placement has taken // place, we just let the window manager Do The Right Thing. if (AreBoundsSane()) { GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size()); - LOG("nsWindow::Create() Initial resize to %d x %d\n", size.width, + LOG(" nsWindow::Create() Initial resize to %d x %d\n", size.width, size.height); gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height); } if (mIsPIPWindow) { - LOG(" Is PIP window\n"); + LOG(" Is PIP window\n"); gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_UTILITY); } else if (mIsAlert) { - LOG(" Is alert window\n"); + LOG(" Is alert window\n"); gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_NOTIFICATION); gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell), TRUE); } else if (mWindowType == WindowType::Dialog) { mGtkWindowRoleName = "Dialog"; SetDefaultIcon(); gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_DIALOG); - LOG("nsWindow::Create(): dialog"); + LOG(" nsWindow::Create(): dialog"); if (parentnsWindow) { GtkWindowSetTransientFor(GTK_WINDOW(mShell), GTK_WINDOW(parentnsWindow->GetGtkWidget())); - LOG(" set parent window [%p]\n", parentnsWindow); + LOG(" set parent window [%p]\n", parentnsWindow); } } else if (mWindowType == WindowType::Popup) { MOZ_ASSERT(aInitData); mGtkWindowRoleName = "Popup"; - LOG("nsWindow::Create() Popup"); + LOG(" nsWindow::Create() Popup"); if (mNoAutoHide) { // ... but the window manager does not decorate this window, // nor provide a separate taskbar icon. if (mBorderStyle == BorderStyle::Default) { @@ -6013,11 +6037,11 @@ } if (aInitData->mIsDragPopup) { gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_DND); mIsDragPopup = true; - LOG("nsWindow::Create() Drag popup\n"); + LOG(" nsWindow::Create() Drag popup\n"); } else if (GdkIsX11Display()) { // Set the window hints on X11 only. Wayland popups are configured // at WaylandPopupConfigure(). GdkWindowTypeHint gtkTypeHint; switch (mPopupType) { @@ -6030,14 +6054,14 @@ default: gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY; break; } gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint); - LOG("nsWindow::Create() popup type %s", GetPopupTypeName().get()); + LOG(" nsWindow::Create() popup type %s", GetPopupTypeName().get()); } if (parentnsWindow) { - LOG(" set parent window [%p] %s", parentnsWindow, + LOG(" set parent window [%p] %s", parentnsWindow, parentnsWindow->mGtkWindowRoleName.get()); GtkWindow* parentWidget = GTK_WINDOW(parentnsWindow->GetGtkWidget()); GtkWindowSetTransientFor(GTK_WINDOW(mShell), parentWidget); // If popup parent is modal, we need to make popup modal too. @@ -6061,11 +6085,11 @@ } } else { // must be WindowType::TopLevel mGtkWindowRoleName = "Toplevel"; SetDefaultIcon(); - LOG("nsWindow::Create() Toplevel\n"); + LOG(" nsWindow::Create() Toplevel\n"); // each toplevel window gets its own window group GtkWindowGroup* group = gtk_window_group_new(); gtk_window_group_add_window(group, GTK_WINDOW(mShell)); g_object_unref(group); @@ -6073,13 +6097,27 @@ if (mAlwaysOnTop) { gtk_window_set_keep_above(GTK_WINDOW(mShell), TRUE); } + GtkWidget* container = nullptr; + +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay()) { + mSurface = new WaylandSurface( + parentnsWindow ? MOZ_WL_SURFACE(parentnsWindow->GetMozContainer()) + : nullptr, + gfx::IntSize(mLastSizeRequest.width, mLastSizeRequest.height)); + } + container = moz_container_new(this, mSurface); +#else + container = moz_container_new(this, nullptr); +#endif + // Create a container to hold child windows and child GtkWidgets. - GtkWidget* container = moz_container_new(); mContainer = MOZ_CONTAINER(container); + g_object_set_data(G_OBJECT(mContainer), "nsWindow", this); // Prevent GtkWindow from painting a background to avoid flickering. gtk_widget_set_app_paintable( GTK_WIDGET(mContainer), StaticPrefs::widget_transparent_windows_AtStartup()); @@ -6148,11 +6186,10 @@ } // Also label mShell toplevel window, // property_notify_event_cb callback also needs to find its way home g_object_set_data(G_OBJECT(GetToplevelGdkWindow()), "nsWindow", this); - g_object_set_data(G_OBJECT(mContainer), "nsWindow", this); g_object_set_data(G_OBJECT(mShell), "nsWindow", this); // attach listeners for events g_signal_connect(mShell, "configure_event", G_CALLBACK(configure_event_cb), nullptr); @@ -6203,10 +6240,11 @@ G_CALLBACK(size_allocate_cb), nullptr); g_signal_connect(mContainer, "hierarchy-changed", G_CALLBACK(hierarchy_changed_cb), nullptr); g_signal_connect(mContainer, "notify::scale-factor", G_CALLBACK(scale_changed_cb), nullptr); + // Initialize mHasMappedToplevel. hierarchy_changed_cb(GTK_WIDGET(mContainer), nullptr); // Expose, focus, key, and drag events are sent even to GTK_NO_WINDOW // widgets. g_signal_connect(G_OBJECT(mContainer), "draw", G_CALLBACK(expose_event_cb), @@ -6232,13 +6270,13 @@ // with BrowserParent::UpdateVsyncParentVsyncDispatcher(). // Only use for toplevel windows for now, see bug 1619246. if (GdkIsWaylandDisplay() && StaticPrefs::widget_wayland_vsync_enabled_AtStartup() && IsTopLevelWidget()) { + LOG_VSYNC(" create WaylandVsyncSource"); mWaylandVsyncSource = new WaylandVsyncSource(this); mWaylandVsyncDispatcher = new VsyncDispatcher(mWaylandVsyncSource); - LOG_VSYNC(" created WaylandVsyncSource"); } #endif // We create input contexts for all containers, except for // toplevel popup windows @@ -6578,43 +6616,22 @@ void nsWindow::WaylandStartVsync() { #ifdef MOZ_WAYLAND if (!mWaylandVsyncSource) { return; } - LOG_VSYNC("nsWindow::WaylandStartVsync"); - - MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate); - if (mCompositorWidgetDelegate->AsGtkCompositorWidget() && - mCompositorWidgetDelegate->AsGtkCompositorWidget() - ->GetNativeLayerRoot()) { - LOG_VSYNC(" use source NativeLayerRootWayland"); - mWaylandVsyncSource->MaybeUpdateSource( - mCompositorWidgetDelegate->AsGtkCompositorWidget() - ->GetNativeLayerRoot() - ->AsNativeLayerRootWayland()); - } else { - LOG_VSYNC(" use source mContainer"); - mWaylandVsyncSource->MaybeUpdateSource(mContainer); - } - - mWaylandVsyncSource->EnableMonitor(); + mWaylandVsyncSource->EnableVSyncSource(); #endif } void nsWindow::WaylandStopVsync() { #ifdef MOZ_WAYLAND if (!mWaylandVsyncSource) { return; } - LOG_VSYNC("nsWindow::WaylandStopVsync"); - - // The widget is going to be hidden, so clear the surface of our - // vsync source. - mWaylandVsyncSource->DisableMonitor(); - mWaylandVsyncSource->MaybeUpdateSource(nullptr); + mWaylandVsyncSource->DisableVSyncSource(); #endif } void nsWindow::NativeShow(bool aAction) { if (aAction) { @@ -8287,11 +8304,11 @@ RefPtr window = get_window_for_gtk_widget(widget); if (!window) { return; } - window->OnScaleChanged(/* aNotify = */ true); + window->OnScaleEvent(); } static gboolean touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent) { UpdateLastInputEventTime(aEvent); @@ -8873,32 +8890,41 @@ } return topmostParentWindow; } gint nsWindow::GdkCeiledScaleFactor() { - if (IsTopLevelWidget()) { + MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); + + // mCeiledScaleFactor is set by notify::scale-factor callback + // for visible windows. + if (mCeiledScaleFactor != sNoScale) { + LOGVERBOSE("nsWindow::GdkCeiledScaleFactor(): ceiled scale %d", + (int)mCeiledScaleFactor); return mCeiledScaleFactor; } + + // We're missing scale for window (is hidden?), read parent scale if (nsWindow* topmost = GetTopmostWindow()) { + LOGVERBOSE("nsWindow::GdkCeiledScaleFactor(): toplevel [%p] scale %d", + topmost, (int)topmost->mCeiledScaleFactor); return topmost->mCeiledScaleFactor; } + + LOGVERBOSE("nsWindow::GdkCeiledScaleFactor(): monitor scale %d", + ScreenHelperGTK::GetGTKMonitorScaleFactor()); return ScreenHelperGTK::GetGTKMonitorScaleFactor(); } double nsWindow::FractionalScaleFactor() { #ifdef MOZ_WAYLAND - double fractional_scale = [&] { - if (IsTopLevelWidget()) { - return mFractionalScaleFactor; - } - if (nsWindow* topmost = GetTopmostWindow()) { - return topmost->mFractionalScaleFactor; + if (mSurface) { + auto scale = mSurface->GetScale(); + if (scale != sNoScale) { + LOGVERBOSE("nsWindow::FractionalScaleFactor(): fractional scale %f", + scale); + return scale; } - return 0.0; - }(); - if (fractional_scale != 0.0) { - return fractional_scale; } #endif return GdkCeiledScaleFactor(); } @@ -9646,28 +9672,28 @@ LOG("nsWindow::SetEGLNativeWindowSize() return, " "COMPOSITOR_PAUSED_FLICKERING is set"); return false; } - gint scale = GdkCeiledScaleFactor(); + float scale = FractionalScaleFactor(); # 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)", + LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %f (unscaled " + "%f x %f)", aEGLWindowSize.width, aEGLWindowSize.height, scale, aEGLWindowSize.width / scale, aEGLWindowSize.height / scale); } } # endif return moz_container_wayland_egl_window_set_size( - mContainer, aEGLWindowSize.ToUnknownSize(), scale); + mContainer, aEGLWindowSize.ToUnknownSize()); } #endif nsWindow* nsWindow::GetWindow(GdkWindow* window) { return get_window_for_gdk_window(window); @@ -9690,11 +9716,11 @@ { MutexAutoLock lock(mWindowVisibilityMutex); mIsMapped = true; EnsureGdkWindow(); - OnScaleChanged(/* aNotify = */ false); + RefreshScale(/* aRefreshScreen */ false); if (mIsAlert) { gdk_window_set_override_redirect(GetToplevelGdkWindow(), TRUE); } @@ -9775,10 +9801,13 @@ if (mGdkWindow) { g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr); mGdkWindow = nullptr; } + // Reset scale for hidden windows + mCeiledScaleFactor = sNoScale; + // 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(); @@ -9881,12 +9910,15 @@ menuPopupFrame->SetIsDragSource(!!aSourceDragContext); } } } -UniquePtr nsWindow::LockSurface() { - if (mIsDestroyed) { +UniquePtr nsWindow::LockSurface() { +#ifdef MOZ_WAYLAND + if (mIsDestroyed || !mSurface) { return nullptr; } - LOG_WAYLAND("nsWindow::LockSurface()"); - return MakeUnique(mContainer); + return MakeUnique(MOZ_WL_SURFACE(mContainer)); +#else + return nullptr; +#endif }