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 312349 c0285428a8a04dd0d8f7ad1ed46a2e04147dfbc6
parent 312348 2467398cd9587802f15f46179bbd8c073b441f48
child 312350 2df13967b7466c92cb629e3600a101a1826dfad8
push id30642
push userkwierso@gmail.com
push dateFri, 02 Sep 2016 19:52:35 +0000
treeherdermozilla-central@38d0defa2db7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersacomminos, jrmuizel
bugs1289251
milestone51.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
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'):