author | stransky <stransky@redhat.com> |
Mon, 25 Oct 2021 09:30:06 +0000 | |
changeset 596813 | 00569d0fc9b92fc99ab56ef014425b3c4f9c3ab3 |
parent 596812 | 334e3d59d932dd2850dec7c582f32f49b504e450 |
child 596814 | 88ecfc06a2672fcf016d3a6cd5ec36ddd0d19ecf |
push id | 38912 |
push user | ncsoregi@mozilla.com |
push date | Mon, 25 Oct 2021 21:41:06 +0000 |
treeherder | mozilla-central@6c01444e1721 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | rmader |
bugs | 1737068 |
milestone | 95.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
widget/gtk/nsWindow.cpp | file | annotate | diff | comparison | revisions | |
widget/gtk/nsWindow.h | file | annotate | diff | comparison | revisions |
--- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -188,17 +188,18 @@ static GdkWindow* get_inner_gdk_window(G gint* retx, gint* rety); static int is_parent_ungrab_enter(GdkEventCrossing* aEvent); static int is_parent_grab_leave(GdkEventCrossing* aEvent); /* callbacks from widgets */ static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr); static gboolean configure_event_cb(GtkWidget* widget, GdkEventConfigure* event); -static void container_unrealize_cb(GtkWidget* widget); +static void widget_map_cb(GtkWidget* widget); +static void widget_unrealize_cb(GtkWidget* widget); static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation); static void toplevel_window_size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation); static gboolean delete_event_cb(GtkWidget* widget, GdkEventAny* event); static gboolean enter_notify_event_cb(GtkWidget* widget, GdkEventCrossing* event); static gboolean leave_notify_event_cb(GtkWidget* widget, GdkEventCrossing* event); @@ -412,16 +413,17 @@ void GetWindowOrigin(GdkWindow* aWindow, #endif } nsWindow::nsWindow() : mIsDestroyed(false), mNeedsDispatchResized(false), mIsShown(false), mNeedsShow(false), + mIsMapped(false), mEnabled(true), mCreated(false), mHandleTouchEvent(false), mIsDragPopup(false), mPopupHint(), mWindowScaleFactorChanged(true), mWindowScaleFactor(1), mCompositedScreen(gdk_screen_is_composited(gdk_screen_get_default())), @@ -442,16 +444,18 @@ nsWindow::nsWindow() mPendingConfigures(0), mGtkWindowDecoration(GTK_DECORATION_NONE), mDrawToContainer(false), mDrawInTitlebar(false), mTitlebarBackdropState(false), mIsPIPWindow(false), mIsWaylandPanelWindow(false), mAlwaysOnTop(false), + mNoAutoHide(false), + mMouseTransparent(false), mIsTransparent(false), mTransparencyBitmap(nullptr), mTransparencyBitmapWidth(0), mTransparencyBitmapHeight(0), mTransparencyBitmapForTitlebar(false), mHasAlphaVisual(false), mLastMotionPressure(0), mLastSizeMode(nsSizeMode_Normal), @@ -477,17 +481,18 @@ nsWindow::nsWindow() #ifdef ACCESSIBILITY , mRootAccessible(nullptr) #endif #ifdef MOZ_X11 , mXWindow(X11None), mXVisual(nullptr), - mXDepth(0) + mXDepth(0), + mIsShaped(false) #endif #ifdef MOZ_WAYLAND , mNativePointerLockCenter(LayoutDeviceIntPoint()), mLockedPointer(nullptr), mRelativePointer(nullptr) #endif { @@ -1612,17 +1617,19 @@ nsWindow* nsWindow::WaylandPopupGetTopmo return parentnsWindow; } } } return nullptr; } bool nsWindow::WaylandPopupNeedsTrackInHierarchy() { - MOZ_RELEASE_ASSERT(!mIsDragPopup); + if (mIsDragPopup) { + return false; + } if (mPopupTrackInHierarchyConfigured) { return mPopupTrackInHierarchy; } nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame()); if (!popupFrame) { return false; @@ -1987,16 +1994,25 @@ void nsWindow::WaylandPopupSetDirectPosi GdkPoint position = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft()); GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size()); LOG_POPUP("nsWindow::WaylandPopupSetDirectPosition %d,%d -> %d x %d\n", position.x, position.y, size.width, size.height); mPopupPosition = position; + if (mIsDragPopup) { + gtk_window_move(GTK_WINDOW(mShell), mPopupPosition.x, mPopupPosition.y); + gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height); + // DND window is placed inside container so we need to make hard size + // request to ensure parent container is resized too. + gtk_widget_set_size_request(GTK_WIDGET(mShell), size.width, size.height); + return; + } + GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)); nsWindow* window = get_window_for_gtk_widget(GTK_WIDGET(parentGtkWindow)); GdkWindow* gdkWindow = gtk_widget_get_window(GTK_WIDGET(window->GetMozContainer())); int parentWidth = gdk_window_get_width(gdkWindow); int popupWidth = size.width; @@ -2364,25 +2380,32 @@ void nsWindow::SetZIndex(int32_t aZIndex if (GetPrevSibling() == oldPrev) { return; } NS_ASSERTION(!mContainer, "Expected Mozilla child widget"); // We skip the nsWindows that don't have mGdkWindows. // These are probably in the process of being destroyed. + if (!mGdkWindow) { + return; + } if (!GetNextSibling()) { // We're to be on top. - if (mGdkWindow) gdk_window_raise(mGdkWindow); + if (mGdkWindow) { + gdk_window_raise(mGdkWindow); + } } else { // All the siblings before us need to be below our widget. for (nsWindow* w = this; w; w = static_cast<nsWindow*>(w->GetPrevSibling())) { - if (w->mGdkWindow) gdk_window_lower(w->mGdkWindow); + if (w->mGdkWindow) { + gdk_window_lower(w->mGdkWindow); + } } } } void nsWindow::SetSizeMode(nsSizeMode aMode) { LOG("nsWindow::SetSizeMode %d\n", aMode); // Save the requested state. @@ -2887,21 +2910,22 @@ LayoutDeviceIntPoint nsWindow::GetClient } gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget, GdkEventProperty* aEvent) { if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) { UpdateClientOffsetFromFrameExtents(); return FALSE; } - + if (!mGdkWindow) { + return FALSE; + } if (GetCurrentTimeGetter()->PropertyNotifyHandler(aWidget, aEvent)) { return TRUE; } - return FALSE; } static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor, int32_t aWidgetScaleFactor) { if (!aCursor.IsCustom()) { return nullptr; } @@ -3146,19 +3170,20 @@ void nsWindow::SetIcon(const nsAString& // leave the default icon intact if no matching icons were found if (foundIcon) { gtk_window_set_icon_name(GTK_WINDOW(mShell), iconName.get()); } } LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() { - nsIntPoint origin; - GetWindowOrigin(mGdkWindow, &origin.x, &origin.y); - + nsIntPoint origin(0, 0); + if (mGdkWindow) { + GetWindowOrigin(mGdkWindow, &origin.x, &origin.y); + } return GdkPointToDevicePixels({origin.x, origin.y}); } void nsWindow::CaptureMouse(bool aCapture) { LOG("nsWindow::CaptureMouse() [%p]\n", (void*)this); if (!mGdkWindow) return; @@ -3703,25 +3728,34 @@ gboolean nsWindow::OnConfigureEvent(GtkW gtk_window_get_size(GTK_WINDOW(mShell), &allocation.width, &allocation.height); OnSizeAllocate(&allocation); } return FALSE; } -void nsWindow::OnContainerUnrealize() { +void nsWindow::OnMap() { + LOG(("nsWindow::OnMap [%p]\n", (void*)this)); + // Gtk mapped out 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::OnUnrealize() { // The GdkWindows are about to be destroyed (but not deleted), so remove // their references back to their container widget while the GdkWindow // hierarchy is still available. - - if (mGdkWindow) { - g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr); - mGdkWindow = nullptr; - } + // This call means we *don't* have X11 (or Wayland) window we can render to. + LOG(("nsWindow::OnUnrealize [%p] GdkWindow %p\n", (void*)this, mGdkWindow)); + mIsMapped = false; + ReleaseGdkWindow(); } void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) { LOG("nsWindow::OnSizeAllocate %d,%d -> %d x %d\n", aAllocation->x, aAllocation->y, aAllocation->width, aAllocation->height); // 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) @@ -3740,25 +3774,27 @@ void nsWindow::OnSizeAllocate(GtkAllocat LOG(" Already the same size"); // We were already resized at nsWindow::OnConfigureEvent() so skip it. return; } // Invalidate the new part of the window now for the pending paint to // minimize background flashes (GDK does not do this for external resizes // of toplevels.) - if (mBounds.width < size.width) { - GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect( - mBounds.width, 0, size.width - mBounds.width, size.height)); - gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE); - } - if (mBounds.height < size.height) { - GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect( - 0, mBounds.height, size.width, size.height - mBounds.height)); - gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE); + if (mGdkWindow) { + if (mBounds.width < size.width) { + GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect( + mBounds.width, 0, size.width - mBounds.width, size.height)); + gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE); + } + if (mBounds.height < size.height) { + GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect( + 0, mBounds.height, size.width, size.height - mBounds.height)); + gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE); + } } mBounds.SizeTo(size); // Notify the GtkCompositorWidget of a ClientSizeChange if (mCompositorWidgetDelegate) { mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize()); } @@ -3819,17 +3855,19 @@ void nsWindow::OnLeaveNotifyEvent(GdkEve // This ignores NotifyVirtual and NotifyNonlinearVirtual leave notify // events when the pointer leaves a child window. If the destination // window is a Gecko window then we'll catch the corresponding event on // that window. // // XXXkt However, we will miss toplevel exits when the pointer directly // leaves a foreign (plugin) child window without passing over a visible // portion of a Gecko window. - if (aEvent->subwindow != nullptr) return; + if (!mGdkWindow || aEvent->subwindow != nullptr) { + return; + } WidgetMouseEvent event(true, eMouseExitFromWidget, this, WidgetMouseEvent::eReal); event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y); event.AssignEventTime(GetWidgetEventTime(aEvent->time)); event.mExitFrom = Some(is_top_level_mouse_exit(mGdkWindow, aEvent) @@ -3892,16 +3930,20 @@ static LayoutDeviceIntPoint GetRefPoint( // XXX we're never quite sure which GdkWindow the event came from due to our // custom bubbling in scroll_event_cb(), so use ScreenToWidget to translate // the screen root coordinates into coordinates relative to this widget. return aWindow->GdkEventCoordsToDevicePixels(aEvent->x_root, aEvent->y_root) - aWindow->WidgetToScreenOffset(); } void nsWindow::OnMotionNotifyEvent(GdkEventMotion* aEvent) { + if (!mGdkWindow) { + return; + } + if (mWindowShouldStartDragging) { mWindowShouldStartDragging = false; // find the top-level window GdkWindow* gdk_window = gdk_window_get_toplevel(mGdkWindow); MOZ_ASSERT(gdk_window, "gdk_window_get_toplevel should not return null"); bool canDrag = true; if (GdkIsX11Display()) { @@ -4169,16 +4211,19 @@ void nsWindow::OnButtonPressEvent(GdkEve if (!StaticPrefs::ui_context_menus_after_mouseup() && eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) { DispatchContextMenuEventFromMouseEvent(domButton, aEvent); } } void nsWindow::OnButtonReleaseEvent(GdkEventButton* aEvent) { LOG("Button %u release\n", aEvent->button); + if (!mGdkWindow) { + return; + } if (mWindowShouldStartDragging) { mWindowShouldStartDragging = false; } uint16_t domButton; switch (aEvent->button) { case 1: @@ -5009,16 +5054,134 @@ nsCString nsWindow::GetPopupTypeName() { return nsCString("Tooltip"); case ePopupTypePanel: return nsCString("Panel/Utility"); default: return nsCString("Unknown"); } } +// Disables all rendering of GtkWidget from Gtk side. +// We do our best to persuade Gtk/Gdk to ignore all painting +// to the widget. +static void GtkWidgetDisableUpdates(GtkWidget* aWidget) { + // clear draw signal from widget class + GTK_WIDGET_GET_CLASS(aWidget)->draw = nullptr; + + // Clear exposure mask - it disabled synthesized events. + GdkWindow* window = gtk_widget_get_window(aWidget); + gdk_window_set_events(window, (GdkEventMask)(gdk_window_get_events(window) & + (~GDK_EXPOSURE_MASK))); + + // Remove before/after paint handles from frame clock. + // It disables widget content updates. + GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window); + g_signal_handlers_disconnect_by_data(frame_clock, window); +} + +void nsWindow::ConfigureGdkWindow() { + LOG(("nsWindow::ConfigureGdkWindow() [%p]", this)); + + mGdkWindow = + gtk_widget_get_window(mDrawToContainer ? GTK_WIDGET(mContainer) : mShell); + g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this); + +#ifdef MOZ_X11 + if (GdkIsX11Display()) { + mXWindow = gdk_x11_window_get_xid(mGdkWindow); + + GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow); + mXVisual = gdk_x11_visual_get_xvisual(gdkVisual); + mXDepth = gdk_visual_get_depth(gdkVisual); + mIsShaped = + mIsTransparent && !mHasAlphaVisual && !mTransparencyBitmapForTitlebar; + mSurfaceProvider.Initialize(mXWindow, mXVisual, mXDepth, mIsShaped); + + if (mIsTopLevel) { + // 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); + } + // Dummy call to a function in mozgtk to prevent the linker from removing + // the dependency with --as-needed. + XShmQueryExtension(DefaultXDisplay()); + } +#endif +#ifdef MOZ_WAYLAND + if (GdkIsWaylandDisplay()) { + mSurfaceProvider.Initialize(this); + } +#endif + + if (mCompositorWidgetDelegate) { + mCompositorWidgetDelegate->EnableRendering(mXWindow, mIsShaped); + } + + if (mIsDragPopup && GdkIsWaylandDisplay()) { + GtkWidget* parent = gtk_widget_get_parent(mShell); + if (parent) { + GtkWidgetDisableUpdates(parent); + } + GtkWidgetDisableUpdates(mShell); + GtkWidgetDisableUpdates(GTK_WIDGET(mContainer)); + } + + if (mWindowType == eWindowType_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. + SetWindowMouseTransparent(mMouseTransparent); + } + + RefreshWindowClass(); + + if (mCompositorState == COMPOSITOR_PAUSED_INITIALLY) { + mCompositorState = COMPOSITOR_PAUSED_MISSING_EGL_WINDOW; + } + + ResumeCompositorHiddenWindow(); + WaylandStartVsync(); + + LOG((" finished, new GdkWindow %p XID 0x%lx\n", mGdkWindow, + GdkIsX11Display() ? gdk_x11_window_get_xid(mGdkWindow) : 0)); +} + +void nsWindow::ReleaseGdkWindow() { + LOG(("nsWindow::ReleaseGdkWindow() [%p]", this)); + + WaylandStopVsync(); + PauseCompositorHiddenWindow(); + + if (mGdkWindow) { + g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr); + mGdkWindow = nullptr; + } + + mSurfaceProvider.CleanupResources(); + + if (mCompositorWidgetDelegate) { + mCompositorWidgetDelegate->DisableRendering(); + } +#ifdef MOZ_X11 + if (GdkIsX11Display()) { + mXWindow = X11None; + mXVisual = nullptr; + mXDepth = 0; + mIsShaped = false; + } +#endif +} + nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent, const LayoutDeviceIntRect& aRect, nsWidgetInitData* aInitData) { LOG("nsWindow::Create\n"); // only set the base parent if we're going to be a dialog or a // toplevel nsIWidget* baseParent = @@ -5088,16 +5251,18 @@ nsresult nsWindow::Create(nsIWidget* aPa // mIsWaylandPanelWindow is a special toplevel window on Wayland which // emulates X11 popup window without parent. mIsWaylandPanelWindow = true; mWindowType = eWindowType_toplevel; } mAlwaysOnTop = aInitData && aInitData->mAlwaysOnTop; mIsPIPWindow = aInitData && aInitData->mPIPWindow; + mNoAutoHide = aInitData && aInitData->mNoAutoHide; + mMouseTransparent = aInitData && aInitData->mMouseTransparent; // ok, create our windows switch (mWindowType) { case eWindowType_dialog: case eWindowType_popup: case eWindowType_toplevel: case eWindowType_invisible: { // Popups that are not noautohide are only temporary. The are used @@ -5108,17 +5273,17 @@ nsresult nsWindow::Create(nsIWidget* aPa // For long-lived windows, their stacking order is managed by the // window manager, as indicated by GTK_WINDOW_TOPLEVEL. // For Wayland we have to always use GTK_WINDOW_POPUP to control // popup window position. GtkWindowType type = GTK_WINDOW_TOPLEVEL; if (mWindowType == eWindowType_popup) { MOZ_ASSERT(aInitData); type = GTK_WINDOW_POPUP; - if (GdkIsX11Display() && aInitData->mNoAutoHide) { + if (GdkIsX11Display() && mNoAutoHide) { type = GTK_WINDOW_TOPLEVEL; } } mShell = gtk_window_new(type); // Ensure gfxPlatform is initialized, since that is what initializes // gfxVars, used below. Unused << gfxPlatform::GetPlatform(); @@ -5198,17 +5363,17 @@ nsresult nsWindow::Create(nsIWidget* aPa } else if (mWindowType == eWindowType_popup) { MOZ_ASSERT(aInitData); mGtkWindowRoleName = "Popup"; mPopupHint = aInitData->mPopupHint; LOG("nsWindow::Create() Popup [%p]\n", this); - if (aInitData->mNoAutoHide) { + if (mNoAutoHide) { // ... but the window manager does not decorate this window, // nor provide a separate taskbar icon. if (mBorderStyle == eBorderStyle_default) { gtk_window_set_decorated(GTK_WINDOW(mShell), FALSE); } else { bool decorate = mBorderStyle & eBorderStyle_title; gtk_window_set_decorated(GTK_WINDOW(mShell), decorate); if (decorate) { @@ -5231,16 +5396,17 @@ nsresult nsWindow::Create(nsIWidget* aPa } #endif } if (aInitData->mIsDragPopup) { gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_DND); mIsDragPopup = true; + LOG_POPUP(("nsWindow::Create() Drag popup [%p]\n", this)); } else if (GdkIsX11Display()) { // Set the window hints on X11 only. Wayland popups are configured // at WaylandPopupNeedsTrackInHierarchy(). GdkWindowTypeHint gtkTypeHint; switch (mPopupHint) { case ePopupTypeMenu: gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU; break; @@ -5294,29 +5460,24 @@ nsresult nsWindow::Create(nsIWidget* aPa if (mAlwaysOnTop) { gtk_window_set_keep_above(GTK_WINDOW(mShell), TRUE); } // Create a container to hold child windows and child GtkWidgets. GtkWidget* container = moz_container_new(); mContainer = MOZ_CONTAINER(container); -#ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay() && mIsAccelerated) { + + // Don't render to invisible window. + if (mWindowType == eWindowType_invisible) { mCompositorState = COMPOSITOR_PAUSED_INITIALLY; - RefPtr<nsWindow> self(this); - moz_container_wayland_add_initial_draw_callback( - mContainer, [this, self]() -> void { - LOG("moz_container_wayland initial create " - "ResumeCompositorHiddenWindow()"); - self->mCompositorState = COMPOSITOR_PAUSED_MISSING_EGL_WINDOW; - self->ResumeCompositorHiddenWindow(); - }); } -#endif + if (mIsAccelerated && (GdkIsWaylandDisplay() || gfxVars::UseEGL())) { + mCompositorState = COMPOSITOR_PAUSED_INITIALLY; + } // "csd" style is set when widget is realized so we need to call // it explicitly now. gtk_widget_realize(mShell); /* There are several cases here: * * 1) We're running on Gtk+ without client side decorations. @@ -5333,16 +5494,17 @@ nsresult nsWindow::Create(nsIWidget* aPa (mGtkWindowDecoration == GTK_DECORATION_CLIENT) || gtk_style_context_has_class(style, "csd"); eventWidget = mDrawToContainer ? container : mShell; // Prevent GtkWindow from painting a background to avoid flickering. gtk_widget_set_app_paintable(eventWidget, gTransparentWindows); gtk_widget_add_events(eventWidget, kEvents); + if (mDrawToContainer) { gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK); gtk_widget_set_app_paintable(mShell, gTransparentWindows); } if (mTransparencyBitmapForTitlebar) { moz_container_force_default_visual(mContainer); } @@ -5362,51 +5524,42 @@ nsresult nsWindow::Create(nsIWidget* aPa // make sure this is the focus widget in the container gtk_widget_show(container); if (!mAlwaysOnTop) { gtk_widget_grab_focus(container); } - // the drawing window - mGdkWindow = gtk_widget_get_window(eventWidget); - if (mIsWaylandPanelWindow) { gtk_window_set_decorated(GTK_WINDOW(mShell), false); } +#ifdef MOZ_WAYLAND + if (mIsDragPopup && GdkIsWaylandDisplay()) { + moz_container_wayland_set_commit_to_parent(mContainer); + } +#endif + if (mWindowType == eWindowType_popup) { MOZ_ASSERT(aInitData); // gdk does not automatically set the cursor for "temporary" // windows, which are what gtk uses for popups. // force SetCursor to actually set the cursor, even though our internal // state indicates that we already have the standard cursor. mUpdateCursor = true; SetCursor(Cursor{eCursor_standard}); - - if (aInitData->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. - SetWindowMouseTransparent(aInitData->mMouseTransparent); } } break; default: MOZ_ASSERT_UNREACHABLE("Unexpected eWindowType"); return NS_ERROR_FAILURE; } - // label the drawing window with this object so we can find our way home - g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this); if (mDrawToContainer) { // Also label mShell toplevel window, // property_notify_event_cb callback also needs to find its way home g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)), "nsWindow", this); } if (mContainer) g_object_set_data(G_OBJECT(mContainer), "nsWindow", this); @@ -5422,16 +5575,19 @@ nsresult nsWindow::Create(nsIWidget* aPa g_signal_connect(mShell, "window_state_event", G_CALLBACK(window_state_event_cb), nullptr); g_signal_connect(mShell, "check-resize", G_CALLBACK(check_resize_cb), nullptr); g_signal_connect(mShell, "composited-changed", G_CALLBACK(widget_composited_changed_cb), nullptr); g_signal_connect(mShell, "property-notify-event", G_CALLBACK(property_notify_event_cb), nullptr); + g_signal_connect(mShell, "map", G_CALLBACK(widget_map_cb), nullptr); + g_signal_connect(mShell, "unrealize", G_CALLBACK(widget_unrealize_cb), + nullptr); if (mWindowType == eWindowType_toplevel) { g_signal_connect_after(mShell, "size_allocate", G_CALLBACK(toplevel_window_size_allocate_cb), nullptr); } GdkScreen* screen = gtk_widget_get_screen(mShell); @@ -5444,18 +5600,16 @@ nsresult nsWindow::Create(nsIWidget* aPa GtkSettings* default_settings = gtk_settings_get_default(); g_signal_connect_after(default_settings, "notify::gtk-xft-dpi", G_CALLBACK(settings_xft_dpi_changed_cb), this); } if (mContainer) { // Widget signals - g_signal_connect(mContainer, "unrealize", - G_CALLBACK(container_unrealize_cb), nullptr); g_signal_connect_after(mContainer, "size_allocate", 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); @@ -5534,51 +5688,20 @@ nsresult nsWindow::Create(nsIWidget* aPa nullptr); } LOG("nsWindow [%p] type %d %s\n", (void*)this, mWindowType, mIsPIPWindow ? "PIP window" : ""); LOG("\tmShell %p mContainer %p mGdkWindow %p XID 0x%lx\n", mShell, mContainer, mGdkWindow, GdkIsX11Display() ? gdk_x11_window_get_xid(mGdkWindow) : 0); -#ifdef MOZ_X11 - if (GdkIsX11Display() && mGdkWindow) { - mXWindow = gdk_x11_window_get_xid(mGdkWindow); - - GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow); - mXVisual = gdk_x11_visual_get_xvisual(gdkVisual); - mXDepth = gdk_visual_get_depth(gdkVisual); - bool shaped = popupNeedsAlphaVisual && !mHasAlphaVisual; - - mSurfaceProvider.Initialize(mXWindow, mXVisual, mXDepth, shaped); - - // 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); - - // Dummy call to a function in mozgtk to prevent the linker from removing - // the dependency with --as-needed. - XShmQueryExtension(DefaultXDisplay()); - } -#endif -#ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { - mSurfaceProvider.Initialize(this); - WaylandStartVsync(); - } -#endif - // Set default application name when it's empty. if (mGtkWindowAppName.IsEmpty()) { mGtkWindowAppName = gAppData->name; } - RefreshWindowClass(); return NS_OK; } void nsWindow::RefreshWindowClass(void) { GdkWindow* gdkWindow = gtk_widget_get_window(mShell); if (!gdkWindow) { return; @@ -5703,73 +5826,65 @@ void nsWindow::NativeMoveResize(bool aMo if (mNeedsShow && mIsShown && aResized) { NativeShow(true); } } void nsWindow::ResumeCompositorHiddenWindow() { MOZ_RELEASE_ASSERT(NS_IsMainThread()); - if (mIsDestroyed || mCompositorState == COMPOSITOR_ENABLED || - mCompositorState == COMPOSITOR_PAUSED_INITIALLY) { + LOG("nsWindow::ResumeCompositorHiddenWindow\n"; + if (mIsDestroyed || mCompositorState == COMPOSITOR_ENABLED) { + LOG(" early quit, mCompositorState = %d\n", mCompositorState); return; } if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) { - LOG("nsWindow::ResumeCompositorHiddenWindow\n"); + LOG(" resume\n"); MOZ_ASSERT(mCompositorWidgetDelegate); if (mCompositorWidgetDelegate) { mCompositorState = COMPOSITOR_ENABLED; remoteRenderer->SendResumeAsync(); } remoteRenderer->SendForcePresent(wr::RenderReasons::WIDGET); + } else { + LOG(" quit, failed to get remote renderer.\n"); } } // Because wl_egl_window is destroyed on moz_container_unmap(), // the current compositor cannot use it anymore. To avoid crash, // pause the compositor and destroy EGLSurface & resume the compositor // and re-create EGLSurface on next expose event. void nsWindow::PauseCompositorHiddenWindow() { + LOG(("nsWindow::PauseCompositorHiddenWindow [%p]\n", (void*)this)); + // TODO: The compositor backend currently relies on the pause event to work // around a Gnome specific bug. Remove again once the fix is widely available. // See bug 1721298 if ((!mIsAccelerated && !gfx::gfxVars::UseWebRenderCompositor()) || - mIsDestroyed || mCompositorState == COMPOSITOR_PAUSED_INITIALLY) { - return; - } - - LOG("nsWindow::PauseCompositorHiddenWindow\n"); + mIsDestroyed) { + LOG((" quit early, compositor state %d", mCompositorState)); + return; + } mCompositorState = COMPOSITOR_PAUSED_MISSING_EGL_WINDOW; // Without remote widget / renderer we can't pause compositor. // So delete LayerManager to avoid EGLSurface access. CompositorBridgeChild* remoteRenderer = GetRemoteRenderer(); if (!remoteRenderer || !mCompositorWidgetDelegate) { LOG(" deleted layer manager"); DestroyLayerManager(); return; } // XXX slow sync IPC LOG(" paused compositor"); remoteRenderer->SendPause(); -#ifdef MOZ_WAYLAND - if (GdkIsWaylandDisplay()) { - // Re-request initial draw callback - RefPtr<nsWindow> self(this); - moz_container_wayland_add_initial_draw_callback( - mContainer, [this, self]() -> void { - LOG("moz_container_wayland resume callback " - "ResumeCompositorHiddenWindow()"); - self->ResumeCompositorHiddenWindow(); - }); - } -#endif } static int WindowResumeCompositor(void* data) { nsWindow* window = static_cast<nsWindow*>(data); window->ResumeCompositor(); return true; } @@ -5848,16 +5963,18 @@ void nsWindow::WaylandStartVsync() { #ifdef MOZ_WAYLAND // only use for toplevel windows for now - see bug 1619246 if (!GdkIsWaylandDisplay() || !StaticPrefs::widget_wayland_vsync_enabled_AtStartup() || mWindowType != eWindowType_toplevel) { return; } + LOG(("nsWindow::WaylandStartVsync() [%p]\n", (void*)this)); + if (!mWaylandVsyncSource) { mWaylandVsyncSource = new WaylandVsyncSource(); } WaylandVsyncSource::WaylandDisplay& display = static_cast<WaylandVsyncSource::WaylandDisplay&>( mWaylandVsyncSource->GetGlobalDisplay()); @@ -5872,16 +5989,17 @@ void nsWindow::WaylandStartVsync() { } display.EnableMonitor(); #endif } void nsWindow::WaylandStopVsync() { #ifdef MOZ_WAYLAND if (mWaylandVsyncSource) { + LOG(("nsWindow::WaylandStopVsync() [%p]\n", (void*)this)); // The widget is going to be hidden, so clear the surface of our // vsync source. WaylandVsyncSource::WaylandDisplay& display = static_cast<WaylandVsyncSource::WaylandDisplay&>( mWaylandVsyncSource->GetGlobalDisplay()); display.DisableMonitor(); display.MaybeUpdateSource(nullptr); } @@ -5907,34 +6025,32 @@ void nsWindow::NativeShow(bool aAction) } } // Set up usertime/startupID metadata for the created window. if (mWindowType != eWindowType_invisible) { SetUserTimeAndStartupIDForActivatedWindow(mShell); } if (GdkIsWaylandDisplay()) { ShowWaylandWindow(); - WaylandStartVsync(); } else { LOG(" calling gtk_widget_show(mShell)\n"); gtk_widget_show(mShell); } if (mHiddenPopupPositioned && IsPopup()) { gtk_window_move(GTK_WINDOW(mShell), mPopupPosition.x, mPopupPosition.y); mHiddenPopupPositioned = false; } } else { // There's a chance that when the popup will be shown again it might be // resized because parent could be moved meanwhile. mPreferredPopupRect = nsRect(0, 0, 0, 0); mPreferredPopupRectFlushed = false; LOG("nsWindow::NativeShow hide\n"); if (GdkIsWaylandDisplay()) { - WaylandStopVsync(); if (IsWaylandPopup()) { // We can't close tracked popups directly as they may have visible // child popups. Just mark is as closed and let // UpdateWaylandPopupHierarchy() do the job. if (IsInPopupHierarchy()) { WaylandPopupMarkAsClosed(); UpdateWaylandPopupHierarchy(); } else { @@ -6323,17 +6439,19 @@ void nsWindow::ClearTransparencyBitmap() delete[] mTransparencyBitmap; mTransparencyBitmap = nullptr; mTransparencyBitmapWidth = 0; mTransparencyBitmapHeight = 0; if (!mShell) return; #ifdef MOZ_X11 - if (!mGdkWindow) return; + if (MOZ_UNLIKELY(!mGdkWindow)) { + return; + } Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow); Window xWindow = gdk_x11_window_get_xid(mGdkWindow); XShapeCombineMask(xDisplay, xWindow, ShapeBounding, 0, 0, X11None, ShapeSet); #endif } @@ -7251,17 +7369,17 @@ static GdkCursor* get_gtk_cursor(nsCurso return gdkcursor; } // gtk callbacks void draw_window_of_widget(GtkWidget* widget, GdkWindow* aWindow, cairo_t* cr) { if (gtk_cairo_should_draw_window(cr, aWindow)) { - RefPtr<nsWindow> window = get_window_for_gdk_window(aWindow); + RefPtr<nsWindow> window = get_window_for_gtk_widget(widget); if (!window) { NS_WARNING("Cannot get nsWindow from GtkWidget"); } else { cairo_save(cr); gtk_cairo_transform_to_window(cr, widget, aWindow); // TODO - window->OnExposeEvent() can destroy this or other windows, // do we need to handle it somehow? window->OnExposeEvent(cr); @@ -7293,23 +7411,33 @@ static gboolean configure_event_cb(GtkWi RefPtr<nsWindow> window = get_window_for_gtk_widget(widget); if (!window) { return FALSE; } return window->OnConfigureEvent(widget, event); } -static void container_unrealize_cb(GtkWidget* widget) { +// 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->OnContainerUnrealize(); + window->OnMap(); +} + +static void widget_unrealize_cb(GtkWidget* widget) { + RefPtr<nsWindow> window = get_window_for_gtk_widget(widget); + if (!window) { + return; + } + window->OnUnrealize(); } static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation) { RefPtr<nsWindow> window = get_window_for_gtk_widget(widget); if (!window) { return; } @@ -8119,45 +8247,58 @@ nsIWidget::WindowRenderer* nsWindow::Get // LayerManager/Compositor during shutdown. Just return what we currently // have, which is most likely null. return mWindowRenderer; } return nsBaseWidget::GetWindowRenderer(); } +/* nsWindow::SetCompositorWidgetDelegate() sets remote GtkCompositorWidget + * to render into with compositor. + * + * If we're already visible we need to recreate compositor/vsync state. + */ void nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) { LOG("nsWindow::SetCompositorWidgetDelegate %p\n", delegate); + // There's a change of remote widget - stop compositor and VSync as + // we're going re-init it. + if (mCompositorWidgetDelegate && mIsMapped) { + PauseCompositorHiddenWindow(); + WaylandStopVsync(); + } + if (delegate) { mCompositorWidgetDelegate = delegate->AsPlatformSpecificDelegate(); MOZ_ASSERT(mCompositorWidgetDelegate, "nsWindow::SetCompositorWidgetDelegate called with a " "non-PlatformCompositorWidgetDelegate"); - if (GdkIsX11Display() && gfxVars::UseEGL() && mIsAccelerated) { - // This is called from nsBaseWidget::CreateCompositor() in which case - // we need to create a new EGL surface in RenderCompositorEGL on X11 - mCompositorState = COMPOSITOR_PAUSED_MISSING_EGL_WINDOW; - } - ResumeCompositorHiddenWindow(); - WaylandStartVsync(); + // This is called from nsBaseWidget::CreateCompositor() in which case + // we need to create a new EGL surface in RenderCompositorEGL on X11 + if (mIsMapped) { + ResumeCompositorHiddenWindow(); + WaylandStartVsync(); + } } else { - WaylandStopVsync(); mCompositorWidgetDelegate = nullptr; } } /* nsWindow::UpdateClientOffsetFromCSDWindow() is designed to be called from * nsWindow::OnConfigureEvent() when mContainer window is already positioned. * * It works only for CSD decorated GtkWindow. */ void nsWindow::UpdateClientOffsetFromCSDWindow() { - int x, y; - gdk_window_get_position(mGdkWindow, &x, &y); + int x = 0, y = 0; + + if (mGdkWindow) { + gdk_window_get_position(mGdkWindow, &x, &y); + } x = GdkCoordToDevicePixels(x); y = GdkCoordToDevicePixels(y); if (mClientOffset.x != x || mClientOffset.y != y) { mClientOffset = nsIntPoint(x, y); LOG("nsWindow::UpdateClientOffsetFromCSDWindow %d, %d\n", mClientOffset.x, @@ -8254,21 +8395,16 @@ void nsWindow::SetDrawsInTitlebar(bool a gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height); } if (visible) { mNeedsShow = true; NativeShow(true); } -#ifdef MOZ_X11 - SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED); -#endif - RefreshWindowClass(); - gtk_widget_destroy(tmpWindow); } mDrawInTitlebar = aState; if (mTransparencyBitmapForTitlebar) { if (mDrawInTitlebar && mSizeState == nsSizeMode_Normal && !mIsTiled) { UpdateTitlebarTransparencyBitmap(); @@ -8290,44 +8426,42 @@ GtkWindow* nsWindow::GetCurrentTopmostWi gint nsWindow::GdkCeiledScaleFactor() { // We depend on notify::scale-factor callback which is reliable for toplevel // windows only, so don't use scale cache for popup windows. if (mWindowType == eWindowType_toplevel && !mWindowScaleFactorChanged) { return mWindowScaleFactor; } - GdkWindow* scaledGdkWindow = mGdkWindow; + GdkWindow* scaledGdkWindow = nullptr; if (GdkIsWaylandDisplay()) { // For popup windows/dialogs with parent window we need to get scale factor // of the topmost window. Otherwise the scale factor of the popup is // not updated during it's hidden. if (mWindowType == eWindowType_popup || mWindowType == eWindowType_dialog) { // Get toplevel window for scale factor: GtkWindow* topmostParentWindow = GetCurrentTopmostWindow(); if (topmostParentWindow) { scaledGdkWindow = gtk_widget_get_window(GTK_WIDGET(topmostParentWindow)); } else { NS_WARNING("Popup/Dialog has no parent."); } - // Fallback for windows which parent has been unrealized. - if (!scaledGdkWindow) { - scaledGdkWindow = mGdkWindow; - } - } - } - + } + } + // Fallback for windows which parent has been unrealized. + if (!scaledGdkWindow) { + scaledGdkWindow = mGdkWindow; + } if (scaledGdkWindow) { mWindowScaleFactor = gdk_window_get_scale_factor(scaledGdkWindow); mWindowScaleFactorChanged = false; } else { mWindowScaleFactor = ScreenHelperGTK::GetGTKMonitorScaleFactor(); } - return mWindowScaleFactor; } bool nsWindow::UseFractionalScale() { #ifdef MOZ_WAYLAND return (GdkIsWaylandDisplay() && StaticPrefs::widget_wayland_fractional_buffer_scale_AtStartup() > 0 && WaylandDisplayGet()->GetViewporter()); @@ -8740,22 +8874,19 @@ void nsWindow::GetCompositorWidgetInitDa if (GdkIsX11Display() && mXWindow != X11None) { // Make sure the window XID is propagated to X server, we can fail otherwise // in GPU process (Bug 1401634). Display* display = DefaultXDisplay(); XFlush(display); displayName = nsCString(XDisplayString(display)); } - - bool isShaped = - mIsTransparent && !mHasAlphaVisual && !mTransparencyBitmapForTitlebar; *aInitData = mozilla::widget::GtkCompositorWidgetInitData( (mXWindow != X11None) ? mXWindow : (uintptr_t) nullptr, displayName, - isShaped, GdkIsX11Display(), GetClientSize()); + mIsShaped, GdkIsX11Display(), GetClientSize()); } #ifdef MOZ_X11 /* XApp progress support currently works by setting a property * on a window with this Atom name. A supporting window manager * will notice this and pass it along to whatever handling has * been implemented on that end (e.g. passing it on to a taskbar * widget.) There is no issue if WM support is lacking, this is
--- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -196,17 +196,18 @@ class nsWindow final : public nsBaseWidg mozilla::widget::IMContextWrapper* GetIMContext() const { return mIMContext; } bool DispatchCommandEvent(nsAtom* aCommand); bool DispatchContentCommandEvent(mozilla::EventMessage aMsg); // event callbacks gboolean OnExposeEvent(cairo_t* cr); gboolean OnConfigureEvent(GtkWidget* aWidget, GdkEventConfigure* aEvent); - void OnContainerUnrealize(); + void OnMap(); + void OnUnrealize(); void OnSizeAllocate(GtkAllocation* aAllocation); void OnDeleteEvent(); void OnEnterNotifyEvent(GdkEventCrossing* aEvent); void OnLeaveNotifyEvent(GdkEventCrossing* aEvent); void OnMotionNotifyEvent(GdkEventMotion* aEvent); void OnButtonPressEvent(GdkEventButton* aEvent); void OnButtonReleaseEvent(GdkEventButton* aEvent); void OnContainerFocusInEvent(GdkEventFocus* aEvent); @@ -258,16 +259,17 @@ class nsWindow final : public nsBaseWidg GtkWidget* GetMozContainerWidget(); GdkWindow* GetGdkWindow() { return mGdkWindow; } GtkWidget* GetGtkWidget() { return mShell; } nsIFrame* GetFrame() const; bool IsDestroyed() const { return mIsDestroyed; } bool IsPopup() const; bool IsWaylandPopup() const; bool IsPIPWindow() const { return mIsPIPWindow; }; + bool IsDragPopup() { return mIsDragPopup; }; nsAutoCString GetDebugTag() const; void DispatchDragEvent(mozilla::EventMessage aMsg, const LayoutDeviceIntPoint& aRefPoint, guint aTime); static void UpdateDragStatus(GdkDragContext* aDragContext, nsIDragService* aDragService); @@ -425,30 +427,35 @@ class nsWindow final : public nsBaseWidg // event handling code void DispatchActivateEvent(void); void DispatchDeactivateEvent(void); void MaybeDispatchResized(); virtual void RegisterTouchWindow() override; virtual bool CompositorInitiallyPaused() override { -#ifdef MOZ_WAYLAND return mCompositorState == COMPOSITOR_PAUSED_INITIALLY; -#else - return false; -#endif } nsCOMPtr<nsIWidget> mParent; // Has this widget been destroyed yet? bool mIsDestroyed; // Does WindowResized need to be called on listeners? bool mNeedsDispatchResized; - // This flag tracks if we're hidden or shown. + // mIsShown tracks requested visible status from browser perspective, i.e. + // if the window should be visible or now. bool mIsShown; + // mNeedsShow is set when browser requested to show this window but we failed + // to do so for some reason (wrong window size for instance). + // In such case we set mIsShown = true and mNeedsShow = true to indicate + // that the window is not actually visible but we report to browser that + // it is visible (mIsShown == true). bool mNeedsShow; + // This track real window visibility from OS perspective. + // It's set by OnMap/OnUnrealize which is based on Gtk events. + bool mIsMapped; // is this widget enabled? bool mEnabled; // has the native window for this been created yet? bool mCreated; // whether we handle touch event bool mHandleTouchEvent; // true if this is a drag and drop feedback popup bool mIsDragPopup; @@ -558,16 +565,18 @@ class nsWindow final : public nsBaseWidg LayoutDeviceIntRegion mDraggableRegion; // It's PictureInPicture window. bool mIsPIPWindow; // It's undecorated popup utility window, without resizers/titlebar, // movable by mouse. Used on Wayland as a workaround for popups without // parent (for instance WebRTC sharing indicator). bool mIsWaylandPanelWindow; bool mAlwaysOnTop; + bool mNoAutoHide; + bool mMouseTransparent; // The cursor cache static GdkCursor* gsGtkCursorCache[eCursorCount]; // Transparency bool mIsTransparent; // This bitmap tracks which pixels are transparent. We don't support // full translucency at this time; each pixel is either fully opaque @@ -595,16 +604,22 @@ class nsWindow final : public nsBaseWidg // to force update mBounds after a size state change from a configure // event. bool mBoundsAreValid; static bool DragInProgress(void); 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(); + // nsBaseWidget virtual WindowRenderer* GetWindowRenderer() override; void SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) override; void CleanLayerManagerRecursive(); virtual int32_t RoundsWidgetCoordinatesTo() override; @@ -793,20 +808,16 @@ class nsWindow final : public nsBaseWidg */ RefPtr<mozilla::widget::IMContextWrapper> mIMContext; mozilla::UniquePtr<mozilla::CurrentX11TimeGetter> mCurrentTimeGetter; static GtkWindowDecoration sGtkWindowDecoration; static bool sTransparentMainWindow; - /* Used for software rendering - */ - mozilla::widget::WindowSurfaceProvider mSurfaceProvider; - #ifdef ACCESSIBILITY RefPtr<mozilla::a11y::LocalAccessible> mRootAccessible; /** * Request to create the accessible for this window if it is top level. */ void CreateRootAccessible(); @@ -853,18 +864,20 @@ class nsWindow final : public nsBaseWidg GTK_WIDGET_COMPOSIDED_DISABLED = 1, GTK_WIDGET_COMPOSIDED_ENABLED = 2} WindowComposeRequest; void SetCompositorHint(WindowComposeRequest aState); bool ConfigureX11GLVisual(); Window mXWindow; Visual* mXVisual; int mXDepth; + bool mIsShaped; #endif #ifdef MOZ_WAYLAND RefPtr<mozilla::gfx::VsyncSource> mWaylandVsyncSource; LayoutDeviceIntPoint mNativePointerLockCenter; zwp_locked_pointer_v1* mLockedPointer; zwp_relative_pointer_v1* mRelativePointer; #endif + mozilla::widget::WindowSurfaceProvider mSurfaceProvider; }; #endif /* __nsWindow_h__ */