Bug 1289251 - Create a CompositorWidget for GTK+X11 platform. r=acomminos,jrmuizel
☠☠ backed out by f35a9b2b2091 ☠ ☠
authorRyan Hunt <rhunt@mozilla.com>
Fri, 22 Jul 2016 10:23:07 -0700
changeset 312455 c0285428a8a04dd0d8f7ad1ed46a2e04147dfbc6
parent 312454 2467398cd9587802f15f46179bbd8c073b441f48
child 312456 2df13967b7466c92cb629e3600a101a1826dfad8
push id20447
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 20:36:44 +0000
treeherderfx-team@969397f22187 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersacomminos, jrmuizel
bugs1289251
milestone51.0a1
Bug 1289251 - Create a CompositorWidget for GTK+X11 platform. r=acomminos,jrmuizel MozReview-Commit-ID: 1eq3rRwv1g3
widget/CompositorWidget.h
widget/gtk/CompositorWidgetChild.cpp
widget/gtk/CompositorWidgetChild.h
widget/gtk/CompositorWidgetParent.cpp
widget/gtk/CompositorWidgetParent.h
widget/gtk/InProcessX11CompositorWidget.cpp
widget/gtk/InProcessX11CompositorWidget.h
widget/gtk/PCompositorWidget.ipdl
widget/gtk/PlatformWidgetTypes.ipdlh
widget/gtk/WindowSurfaceProvider.cpp
widget/gtk/WindowSurfaceProvider.h
widget/gtk/X11CompositorWidget.cpp
widget/gtk/X11CompositorWidget.h
widget/gtk/moz.build
widget/gtk/nsApplicationChooser.cpp
widget/gtk/nsApplicationChooser.h
widget/gtk/nsColorPicker.cpp
widget/gtk/nsDeviceContextSpecG.cpp
widget/gtk/nsScreenGtk.cpp
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
widget/moz.build
--- a/widget/CompositorWidget.h
+++ b/widget/CompositorWidget.h
@@ -24,27 +24,28 @@ class Composer2D;
 } // namespace layers
 namespace gfx {
 class DrawTarget;
 class SourceSurface;
 } // namespace gfx
 namespace widget {
 
 class WinCompositorWidget;
+class X11CompositorWidget;
 class CompositorWidgetInitData;
 
 // Gecko widgets usually need to communicate with the CompositorWidget with
 // platform-specific messages (for example to update the window size or
 // transparency). This functionality is controlled through a "host". Since
 // this functionality is platform-dependent, it is only forward declared
 // here.
 class CompositorWidgetDelegate;
 
 // Platforms that support out-of-process widgets.
-#if defined(XP_WIN)
+#if defined(XP_WIN) || defined(MOZ_X11)
 // CompositorWidgetParent should implement CompositorWidget and
 // PCompositorWidgetParent.
 class CompositorWidgetParent;
 
 // CompositorWidgetChild should implement CompositorWidgetDelegate and
 // PCompositorWidgetChild.
 class CompositorWidgetChild;
 
@@ -240,16 +241,19 @@ public:
   /**
    * This is only used by out-of-process compositors.
    */
   virtual RefPtr<VsyncObserver> GetVsyncObserver() const;
 
   virtual WinCompositorWidget* AsWindows() {
     return nullptr;
   }
+  virtual X11CompositorWidget* AsX11() {
+    return nullptr;
+  }
 
   /**
    * Return the platform-specific delegate for the widget, if any.
    */
   virtual CompositorWidgetDelegate* AsDelegate() {
     return nullptr;
   }
 
new file mode 100644
--- /dev/null
+++ b/widget/gtk/CompositorWidgetChild.cpp
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CompositorWidgetChild.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace widget {
+
+CompositorWidgetChild::CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
+                                             RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver)
+  : mVsyncDispatcher(aVsyncDispatcher)
+  , mVsyncObserver(aVsyncObserver)
+{
+  MOZ_ASSERT(XRE_IsParentProcess());
+}
+
+CompositorWidgetChild::~CompositorWidgetChild()
+{
+}
+
+bool
+CompositorWidgetChild::RecvObserveVsync()
+{
+  mVsyncDispatcher->SetCompositorVsyncObserver(mVsyncObserver);
+  return true;
+}
+
+bool
+CompositorWidgetChild::RecvUnobserveVsync()
+{
+  mVsyncDispatcher->SetCompositorVsyncObserver(nullptr);
+  return true;
+}
+
+void
+CompositorWidgetChild::NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize)
+{
+  Unused << SendNotifyClientSizeChanged(aClientSize);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/CompositorWidgetChild.h
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef widget_gtk_CompositorWidgetChild_h
+#define widget_gtk_CompositorWidgetChild_h
+
+#include "X11CompositorWidget.h"
+#include "mozilla/widget/PCompositorWidgetChild.h"
+#include "mozilla/widget/CompositorWidgetVsyncObserver.h"
+
+namespace mozilla {
+namespace widget {
+
+class CompositorWidgetChild final
+ : public PCompositorWidgetChild
+ , public CompositorWidgetDelegate
+{
+public:
+  CompositorWidgetChild(RefPtr<CompositorVsyncDispatcher> aVsyncDispatcher,
+                        RefPtr<CompositorWidgetVsyncObserver> aVsyncObserver);
+  ~CompositorWidgetChild() override;
+
+  bool RecvObserveVsync() override;
+  bool RecvUnobserveVsync() override;
+
+  void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
+
+private:
+  RefPtr<CompositorVsyncDispatcher> mVsyncDispatcher;
+  RefPtr<CompositorWidgetVsyncObserver> mVsyncObserver;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // widget_gtk_CompositorWidgetChild_h
new file mode 100644
--- /dev/null
+++ b/widget/gtk/CompositorWidgetParent.cpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "CompositorWidgetParent.h"
+#include "mozilla/Unused.h"
+
+namespace mozilla {
+namespace widget {
+
+CompositorWidgetParent::CompositorWidgetParent(const CompositorWidgetInitData& aInitData)
+ : X11CompositorWidget(aInitData)
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
+}
+
+CompositorWidgetParent::~CompositorWidgetParent()
+{
+}
+
+void
+CompositorWidgetParent::ObserveVsync(VsyncObserver* aObserver)
+{
+  if (aObserver) {
+    Unused << SendObserveVsync();
+  } else {
+    Unused << SendUnobserveVsync();
+  }
+  mVsyncObserver = aObserver;
+}
+
+RefPtr<VsyncObserver>
+CompositorWidgetParent::GetVsyncObserver() const
+{
+  MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_GPU);
+  return mVsyncObserver;
+}
+
+bool
+CompositorWidgetParent::RecvNotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize)
+{
+  NotifyClientSizeChanged(aClientSize);
+  return true;
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/CompositorWidgetParent.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef widget_gtk_CompositorWidgetParent_h
+#define widget_gtk_CompositorWidgetParent_h
+
+#include "X11CompositorWidget.h"
+#include "mozilla/widget/PCompositorWidgetParent.h"
+
+namespace mozilla {
+namespace widget {
+
+class CompositorWidgetParent final
+ : public PCompositorWidgetParent,
+   public X11CompositorWidget
+{
+public:
+  explicit CompositorWidgetParent(const CompositorWidgetInitData& aInitData);
+  ~CompositorWidgetParent() override;
+
+  void ActorDestroy(ActorDestroyReason aWhy) override { }
+
+  void ObserveVsync(VsyncObserver* aObserver) override;
+  RefPtr<VsyncObserver> GetVsyncObserver() const override;
+
+  bool RecvNotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
+
+private:
+  RefPtr<VsyncObserver> mVsyncObserver;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // widget_gtk_CompositorWidgetParent_h
new file mode 100644
--- /dev/null
+++ b/widget/gtk/InProcessX11CompositorWidget.cpp
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "InProcessX11CompositorWidget.h"
+
+#include "nsWindow.h"
+
+namespace mozilla {
+namespace widget {
+
+/* static */ RefPtr<CompositorWidget>
+CompositorWidget::CreateLocal(const CompositorWidgetInitData& aInitData, nsIWidget* aWidget)
+{
+  return new InProcessX11CompositorWidget(aInitData, static_cast<nsWindow*>(aWidget));
+}
+
+InProcessX11CompositorWidget::InProcessX11CompositorWidget(const CompositorWidgetInitData& aInitData,
+                                                           nsWindow* aWindow)
+  : X11CompositorWidget(aInitData, aWindow)
+{
+}
+
+void
+InProcessX11CompositorWidget::ObserveVsync(VsyncObserver* aObserver)
+{
+  RefPtr<CompositorVsyncDispatcher> cvd = mWidget->GetCompositorVsyncDispatcher();
+  cvd->SetCompositorVsyncObserver(aObserver);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/InProcessX11CompositorWidget.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef widget_gtk_InProcessX11CompositorWidgetParent_h
+#define widget_gtk_InProcessX11CompositorWidgetParent_h
+
+#include "X11CompositorWidget.h"
+
+class nsWindow;
+
+namespace mozilla {
+namespace widget {
+
+class InProcessX11CompositorWidget final : public X11CompositorWidget
+{
+public:
+  InProcessX11CompositorWidget(const CompositorWidgetInitData& aInitData,
+                               nsWindow* aWindow);
+
+  // CompositorWidgetDelegate
+
+  void ObserveVsync(VsyncObserver* aObserver) override;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // widget_gtk_InProcessX11CompositorWidgetParent_h
new file mode 100644
--- /dev/null
+++ b/widget/gtk/PCompositorWidget.ipdl
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PCompositorBridge;
+
+using mozilla::LayoutDeviceIntSize from "Units.h";
+
+namespace mozilla {
+namespace widget {
+
+sync protocol PCompositorWidget
+{
+  manager PCompositorBridge;
+
+parent:
+  async __delete__();
+
+  async NotifyClientSizeChanged(LayoutDeviceIntSize aClientSize);
+
+child:
+
+  async ObserveVsync();
+  async UnobserveVsync();
+};
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/PlatformWidgetTypes.ipdlh
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// This file is a stub, for platforms that do not yet support out-of-process
+// compositing or do not need specialized types to do so.
+
+using mozilla::LayoutDeviceIntSize from "Units.h";
+
+namespace mozilla {
+namespace widget {
+
+struct CompositorWidgetInitData
+{
+  uintptr_t           XWindow;
+  nsCString           XDisplayString;
+
+  LayoutDeviceIntSize InitialClientSize;
+};
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceProvider.cpp
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WindowSurfaceProvider.h"
+
+#include "gfxPlatformGtk.h"
+#include "mozilla/layers/LayersTypes.h"
+#include "WindowSurfaceX11Image.h"
+#include "WindowSurfaceX11SHM.h"
+#include "WindowSurfaceXRender.h"
+
+namespace mozilla {
+namespace widget {
+
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+WindowSurfaceProvider::WindowSurfaceProvider()
+    : mXDisplay(nullptr)
+    , mXWindow(0)
+    , mXVisual(nullptr)
+    , mXDepth(0)
+    , mWindowSurface(nullptr)
+{
+}
+
+void WindowSurfaceProvider::Initialize(
+      Display* aDisplay,
+      Window aWindow,
+      Visual* aVisual,
+      int aDepth)
+{
+  // We should not be initialized
+  MOZ_ASSERT(!mXDisplay);
+
+  // This should also be a valid initialization
+  MOZ_ASSERT(aDisplay && aWindow != None && aVisual);
+
+  mXDisplay = aDisplay;
+  mXWindow = aWindow;
+  mXVisual = aVisual;
+  mXDepth = aDepth;
+}
+void WindowSurfaceProvider::CleanupResources()
+{
+  mWindowSurface = nullptr;
+}
+
+UniquePtr<WindowSurface>
+WindowSurfaceProvider::CreateWindowSurface()
+{
+  // We should be initialized
+  MOZ_ASSERT(mXDisplay);
+
+  // Blit to the window with the following priority:
+  // 1. XRender (iff XRender is enabled && we are in-process)
+  // 2. MIT-SHM
+  // 3. XPutImage
+
+#ifdef MOZ_WIDGET_GTK
+  if (gfxVars::UseXRender()) {
+    LOGDRAW(("Drawing to nsWindow %p using XRender\n", (void*)this));
+    return MakeUnique<WindowSurfaceXRender>(mXDisplay, mXWindow, mXVisual, mXDepth);
+  }
+#endif // MOZ_WIDGET_GTK
+
+#ifdef MOZ_HAVE_SHMIMAGE
+  if (nsShmImage::UseShm()) {
+    LOGDRAW(("Drawing to nsWindow %p using MIT-SHM\n", (void*)this));
+    return MakeUnique<WindowSurfaceX11SHM>(mXDisplay, mXWindow, mXVisual, mXDepth);
+  }
+#endif // MOZ_HAVE_SHMIMAGE
+
+  LOGDRAW(("Drawing to nsWindow %p using XPutImage\n", (void*)this));
+  return MakeUnique<WindowSurfaceX11Image>(mXDisplay, mXWindow, mXVisual, mXDepth);
+}
+
+already_AddRefed<gfx::DrawTarget>
+WindowSurfaceProvider::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
+                                                layers::BufferMode* aBufferMode)
+{
+  if (aInvalidRegion.IsEmpty())
+    return nullptr;
+
+  if (!mWindowSurface) {
+    mWindowSurface = CreateWindowSurface();
+    if (!mWindowSurface)
+      return nullptr;
+  }
+
+  *aBufferMode = BufferMode::BUFFER_NONE;
+  RefPtr<DrawTarget> dt = nullptr;
+  if (!(dt = mWindowSurface->Lock(aInvalidRegion))) {
+    gfxWarningOnce() << "Failed to lock WindowSurface, falling back to XPutImage backend.";
+    mWindowSurface = MakeUnique<WindowSurfaceX11Image>(mXDisplay, mXWindow, mXVisual, mXDepth);
+  }
+  return dt.forget();
+}
+
+void
+WindowSurfaceProvider::EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
+                                              LayoutDeviceIntRegion& aInvalidRegion)
+{
+  if (mWindowSurface)
+    mWindowSurface->Commit(aInvalidRegion);
+}
+
+} // namespace mozilla
+} // namespace widget
new file mode 100644
--- /dev/null
+++ b/widget/gtk/WindowSurfaceProvider.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_PROVIDER_H
+#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_PROVIDER_H
+
+#include "mozilla/widget/WindowSurface.h"
+#include "mozilla/gfx/Types.h"
+#include "mozilla/gfx/2D.h"
+#include "Units.h"
+
+#include <X11/Xlib.h> // for Window, Display, Visual, etc.
+
+namespace mozilla {
+namespace widget {
+
+/*
+ * Holds the logic for creating WindowSurface's for a GTK nsWindow.
+ * The main purpose of this class is to allow sharing of logic between
+ * nsWindow and X11CompositorWidget, for when OMTC is enabled or disabled.
+ */
+class WindowSurfaceProvider final
+{
+public:
+  WindowSurfaceProvider();
+
+  /**
+   * Initializes the WindowSurfaceProvider by giving it the window
+   * handle and display to attach to. WindowSurfaceProvider doesn't
+   * own the Display, Window, etc, and they must continue to exist
+   * while WindowSurfaceProvider is used.
+   */
+  void Initialize(
+      Display* aDisplay,
+      Window aWindow,
+      Visual* aVisual,
+      int aDepth);
+
+  /**
+   * Releases any surfaces created by this provider.
+   * This is used by X11CompositorWidget to get rid
+   * of resources before we close the display connection.
+   */
+  void CleanupResources();
+
+  already_AddRefed<gfx::DrawTarget>
+  StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
+                             layers::BufferMode* aBufferMode);
+  void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
+                                LayoutDeviceIntRegion& aInvalidRegion);
+
+private:
+  UniquePtr<WindowSurface> CreateWindowSurface();
+
+  Display*  mXDisplay;
+  Window    mXWindow;
+  Visual*   mXVisual;
+  int       mXDepth;
+
+  UniquePtr<WindowSurface> mWindowSurface;
+};
+
+}  // namespace widget
+}  // namespace mozilla
+
+#endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_PROVIDER_H
new file mode 100644
--- /dev/null
+++ b/widget/gtk/X11CompositorWidget.cpp
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "X11CompositorWidget.h"
+
+#include "gfxPlatformGtk.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/widget/InProcessCompositorWidget.h"
+#include "mozilla/widget/PlatformWidgetTypes.h"
+#include "nsWindow.h"
+
+namespace mozilla {
+namespace widget {
+
+X11CompositorWidget::X11CompositorWidget(const CompositorWidgetInitData& aInitData,
+                                         nsWindow* aWindow)
+      : mWidget(aWindow)
+{
+  // If we have a nsWindow, then grab the already existing display connection
+  // If we don't, then use the init data to connect to the display
+  if (aWindow) {
+    mXDisplay = (Display*)aWindow->GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);
+  } else {
+    mXDisplay = XOpenDisplay(aInitData.XDisplayString().get());
+  }
+  mXWindow = (Window)aInitData.XWindow();
+
+  // Grab the window's visual and depth
+  XWindowAttributes windowAttrs;
+  XGetWindowAttributes(mXDisplay, mXWindow, &windowAttrs);
+
+  Visual*   visual = windowAttrs.visual;
+  int       depth = windowAttrs.depth;
+
+  // Initialize the window surface provider
+  mProvider.Initialize(
+    mXDisplay,
+    mXWindow,
+    visual,
+    depth
+    );
+
+  mClientSize = aInitData.InitialClientSize();
+}
+
+X11CompositorWidget::~X11CompositorWidget()
+{
+  mProvider.CleanupResources();
+
+  // If we created our own display connection, we need to destroy it
+  if (!mWidget && mXDisplay) {
+    XCloseDisplay(mXDisplay);
+    mXDisplay = nullptr;
+  }
+}
+
+already_AddRefed<gfx::DrawTarget>
+X11CompositorWidget::StartRemoteDrawing()
+{
+  return nullptr;
+}
+void
+X11CompositorWidget::EndRemoteDrawing()
+{
+}
+
+already_AddRefed<gfx::DrawTarget>
+X11CompositorWidget::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
+                                                layers::BufferMode* aBufferMode)
+{
+  return mProvider.StartRemoteDrawingInRegion(aInvalidRegion,
+                                              aBufferMode);
+}
+
+void X11CompositorWidget::EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
+                              LayoutDeviceIntRegion& aInvalidRegion)
+{
+  mProvider.EndRemoteDrawingInRegion(aDrawTarget,
+                                     aInvalidRegion);
+}
+
+nsIWidget* X11CompositorWidget::RealWidget()
+{
+  return mWidget;
+}
+
+void
+X11CompositorWidget::NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize)
+{
+  mClientSize = aClientSize;
+}
+
+LayoutDeviceIntSize
+X11CompositorWidget::GetClientSize()
+{
+  return mClientSize;
+}
+
+uintptr_t
+X11CompositorWidget::GetWidgetKey()
+{
+  return reinterpret_cast<uintptr_t>(mWidget);
+}
+
+} // namespace widget
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/widget/gtk/X11CompositorWidget.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef widget_gtk_X11CompositorWidget_h
+#define widget_gtk_X11CompositorWidget_h
+
+#include "mozilla/widget/CompositorWidget.h"
+#include "WindowSurfaceProvider.h"
+
+class nsIWidget;
+class nsWindow;
+
+namespace mozilla {
+namespace widget {
+
+class CompositorWidgetDelegate
+{
+public:
+  virtual void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) = 0;
+};
+
+class X11CompositorWidget
+ : public CompositorWidget
+ , public CompositorWidgetDelegate
+{
+public:
+  X11CompositorWidget(const CompositorWidgetInitData& aInitData,
+                      nsWindow* aWindow = nullptr);
+  ~X11CompositorWidget();
+
+  // CompositorWidget Overrides
+
+  already_AddRefed<gfx::DrawTarget> StartRemoteDrawing() override;
+  void EndRemoteDrawing() override;
+
+  already_AddRefed<gfx::DrawTarget>
+  StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion,
+                             layers::BufferMode* aBufferMode) override;
+  void EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget,
+                                LayoutDeviceIntRegion& aInvalidRegion) override;
+  uintptr_t GetWidgetKey() override;
+
+  void NotifyClientSizeChanged(const LayoutDeviceIntSize& aClientSize) override;
+  LayoutDeviceIntSize GetClientSize() override;
+
+  nsIWidget* RealWidget() override;
+  X11CompositorWidget* AsX11() override { return this; }
+  CompositorWidgetDelegate* AsDelegate() override { return this; }
+
+protected:
+  nsWindow* mWidget;
+
+private:
+  LayoutDeviceIntSize mClientSize;
+
+  Display* mXDisplay;
+  Window   mXWindow;
+  WindowSurfaceProvider mProvider;
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // widget_gtk_X11CompositorWidget_h
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -40,17 +40,27 @@ UNIFIED_SOURCES += [
 ]
 
 SOURCES += [
     'nsWindow.cpp', # conflicts with X11 headers
 ]
 
 if CONFIG['MOZ_X11']:
     UNIFIED_SOURCES += [
+        'CompositorWidgetChild.cpp',
+        'CompositorWidgetParent.cpp',
+        'InProcessX11CompositorWidget.cpp',
         'nsIdleServiceGTK.cpp',
+        'X11CompositorWidget.cpp',
+    ]
+    EXPORTS.mozilla.widget += [
+        'CompositorWidgetChild.h',
+        'CompositorWidgetParent.h',
+        'InProcessX11CompositorWidget.h',
+        'X11CompositorWidget.h',
     ]
 
 if CONFIG['NS_PRINTING']:
     UNIFIED_SOURCES += [
         'nsCUPSShim.cpp',
         'nsDeviceContextSpecG.cpp',
         'nsPaperPS.cpp',
         'nsPrintDialogGTK.cpp',
@@ -58,20 +68,24 @@ if CONFIG['NS_PRINTING']:
         'nsPrintSettingsGTK.cpp',
         'nsPSPrinters.cpp',
     ]
 
 if CONFIG['MOZ_X11']:
     UNIFIED_SOURCES += [
         'nsClipboard.cpp',
         'nsDragService.cpp',
+        'WindowSurfaceProvider.cpp',
         'WindowSurfaceX11.cpp',
         'WindowSurfaceX11Image.cpp',
         'WindowSurfaceXRender.cpp',
     ]
+    EXPORTS.mozilla.widget += [
+        'WindowSurfaceProvider.h',
+    ]
 
 if CONFIG['ACCESSIBILITY']:
     UNIFIED_SOURCES += [
         'maiRedundantObjectFactory.c',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gtk2':
     UNIFIED_SOURCES += [
--- a/widget/gtk/nsApplicationChooser.cpp
+++ b/widget/gtk/nsApplicationChooser.cpp
@@ -5,18 +5,21 @@
 
 #include "mozilla/Types.h"
 
 #include <gtk/gtk.h>
 
 #include "nsApplicationChooser.h"
 #include "WidgetUtils.h"
 #include "nsIMIMEInfo.h"
+#include "nsIWidget.h"
 #include "nsCExternalHandlerService.h"
+#include "nsComponentManagerUtils.h"
 #include "nsGtkUtils.h"
+#include "nsPIDOMWindow.h"
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsApplicationChooser, nsIApplicationChooser)
 
 nsApplicationChooser::nsApplicationChooser()
 {
 }
--- a/widget/gtk/nsApplicationChooser.h
+++ b/widget/gtk/nsApplicationChooser.h
@@ -2,17 +2,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsApplicationChooser_h__
 #define nsApplicationChooser_h__
 
 #include <gtk/gtk.h>
+#include "nsCOMPtr.h"
 #include "nsIApplicationChooser.h"
+#include "nsString.h"
+
+class nsIWidget;
 
 class nsApplicationChooser final : public nsIApplicationChooser
 {
 public:
   nsApplicationChooser();
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAPPLICATIONCHOOSER
   void Done(GtkWidget* chooser, gint response);
--- a/widget/gtk/nsColorPicker.cpp
+++ b/widget/gtk/nsColorPicker.cpp
@@ -5,16 +5,17 @@
 
 #include <gtk/gtk.h>
 
 #include "nsColor.h"
 #include "nsColorPicker.h"
 #include "nsGtkUtils.h"
 #include "nsIWidget.h"
 #include "WidgetUtils.h"
+#include "nsPIDOMWindow.h"
 
 NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
 
 #if defined(ACTIVATE_GTK3_COLOR_PICKER) && GTK_CHECK_VERSION(3,4,0)
 int nsColorPicker::convertGdkRgbaComponent(gdouble color_component) {
   // GdkRGBA value is in range [0.0..1.0]. We need something in range [0..255]
   return color_component * 255 + 0.5;
 }
--- a/widget/gtk/nsDeviceContextSpecG.cpp
+++ b/widget/gtk/nsDeviceContextSpecG.cpp
@@ -11,16 +11,17 @@
 
 #include "plstr.h"
 #include "prenv.h" /* for PR_GetEnv */
 
 #include "nsPrintfCString.h"
 #include "nsReadableUtils.h"
 #include "nsStringEnumerator.h"
 #include "nsIServiceManager.h" 
+#include "nsThreadUtils.h"
 
 #include "nsPSPrinters.h"
 #include "nsPaperPS.h"  /* Paper size list */
 
 #include "nsPrintSettingsGTK.h"
 
 #include "nsIFileStreams.h"
 #include "nsIFile.h"
--- a/widget/gtk/nsScreenGtk.cpp
+++ b/widget/gtk/nsScreenGtk.cpp
@@ -1,15 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsScreenGtk.h"
 
+#include "nsIWidget.h"
+
 #include <gdk/gdk.h>
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #include <X11/Xatom.h>
 #endif
 #include <gtk/gtk.h>
 #include <dlfcn.h>
 #include "gfxPlatformGtk.h"
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -112,16 +112,17 @@ using namespace mozilla::widget;
 #include "Layers.h"
 #include "GLContextProvider.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/HelpersCairo.h"
 #include "mozilla/layers/CompositorBridgeParent.h"
 #include "mozilla/layers/CompositorThread.h"
 
 #ifdef MOZ_X11
+#include "X11CompositorWidget.h"
 #include "gfxXlibSurface.h"
 #include "WindowSurfaceX11Image.h"
 #include "WindowSurfaceX11SHM.h"
 #include "WindowSurfaceXRender.h"
 #endif // MOZ_X11
 
 #include "nsShmImage.h"
 
@@ -2484,16 +2485,23 @@ nsWindow::OnSizeAllocate(GtkAllocation *
         GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
             LayoutDeviceIntRect(0, mBounds.height,
                                 size.width, size.height - mBounds.height));
         gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
     }
 
     mBounds.SizeTo(size);
 
+#ifdef MOZ_X11
+    // Notify the X11CompositorWidget of a ClientSizeChange
+    if (mCompositorWidgetDelegate) {
+      mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
+    }
+#endif
+
     // Gecko permits running nested event loops during processing of events,
     // GtkWindow callers of gtk_widget_size_allocate expect the signal
     // handlers to return sometime in the near future.
     mNeedsDispatchResized = true;
     NS_DispatchToCurrentThread(NewRunnableMethod(this, &nsWindow::MaybeDispatchResized));
 }
 
 void
@@ -3985,16 +3993,18 @@ nsWindow::Create(nsIWidget* aParent,
 #ifdef MOZ_X11
     if (mIsX11Display && mGdkWindow) {
       mXDisplay = GDK_WINDOW_XDISPLAY(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);
+
+      mSurfaceProvider.Initialize(mXDisplay, mXWindow, mXVisual, mXDepth);
     }
 #endif
 
     return NS_OK;
 }
 
 void
 nsWindow::SetWindowClass(const nsAString &xulWinType)
@@ -4086,16 +4096,24 @@ nsWindow::NativeResize()
         allocation.width = size.width;
         allocation.height = size.height;
         gtk_widget_size_allocate(widget, &allocation);
     }
     else if (mGdkWindow) {
         gdk_window_resize(mGdkWindow, size.width, size.height);
     }
 
+#ifdef MOZ_X11
+    // Notify the X11CompositorWidget of a ClientSizeChange
+    // This is different than OnSizeAllocate to catch initial sizing
+    if (mCompositorWidgetDelegate) {
+      mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
+    }
+#endif
+
     // Does it need to be shown because bounds were previously insane?
     if (mNeedsShow && mIsShown) {
         NativeShow(true);
     }
 }
 
 void
 nsWindow::NativeMoveResize()
@@ -4134,16 +4152,24 @@ nsWindow::NativeMoveResize()
         allocation.height = size.height;
         gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
     }
     else if (mGdkWindow) {
         gdk_window_move_resize(mGdkWindow,
                                topLeft.x, topLeft.y, size.width, size.height);
     }
 
+#ifdef MOZ_X11
+    // Notify the X11CompositorWidget of a ClientSizeChange
+    // This is different than OnSizeAllocate to catch initial sizing
+    if (mCompositorWidgetDelegate) {
+      mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
+    }
+#endif
+
     // Does it need to be shown because bounds were previously insane?
     if (mNeedsShow && mIsShown) {
         NativeShow(true);
     }
 }
 
 void
 nsWindow::NativeShow(bool aAction)
@@ -6530,44 +6556,24 @@ nsWindow::GetDrawTargetForGdkDrawable(Gd
 
     return dt.forget();
 }
 #endif
 
 already_AddRefed<DrawTarget>
 nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode)
 {
-  if (aInvalidRegion.IsEmpty())
-    return nullptr;
-
-  if (!mWindowSurface) {
-    mWindowSurface = CreateWindowSurface();
-    if (!mWindowSurface)
-      return nullptr;
-  }
-
-  *aBufferMode = BufferMode::BUFFER_NONE;
-  RefPtr<DrawTarget> dt = nullptr;
-  if (!(dt = mWindowSurface->Lock(aInvalidRegion))) {
-#ifdef MOZ_X11
-    if (mIsX11Display) {
-      gfxWarningOnce() << "Failed to lock WindowSurface, falling back to XPutImage backend.";
-      mWindowSurface = MakeUnique<WindowSurfaceX11Image>(mXDisplay, mXWindow, mXVisual, mXDepth);
-    }
-#endif // MOZ_X11
-  }
-  return dt.forget();
+  return mSurfaceProvider.StartRemoteDrawingInRegion(aInvalidRegion, aBufferMode);
 }
 
 void
 nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget,
                                    LayoutDeviceIntRegion& aInvalidRegion)
 {
-  if (mWindowSurface)
-    mWindowSurface->Commit(aInvalidRegion);
+  mSurfaceProvider.EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion);
 }
 
 // Code shared begin BeginMoveDrag and BeginResizeDrag
 bool
 nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent,
                       GdkWindow** aWindow, gint* aButton,
                       gint* aRootX, gint* aRootY)
 {
@@ -6994,50 +7000,20 @@ nsWindow::SynthesizeNativeTouchPoint(uin
 #endif
 
 int32_t
 nsWindow::RoundsWidgetCoordinatesTo()
 {
     return GdkScaleFactor();
 }
 
-UniquePtr<WindowSurface>
-nsWindow::CreateWindowSurface()
-{
-  if (!mGdkWindow)
-    return nullptr;
-
-  // TODO: Add path for Wayland. We can't use gdk_cairo_create as it's not
-  //       threadsafe.
-  if (!mIsX11Display)
-    return nullptr;
-
-#ifdef MOZ_X11
-  // Blit to the window with the following priority:
-  // 1. XRender (iff XRender is enabled)
-  // 2. MIT-SHM
-  // 3. XPutImage
-
-#ifdef MOZ_WIDGET_GTK
-  if (gfxVars::UseXRender()) {
-    LOGDRAW(("Drawing to nsWindow %p using XRender\n", (void*)this));
-    return MakeUnique<WindowSurfaceXRender>(mXDisplay, mXWindow, mXVisual, mXDepth);
-  }
-#endif // MOZ_WIDGET_GTK
-
-  Display* display;
-  if (CompositorThreadHolder::IsInCompositorThread()) {
-    display = gfxPlatformGtk::GetPlatform()->GetCompositorDisplay();
-  } else {
-    display = mXDisplay;
-  }
-
-#ifdef MOZ_HAVE_SHMIMAGE
-  if (nsShmImage::UseShm()) {
-    LOGDRAW(("Drawing to nsWindow %p using MIT-SHM\n", (void*)this));
-    return MakeUnique<WindowSurfaceX11SHM>(display, mXWindow, mXVisual, mXDepth);
-  }
-#endif // MOZ_HAVE_SHMIMAGE
-
-  LOGDRAW(("Drawing to nsWindow %p using XPutImage\n", (void*)this));
-  return MakeUnique<WindowSurfaceX11Image>(display, mXWindow, mXVisual, mXDepth);
-#endif // MOZ_X11
-}
+void nsWindow::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData)
+{
+  #ifdef MOZ_X11
+  Display* xDisplay = (Display*)GetNativeData(NS_NATIVE_COMPOSITOR_DISPLAY);
+  char* xDisplayString = XDisplayString(xDisplay);
+
+  *aInitData = mozilla::widget::CompositorWidgetInitData(
+                                  mXWindow,
+                                  nsCString(xDisplayString),
+                                  GetClientSize());
+  #endif
+}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -20,16 +20,17 @@
 #include <gdk/gdk.h>
 #include <gtk/gtk.h>
 
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #endif /* MOZ_X11 */
 
 #include "mozilla/widget/WindowSurface.h"
+#include "mozilla/widget/WindowSurfaceProvider.h"
 
 #ifdef ACCESSIBILITY
 #include "mozilla/a11y/Accessible.h"
 #endif
 #include "mozilla/EventForwards.h"
 #include "mozilla/TouchEvents.h"
 
 #include "IMContextWrapper.h"
@@ -340,16 +341,18 @@ public:
     virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId,
                                                 TouchPointerState aPointerState,
                                                 LayoutDeviceIntPoint aPoint,
                                                 double aPointerPressure,
                                                 uint32_t aPointerOrientation,
                                                 nsIObserver* aObserver) override;
 #endif
 
+    virtual void GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData) override;
+
     // HiDPI scale conversion
     gint GdkScaleFactor();
 
     // To GDK
     gint DevicePixelsToGdkCoordRoundUp(int pixels);
     gint DevicePixelsToGdkCoordRoundDown(int pixels);
     GdkPoint DevicePixelsToGdkPointRoundDown(LayoutDeviceIntPoint point);
     GdkRectangle DevicePixelsToGdkSizeRoundUp(LayoutDeviceIntSize pixelSize);
@@ -445,23 +448,22 @@ private:
 #if GTK_CHECK_VERSION(3,4,0)
     // This field omits duplicate scroll events caused by GNOME bug 726878.
     guint32             mLastScrollEventTime;
 
     // for touch event handling
     nsRefPtrHashtable<nsPtrHashKey<GdkEventSequence>, mozilla::dom::Touch> mTouches;
 #endif
 
-    mozilla::UniquePtr<mozilla::widget::WindowSurface> mWindowSurface;
-
 #ifdef MOZ_X11
     Display*            mXDisplay;
     Window              mXWindow;
     Visual*             mXVisual;
     int                 mXDepth;
+    mozilla::widget::WindowSurfaceProvider mSurfaceProvider;
 #endif
 
     // Upper bound on pending ConfigureNotify events to be dispatched to the
     // window. See bug 1225044.
     int mPendingConfigures;
 
 #ifdef ACCESSIBILITY
     RefPtr<mozilla::a11y::Accessible> mRootAccessible;
@@ -542,18 +544,16 @@ private:
     virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT) override;
 
     void CleanLayerManagerRecursive();
 
     virtual int32_t RoundsWidgetCoordinatesTo() override;
 
-    mozilla::UniquePtr<mozilla::widget::WindowSurface> CreateWindowSurface();
-
     /**
      * |mIMContext| takes all IME related stuff.
      *
      * This is owned by the top-level nsWindow or the topmost child
      * nsWindow embedded in a non-Gecko widget.
      *
      * The instance is created when the top level widget is created.  And when
      * the widget is destroyed, it's released.  All child windows refer its
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -252,16 +252,21 @@ LOCAL_INCLUDES += [
     '/widget',
 ]
 
 if toolkit == 'windows':
     IPDL_SOURCES = [
         'windows/PCompositorWidget.ipdl',
         'windows/PlatformWidgetTypes.ipdlh',
     ]
+elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT'] and CONFIG['MOZ_X11']:
+    IPDL_SOURCES = [
+        'gtk/PCompositorWidget.ipdl',
+        'gtk/PlatformWidgetTypes.ipdlh',
+    ]
 else:
     IPDL_SOURCES = [
         'PCompositorWidget.ipdl',
         'PlatformWidgetTypes.ipdlh',
     ]
 
 widget_dir = toolkit
 if widget_dir in ('gtk3', 'gtk2'):