diff --git a/.firefox.metadata b/.firefox.metadata
index 37c649f..61dcda4 100644
--- a/.firefox.metadata
+++ b/.firefox.metadata
@@ -1,6 +1,6 @@
 18a8f30a0356c751b8d0ea6f76e764cab13ee046 SOURCES/Python-2.7.13.tar.xz
-0fa5a71ce2cb90ea4be719a92645aa09dff3721f SOURCES/firefox-60.4.0esr.source.tar.xz
-9d86cb1d4ccc300f5033e3fdb87c8d5fe5cd4786 SOURCES/firefox-langpacks-60.4.0esr-20181205.tar.xz
+f375ffedfc3f86695623becc28a9a6f382535d37 SOURCES/firefox-60.5.0esr.source.tar.xz
+df0031b81c1cf73ed05a2c92b9e13d155b9bf6c5 SOURCES/firefox-langpacks-60.5.0esr-20190125.tar.xz
 6724218efbb1f3fa14541cb2f255970b98446a45 SOURCES/firefox-symbolic.svg
 0de63f863b158454b9429234b52ed28a397ec45c SOURCES/gtk3-private-3.22.26-1.el6.src.rpm
 e188ab1a444697bc649e223c28389d82ca94c472 SOURCES/libffi-3.0.13-18.el7_3.src.rpm
diff --git a/.gitignore b/.gitignore
index c45903b..a031e84 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
 SOURCES/Python-2.7.13.tar.xz
-SOURCES/firefox-60.4.0esr.source.tar.xz
-SOURCES/firefox-langpacks-60.4.0esr-20181205.tar.xz
+SOURCES/firefox-60.5.0esr.source.tar.xz
+SOURCES/firefox-langpacks-60.5.0esr-20190125.tar.xz
 SOURCES/firefox-symbolic.svg
 SOURCES/gtk3-private-3.22.26-1.el6.src.rpm
 SOURCES/libffi-3.0.13-18.el7_3.src.rpm
diff --git a/SOURCES/Bug-1238661---fix-mozillaSignalTrampoline-to-work-.patch b/SOURCES/Bug-1238661---fix-mozillaSignalTrampoline-to-work-.patch
deleted file mode 100644
index 70e45ff..0000000
--- a/SOURCES/Bug-1238661---fix-mozillaSignalTrampoline-to-work-.patch
+++ /dev/null
@@ -1,19 +0,0 @@
-diff -up firefox-60.0/mfbt/LinuxSignal.h.mozilla-1238661 firefox-60.0/mfbt/LinuxSignal.h
---- firefox-60.0/mfbt/LinuxSignal.h.mozilla-1238661	2018-04-27 08:55:38.848241768 +0200
-+++ firefox-60.0/mfbt/LinuxSignal.h	2018-04-27 09:06:47.946769859 +0200
-@@ -25,10 +25,13 @@ SignalTrampoline(int aSignal, siginfo_t*
-     "nop; nop; nop; nop"
-     : : : "memory");
- 
-+  // Because the assembler may generate additional insturctions below, we
-+  // need to ensure NOPs are inserted first by separating them out above.
-+
-   asm volatile (
--    "b %0"
-+    "bx %0"
-     :
--    : "X"(H)
-+    : "r"(H), "l"(aSignal), "l"(aInfo), "l"(aContext)
-     : "memory");
- }
- 
diff --git a/SOURCES/build-disable-elfhack.patch b/SOURCES/build-disable-elfhack.patch
index 172ecf0..1db9bdf 100644
--- a/SOURCES/build-disable-elfhack.patch
+++ b/SOURCES/build-disable-elfhack.patch
@@ -1,12 +1,12 @@
-diff -up firefox-63.0/toolkit/moz.configure.disable-elfhack firefox-63.0/toolkit/moz.configure
---- firefox-63.0/toolkit/moz.configure.disable-elfhack	2018-10-18 13:35:35.870039190 +0200
-+++ firefox-63.0/toolkit/moz.configure	2018-10-18 13:36:41.682515492 +0200
-@@ -1010,7 +1010,7 @@ with only_when('--enable-compile-environ
-                help='Disable elf hacks')
+diff -up firefox-60.4.0/toolkit/moz.configure.disable-elfhack firefox-60.4.0/toolkit/moz.configure
+--- firefox-60.4.0/toolkit/moz.configure.disable-elfhack	2019-01-03 14:47:00.566556623 +0100
++++ firefox-60.4.0/toolkit/moz.configure	2019-01-03 14:49:14.243887620 +0100
+@@ -1192,7 +1192,7 @@ with only_when(has_elfhack):
+     option('--disable-elf-hack', help='Disable elf hacks')
  
-         set_config('USE_ELF_HACK',
--                   depends_if('--enable-elf-hack')(lambda _: True))
-+                   depends_if('--enable-elf-hack')(lambda _: False))
+     set_config('USE_ELF_HACK',
+-               depends_if('--enable-elf-hack')(lambda _: True))
++               depends_if('--enable-elf-hack')(lambda _: False))
  
  
  @depends(check_build_environment)
diff --git a/SOURCES/build-jit-atomic-always-lucky.patch b/SOURCES/build-jit-atomic-always-lucky.patch
index 31bc5ec..ab99524 100644
--- a/SOURCES/build-jit-atomic-always-lucky.patch
+++ b/SOURCES/build-jit-atomic-always-lucky.patch
@@ -1,30 +1,12 @@
-diff -up firefox-57.0b5/js/src/jit/AtomicOperations.h.jit-atomic-lucky firefox-57.0b5/js/src/jit/AtomicOperations.h
---- firefox-57.0b5/js/src/jit/AtomicOperations.h.jit-atomic-lucky	2017-10-06 12:34:02.338973607 +0200
-+++ firefox-57.0b5/js/src/jit/AtomicOperations.h	2017-10-06 12:38:24.632622215 +0200
-@@ -415,7 +415,7 @@ AtomicOperations::isLockfreeJS(int32_t s
+diff -up firefox-60.5.0/js/src/jit/AtomicOperations.h.jit-atomic-lucky firefox-60.5.0/js/src/jit/AtomicOperations.h
+--- firefox-60.5.0/js/src/jit/AtomicOperations.h.jit-atomic-lucky	2019-01-22 10:20:27.993697161 +0100
++++ firefox-60.5.0/js/src/jit/AtomicOperations.h	2019-01-22 10:23:15.337873762 +0100
+@@ -394,7 +394,7 @@ inline bool AtomicOperations::isLockfree
  #elif defined(__s390__) || defined(__s390x__)
- # include "jit/none/AtomicOperations-feeling-lucky.h"
+ #include "jit/none/AtomicOperations-feeling-lucky.h"
  #else
--# error "No AtomicOperations support provided for this platform"
-+# include "jit/none/AtomicOperations-feeling-lucky.h"
+-#error "No AtomicOperations support provided for this platform"
++#include "jit/none/AtomicOperations-feeling-lucky.h"
  #endif
  
- #endif // jit_AtomicOperations_h
-diff -up firefox-57.0b5/js/src/jit/none/AtomicOperations-feeling-lucky.h.jit-atomic-lucky firefox-57.0b5/js/src/jit/none/AtomicOperations-feeling-lucky.h
---- firefox-57.0b5/js/src/jit/none/AtomicOperations-feeling-lucky.h.jit-atomic-lucky	2017-09-19 06:18:28.000000000 +0200
-+++ firefox-57.0b5/js/src/jit/none/AtomicOperations-feeling-lucky.h	2017-10-06 12:34:02.338973607 +0200
-@@ -79,6 +79,14 @@
- #  define GNUC_COMPATIBLE
- #endif
- 
-+#ifdef __s390__
-+#  define GNUC_COMPATIBLE
-+#endif
-+
-+#ifdef __s390x__
-+#  define GNUC_COMPATIBLE
-+#endif
-+
- // The default implementation tactic for gcc/clang is to use the newer
- // __atomic intrinsics added for use in C++11 <atomic>.  Where that
- // isn't available, we use GCC's older __sync functions instead.
+ #endif  // jit_AtomicOperations_h
diff --git a/SOURCES/build-nss-version.patch b/SOURCES/build-nss-version.patch
index 58e62c9..94947f2 100644
--- a/SOURCES/build-nss-version.patch
+++ b/SOURCES/build-nss-version.patch
@@ -5,7 +5,7 @@ diff -up firefox-60.1.0/old-configure.in.nss-version firefox-60.1.0/old-configur
      _USE_SYSTEM_NSS=1 )
  
  if test -n "$_USE_SYSTEM_NSS"; then
--    AM_PATH_NSS(3.36.6, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
+-    AM_PATH_NSS(3.36.7, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
 +    AM_PATH_NSS(3.36.0, [MOZ_SYSTEM_NSS=1], [AC_MSG_ERROR([you don't have NSS installed or your version is too old])])
  fi
  
diff --git a/SOURCES/distribution.ini b/SOURCES/distribution.ini
index 0a0429e..8bf461e 100644
--- a/SOURCES/distribution.ini
+++ b/SOURCES/distribution.ini
@@ -1,7 +1,7 @@
 [Global]
 id=redhat
 version=1.0
-about=Mozilla Firefox for CentOS Linux
+about=Mozilla Firefox for Red Hat Enterprise Linux
 
 [Preferences]
 app.distributor=redhat
diff --git a/SOURCES/firefox-centos-default-prefs.js b/SOURCES/firefox-centos-default-prefs.js
deleted file mode 100644
index f0e4a19..0000000
--- a/SOURCES/firefox-centos-default-prefs.js
+++ /dev/null
@@ -1,33 +0,0 @@
-pref("app.update.auto",                     false);
-pref("app.update.enabled",                  false);
-pref("app.update.autoInstallEnabled",       false);
-pref("general.smoothScroll",                true);
-pref("intl.locale.matchOS",                 true);
-pref("toolkit.storage.synchronous",         0);
-pref("toolkit.networkmanager.disable",      false);
-pref("offline.autoDetect",                  true);
-pref("browser.backspace_action",            2);
-pref("browser.display.use_system_colors",   true);
-pref("browser.download.folderList",         1);
-pref("browser.link.open_external",          3);
-pref("browser.shell.checkDefaultBrowser",   false);
-pref("network.manage-offline-status",       true);
-pref("extensions.shownSelectionUI",         true);
-pref("ui.SpellCheckerUnderlineStyle",       1);
-pref("startup.homepage_override_url",       "http://www.centos.org");
-pref("startup.homepage_welcome_url",        "http://www.centos.org");
-pref("browser.startup.homepage",            "data:text/plain,browser.startup.homepage=file:///usr/share/doc/HTML/index.html");
-pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
-pref("media.gmp-gmpopenh264.provider.enabled",false);
-pref("media.gmp-gmpopenh264.autoupdate",false);
-pref("media.gmp-gmpopenh264.enabled",false);
-pref("media.gmp-gmpopenh264.enabled",false);
-pref("plugins.notifyMissingFlash", false);
-/* See https://bugzilla.redhat.com/show_bug.cgi?id=1226489 */
-pref("browser.display.use_system_colors", false);
-pref("layers.use-image-offscreen-surfaces", false);
-/* Allow sending credetials to all https:// sites */
-pref("network.negotiate-auth.trusted-uris", "https://");
-pref("security.use_sqldb", false);
-/* Use OS settings for UI language */
-pref("intl.locale.requested", "");
diff --git a/SOURCES/firefox-disable-dbus-remote.patch b/SOURCES/firefox-disable-dbus-remote.patch
deleted file mode 100644
index 33b21cb..0000000
--- a/SOURCES/firefox-disable-dbus-remote.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-diff -up firefox-60.1.0/toolkit/components/remote/moz.build.disable-dbus-remote firefox-60.1.0/toolkit/components/remote/moz.build
---- firefox-60.1.0/toolkit/components/remote/moz.build.disable-dbus-remote	2018-06-21 09:29:35.975729500 +0200
-+++ firefox-60.1.0/toolkit/components/remote/moz.build	2018-06-21 09:29:53.863631963 +0200
-@@ -22,11 +22,6 @@ if 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']
-         'nsGTKRemoteService.cpp',
-         'nsRemoteService.cpp',
-     ]
--    if CONFIG['MOZ_ENABLE_DBUS']:
--        SOURCES += [
--            'nsDBusRemoteService.cpp',
--        ]
--        CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
- 
- FINAL_LIBRARY = 'xul'
- 
-diff -up firefox-60.1.0/toolkit/components/remote/nsRemoteService.cpp.disable-dbus-remote firefox-60.1.0/toolkit/components/remote/nsRemoteService.cpp
---- firefox-60.1.0/toolkit/components/remote/nsRemoteService.cpp.disable-dbus-remote	2018-06-19 22:35:27.000000000 +0200
-+++ firefox-60.1.0/toolkit/components/remote/nsRemoteService.cpp	2018-06-21 09:30:24.949462465 +0200
-@@ -6,7 +6,7 @@
-  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- 
- #include "nsGTKRemoteService.h"
--#ifdef MOZ_ENABLE_DBUS
-+#if 0 // Disable DBus remote
- #include "nsDBusRemoteService.h"
- #endif
- #include "nsRemoteService.h"
-@@ -34,7 +34,7 @@ NS_IMPL_ISUPPORTS(nsRemoteService,
- NS_IMETHODIMP
- nsRemoteService::Startup(const char* aAppName, const char* aProfileName)
- {
--#if defined(MOZ_ENABLE_DBUS)
-+#if 0 // Disable DBus remote
-     nsresult rv;
-     mDBusRemoteService = new nsDBusRemoteService();
-     rv = mDBusRemoteService->Startup(aAppName, aProfileName);
diff --git a/SOURCES/firefox-pipewire.patch b/SOURCES/firefox-pipewire.patch
new file mode 100644
index 0000000..57bf8b4
--- /dev/null
+++ b/SOURCES/firefox-pipewire.patch
@@ -0,0 +1,2572 @@
+diff -up firefox-60.3.0/config/system-headers.mozbuild.pipewire firefox-60.3.0/config/system-headers.mozbuild
+--- firefox-60.3.0/config/system-headers.mozbuild.pipewire	2018-10-17 22:39:27.000000000 +0200
++++ firefox-60.3.0/config/system-headers.mozbuild	2019-01-07 14:53:17.200061752 +0100
+@@ -314,6 +314,7 @@ system_headers = [
+     'Gestalt.h',
+     'getopt.h',
+     'gio/gio.h',
++    'gio/gunixfdlist.h',
+     'glibconfig.h',
+     'glib.h',
+     'glib-object.h',
+@@ -607,6 +608,7 @@ system_headers = [
+     'Pgenerr.h',
+     'PGenErr.h',
+     'Ph.h',
++    'pipewire/pipewire.h',
+     'pixman.h',
+     'pk11func.h',
+     'pk11pqg.h',
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_linux.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_linux.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_linux.cc.pipewire	2019-01-07 14:53:17.200061752 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_linux.cc	2019-01-07 14:53:17.200061752 +0100
+@@ -0,0 +1,39 @@
++/*
++ *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++
++#if defined(USE_X11)
++#include "webrtc/modules/desktop_capture/app_capturer_x11.h"
++#endif // defined(USE_X11)
++
++namespace webrtc {
++
++// static
++AppCapturer* AppCapturer::Create(const DesktopCaptureOptions& options) {
++#if defined(USE_X11)
++    return AppCapturerX11::Create(options);
++#endif // defined(USE_X11)
++
++  return nullptr;
++}
++
++// static
++std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawAppCapturer(
++    const DesktopCaptureOptions& options) {
++#if defined(USE_X11)
++  return AppCapturerX11::CreateRawAppCapturer(options);
++#endif // defined(USE_X11)
++
++  return nullptr;
++}
++
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.cc	2019-01-07 14:53:17.201061764 +0100
+@@ -7,9 +7,6 @@
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+-#include "webrtc/modules/desktop_capture/app_capturer.h"
+-#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
+-#include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
+ 
+ #include <assert.h>
+ #include <string.h>
+@@ -21,80 +18,19 @@
+ 
+ #include <algorithm>
+ 
++#include "webrtc/modules/desktop_capture/app_capturer_x11.h"
++
+ #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
+ #include "webrtc/modules/desktop_capture/desktop_frame.h"
+ #include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
++#include "webrtc/modules/desktop_capture/x11/shared_x_util.h"
+ #include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
+ #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
+ #include "webrtc/system_wrappers/include/logging.h"
+ 
+ namespace webrtc {
+ 
+-namespace {
+-
+-class ScreenCapturerProxy : DesktopCapturer::Callback {
+-public:
+-  ScreenCapturerProxy()
+-    : screen_capturer_(DesktopCapturer::CreateScreenCapturer(DesktopCaptureOptions::CreateDefault())) {
+-    screen_capturer_->SelectSource(kFullDesktopScreenId);
+-    screen_capturer_->Start(this);
+-  }
+-  void CaptureFrame() { screen_capturer_->CaptureFrame(); }
+-  std::unique_ptr<DesktopFrame> GetFrame() { return std::move(frame_); }
+-
+-   // Callback interface
+-  virtual void OnCaptureResult(DesktopCapturer::Result result,
+-                               std::unique_ptr<DesktopFrame> frame) {
+-    frame_ = std::move(frame);
+-  }
+-
+-protected:
+-  std::unique_ptr<DesktopCapturer> screen_capturer_;
+-  std::unique_ptr<DesktopFrame> frame_;
+-};
+-
+-class AppCapturerLinux : public AppCapturer {
+-public:
+-  AppCapturerLinux(const DesktopCaptureOptions& options);
+-  virtual ~AppCapturerLinux();
+-
+-  // AppCapturer interface.
+-  virtual bool GetAppList(AppList* apps) override;
+-  virtual bool SelectApp(ProcessId processId) override;
+-  virtual bool BringAppToFront() override;
+-
+-  // DesktopCapturer interface.
+-  virtual void Start(Callback* callback) override;
+-  virtual void Stop() override;
+-  virtual void CaptureFrame() override;
+-  virtual bool SelectSource(SourceId id) override
+-  {
+-    return SelectApp(static_cast<ProcessId>(id));
+-  }
+-
+-protected:
+-  Display* GetDisplay() { return x_display_->display(); }
+-  bool UpdateRegions();
+-
+-  void FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame,Region rgn, uint32_t color);
+-private:
+-  Callback* callback_;
+-  ProcessId selected_process_;
+-
+-  // Sample Mode
+-  ScreenCapturerProxy screen_capturer_proxy_;
+-  // Mask of foreground (non-app windows in front of selected)
+-  Region rgn_mask_;
+-  // Region of selected windows
+-  Region rgn_visual_;
+-  // Mask of background (desktop, non-app windows behind selected)
+-  Region rgn_background_;
+-
+-  rtc::scoped_refptr<SharedXDisplay> x_display_;
+-  RTC_DISALLOW_COPY_AND_ASSIGN(AppCapturerLinux);
+-};
+-
+-AppCapturerLinux::AppCapturerLinux(const DesktopCaptureOptions& options)
++AppCapturerX11::AppCapturerX11(const DesktopCaptureOptions& options)
+     : callback_(NULL),
+       selected_process_(0),
+       x_display_(options.x_display()) {
+@@ -103,7 +39,7 @@ AppCapturerLinux::AppCapturerLinux(const
+   rgn_background_ = XCreateRegion();
+ }
+ 
+-AppCapturerLinux::~AppCapturerLinux() {
++AppCapturerX11::~AppCapturerX11() {
+   if (rgn_mask_) {
+     XDestroyRegion(rgn_mask_);
+   }
+@@ -116,32 +52,32 @@ AppCapturerLinux::~AppCapturerLinux() {
+ }
+ 
+ // AppCapturer interface.
+-bool AppCapturerLinux::GetAppList(AppList* apps) {
++bool AppCapturerX11::GetAppList(AppList* apps) {
+   // Implemented in DesktopDeviceInfo
+   return true;
+ }
+-bool AppCapturerLinux::SelectApp(ProcessId processId) {
++bool AppCapturerX11::SelectApp(ProcessId processId) {
+   selected_process_ = processId;
+   return true;
+ }
+-bool AppCapturerLinux::BringAppToFront() {
++bool AppCapturerX11::BringAppToFront() {
+   // Not implemented yet: See Bug 1036653
+   return true;
+ }
+ 
+ // DesktopCapturer interface.
+-void AppCapturerLinux::Start(Callback* callback) {
++void AppCapturerX11::Start(Callback* callback) {
+   assert(!callback_);
+   assert(callback);
+ 
+   callback_ = callback;
+ }
+ 
+-void AppCapturerLinux::Stop() {
++void AppCapturerX11::Stop() {
+   callback_ = NULL;
+ }
+ 
+-void AppCapturerLinux::CaptureFrame() {
++void AppCapturerX11::CaptureFrame() {
+   XErrorTrap error_trap(GetDisplay());
+ 
+   //Capture screen >> set root window as capture window
+@@ -169,7 +105,7 @@ void AppCapturerLinux::CaptureFrame() {
+   }
+ }
+ 
+-void AppCapturerLinux::FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame, Region rgn, uint32_t color) {
++void AppCapturerX11::FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame, Region rgn, uint32_t color) {
+   XErrorTrap error_trap(GetDisplay());
+ 
+   if (!pDesktopFrame) {
+@@ -192,7 +128,7 @@ void AppCapturerLinux::FillDesktopFrameR
+   }
+ }
+ 
+-bool AppCapturerLinux::UpdateRegions() {
++bool AppCapturerX11::UpdateRegions() {
+   XErrorTrap error_trap(GetDisplay());
+ 
+   XSubtractRegion(rgn_visual_, rgn_visual_, rgn_visual_);
+@@ -269,21 +205,19 @@ bool AppCapturerLinux::UpdateRegions() {
+   return true;
+ }
+ 
+-}  // namespace
+-
+ // static
+-AppCapturer* AppCapturer::Create(const DesktopCaptureOptions& options) {
+-  return new AppCapturerLinux(options);
++AppCapturer* AppCapturerX11::Create(const DesktopCaptureOptions& options) {
++  return new AppCapturerX11(options);
+ }
+ 
+ // static
+-std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawAppCapturer(
++std::unique_ptr<DesktopCapturer> AppCapturerX11::CreateRawAppCapturer(
+     const DesktopCaptureOptions& options) {
+ 
+   if (!options.x_display())
+     return nullptr;
+ 
+-  std::unique_ptr<AppCapturerLinux> capturer(new AppCapturerLinux(options));
++  std::unique_ptr<AppCapturerX11> capturer(new AppCapturerX11(options));
+ 
+   return std::unique_ptr<DesktopCapturer>(std::move(capturer));
+ }
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.h.pipewire	2019-01-07 14:53:17.201061764 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_x11.h	2019-01-07 14:53:17.201061764 +0100
+@@ -0,0 +1,98 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_APP_CAPTURER_X11_H_
++#define MODULES_DESKTOP_CAPTURE_APP_CAPTURER_X11_H_
++
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <memory>
++#include <string>
++
++#include "webrtc/modules/desktop_capture/app_capturer.h"
++#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++#include "webrtc/modules/desktop_capture/desktop_geometry.h"
++#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
++#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
++#include "webrtc/base/constructormagic.h"
++#include "webrtc/base/scoped_ref_ptr.h"
++
++namespace webrtc {
++
++class ScreenCapturerProxy : DesktopCapturer::Callback {
++public:
++  ScreenCapturerProxy()
++    : screen_capturer_(DesktopCapturer::CreateScreenCapturer(DesktopCaptureOptions::CreateDefault())) {
++    screen_capturer_->SelectSource(kFullDesktopScreenId);
++    screen_capturer_->Start(this);
++  }
++  void CaptureFrame() { screen_capturer_->CaptureFrame(); }
++  std::unique_ptr<DesktopFrame> GetFrame() { return std::move(frame_); }
++
++   // Callback interface
++  virtual void OnCaptureResult(DesktopCapturer::Result result,
++                               std::unique_ptr<DesktopFrame> frame) {
++    frame_ = std::move(frame);
++  }
++
++protected:
++  std::unique_ptr<DesktopCapturer> screen_capturer_;
++  std::unique_ptr<DesktopFrame> frame_;
++};
++
++class AppCapturerX11 : public AppCapturer {
++public:
++  AppCapturerX11(const DesktopCaptureOptions& options);
++  virtual ~AppCapturerX11();
++
++  static AppCapturer* Create(const DesktopCaptureOptions& options);
++  static std::unique_ptr<DesktopCapturer> CreateRawAppCapturer(const DesktopCaptureOptions& options);
++
++  // AppCapturer interface.
++  virtual bool GetAppList(AppList* apps) override;
++  virtual bool SelectApp(ProcessId processId) override;
++  virtual bool BringAppToFront() override;
++
++  // DesktopCapturer interface.
++  virtual void Start(Callback* callback) override;
++  virtual void Stop() override;
++  virtual void CaptureFrame() override;
++  virtual bool SelectSource(SourceId id) override
++  {
++    return SelectApp(static_cast<ProcessId>(id));
++  }
++
++protected:
++  Display* GetDisplay() { return x_display_->display(); }
++  bool UpdateRegions();
++
++  void FillDesktopFrameRegionWithColor(DesktopFrame* pDesktopFrame,Region rgn, uint32_t color);
++private:
++  Callback* callback_;
++  ProcessId selected_process_;
++
++  // Sample Mode
++  ScreenCapturerProxy screen_capturer_proxy_;
++  // Mask of foreground (non-app windows in front of selected)
++  Region rgn_mask_;
++  // Region of selected windows
++  Region rgn_visual_;
++  // Mask of background (desktop, non-app windows behind selected)
++  Region rgn_background_;
++
++  rtc::scoped_refptr<SharedXDisplay> x_display_;
++  RTC_DISALLOW_COPY_AND_ASSIGN(AppCapturerX11);
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_APP_CAPTURER_X11_H_
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.cc.pipewire	2019-01-07 14:53:17.201061764 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.cc	2019-01-07 14:53:17.201061764 +0100
+@@ -0,0 +1,849 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include <cstring>
++#include <gio/gunixfdlist.h>
++#include <glib-object.h>
++
++#include <spa/param/format-utils.h>
++#include <spa/param/props.h>
++#include <spa/param/video/raw-utils.h>
++#include <spa/support/type-map.h>
++
++#include "webrtc/modules/desktop_capture/base_capturer_pipewire.h"
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++#include "webrtc/base/checks.h"
++#include "webrtc/base/logging.h"
++
++namespace webrtc {
++
++const char kDesktopBusName[] = "org.freedesktop.portal.Desktop";
++const char kDesktopObjectPath[] = "/org/freedesktop/portal/desktop";
++const char kDesktopRequestObjectPath[] =
++    "/org/freedesktop/portal/desktop/request";
++const char kSessionInterfaceName[] = "org.freedesktop.portal.Session";
++const char kRequestInterfaceName[] = "org.freedesktop.portal.Request";
++const char kScreenCastInterfaceName[] = "org.freedesktop.portal.ScreenCast";
++
++const int kBytesPerPixelPw = 4;
++
++// static
++void BaseCapturerPipeWire::OnStateChanged(void* data,
++                                            pw_remote_state old_state,
++                                            pw_remote_state state,
++                                            const char* error_message) {
++  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
++  RTC_DCHECK(that);
++
++  switch (state) {
++    case PW_REMOTE_STATE_ERROR:
++      LOG(LS_ERROR) << "PipeWire remote state error: " << error_message;
++      break;
++    case PW_REMOTE_STATE_CONNECTED:
++      LOG(LS_INFO) << "PipeWire remote state: connected.";
++      that->CreateReceivingStream();
++      break;
++    case PW_REMOTE_STATE_CONNECTING:
++      LOG(LS_INFO) << "PipeWire remote state: connecting.";
++      break;
++    case PW_REMOTE_STATE_UNCONNECTED:
++      LOG(LS_INFO) << "PipeWire remote state: unconnected.";
++      break;
++  }
++}
++
++// static
++void BaseCapturerPipeWire::OnStreamStateChanged(void* data,
++                                                  pw_stream_state old_state,
++                                                  pw_stream_state state,
++                                                  const char* error_message) {
++  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
++  RTC_DCHECK(that);
++
++  switch (state) {
++    case PW_STREAM_STATE_ERROR:
++      LOG(LS_ERROR) << "PipeWire stream state error: " << error_message;
++      break;
++    case PW_STREAM_STATE_CONFIGURE:
++      pw_stream_set_active(that->pw_stream_, true);
++      break;
++    case PW_STREAM_STATE_UNCONNECTED:
++    case PW_STREAM_STATE_CONNECTING:
++    case PW_STREAM_STATE_READY:
++    case PW_STREAM_STATE_PAUSED:
++    case PW_STREAM_STATE_STREAMING:
++      break;
++  }
++}
++
++// static
++void BaseCapturerPipeWire::OnStreamFormatChanged(
++    void* data,
++    const struct spa_pod* format) {
++  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
++  RTC_DCHECK(that);
++
++  LOG(LS_INFO) << "PipeWire stream format changed.";
++
++  if (!format) {
++    pw_stream_finish_format(that->pw_stream_, /*res=*/0, /*params=*/nullptr,
++                            /*n_params=*/0);
++    return;
++  }
++
++  that->spa_video_format_ = new spa_video_info_raw();
++  spa_format_video_raw_parse(format, that->spa_video_format_,
++                             &that->pw_type_->format_video);
++
++  auto width = that->spa_video_format_->size.width;
++  auto height = that->spa_video_format_->size.height;
++  auto stride = SPA_ROUND_UP_N(width * kBytesPerPixelPw, 4);
++  auto size = height * stride;
++
++  uint8_t buffer[1024] = {};
++  auto builder = spa_pod_builder{buffer, sizeof(buffer)};
++
++  // Setup buffers and meta header for new format.
++  const struct spa_pod* params[2];
++  params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
++      &builder,
++      // id to enumerate buffer requirements
++      that->pw_core_type_->param.idBuffers,
++      that->pw_core_type_->param_buffers.Buffers,
++      // Size: specified as integer (i) and set to specified size
++      ":", that->pw_core_type_->param_buffers.size, "i", size,
++      // Stride: specified as integer (i) and set to specified stride
++      ":", that->pw_core_type_->param_buffers.stride, "i", stride,
++      // Buffers: specifies how many buffers we want to deal with, set as
++      // integer (i) where preferred number is 8, then allowed number is defined
++      // as range (r) from min and max values and it is undecided (u) to allow
++      // negotiation
++      ":", that->pw_core_type_->param_buffers.buffers, "iru", 8,
++      SPA_POD_PROP_MIN_MAX(1, 32),
++      // Align: memory alignment of the buffer, set as integer (i) to specified
++      // value
++      ":", that->pw_core_type_->param_buffers.align, "i", 16));
++  params[1] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
++      &builder,
++      // id to enumerate supported metadata
++      that->pw_core_type_->param.idMeta, that->pw_core_type_->param_meta.Meta,
++      // Type: specified as id or enum (I)
++      ":", that->pw_core_type_->param_meta.type, "I",
++      that->pw_core_type_->meta.Header,
++      // Size: size of the metadata, specified as integer (i)
++      ":", that->pw_core_type_->param_meta.size, "i",
++      sizeof(struct spa_meta_header)));
++
++  pw_stream_finish_format(that->pw_stream_, /*res=*/0, params, /*n_params=*/2);
++}
++
++// static
++void BaseCapturerPipeWire::OnStreamProcess(void* data) {
++  BaseCapturerPipeWire* that = static_cast<BaseCapturerPipeWire*>(data);
++  RTC_DCHECK(that);
++
++  pw_buffer* buf = nullptr;
++
++  if (!(buf = pw_stream_dequeue_buffer(that->pw_stream_))) {
++    return;
++  }
++
++  that->HandleBuffer(buf);
++
++  pw_stream_queue_buffer(that->pw_stream_, buf);
++}
++
++BaseCapturerPipeWire::BaseCapturerPipeWire(CaptureSourceType source_type)
++    : capture_source_type_(source_type) {}
++
++BaseCapturerPipeWire::~BaseCapturerPipeWire() {
++  if (pw_main_loop_) {
++    pw_thread_loop_stop(pw_main_loop_);
++  }
++
++  if (pw_type_) {
++    delete pw_type_;
++  }
++
++  if (spa_video_format_) {
++    delete spa_video_format_;
++  }
++
++  if (pw_stream_) {
++    pw_stream_destroy(pw_stream_);
++  }
++
++  if (pw_remote_) {
++    pw_remote_destroy(pw_remote_);
++  }
++
++  if (pw_core_) {
++    pw_core_destroy(pw_core_);
++  }
++
++  if (pw_main_loop_) {
++    pw_thread_loop_destroy(pw_main_loop_);
++  }
++
++  if (pw_loop_) {
++    pw_loop_destroy(pw_loop_);
++  }
++
++  if (current_frame_) {
++    free(current_frame_);
++  }
++
++  if (start_request_signal_id_) {
++    g_dbus_connection_signal_unsubscribe(connection_, start_request_signal_id_);
++  }
++  if (sources_request_signal_id_) {
++    g_dbus_connection_signal_unsubscribe(connection_,
++                                         sources_request_signal_id_);
++  }
++  if (session_request_signal_id_) {
++    g_dbus_connection_signal_unsubscribe(connection_,
++                                         session_request_signal_id_);
++  }
++
++  if (session_handle_) {
++    GDBusMessage* message = g_dbus_message_new_method_call(
++        kDesktopBusName, session_handle_, kSessionInterfaceName, "Close");
++    if (message) {
++      GError* error = nullptr;
++      g_dbus_connection_send_message(connection_, message,
++                                     G_DBUS_SEND_MESSAGE_FLAGS_NONE,
++                                     /*out_serial=*/nullptr, &error);
++      if (error) {
++        LOG(LS_ERROR) << "Failed to close the session: " << error->message;
++        g_error_free(error);
++      }
++      g_object_unref(message);
++    }
++  }
++
++  g_free(start_handle_);
++  g_free(sources_handle_);
++  g_free(session_handle_);
++  g_free(portal_handle_);
++
++  if (proxy_) {
++    g_clear_object(&proxy_);
++  }
++}
++
++void BaseCapturerPipeWire::InitPortals() {
++  g_dbus_proxy_new_for_bus(
++      G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, /*info=*/nullptr,
++      kDesktopBusName, kDesktopObjectPath, kScreenCastInterfaceName,
++      /*cancellable=*/nullptr,
++      reinterpret_cast<GAsyncReadyCallback>(OnProxyRequested), this);
++}
++
++void BaseCapturerPipeWire::InitPipeWire() {
++  pw_init(/*argc=*/nullptr, /*argc=*/nullptr);
++
++  pw_loop_ = pw_loop_new(/*properties=*/nullptr);
++  pw_main_loop_ = pw_thread_loop_new(pw_loop_, "pipewire-main-loop");
++
++  pw_core_ = pw_core_new(pw_loop_, /*properties=*/nullptr);
++  pw_core_type_ = pw_core_get_type(pw_core_);
++  pw_remote_ = pw_remote_new(pw_core_, nullptr, /*user_data_size=*/0);
++
++  InitPipeWireTypes();
++
++  // Initialize event handlers, remote end and stream-related.
++  pw_remote_events_.version = PW_VERSION_REMOTE_EVENTS;
++  pw_remote_events_.state_changed = &OnStateChanged;
++
++  pw_stream_events_.version = PW_VERSION_STREAM_EVENTS;
++  pw_stream_events_.state_changed = &OnStreamStateChanged;
++  pw_stream_events_.format_changed = &OnStreamFormatChanged;
++  pw_stream_events_.process = &OnStreamProcess;
++
++  pw_remote_add_listener(pw_remote_, &spa_remote_listener_, &pw_remote_events_,
++                         this);
++  pw_remote_connect_fd(pw_remote_, pw_fd_);
++
++  if (pw_thread_loop_start(pw_main_loop_) < 0) {
++    LOG(LS_ERROR) << "Failed to start main PipeWire loop";
++    portal_init_failed_ = true;
++  }
++}
++
++void BaseCapturerPipeWire::InitPipeWireTypes() {
++  spa_type_map* map = pw_core_type_->map;
++  pw_type_ = new PipeWireType();
++
++  spa_type_media_type_map(map, &pw_type_->media_type);
++  spa_type_media_subtype_map(map, &pw_type_->media_subtype);
++  spa_type_format_video_map(map, &pw_type_->format_video);
++  spa_type_video_format_map(map, &pw_type_->video_format);
++}
++
++void BaseCapturerPipeWire::CreateReceivingStream() {
++  spa_rectangle pwMinScreenBounds = spa_rectangle{1, 1};
++  spa_rectangle pwScreenBounds =
++      spa_rectangle{static_cast<uint32_t>(desktop_size_.width()),
++                    static_cast<uint32_t>(desktop_size_.height())};
++
++  spa_fraction pwFrameRateMin = spa_fraction{0, 1};
++  spa_fraction pwFrameRateMax = spa_fraction{60, 1};
++
++  pw_properties* reuseProps = pw_properties_new("pipewire.client.reuse", "1",
++                                                /*end of varargs*/ nullptr);
++  pw_stream_ = pw_stream_new(pw_remote_, "webrtc-consume-stream", reuseProps);
++
++  uint8_t buffer[1024] = {};
++  const spa_pod* params[1];
++  spa_pod_builder builder = spa_pod_builder{buffer, sizeof(buffer)};
++  params[0] = reinterpret_cast<spa_pod*>(spa_pod_builder_object(
++      &builder,
++      // id to enumerate formats
++      pw_core_type_->param.idEnumFormat, pw_core_type_->spa_format, "I",
++      pw_type_->media_type.video, "I", pw_type_->media_subtype.raw,
++      // Video format: specified as id or enum (I), preferred format is BGRx,
++      // then allowed formats are enumerated (e) and the format is undecided (u)
++      // to allow negotiation
++      ":", pw_type_->format_video.format, "Ieu", pw_type_->video_format.BGRx,
++      SPA_POD_PROP_ENUM(2, pw_type_->video_format.RGBx,
++                        pw_type_->video_format.BGRx),
++      // Video size: specified as rectangle (R), preferred size is specified as
++      // first parameter, then allowed size is defined as range (r) from min and
++      // max values and the format is undecided (u) to allow negotiation
++      ":", pw_type_->format_video.size, "Rru", &pwScreenBounds, 2,
++      &pwMinScreenBounds, &pwScreenBounds,
++      // Frame rate: specified as fraction (F) and set to minimum frame rate
++      // value
++      ":", pw_type_->format_video.framerate, "F", &pwFrameRateMin,
++      // Max frame rate: specified as fraction (F), preferred frame rate is set
++      // to maximum value, then allowed frame rate is defined as range (r) from
++      // min and max values and it is undecided (u) to allow negotiation
++      ":", pw_type_->format_video.max_framerate, "Fru", &pwFrameRateMax, 2,
++      &pwFrameRateMin, &pwFrameRateMax));
++
++  pw_stream_add_listener(pw_stream_, &spa_stream_listener_, &pw_stream_events_,
++                         this);
++  pw_stream_flags flags = static_cast<pw_stream_flags>(
++      PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE |
++      PW_STREAM_FLAG_MAP_BUFFERS);
++  if (pw_stream_connect(pw_stream_, PW_DIRECTION_INPUT, /*port_path=*/nullptr,
++                        flags, params,
++                        /*n_params=*/1) != 0) {
++    LOG(LS_ERROR) << "Could not connect receiving stream.";
++    portal_init_failed_ = true;
++    return;
++  }
++}
++
++void BaseCapturerPipeWire::HandleBuffer(pw_buffer* buffer) {
++  spa_buffer* spaBuffer = buffer->buffer;
++  void* src = nullptr;
++
++  if (!(src = spaBuffer->datas[0].data)) {
++    return;
++  }
++
++  uint32_t maxSize = spaBuffer->datas[0].maxsize;
++  int32_t srcStride = spaBuffer->datas[0].chunk->stride;
++  if (srcStride != (desktop_size_.width() * kBytesPerPixelPw)) {
++    LOG(LS_ERROR) << "Got buffer with stride different from screen stride: "
++                      << srcStride
++                      << " != " << (desktop_size_.width() * kBytesPerPixelPw);
++    portal_init_failed_ = true;
++    return;
++  }
++
++  if (!current_frame_) {
++    current_frame_ = static_cast<uint8_t*>(malloc(maxSize));
++  }
++  RTC_DCHECK(current_frame_ != nullptr);
++
++  // If both sides decided to go with the RGBx format we need to convert it to
++  // BGRx to match color format expected by WebRTC.
++  if (spa_video_format_->format == pw_type_->video_format.RGBx) {
++    uint8_t* tempFrame = static_cast<uint8_t*>(malloc(maxSize));
++    std::memcpy(tempFrame, src, maxSize);
++    ConvertRGBxToBGRx(tempFrame, maxSize);
++    std::memcpy(current_frame_, tempFrame, maxSize);
++    free(tempFrame);
++  } else {
++    std::memcpy(current_frame_, src, maxSize);
++  }
++}
++
++void BaseCapturerPipeWire::ConvertRGBxToBGRx(uint8_t* frame, uint32_t size) {
++  // Change color format for KDE KWin which uses RGBx and not BGRx
++  for (uint32_t i = 0; i < size; i += 4) {
++    uint8_t tempR = frame[i];
++    uint8_t tempB = frame[i + 2];
++    frame[i] = tempB;
++    frame[i + 2] = tempR;
++  }
++}
++
++guint BaseCapturerPipeWire::SetupRequestResponseSignal(
++    const gchar* object_path,
++    GDBusSignalCallback callback) {
++  return g_dbus_connection_signal_subscribe(
++      connection_, kDesktopBusName, kRequestInterfaceName, "Response",
++      object_path, /*arg0=*/nullptr, G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
++      callback, this, /*user_data_free_func=*/nullptr);
++}
++
++// static
++void BaseCapturerPipeWire::OnProxyRequested(GObject* /*object*/,
++                                              GAsyncResult* result,
++                                              gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  GError* error = nullptr;
++  that->proxy_ = g_dbus_proxy_new_finish(result, &error);
++  if (!that->proxy_) {
++    LOG(LS_ERROR) << "Failed to create a proxy for the screen cast portal: "
++                      << error->message;
++    g_error_free(error);
++    that->portal_init_failed_ = true;
++    return;
++  }
++  that->connection_ = g_dbus_proxy_get_connection(that->proxy_);
++
++  LOG(LS_INFO) << "Created proxy for the screen cast portal.";
++  that->SessionRequest();
++}
++
++// static
++gchar* BaseCapturerPipeWire::PrepareSignalHandle(GDBusConnection* connection,
++                                                   const gchar* token) {
++  gchar* sender = g_strdup(g_dbus_connection_get_unique_name(connection) + 1);
++  for (int i = 0; sender[i]; i++) {
++    if (sender[i] == '.') {
++      sender[i] = '_';
++    }
++  }
++
++  gchar* handle = g_strconcat(kDesktopRequestObjectPath, "/", sender, "/",
++                              token, /*end of varargs*/ nullptr);
++  g_free(sender);
++
++  return handle;
++}
++
++void BaseCapturerPipeWire::SessionRequest() {
++  GVariantBuilder builder;
++  gchar* variant_string;
++
++  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
++  variant_string =
++      g_strdup_printf("webrtc_session%d", g_random_int_range(0, G_MAXINT));
++  g_variant_builder_add(&builder, "{sv}", "session_handle_token",
++                        g_variant_new_string(variant_string));
++  g_free(variant_string);
++  variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
++  g_variant_builder_add(&builder, "{sv}", "handle_token",
++                        g_variant_new_string(variant_string));
++
++  portal_handle_ = PrepareSignalHandle(connection_, variant_string);
++  session_request_signal_id_ = SetupRequestResponseSignal(
++      portal_handle_, OnSessionRequestResponseSignal);
++  g_free(variant_string);
++
++  LOG(LS_INFO) << "Screen cast session requested.";
++  g_dbus_proxy_call(
++      proxy_, "CreateSession", g_variant_new("(a{sv})", &builder),
++      G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, /*cancellable=*/nullptr,
++      reinterpret_cast<GAsyncReadyCallback>(OnSessionRequested), this);
++}
++
++// static
++void BaseCapturerPipeWire::OnSessionRequested(GDBusConnection* connection,
++                                                GAsyncResult* result,
++                                                gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  GError* error = nullptr;
++  GVariant* variant = g_dbus_proxy_call_finish(that->proxy_, result, &error);
++  if (!variant) {
++    LOG(LS_ERROR) << "Failed to create a screen cast session: "
++                      << error->message;
++    g_error_free(error);
++    that->portal_init_failed_ = true;
++    return;
++  }
++  LOG(LS_INFO) << "Initializing the screen cast session.";
++
++  gchar* handle = nullptr;
++  g_variant_get_child(variant, 0, "o", &handle);
++  g_variant_unref(variant);
++  if (!handle) {
++    LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
++    if (that->session_request_signal_id_) {
++      g_dbus_connection_signal_unsubscribe(connection,
++                                           that->session_request_signal_id_);
++      that->session_request_signal_id_ = 0;
++    }
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  g_free(handle);
++
++  LOG(LS_INFO) << "Subscribing to the screen cast session.";
++}
++
++// static
++void BaseCapturerPipeWire::OnSessionRequestResponseSignal(
++    GDBusConnection* connection,
++    const gchar* sender_name,
++    const gchar* object_path,
++    const gchar* interface_name,
++    const gchar* signal_name,
++    GVariant* parameters,
++    gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++
++  LOG(LS_INFO)
++      << "Received response for the screen cast session subscription.";
++
++  guint32 portal_response;
++  GVariant* response_data;
++  g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data);
++  g_variant_lookup(response_data, "session_handle", "s",
++                   &that->session_handle_);
++  g_variant_unref(response_data);
++
++  if (!that->session_handle_ || portal_response) {
++    LOG(LS_ERROR)
++        << "Failed to request the screen cast session subscription.";
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  that->SourcesRequest();
++}
++
++void BaseCapturerPipeWire::SourcesRequest() {
++  GVariantBuilder builder;
++  gchar* variant_string;
++
++  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
++  // We want to record monitor content.
++  g_variant_builder_add(&builder, "{sv}", "types",
++                        g_variant_new_uint32(capture_source_type_));
++  // We don't want to allow selection of multiple sources.
++  g_variant_builder_add(&builder, "{sv}", "multiple",
++                        g_variant_new_boolean(false));
++  variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
++  g_variant_builder_add(&builder, "{sv}", "handle_token",
++                        g_variant_new_string(variant_string));
++
++  sources_handle_ = PrepareSignalHandle(connection_, variant_string);
++  sources_request_signal_id_ = SetupRequestResponseSignal(
++      sources_handle_, OnSourcesRequestResponseSignal);
++  g_free(variant_string);
++
++  LOG(LS_INFO) << "Requesting sources from the screen cast session.";
++  g_dbus_proxy_call(
++      proxy_, "SelectSources",
++      g_variant_new("(oa{sv})", session_handle_, &builder),
++      G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, /*cancellable=*/nullptr,
++      reinterpret_cast<GAsyncReadyCallback>(OnSourcesRequested), this);
++}
++
++// static
++void BaseCapturerPipeWire::OnSourcesRequested(GDBusConnection* connection,
++                                                GAsyncResult* result,
++                                                gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  GError* error = nullptr;
++  GVariant* variant = g_dbus_proxy_call_finish(that->proxy_, result, &error);
++  if (!variant) {
++    LOG(LS_ERROR) << "Failed to request the sources: " << error->message;
++    g_error_free(error);
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  LOG(LS_INFO) << "Sources requested from the screen cast session.";
++
++  gchar* handle = nullptr;
++  g_variant_get_child(variant, 0, "o", &handle);
++  g_variant_unref(variant);
++  if (!handle) {
++    LOG(LS_ERROR) << "Failed to initialize the screen cast session.";
++    if (that->sources_request_signal_id_) {
++      g_dbus_connection_signal_unsubscribe(connection,
++                                           that->sources_request_signal_id_);
++      that->sources_request_signal_id_ = 0;
++    }
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  g_free(handle);
++
++  LOG(LS_INFO) << "Subscribed to sources signal.";
++}
++
++// static
++void BaseCapturerPipeWire::OnSourcesRequestResponseSignal(
++    GDBusConnection* connection,
++    const gchar* sender_name,
++    const gchar* object_path,
++    const gchar* interface_name,
++    const gchar* signal_name,
++    GVariant* parameters,
++    gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  guint32 portal_response;
++  g_variant_get(parameters, "(u@a{sv})", &portal_response, nullptr);
++  if (portal_response) {
++    LOG(LS_ERROR)
++        << "Failed to select sources for the screen cast session.";
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  LOG(LS_INFO) << "Received sources signal from session.";
++  that->StartRequest();
++}
++
++void BaseCapturerPipeWire::StartRequest() {
++  GVariantBuilder builder;
++  gchar* variant_string;
++
++  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
++  variant_string = g_strdup_printf("webrtc%d", g_random_int_range(0, G_MAXINT));
++  g_variant_builder_add(&builder, "{sv}", "handle_token",
++                        g_variant_new_string(variant_string));
++
++  start_handle_ = PrepareSignalHandle(connection_, variant_string);
++  start_request_signal_id_ =
++      SetupRequestResponseSignal(start_handle_, OnStartRequestResponseSignal);
++  g_free(variant_string);
++
++  // "Identifier for the application window", this is Wayland, so not "x11:...".
++  const gchar parent_window[] = "";
++
++  LOG(LS_INFO) << "Starting the screen cast session.";
++  g_dbus_proxy_call(
++      proxy_, "Start",
++      g_variant_new("(osa{sv})", session_handle_, parent_window, &builder),
++      G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, /*cancellable=*/nullptr,
++      reinterpret_cast<GAsyncReadyCallback>(OnStartRequested), this);
++}
++
++// static
++void BaseCapturerPipeWire::OnStartRequested(GDBusConnection* connection,
++                                              GAsyncResult* result,
++                                              gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  GError* error = nullptr;
++  GVariant* variant = g_dbus_proxy_call_finish(that->proxy_, result, &error);
++  if (!variant) {
++    LOG(LS_ERROR) << "Failed to start the screen cast session: "
++                      << error->message;
++    g_error_free(error);
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  LOG(LS_INFO) << "Initializing the start of the screen cast session.";
++
++  gchar* handle = nullptr;
++  g_variant_get_child(variant, 0, "o", &handle);
++  g_variant_unref(variant);
++  if (!handle) {
++    LOG(LS_ERROR)
++        << "Failed to initialize the start of the screen cast session.";
++    if (that->start_request_signal_id_) {
++      g_dbus_connection_signal_unsubscribe(connection,
++                                           that->start_request_signal_id_);
++      that->start_request_signal_id_ = 0;
++    }
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  g_free(handle);
++
++  LOG(LS_INFO) << "Subscribed to the start signal.";
++}
++
++// static
++void BaseCapturerPipeWire::OnStartRequestResponseSignal(
++    GDBusConnection* connection,
++    const gchar* sender_name,
++    const gchar* object_path,
++    const gchar* interface_name,
++    const gchar* signal_name,
++    GVariant* parameters,
++    gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  LOG(LS_INFO) << "Start signal received.";
++  guint32 portal_response;
++  GVariant* response_data;
++  GVariantIter* iter = nullptr;
++  g_variant_get(parameters, "(u@a{sv})", &portal_response, &response_data);
++  if (portal_response || !response_data) {
++    LOG(LS_ERROR) << "Failed to start the screen cast session.";
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  // Array of PipeWire streams. See
++  // https://github.com/flatpak/xdg-desktop-portal/blob/master/data/org.freedesktop.portal.ScreenCast.xml
++  // documentation for <method name="Start">.
++  if (g_variant_lookup(response_data, "streams", "a(ua{sv})", &iter)) {
++    GVariant* variant;
++
++    while (g_variant_iter_next(iter, "@(ua{sv})", &variant)) {
++      guint32 stream_id;
++      gint32 width;
++      gint32 height;
++      GVariant* options;
++
++      g_variant_get(variant, "(u@a{sv})", &stream_id, &options);
++      RTC_DCHECK(options != nullptr);
++
++      g_variant_lookup(options, "size", "(ii)", &width, &height);
++
++      that->desktop_size_.set(width, height);
++
++      g_variant_unref(options);
++      g_variant_unref(variant);
++    }
++  }
++  g_variant_iter_free(iter);
++  g_variant_unref(response_data);
++
++  that->OpenPipeWireRemote();
++}
++
++void BaseCapturerPipeWire::OpenPipeWireRemote() {
++  GVariantBuilder builder;
++  g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
++
++  LOG(LS_INFO) << "Opening the PipeWire remote.";
++
++  g_dbus_proxy_call_with_unix_fd_list(
++      proxy_, "OpenPipeWireRemote",
++      g_variant_new("(oa{sv})", session_handle_, &builder),
++      G_DBUS_CALL_FLAGS_NONE, /*timeout=*/-1, /*fd_list=*/nullptr,
++      /*cancellable=*/nullptr,
++      reinterpret_cast<GAsyncReadyCallback>(OnOpenPipeWireRemoteRequested),
++      this);
++}
++
++// static
++void BaseCapturerPipeWire::OnOpenPipeWireRemoteRequested(
++    GDBusConnection* connection,
++    GAsyncResult* result,
++    gpointer user_data) {
++  BaseCapturerPipeWire* that =
++      static_cast<BaseCapturerPipeWire*>(user_data);
++  RTC_DCHECK(that);
++
++  GError* error = nullptr;
++  GUnixFDList* outlist = nullptr;
++  GVariant* variant = g_dbus_proxy_call_with_unix_fd_list_finish(
++      that->proxy_, &outlist, result, &error);
++  if (!variant) {
++    LOG(LS_ERROR) << "Failed to open the PipeWire remote: "
++                      << error->message;
++    g_error_free(error);
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  gint32 index;
++  g_variant_get(variant, "(h)", &index);
++
++  if ((that->pw_fd_ = g_unix_fd_list_get(outlist, index, &error)) == -1) {
++    LOG(LS_ERROR) << "Failed to get file descriptor from the list: "
++                      << error->message;
++    g_error_free(error);
++    g_variant_unref(variant);
++    that->portal_init_failed_ = true;
++    return;
++  }
++
++  g_variant_unref(variant);
++  g_object_unref(outlist);
++
++  that->InitPipeWire();
++  LOG(LS_INFO) << "PipeWire remote opened.";
++}
++
++void BaseCapturerPipeWire::Start(Callback* callback) {
++  RTC_DCHECK(!callback_);
++  RTC_DCHECK(callback);
++
++  InitPortals();
++
++  callback_ = callback;
++}
++
++void BaseCapturerPipeWire::CaptureFrame() {
++  if (portal_init_failed_) {
++    callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
++    return;
++  }
++
++  if (!current_frame_) {
++    callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
++    return;
++  }
++
++  std::unique_ptr<DesktopFrame> result(new BasicDesktopFrame(desktop_size_));
++  result->CopyPixelsFrom(
++      current_frame_, (desktop_size_.width() * kBytesPerPixelPw),
++      DesktopRect::MakeWH(desktop_size_.width(), desktop_size_.height()));
++  if (!result) {
++    callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
++    return;
++  }
++  callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
++}
++
++bool BaseCapturerPipeWire::GetSourceList(SourceList* sources) {
++  RTC_DCHECK(sources->size() == 0);
++  // List of available screens is already presented by the xdg-desktop-portal.
++  // But we have to add an empty source as the code expects it.
++  sources->push_back({0});
++  return true;
++}
++
++bool BaseCapturerPipeWire::SelectSource(SourceId id) {
++  // Screen selection is handled by the xdg-desktop-portal.
++  return true;
++}
++
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.h.pipewire	2019-01-07 14:53:17.201061764 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.h	2019-01-07 14:53:17.201061764 +0100
+@@ -0,0 +1,167 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_BASE_CAPTURER_PIPEWIRE_H_
++#define MODULES_DESKTOP_CAPTURE_BASE_CAPTURER_PIPEWIRE_H_
++
++#include <gio/gio.h>
++#define typeof __typeof__
++#include <pipewire/pipewire.h>
++#include <spa/param/video/format-utils.h>
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++
++namespace webrtc {
++
++class PipeWireType {
++ public:
++  spa_type_media_type media_type;
++  spa_type_media_subtype media_subtype;
++  spa_type_format_video format_video;
++  spa_type_video_format video_format;
++};
++
++class BaseCapturerPipeWire : public DesktopCapturer {
++ public:
++  enum CaptureSourceType { Screen = 1, Window };
++
++  explicit BaseCapturerPipeWire(CaptureSourceType source_type);
++  ~BaseCapturerPipeWire() override;
++
++  // DesktopCapturer interface.
++  void Start(Callback* delegate) override;
++  void Stop() override { callback_ = nullptr; }
++  void CaptureFrame() override;
++  bool GetSourceList(SourceList* sources) override;
++  bool SelectSource(SourceId id) override;
++
++ private:
++  // PipeWire types -->
++  pw_core* pw_core_ = nullptr;
++  pw_type* pw_core_type_ = nullptr;
++  pw_stream* pw_stream_ = nullptr;
++  pw_remote* pw_remote_ = nullptr;
++  pw_loop* pw_loop_ = nullptr;
++  pw_thread_loop* pw_main_loop_ = nullptr;
++  PipeWireType* pw_type_ = nullptr;
++
++  spa_hook spa_stream_listener_ = {};
++  spa_hook spa_remote_listener_ = {};
++
++  pw_stream_events pw_stream_events_ = {};
++  pw_remote_events pw_remote_events_ = {};
++
++  spa_video_info_raw* spa_video_format_ = nullptr;
++
++  gint32 pw_fd_ = -1;
++
++  CaptureSourceType capture_source_type_ =
++      BaseCapturerPipeWire::CaptureSourceType::Screen;
++
++  // <-- end of PipeWire types
++
++  GDBusConnection* connection_ = nullptr;
++  GDBusProxy* proxy_ = nullptr;
++  gchar* portal_handle_ = nullptr;
++  gchar* session_handle_ = nullptr;
++  gchar* sources_handle_ = nullptr;
++  gchar* start_handle_ = nullptr;
++  guint session_request_signal_id_ = 0;
++  guint sources_request_signal_id_ = 0;
++  guint start_request_signal_id_ = 0;
++
++  DesktopSize desktop_size_ = {};
++  DesktopCaptureOptions options_ = {};
++
++  uint8_t* current_frame_ = nullptr;
++  Callback* callback_ = nullptr;
++
++  bool portal_init_failed_ = false;
++
++  void InitPortals();
++  void InitPipeWire();
++  void InitPipeWireTypes();
++
++  void CreateReceivingStream();
++  void HandleBuffer(pw_buffer* buffer);
++
++  void ConvertRGBxToBGRx(uint8_t* frame, uint32_t size);
++
++  static void OnStateChanged(void* data,
++                             pw_remote_state old_state,
++                             pw_remote_state state,
++                             const char* error);
++  static void OnStreamStateChanged(void* data,
++                                   pw_stream_state old_state,
++                                   pw_stream_state state,
++                                   const char* error_message);
++
++  static void OnStreamFormatChanged(void* data, const struct spa_pod* format);
++  static void OnStreamProcess(void* data);
++  static void OnNewBuffer(void* data, uint32_t id);
++
++  guint SetupRequestResponseSignal(const gchar* object_path,
++                                   GDBusSignalCallback callback);
++
++  static void OnProxyRequested(GObject* object,
++                               GAsyncResult* result,
++                               gpointer user_data);
++
++  static gchar* PrepareSignalHandle(GDBusConnection* connection,
++                                    const gchar* token);
++
++  void SessionRequest();
++  static void OnSessionRequested(GDBusConnection* connection,
++                                 GAsyncResult* result,
++                                 gpointer user_data);
++  static void OnSessionRequestResponseSignal(GDBusConnection* connection,
++                                             const gchar* sender_name,
++                                             const gchar* object_path,
++                                             const gchar* interface_name,
++                                             const gchar* signal_name,
++                                             GVariant* parameters,
++                                             gpointer user_data);
++
++  void SourcesRequest();
++  static void OnSourcesRequested(GDBusConnection* connection,
++                                 GAsyncResult* result,
++                                 gpointer user_data);
++  static void OnSourcesRequestResponseSignal(GDBusConnection* connection,
++                                             const gchar* sender_name,
++                                             const gchar* object_path,
++                                             const gchar* interface_name,
++                                             const gchar* signal_name,
++                                             GVariant* parameters,
++                                             gpointer user_data);
++
++  void StartRequest();
++  static void OnStartRequested(GDBusConnection* connection,
++                               GAsyncResult* result,
++                               gpointer user_data);
++  static void OnStartRequestResponseSignal(GDBusConnection* connection,
++                                           const gchar* sender_name,
++                                           const gchar* object_path,
++                                           const gchar* interface_name,
++                                           const gchar* signal_name,
++                                           GVariant* parameters,
++                                           gpointer user_data);
++
++  void OpenPipeWireRemote();
++  static void OnOpenPipeWireRemoteRequested(GDBusConnection* connection,
++                                            GAsyncResult* result,
++                                            gpointer user_data);
++
++  RTC_DISALLOW_COPY_AND_ASSIGN(BaseCapturerPipeWire);
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_BASE_CAPTURER_PIPEWIRE_H_
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_gn/moz.build.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_gn/moz.build
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_gn/moz.build.pipewire	2019-01-07 14:53:17.201061764 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_gn/moz.build	2019-01-07 14:56:57.674544724 +0100
+@@ -144,14 +144,26 @@ if CONFIG["OS_TARGET"] == "FreeBSD":
+         "/media/webrtc/trunk/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc"
+     ]
+ 
++# Common Linux stuff between X11 and PipeWire
+ if CONFIG["OS_TARGET"] == "Linux":
+ 
+     DEFINES["USE_NSS_CERTS"] = "1"
+-    DEFINES["USE_X11"] = "1"
+     DEFINES["WEBRTC_LINUX"] = True
+     DEFINES["WEBRTC_POSIX"] = True
+     DEFINES["_FILE_OFFSET_BITS"] = "64"
+ 
++    UNIFIED_SOURCES += [
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/app_capturer_linux.cc",
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc",
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_linux.cc",
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_linux.cc",
++    ]
++
++# X11 specific files
++if CONFIG["OS_TARGET"] == "Linux":
++
++    DEFINES["USE_X11"] = "1"
++
+     OS_LIBS += [
+         "rt",
+         "X11",
+@@ -178,6 +190,28 @@ if CONFIG["OS_TARGET"] == "Linux":
+         "/media/webrtc/trunk/webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.cc"
+     ]
+ 
++# PipeWire specific files
++if CONFIG["OS_TARGET"] == "Linux":
++
++    DEFINES["WEBRTC_USE_PIPEWIRE"] = "1"
++
++    OS_LIBS += [
++        "rt",
++        "pipewire-0.2",
++        "glib-2.0",
++        "gio-2.0",
++        "gobject-2.0"
++    ]
++
++    CXXFLAGS += CONFIG['TK_CFLAGS']
++
++    UNIFIED_SOURCES += [
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/base_capturer_pipewire.cc",
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.cc",
++        "/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.cc"
++    ]
++
++
+ if CONFIG["OS_TARGET"] == "NetBSD":
+ 
+     DEFINES["USE_X11"] = "1"
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_options.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_options.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_options.h.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capture_options.h	2019-01-07 14:53:17.202061775 +0100
+@@ -107,6 +107,11 @@ class DesktopCaptureOptions {
+   }
+ #endif
+ 
++#if defined(WEBRTC_USE_PIPEWIRE)
++  bool allow_pipewire() const { return allow_pipewire_; }
++  void set_allow_pipewire(bool allow) { allow_pipewire_ = allow; }
++#endif
++
+  private:
+ #if defined(USE_X11)
+   rtc::scoped_refptr<SharedXDisplay> x_display_;
+@@ -129,6 +134,9 @@ class DesktopCaptureOptions {
+ #endif
+   bool disable_effects_ = true;
+   bool detect_updated_region_ = false;
++#if defined(WEBRTC_USE_PIPEWIRE)
++  bool allow_pipewire_ = true;
++#endif
+ };
+ 
+ }  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.cc	2019-01-07 14:53:17.202061775 +0100
+@@ -66,4 +66,17 @@ std::unique_ptr<DesktopCapturer> Desktop
+   return capturer;
+ }
+ 
++#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
++bool DesktopCapturer::IsRunningUnderWayland() {
++  const char* xdg_session_type = getenv("XDG_SESSION_TYPE");
++  if (!xdg_session_type || strncmp(xdg_session_type, "wayland", 7) != 0)
++    return false;
++
++  if (!(getenv("WAYLAND_DISPLAY")))
++    return false;
++
++  return true;
++}
++#endif
++
+ }  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/desktop_capturer.h	2019-01-07 14:53:17.202061775 +0100
+@@ -129,6 +129,10 @@ class DesktopCapturer {
+   static std::unique_ptr<DesktopCapturer> CreateAppCapturer(
+       const DesktopCaptureOptions& options);
+ 
++#if defined(WEBRTC_USE_PIPEWIRE) || defined(USE_X11)
++  static bool IsRunningUnderWayland();
++#endif
++
+  protected:
+   // CroppingWindowCapturer needs to create raw capturers without wrappers, so
+   // the following two functions are protected.
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc.pipewire	2019-01-07 14:53:17.202061775 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_linux.cc	2019-01-07 14:53:17.202061775 +0100
+@@ -0,0 +1,40 @@
++/*
++ *  Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
++
++#if defined(USE_X11)
++#include "webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.h"
++#endif // defined(USE_X11)
++
++namespace webrtc {
++
++// static
++MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
++    const DesktopCaptureOptions& options, WindowId window) {
++#if defined(USE_X11)
++  return MouseCursorMonitorX11::CreateForWindow(options, window);
++#else
++  return nullptr;
++#endif // defined(USE_X11)
++}
++
++// static
++MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
++    const DesktopCaptureOptions& options,
++    ScreenId screen) {
++#if defined(USE_X11)
++  return MouseCursorMonitorX11::CreateForScreen(options, screen);
++#else
++  return nullptr;
++#endif // defined(USE_X11)
++}
++
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.cc	2019-01-07 14:53:17.202061775 +0100
+@@ -16,6 +16,8 @@
+ #include <X11/Xlib.h>
+ #include <X11/Xutil.h>
+ 
++#include "webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.h"
++
+ #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
+ #include "webrtc/modules/desktop_capture/desktop_frame.h"
+ #include "webrtc/modules/desktop_capture/mouse_cursor.h"
+@@ -59,38 +61,6 @@ Window GetTopLevelWindow(Display* displa
+ 
+ namespace webrtc {
+ 
+-class MouseCursorMonitorX11 : public MouseCursorMonitor,
+-                              public SharedXDisplay::XEventHandler {
+- public:
+-  MouseCursorMonitorX11(const DesktopCaptureOptions& options, Window window, Window inner_window);
+-  ~MouseCursorMonitorX11() override;
+-
+-  void Start(Callback* callback, Mode mode) override;
+-  void Stop() override;
+-  void Capture() override;
+-
+- private:
+-  // SharedXDisplay::XEventHandler interface.
+-  bool HandleXEvent(const XEvent& event) override;
+-
+-  Display* display() { return x_display_->display(); }
+-
+-  // Captures current cursor shape and stores it in |cursor_shape_|.
+-  void CaptureCursor();
+-
+-  rtc::scoped_refptr<SharedXDisplay> x_display_;
+-  Callback* callback_;
+-  Mode mode_;
+-  Window window_;
+-  Window inner_window_;
+-
+-  bool have_xfixes_;
+-  int xfixes_event_base_;
+-  int xfixes_error_base_;
+-
+-  std::unique_ptr<MouseCursor> cursor_shape_;
+-};
+-
+ MouseCursorMonitorX11::MouseCursorMonitorX11(
+     const DesktopCaptureOptions& options,
+     Window window, Window inner_window)
+@@ -244,7 +214,7 @@ void MouseCursorMonitorX11::CaptureCurso
+ }
+ 
+ // static
+-MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
++MouseCursorMonitor* MouseCursorMonitorX11::CreateForWindow(
+     const DesktopCaptureOptions& options, WindowId window) {
+   if (!options.x_display())
+     return NULL;
+@@ -254,7 +224,7 @@ MouseCursorMonitor* MouseCursorMonitor::
+   return new MouseCursorMonitorX11(options, outer_window, window);
+ }
+ 
+-MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
++MouseCursorMonitor* MouseCursorMonitorX11::CreateForScreen(
+     const DesktopCaptureOptions& options,
+     ScreenId screen) {
+   if (!options.x_display())
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.h.pipewire	2019-01-07 14:53:17.202061775 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/mouse_cursor_monitor_x11.h	2019-01-07 14:53:17.202061775 +0100
+@@ -0,0 +1,63 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_MOUSE_CURSOR_MONITOR_X11_H_
++#define MODULES_DESKTOP_CAPTURE_MOUSE_CURSOR_MONITOR_X11_H_
++
++#include <X11/X.h>
++#include <memory>
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capture_types.h"
++#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
++#include "webrtc/modules/desktop_capture/mouse_cursor.h"
++#include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
++#include "webrtc/base/scoped_ref_ptr.h"
++
++namespace webrtc {
++
++class MouseCursorMonitorX11 : public MouseCursorMonitor,
++                              public SharedXDisplay::XEventHandler {
++ public:
++  MouseCursorMonitorX11(const DesktopCaptureOptions& options, Window window, Window inner_window);
++  ~MouseCursorMonitorX11() override;
++
++  void Start(Callback* callback, Mode mode) override;
++  void Stop() override;
++  void Capture() override;
++
++  static MouseCursorMonitor* CreateForWindow(const DesktopCaptureOptions& options, WindowId window);
++  static MouseCursorMonitor* CreateForScreen(const DesktopCaptureOptions& options, ScreenId screen);
++
++ private:
++  // SharedXDisplay::XEventHandler interface.
++  bool HandleXEvent(const XEvent& event) override;
++
++  Display* display() { return x_display_->display(); }
++
++  // Captures current cursor shape and stores it in |cursor_shape_|.
++  void CaptureCursor();
++
++  rtc::scoped_refptr<SharedXDisplay> x_display_;
++  Callback* callback_;
++  Mode mode_;
++  Window window_;
++  Window inner_window_;
++
++  bool have_xfixes_;
++  int xfixes_event_base_;
++  int xfixes_error_base_;
++
++  std::unique_ptr<MouseCursor> cursor_shape_;
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_MOUSE_CURSOR_MONITOR_X11_H_
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_linux.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_linux.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_linux.cc.pipewire	2019-01-07 14:53:17.203061786 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_linux.cc	2019-01-07 14:53:17.203061786 +0100
+@@ -0,0 +1,40 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++
++#if defined(WEBRTC_USE_PIPEWIRE)
++#include "webrtc/modules/desktop_capture/screen_capturer_pipewire.h"
++#endif  // defined(WEBRTC_USE_PIPEWIRE)
++
++#if defined(USE_X11)
++#include "webrtc/modules/desktop_capture/screen_capturer_x11.h"
++#endif  // defined(USE_X11)
++
++namespace webrtc {
++
++// static
++std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
++    const DesktopCaptureOptions& options) {
++#if defined(WEBRTC_USE_PIPEWIRE)
++  if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
++    return ScreenCapturerPipeWire::CreateRawScreenCapturer(options);
++  }
++#endif  // defined(WEBRTC_USE_PIPEWIRE)
++
++#if defined(USE_X11)
++  return ScreenCapturerX11::CreateRawScreenCapturer(options);
++#endif  // defined(USE_X11)
++
++  return nullptr;
++}
++
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.cc.pipewire	2019-01-07 14:53:17.203061786 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.cc	2019-01-07 14:53:17.203061786 +0100
+@@ -0,0 +1,31 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include "webrtc/modules/desktop_capture/screen_capturer_pipewire.h"
++
++#include <memory>
++
++namespace webrtc {
++
++ScreenCapturerPipeWire::ScreenCapturerPipeWire()
++    : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Screen) {}
++ScreenCapturerPipeWire::~ScreenCapturerPipeWire() {}
++
++// static
++std::unique_ptr<DesktopCapturer>
++ScreenCapturerPipeWire::CreateRawScreenCapturer(
++    const DesktopCaptureOptions& options) {
++  std::unique_ptr<ScreenCapturerPipeWire> capturer(
++      new ScreenCapturerPipeWire());
++
++  return std::move(capturer);
++}
++
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.h.pipewire	2019-01-07 14:53:17.203061786 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_pipewire.h	2019-01-07 14:53:17.203061786 +0100
+@@ -0,0 +1,33 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_PIPEWIRE_H_
++#define MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_PIPEWIRE_H_
++
++#include <memory>
++
++#include "webrtc/modules/desktop_capture/base_capturer_pipewire.h"
++
++namespace webrtc {
++
++class ScreenCapturerPipeWire : public BaseCapturerPipeWire {
++ public:
++  ScreenCapturerPipeWire();
++  ~ScreenCapturerPipeWire() override;
++
++  static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(
++      const DesktopCaptureOptions& options);
++
++  RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerPipeWire);
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_PIPEWIRE_H_
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.cc	2019-01-07 14:53:17.203061786 +0100
+@@ -19,6 +19,8 @@
+ #include <X11/Xlib.h>
+ #include <X11/Xutil.h>
+ 
++#include "webrtc/modules/desktop_capture/screen_capturer_x11.h"
++
+ #include "webrtc/base/checks.h"
+ #include "webrtc/base/constructormagic.h"
+ #include "webrtc/base/timeutils.h"
+@@ -32,100 +34,12 @@
+ #include "webrtc/system_wrappers/include/logging.h"
+ 
+ namespace webrtc {
+-namespace {
+-
+-// A class to perform video frame capturing for Linux.
+-//
+-// If XDamage is used, this class sets DesktopFrame::updated_region() according
+-// to the areas reported by XDamage. Otherwise this class does not detect
+-// DesktopFrame::updated_region(), the field is always set to the entire frame
+-// rectangle. ScreenCapturerDifferWrapper should be used if that functionality
+-// is necessary.
+-class ScreenCapturerLinux : public DesktopCapturer,
+-                            public SharedXDisplay::XEventHandler {
+- public:
+-  ScreenCapturerLinux();
+-  ~ScreenCapturerLinux() override;
+-
+-  // TODO(ajwong): Do we really want this to be synchronous?
+-  bool Init(const DesktopCaptureOptions& options);
+-
+-  // DesktopCapturer interface.
+-  void Start(Callback* delegate) override;
+-  void Stop() override;
+-  void CaptureFrame() override;
+-  bool GetSourceList(SourceList* sources) override;
+-  bool SelectSource(SourceId id) override;
+-
+- private:
+-  Display* display() { return options_.x_display()->display(); }
+-
+-  // SharedXDisplay::XEventHandler interface.
+-  bool HandleXEvent(const XEvent& event) override;
+-
+-  void InitXDamage();
+-
+-  // Capture screen pixels to the current buffer in the queue. In the DAMAGE
+-  // case, the ScreenCapturerHelper already holds the list of invalid rectangles
+-  // from HandleXEvent(). In the non-DAMAGE case, this captures the
+-  // whole screen, then calculates some invalid rectangles that include any
+-  // differences between this and the previous capture.
+-  std::unique_ptr<DesktopFrame> CaptureScreen();
+-
+-  // Called when the screen configuration is changed.
+-  void ScreenConfigurationChanged();
+-
+-  // Synchronize the current buffer with |last_buffer_|, by copying pixels from
+-  // the area of |last_invalid_rects|.
+-  // Note this only works on the assumption that kNumBuffers == 2, as
+-  // |last_invalid_rects| holds the differences from the previous buffer and
+-  // the one prior to that (which will then be the current buffer).
+-  void SynchronizeFrame();
+-
+-  void DeinitXlib();
+-
+-  DesktopCaptureOptions options_;
+-
+-  Callback* callback_ = nullptr;
+-
+-  // X11 graphics context.
+-  GC gc_ = nullptr;
+-  Window root_window_ = BadValue;
+-
+-  // XFixes.
+-  bool has_xfixes_ = false;
+-  int xfixes_event_base_ = -1;
+-  int xfixes_error_base_ = -1;
+-
+-  // XDamage information.
+-  bool use_damage_ = false;
+-  Damage damage_handle_ = 0;
+-  int damage_event_base_ = -1;
+-  int damage_error_base_ = -1;
+-  XserverRegion damage_region_ = 0;
+-
+-  // Access to the X Server's pixel buffer.
+-  XServerPixelBuffer x_server_pixel_buffer_;
+-
+-  // A thread-safe list of invalid rectangles, and the size of the most
+-  // recently captured screen.
+-  ScreenCapturerHelper helper_;
+-
+-  // Queue of the frames buffers.
+-  ScreenCaptureFrameQueue<SharedDesktopFrame> queue_;
+-
+-  // Invalid region from the previous capture. This is used to synchronize the
+-  // current with the last buffer used.
+-  DesktopRegion last_invalid_region_;
+ 
+-  RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
+-};
+-
+-ScreenCapturerLinux::ScreenCapturerLinux() {
++ScreenCapturerX11::ScreenCapturerX11() {
+   helper_.SetLogGridSize(4);
+ }
+ 
+-ScreenCapturerLinux::~ScreenCapturerLinux() {
++ScreenCapturerX11::~ScreenCapturerX11() {
+   options_.x_display()->RemoveEventHandler(ConfigureNotify, this);
+   if (use_damage_) {
+     options_.x_display()->RemoveEventHandler(
+@@ -134,7 +48,7 @@ ScreenCapturerLinux::~ScreenCapturerLinu
+   DeinitXlib();
+ }
+ 
+-bool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) {
++bool ScreenCapturerX11::Init(const DesktopCaptureOptions& options) {
+   options_ = options;
+ 
+   root_window_ = RootWindow(display(), DefaultScreen(display()));
+@@ -177,7 +91,7 @@ bool ScreenCapturerLinux::Init(const Des
+   return true;
+ }
+ 
+-void ScreenCapturerLinux::InitXDamage() {
++void ScreenCapturerX11::InitXDamage() {
+   // Our use of XDamage requires XFixes.
+   if (!has_xfixes_) {
+     return;
+@@ -218,18 +132,18 @@ void ScreenCapturerLinux::InitXDamage()
+   LOG(LS_INFO) << "Using XDamage extension.";
+ }
+ 
+-void ScreenCapturerLinux::Start(Callback* callback) {
++void ScreenCapturerX11::Start(Callback* callback) {
+   RTC_DCHECK(!callback_);
+   RTC_DCHECK(callback);
+ 
+   callback_ = callback;
+ }
+ 
+-void ScreenCapturerLinux::Stop() {
++void ScreenCapturerX11::Stop() {
+   callback_ = NULL;
+ }
+ 
+-void ScreenCapturerLinux::CaptureFrame() {
++void ScreenCapturerX11::CaptureFrame() {
+   int64_t capture_start_time_nanos = rtc::TimeNanos();
+ 
+   queue_.MoveToNextFrame();
+@@ -243,6 +157,7 @@ void ScreenCapturerLinux::CaptureFrame()
+   // in a good shape.
+   if (!x_server_pixel_buffer_.is_initialized()) {
+      // We failed to initialize pixel buffer.
++     LOG(LS_ERROR) << "Pixel buffer is not initialized.";
+      callback_->OnCaptureResult(Result::ERROR_PERMANENT, nullptr);
+      return;
+   }
+@@ -258,6 +173,7 @@ void ScreenCapturerLinux::CaptureFrame()
+ 
+   std::unique_ptr<DesktopFrame> result = CaptureScreen();
+   if (!result) {
++    LOG(LS_WARNING) << "Temporarily failed to capture screen.";
+     callback_->OnCaptureResult(Result::ERROR_TEMPORARY, nullptr);
+     return;
+   }
+@@ -268,19 +184,19 @@ void ScreenCapturerLinux::CaptureFrame()
+   callback_->OnCaptureResult(Result::SUCCESS, std::move(result));
+ }
+ 
+-bool ScreenCapturerLinux::GetSourceList(SourceList* sources) {
++bool ScreenCapturerX11::GetSourceList(SourceList* sources) {
+   RTC_DCHECK(sources->size() == 0);
+   // TODO(jiayl): implement screen enumeration.
+   sources->push_back({0});
+   return true;
+ }
+ 
+-bool ScreenCapturerLinux::SelectSource(SourceId id) {
++bool ScreenCapturerX11::SelectSource(SourceId id) {
+   // TODO(jiayl): implement screen selection.
+   return true;
+ }
+ 
+-bool ScreenCapturerLinux::HandleXEvent(const XEvent& event) {
++bool ScreenCapturerX11::HandleXEvent(const XEvent& event) {
+   if (use_damage_ && (event.type == damage_event_base_ + XDamageNotify)) {
+     const XDamageNotifyEvent* damage_event =
+         reinterpret_cast<const XDamageNotifyEvent*>(&event);
+@@ -295,7 +211,7 @@ bool ScreenCapturerLinux::HandleXEvent(c
+   return false;
+ }
+ 
+-std::unique_ptr<DesktopFrame> ScreenCapturerLinux::CaptureScreen() {
++std::unique_ptr<DesktopFrame> ScreenCapturerX11::CaptureScreen() {
+   std::unique_ptr<SharedDesktopFrame> frame = queue_.current_frame()->Share();
+   RTC_DCHECK(x_server_pixel_buffer_.window_size().equals(frame->size()));
+ 
+@@ -345,14 +261,15 @@ std::unique_ptr<DesktopFrame> ScreenCapt
+     // Doing full-screen polling, or this is the first capture after a
+     // screen-resolution change.  In either case, need a full-screen capture.
+     DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
+-    x_server_pixel_buffer_.CaptureRect(screen_rect, frame.get());
++    if (!x_server_pixel_buffer_.CaptureRect(screen_rect, frame.get()))
++      return nullptr;
+     updated_region->SetRect(screen_rect);
+   }
+ 
+   return std::move(frame);
+ }
+ 
+-void ScreenCapturerLinux::ScreenConfigurationChanged() {
++void ScreenCapturerX11::ScreenConfigurationChanged() {
+   // Make sure the frame buffers will be reallocated.
+   queue_.Reset();
+ 
+@@ -363,7 +280,7 @@ void ScreenCapturerLinux::ScreenConfigur
+   }
+ }
+ 
+-void ScreenCapturerLinux::SynchronizeFrame() {
++void ScreenCapturerX11::SynchronizeFrame() {
+   // Synchronize the current buffer with the previous one since we do not
+   // capture the entire desktop. Note that encoder may be reading from the
+   // previous buffer at this time so thread access complaints are false
+@@ -383,7 +300,7 @@ void ScreenCapturerLinux::SynchronizeFra
+   }
+ }
+ 
+-void ScreenCapturerLinux::DeinitXlib() {
++void ScreenCapturerX11::DeinitXlib() {
+   if (gc_) {
+     XFreeGC(display(), gc_);
+     gc_ = nullptr;
+@@ -404,20 +321,18 @@ void ScreenCapturerLinux::DeinitXlib() {
+   }
+ }
+ 
+-}  // namespace
+-
+ // static
+-std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawScreenCapturer(
++std::unique_ptr<DesktopCapturer> ScreenCapturerX11::CreateRawScreenCapturer(
+     const DesktopCaptureOptions& options) {
+   if (!options.x_display())
+     return nullptr;
+ 
+-  std::unique_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
++  std::unique_ptr<ScreenCapturerX11> capturer(new ScreenCapturerX11());
+   if (!capturer.get()->Init(options)) {
+     return nullptr;
+   }
+ 
+-  return std::unique_ptr<DesktopCapturer>(capturer.release());
++  return std::move(capturer);
+ }
+ 
+ }  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.h.pipewire	2019-01-07 14:53:17.203061786 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/screen_capturer_x11.h	2019-01-07 14:53:17.203061786 +0100
+@@ -0,0 +1,124 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_X11_H_
++#define MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_X11_H_
++
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <X11/extensions/Xdamage.h>
++#include <X11/extensions/Xfixes.h>
++#include <memory>
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++#include "webrtc/modules/desktop_capture/desktop_frame.h"
++#include "webrtc/modules/desktop_capture/desktop_region.h"
++#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
++#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
++#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
++#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
++#include "webrtc/modules/desktop_capture/shared_desktop_frame.h"
++#include "webrtc/base/constructormagic.h"
++
++namespace webrtc {
++
++// A class to perform video frame capturing for Linux on X11.
++//
++// If XDamage is used, this class sets DesktopFrame::updated_region() according
++// to the areas reported by XDamage. Otherwise this class does not detect
++// DesktopFrame::updated_region(), the field is always set to the entire frame
++// rectangle. ScreenCapturerDifferWrapper should be used if that functionality
++// is necessary.
++class ScreenCapturerX11 : public DesktopCapturer,
++                          public SharedXDisplay::XEventHandler {
++ public:
++  ScreenCapturerX11();
++  ~ScreenCapturerX11() override;
++
++  static std::unique_ptr<DesktopCapturer> CreateRawScreenCapturer(const DesktopCaptureOptions& options);
++
++  // TODO(ajwong): Do we really want this to be synchronous?
++  bool Init(const DesktopCaptureOptions& options);
++
++  // DesktopCapturer interface.
++  void Start(Callback* delegate) override;
++  void Stop() override;
++  void CaptureFrame() override;
++  bool GetSourceList(SourceList* sources) override;
++  bool SelectSource(SourceId id) override;
++
++ private:
++  Display* display() { return options_.x_display()->display(); }
++
++  // SharedXDisplay::XEventHandler interface.
++  bool HandleXEvent(const XEvent& event) override;
++
++  void InitXDamage();
++
++  // Capture screen pixels to the current buffer in the queue. In the DAMAGE
++  // case, the ScreenCapturerHelper already holds the list of invalid rectangles
++  // from HandleXEvent(). In the non-DAMAGE case, this captures the
++  // whole screen, then calculates some invalid rectangles that include any
++  // differences between this and the previous capture.
++  std::unique_ptr<DesktopFrame> CaptureScreen();
++
++  // Called when the screen configuration is changed.
++  void ScreenConfigurationChanged();
++
++  // Synchronize the current buffer with |last_buffer_|, by copying pixels from
++  // the area of |last_invalid_rects|.
++  // Note this only works on the assumption that kNumBuffers == 2, as
++  // |last_invalid_rects| holds the differences from the previous buffer and
++  // the one prior to that (which will then be the current buffer).
++  void SynchronizeFrame();
++
++  void DeinitXlib();
++
++  DesktopCaptureOptions options_;
++
++  Callback* callback_ = nullptr;
++
++  // X11 graphics context.
++  GC gc_ = nullptr;
++  Window root_window_ = BadValue;
++
++  // XFixes.
++  bool has_xfixes_ = false;
++  int xfixes_event_base_ = -1;
++  int xfixes_error_base_ = -1;
++
++  // XDamage information.
++  bool use_damage_ = false;
++  Damage damage_handle_ = 0;
++  int damage_event_base_ = -1;
++  int damage_error_base_ = -1;
++  XserverRegion damage_region_ = 0;
++
++  // Access to the X Server's pixel buffer.
++  XServerPixelBuffer x_server_pixel_buffer_;
++
++  // A thread-safe list of invalid rectangles, and the size of the most
++  // recently captured screen.
++  ScreenCapturerHelper helper_;
++
++  // Queue of the frames buffers.
++  ScreenCaptureFrameQueue<SharedDesktopFrame> queue_;
++
++  // Invalid region from the previous capture. This is used to synchronize the
++  // current with the last buffer used.
++  DesktopRegion last_invalid_region_;
++
++  RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerX11);
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_SCREEN_CAPTURER_X11_H_
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_linux.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_linux.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_linux.cc.pipewire	2019-01-07 14:53:17.203061786 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_linux.cc	2019-01-07 14:53:17.203061786 +0100
+@@ -0,0 +1,40 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++
++#if defined(WEBRTC_USE_PIPEWIRE)
++#include "webrtc/modules/desktop_capture/window_capturer_pipewire.h"
++#endif  // defined(WEBRTC_USE_PIPEWIRE)
++
++#if defined(USE_X11)
++#include "webrtc/modules/desktop_capture/window_capturer_x11.h"
++#endif  // defined(USE_X11)
++
++namespace webrtc {
++
++// static
++std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
++    const DesktopCaptureOptions& options) {
++#if defined(WEBRTC_USE_PIPEWIRE)
++  if (options.allow_pipewire() && DesktopCapturer::IsRunningUnderWayland()) {
++    return WindowCapturerPipeWire::CreateRawWindowCapturer(options);
++  }
++#endif  // defined(WEBRTC_USE_PIPEWIRE)
++
++#if defined(USE_X11)
++  return WindowCapturerX11::CreateRawWindowCapturer(options);
++#endif  // defined(USE_X11)
++
++  return nullptr;
++}
++
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.cc.pipewire	2019-01-07 14:53:17.204061797 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.cc	2019-01-07 14:53:17.204061797 +0100
+@@ -0,0 +1,28 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#include "webrtc/modules/desktop_capture/window_capturer_pipewire.h"
++
++namespace webrtc {
++
++WindowCapturerPipeWire::WindowCapturerPipeWire()
++    : BaseCapturerPipeWire(BaseCapturerPipeWire::CaptureSourceType::Window) {}
++WindowCapturerPipeWire::~WindowCapturerPipeWire() {}
++
++// static
++std::unique_ptr<DesktopCapturer>
++WindowCapturerPipeWire::CreateRawWindowCapturer(
++    const DesktopCaptureOptions& options) {
++  std::unique_ptr<WindowCapturerPipeWire> capturer(
++      new WindowCapturerPipeWire());
++
++  return std::move(capturer);
++}
++}  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.h.pipewire	2019-01-07 14:53:17.204061797 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_pipewire.h	2019-01-07 14:53:17.204061797 +0100
+@@ -0,0 +1,33 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_PIPEWIRE_H_
++#define MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_PIPEWIRE_H_
++
++#include <memory>
++
++#include "webrtc/modules/desktop_capture/base_capturer_pipewire.h"
++
++namespace webrtc {
++
++class WindowCapturerPipeWire : public BaseCapturerPipeWire {
++ public:
++  WindowCapturerPipeWire();
++  ~WindowCapturerPipeWire() override;
++
++  static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
++      const DesktopCaptureOptions& options);
++
++  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerPipeWire);
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_PIPEWIRE_H_
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc.pipewire	2018-10-17 22:39:32.000000000 +0200
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.cc	2019-01-07 14:53:17.204061797 +0100
+@@ -17,6 +17,8 @@
+ 
+ #include <algorithm>
+ 
++#include "webrtc/modules/desktop_capture/window_capturer_x11.h"
++
+ #include "webrtc/base/constructormagic.h"
+ #include "webrtc/base/scoped_ref_ptr.h"
+ #include "webrtc/modules/desktop_capture/desktop_capturer.h"
+@@ -30,58 +32,7 @@
+ 
+ namespace webrtc {
+ 
+-namespace {
+-
+-class WindowCapturerLinux : public DesktopCapturer,
+-                            public SharedXDisplay::XEventHandler {
+- public:
+-  WindowCapturerLinux(const DesktopCaptureOptions& options);
+-  ~WindowCapturerLinux() override;
+-
+-  // DesktopCapturer interface.
+-  void Start(Callback* callback) override;
+-  void Stop() override;
+-  void CaptureFrame() override;
+-  bool GetSourceList(SourceList* sources) override;
+-  bool SelectSource(SourceId id) override;
+-  bool FocusOnSelectedSource() override;
+-
+-  // SharedXDisplay::XEventHandler interface.
+-  bool HandleXEvent(const XEvent& event) override;
+-
+- private:
+-  Display* display() { return x_display_->display(); }
+-
+-  // Iterates through |window| hierarchy to find first visible window, i.e. one
+-  // that has WM_STATE property set to NormalState.
+-  // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 .
+-  ::Window GetApplicationWindow(::Window window);
+-
+-  // Returns true if the |window| is a desktop element.
+-  bool IsDesktopElement(::Window window);
+-
+-  // Returns window title for the specified X |window|.
+-  bool GetWindowTitle(::Window window, std::string* title);
+-
+-  // Returns the id of the owning process.
+-  int GetWindowProcessID(::Window window);
+-
+-  Callback* callback_ = nullptr;
+-
+-  rtc::scoped_refptr<SharedXDisplay> x_display_;
+-
+-  Atom wm_state_atom_;
+-  Atom window_type_atom_;
+-  Atom normal_window_type_atom_;
+-  bool has_composite_extension_ = false;
+-
+-  ::Window selected_window_ = 0;
+-  XServerPixelBuffer x_server_pixel_buffer_;
+-
+-  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux);
+-};
+-
+-WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options)
++WindowCapturerX11::WindowCapturerX11(const DesktopCaptureOptions& options)
+     : x_display_(options.x_display()) {
+   // Create Atoms so we don't need to do it every time they are used.
+   wm_state_atom_ = XInternAtom(display(), "WM_STATE", True);
+@@ -102,11 +53,11 @@ WindowCapturerLinux::WindowCapturerLinux
+   x_display_->AddEventHandler(ConfigureNotify, this);
+ }
+ 
+-WindowCapturerLinux::~WindowCapturerLinux() {
++WindowCapturerX11::~WindowCapturerX11() {
+   x_display_->RemoveEventHandler(ConfigureNotify, this);
+ }
+ 
+-bool WindowCapturerLinux::GetSourceList(SourceList* sources) {
++bool WindowCapturerX11::GetSourceList(SourceList* sources) {
+   SourceList result;
+ 
+   XErrorTrap error_trap(display());
+@@ -159,7 +110,7 @@ bool WindowCapturerLinux::GetSourceList(
+   return true;
+ }
+ 
+-bool WindowCapturerLinux::SelectSource(SourceId id) {
++bool WindowCapturerX11::SelectSource(SourceId id) {
+   if (!x_server_pixel_buffer_.Init(display(), id))
+     return false;
+ 
+@@ -180,7 +131,7 @@ bool WindowCapturerLinux::SelectSource(S
+   return true;
+ }
+ 
+-bool WindowCapturerLinux::FocusOnSelectedSource() {
++bool WindowCapturerX11::FocusOnSelectedSource() {
+   if (!selected_window_)
+     return false;
+ 
+@@ -229,18 +180,18 @@ bool WindowCapturerLinux::FocusOnSelecte
+   return true;
+ }
+ 
+-void WindowCapturerLinux::Start(Callback* callback) {
++void WindowCapturerX11::Start(Callback* callback) {
+   assert(!callback_);
+   assert(callback);
+ 
+   callback_ = callback;
+ }
+ 
+-void WindowCapturerLinux::Stop() {
++void WindowCapturerX11::Stop() {
+   callback_ = NULL;
+ }
+ 
+-void WindowCapturerLinux::CaptureFrame() {
++void WindowCapturerX11::CaptureFrame() {
+   x_display_->ProcessPendingXEvents();
+ 
+   if (!x_server_pixel_buffer_.IsWindowValid()) {
+@@ -274,7 +225,7 @@ void WindowCapturerLinux::CaptureFrame()
+   callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
+ }
+ 
+-bool WindowCapturerLinux::HandleXEvent(const XEvent& event) {
++bool WindowCapturerX11::HandleXEvent(const XEvent& event) {
+   if (event.type == ConfigureNotify) {
+     XConfigureEvent xce = event.xconfigure;
+     if (!DesktopSize(xce.width, xce.height).equals(
+@@ -288,7 +239,7 @@ bool WindowCapturerLinux::HandleXEvent(c
+   return false;
+ }
+ 
+-::Window WindowCapturerLinux::GetApplicationWindow(::Window window) {
++::Window WindowCapturerX11::GetApplicationWindow(::Window window) {
+   // Get WM_STATE property of the window.
+   XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_);
+ 
+@@ -326,7 +277,7 @@ bool WindowCapturerLinux::HandleXEvent(c
+   return app_window;
+ }
+ 
+-bool WindowCapturerLinux::IsDesktopElement(::Window window) {
++bool WindowCapturerX11::IsDesktopElement(::Window window) {
+   if (window == 0)
+     return false;
+ 
+@@ -361,7 +312,7 @@ bool WindowCapturerLinux::IsDesktopEleme
+   return result;
+ }
+ 
+-bool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) {
++bool WindowCapturerX11::GetWindowTitle(::Window window, std::string* title) {
+   int status;
+   bool result = false;
+   XTextProperty window_name;
+@@ -390,9 +341,7 @@ bool WindowCapturerLinux::GetWindowTitle
+   return result;
+ }
+ 
+-}  // namespace
+-
+-int WindowCapturerLinux::GetWindowProcessID(::Window window) {
++int WindowCapturerX11::GetWindowProcessID(::Window window) {
+   // Get _NET_WM_PID property of the window.
+   Atom process_atom = XInternAtom(display(), "_NET_WM_PID", True);
+   XWindowProperty<uint32_t> process_id(display(), window, process_atom);
+@@ -401,11 +350,11 @@ int WindowCapturerLinux::GetWindowProces
+ }
+ 
+ // static
+-std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
++std::unique_ptr<DesktopCapturer> WindowCapturerX11::CreateRawWindowCapturer(
+     const DesktopCaptureOptions& options) {
+   if (!options.x_display())
+     return nullptr;
+-  return std::unique_ptr<DesktopCapturer>(new WindowCapturerLinux(options));
++  return std::unique_ptr<DesktopCapturer>(new WindowCapturerX11(options));
+ }
+ 
+ }  // namespace webrtc
+diff -up firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.h.pipewire firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.h
+--- firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.h.pipewire	2019-01-07 14:53:17.204061797 +0100
++++ firefox-60.3.0/media/webrtc/trunk/webrtc/modules/desktop_capture/window_capturer_x11.h	2019-01-07 14:53:17.204061797 +0100
+@@ -0,0 +1,83 @@
++/*
++ *  Copyright 2018 The WebRTC project authors. All Rights Reserved.
++ *
++ *  Use of this source code is governed by a BSD-style license
++ *  that can be found in the LICENSE file in the root of the source
++ *  tree. An additional intellectual property rights grant can be found
++ *  in the file PATENTS.  All contributing project authors may
++ *  be found in the AUTHORS file in the root of the source tree.
++ */
++
++#ifndef MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_X11_H_
++#define MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_X11_H_
++
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <memory>
++#include <string>
++
++#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
++#include "webrtc/modules/desktop_capture/desktop_capturer.h"
++#include "webrtc/modules/desktop_capture/desktop_geometry.h"
++#include "webrtc/modules/desktop_capture/x11/shared_x_display.h"
++#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
++#include "webrtc/base/constructormagic.h"
++#include "webrtc/base/scoped_ref_ptr.h"
++
++namespace webrtc {
++
++class WindowCapturerX11 : public DesktopCapturer,
++                          public SharedXDisplay::XEventHandler {
++ public:
++  explicit WindowCapturerX11(const DesktopCaptureOptions& options);
++  ~WindowCapturerX11() override;
++
++  static std::unique_ptr<DesktopCapturer> CreateRawWindowCapturer(
++      const DesktopCaptureOptions& options);
++
++  // DesktopCapturer interface.
++  void Start(Callback* callback) override;
++  void Stop() override;
++  void CaptureFrame() override;
++  bool GetSourceList(SourceList* sources) override;
++  bool SelectSource(SourceId id) override;
++  bool FocusOnSelectedSource() override;
++
++  // SharedXDisplay::XEventHandler interface.
++  bool HandleXEvent(const XEvent& event) override;
++
++ private:
++  Display* display() { return x_display_->display(); }
++
++  // Iterates through |window| hierarchy to find first visible window, i.e. one
++  // that has WM_STATE property set to NormalState.
++  // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 .
++  ::Window GetApplicationWindow(::Window window);
++
++  // Returns true if the |window| is a desktop element.
++  bool IsDesktopElement(::Window window);
++
++  // Returns window title for the specified X |window|.
++  bool GetWindowTitle(::Window window, std::string* title);
++
++  // Returns the id of the owning process.
++  int GetWindowProcessID(::Window window);
++
++  Callback* callback_ = nullptr;
++
++  rtc::scoped_refptr<SharedXDisplay> x_display_;
++
++  Atom wm_state_atom_;
++  Atom window_type_atom_;
++  Atom normal_window_type_atom_;
++  bool has_composite_extension_ = false;
++
++  ::Window selected_window_ = 0;
++  XServerPixelBuffer x_server_pixel_buffer_;
++
++  RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerX11);
++};
++
++}  // namespace webrtc
++
++#endif  // MODULES_DESKTOP_CAPTURE_WINDOW_CAPTURER_X11_H_
diff --git a/SOURCES/firefox-redhat-default-prefs.js b/SOURCES/firefox-redhat-default-prefs.js
new file mode 100644
index 0000000..71d6506
--- /dev/null
+++ b/SOURCES/firefox-redhat-default-prefs.js
@@ -0,0 +1,33 @@
+pref("app.update.auto",                     false);
+pref("app.update.enabled",                  false);
+pref("app.update.autoInstallEnabled",       false);
+pref("general.smoothScroll",                true);
+pref("intl.locale.matchOS",                 true);
+pref("toolkit.storage.synchronous",         0);
+pref("toolkit.networkmanager.disable",      false);
+pref("offline.autoDetect",                  true);
+pref("browser.backspace_action",            2);
+pref("browser.display.use_system_colors",   true);
+pref("browser.download.folderList",         1);
+pref("browser.link.open_external",          3);
+pref("browser.shell.checkDefaultBrowser",   false);
+pref("network.manage-offline-status",       true);
+pref("extensions.shownSelectionUI",         true);
+pref("ui.SpellCheckerUnderlineStyle",       1);
+pref("startup.homepage_override_url",       "http://www.redhat.com");
+pref("startup.homepage_welcome_url",        "http://www.redhat.com");
+pref("browser.startup.homepage",            "data:text/plain,browser.startup.homepage=file:///usr/share/doc/HTML/index.html");
+pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
+pref("media.gmp-gmpopenh264.provider.enabled",false);
+pref("media.gmp-gmpopenh264.autoupdate",false);
+pref("media.gmp-gmpopenh264.enabled",false);
+pref("media.gmp-gmpopenh264.enabled",false);
+pref("plugins.notifyMissingFlash", false);
+/* See https://bugzilla.redhat.com/show_bug.cgi?id=1226489 */
+pref("browser.display.use_system_colors", false);
+pref("layers.use-image-offscreen-surfaces", false);
+/* Allow sending credetials to all https:// sites */
+pref("network.negotiate-auth.trusted-uris", "https://");
+pref("security.use_sqldb", false);
+/* Use OS settings for UI language */
+pref("intl.locale.requested", "");
diff --git a/SOURCES/mozilla-1170092.patch b/SOURCES/mozilla-1170092.patch
index 9e8906f..b182d64 100644
--- a/SOURCES/mozilla-1170092.patch
+++ b/SOURCES/mozilla-1170092.patch
@@ -1,33 +1,32 @@
-diff -up firefox-58.0/extensions/pref/autoconfig/src/nsReadConfig.cpp.1170092 firefox-58.0/extensions/pref/autoconfig/src/nsReadConfig.cpp
---- firefox-58.0/extensions/pref/autoconfig/src/nsReadConfig.cpp.1170092	2018-01-11 21:17:03.000000000 +0100
-+++ firefox-58.0/extensions/pref/autoconfig/src/nsReadConfig.cpp	2018-01-23 13:59:45.446495820 +0100
-@@ -239,9 +239,20 @@ nsresult nsReadConfig::openAndEvaluateJS
-             return rv;
+diff -up firefox-60.5.0/extensions/pref/autoconfig/src/nsReadConfig.cpp.1170092 firefox-60.5.0/extensions/pref/autoconfig/src/nsReadConfig.cpp
+--- firefox-60.5.0/extensions/pref/autoconfig/src/nsReadConfig.cpp.1170092	2019-01-22 10:48:38.187383614 +0100
++++ firefox-60.5.0/extensions/pref/autoconfig/src/nsReadConfig.cpp	2019-01-22 11:26:11.027108692 +0100
+@@ -225,8 +225,20 @@ nsresult nsReadConfig::openAndEvaluateJS
+     if (NS_FAILED(rv)) return rv;
  
-         rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile);
--        if (NS_FAILED(rv))
--            return rv;
-+        if (NS_FAILED(rv)) {
-+          // Look for cfg file in /etc/<application>/pref
-+          rv = NS_GetSpecialDirectory(NS_APP_PREFS_SYSTEM_CONFIG_DIR,
-+                                      getter_AddRefs(jsFile));
-+          NS_ENSURE_SUCCESS(rv, rv);
+     rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile);
+-    if (NS_FAILED(rv)) return rv;
++    if (NS_FAILED(rv)) {
++      // Look for cfg file in /etc/<application>/pref
++      rv = NS_GetSpecialDirectory(NS_APP_PREFS_SYSTEM_CONFIG_DIR,
++                                  getter_AddRefs(jsFile));
++      NS_ENSURE_SUCCESS(rv, rv);
 +
-+          rv = jsFile->AppendNative(NS_LITERAL_CSTRING("pref"));
-+          NS_ENSURE_SUCCESS(rv, rv);
-+          rv = jsFile->AppendNative(nsDependentCString(aFileName));
-+          NS_ENSURE_SUCCESS(rv, rv);
++      rv = jsFile->AppendNative(NS_LITERAL_CSTRING("pref"));
++      NS_ENSURE_SUCCESS(rv, rv);
++      rv = jsFile->AppendNative(nsDependentCString(aFileName));
++      NS_ENSURE_SUCCESS(rv, rv);
  
-+          rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile);
-+          NS_ENSURE_SUCCESS(rv, rv);
-+        }
-     } else {
-         nsAutoCString location("resource://gre/defaults/autoconfig/");
-         location += aFileName;
-diff -up firefox-58.0/modules/libpref/Preferences.cpp.1170092 firefox-58.0/modules/libpref/Preferences.cpp
---- firefox-58.0/modules/libpref/Preferences.cpp.1170092	2018-01-23 13:59:45.447495817 +0100
-+++ firefox-58.0/modules/libpref/Preferences.cpp	2018-01-23 14:02:51.456987774 +0100
-@@ -4402,6 +4402,8 @@ pref_InitInitialObjects()
++      rv = NS_NewLocalFileInputStream(getter_AddRefs(inStr), jsFile);
++      NS_ENSURE_SUCCESS(rv, rv);
++    }
+   } else {
+     nsAutoCString location("resource://gre/defaults/autoconfig/");
+     location += aFileName;
+diff -up firefox-60.5.0/modules/libpref/Preferences.cpp.1170092 firefox-60.5.0/modules/libpref/Preferences.cpp
+--- firefox-60.5.0/modules/libpref/Preferences.cpp.1170092	2019-01-21 17:38:16.000000000 +0100
++++ firefox-60.5.0/modules/libpref/Preferences.cpp	2019-01-22 10:48:38.187383614 +0100
+@@ -3459,6 +3459,8 @@ static nsresult pref_ReadPrefFromJar(nsZ
    //
    // Thus, in the omni.jar case, we always load app-specific default
    // preferences from omni.jar, whether or not `$app == $gre`.
@@ -36,10 +35,10 @@ diff -up firefox-58.0/modules/libpref/Preferences.cpp.1170092 firefox-58.0/modul
  
    nsresult rv;
    nsZipFind* findPtr;
-diff -up firefox-58.0/toolkit/xre/nsXREDirProvider.cpp.1170092 firefox-58.0/toolkit/xre/nsXREDirProvider.cpp
---- firefox-58.0/toolkit/xre/nsXREDirProvider.cpp.1170092	2018-01-11 21:17:06.000000000 +0100
-+++ firefox-58.0/toolkit/xre/nsXREDirProvider.cpp	2018-01-23 13:59:45.447495817 +0100
-@@ -59,6 +59,7 @@
+diff -up firefox-60.5.0/toolkit/xre/nsXREDirProvider.cpp.1170092 firefox-60.5.0/toolkit/xre/nsXREDirProvider.cpp
+--- firefox-60.5.0/toolkit/xre/nsXREDirProvider.cpp.1170092	2019-01-21 17:38:51.000000000 +0100
++++ firefox-60.5.0/toolkit/xre/nsXREDirProvider.cpp	2019-01-22 11:37:01.868896974 +0100
+@@ -58,6 +58,7 @@
  #endif
  #ifdef XP_UNIX
  #include <ctype.h>
@@ -47,10 +46,11 @@ diff -up firefox-58.0/toolkit/xre/nsXREDirProvider.cpp.1170092 firefox-58.0/tool
  #endif
  #ifdef XP_IOS
  #include "UIKitDirProvider.h"
-@@ -554,6 +555,20 @@ nsXREDirProvider::GetFile(const char* aP
+@@ -491,6 +492,21 @@ nsXREDirProvider::GetFile(const char* aP
        }
      }
    }
++
 +#if defined(XP_UNIX)
 +  if (!strcmp(aProperty, NS_APP_PREFS_SYSTEM_CONFIG_DIR)) {
 +    nsCString sysConfigDir = NS_LITERAL_CSTRING("/etc/");
@@ -65,32 +65,34 @@ diff -up firefox-58.0/toolkit/xre/nsXREDirProvider.cpp.1170092 firefox-58.0/tool
 +  }
 +#endif
 +
-   if (NS_FAILED(rv) || !file)
-     return NS_ERROR_FAILURE;
+   if (NS_FAILED(rv) || !file) return NS_ERROR_FAILURE;
  
-@@ -887,6 +902,14 @@ nsXREDirProvider::GetFilesInternal(const
+   if (ensureFilePermissions) {
+@@ -796,6 +812,16 @@ nsresult nsXREDirProvider::GetFilesInter
      LoadDirIntoArray(mXULAppDir, kAppendPrefDir, directories);
-     LoadDirsIntoArray(mAppBundleDirectories,
-                       kAppendPrefDir, directories);
+     LoadDirsIntoArray(mAppBundleDirectories, kAppendPrefDir, directories);
+ 
 +    // Add /etc/<application>/pref/ directory if it exists
 +    nsCOMPtr<nsIFile> systemPrefDir;
-+    rv = NS_GetSpecialDirectory(NS_APP_PREFS_SYSTEM_CONFIG_DIR, getter_AddRefs(systemPrefDir));
++    rv = NS_GetSpecialDirectory(NS_APP_PREFS_SYSTEM_CONFIG_DIR,
++                                getter_AddRefs(systemPrefDir));
 +    if (NS_SUCCEEDED(rv)) {
 +      rv = systemPrefDir->AppendNative(NS_LITERAL_CSTRING("pref"));
 +      if (NS_SUCCEEDED(rv))
 +        directories.AppendObject(systemPrefDir);
 +    }
- 
++
      rv = NS_NewArrayEnumerator(aResult, directories);
-   }
-diff -up firefox-58.0/xpcom/io/nsAppDirectoryServiceDefs.h.1170092 firefox-58.0/xpcom/io/nsAppDirectoryServiceDefs.h
---- firefox-58.0/xpcom/io/nsAppDirectoryServiceDefs.h.1170092	2018-01-23 13:59:45.447495817 +0100
-+++ firefox-58.0/xpcom/io/nsAppDirectoryServiceDefs.h	2018-01-23 14:02:02.871120476 +0100
-@@ -59,6 +59,7 @@
- #define NS_APP_PREFS_50_FILE                    "PrefF"
- #define NS_APP_PREFS_DEFAULTS_DIR_LIST          "PrefDL"
- #define NS_APP_PREFS_OVERRIDE_DIR               "PrefDOverride" // Directory for per-profile defaults
+   } else if (!strcmp(aProperty, NS_APP_CHROME_DIR_LIST)) {
+     // NS_APP_CHROME_DIR_LIST is only used to get default (native) icons
+diff -up firefox-60.5.0/xpcom/io/nsAppDirectoryServiceDefs.h.1170092 firefox-60.5.0/xpcom/io/nsAppDirectoryServiceDefs.h
+--- firefox-60.5.0/xpcom/io/nsAppDirectoryServiceDefs.h.1170092	2019-01-22 10:48:38.188383609 +0100
++++ firefox-60.5.0/xpcom/io/nsAppDirectoryServiceDefs.h	2019-01-22 11:08:12.068459480 +0100
+@@ -62,6 +62,7 @@
+ #define NS_APP_PREFS_DEFAULTS_DIR_LIST "PrefDL"
+ #define NS_APP_PREFS_OVERRIDE_DIR \
+   "PrefDOverride"  // Directory for per-profile defaults
 +#define NS_APP_PREFS_SYSTEM_CONFIG_DIR          "PrefSysConf"   // Directory with system-wide configuration
  
- #define NS_APP_USER_PROFILE_50_DIR              "ProfD"
- #define NS_APP_USER_PROFILE_LOCAL_50_DIR        "ProfLD"
+ #define NS_APP_USER_PROFILE_50_DIR "ProfD"
+ #define NS_APP_USER_PROFILE_LOCAL_50_DIR "ProfLD"
diff --git a/SOURCES/mozilla-1196777.patch b/SOURCES/mozilla-1196777.patch
index ba5e4b7..c28cf94 100644
--- a/SOURCES/mozilla-1196777.patch
+++ b/SOURCES/mozilla-1196777.patch
@@ -1,28 +1,13 @@
-# HG changeset patch
-# User Martin Stransky <stransky@redhat.com>
-# Parent  4e3ad95d689a5beabf3c1f41d958794fe00e3767
-Bug 1196777 - Ask GDK to receive focus events, r=?karlt
-
-diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
---- a/widget/gtk/nsWindow.cpp
-+++ b/widget/gtk/nsWindow.cpp
-@@ -142,17 +142,18 @@ const gint kEvents = GDK_EXPOSURE_MASK |
-                      GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
-                      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
- #if GTK_CHECK_VERSION(3,4,0)
-                      GDK_SMOOTH_SCROLL_MASK |
-                      GDK_TOUCH_MASK |
+diff -up firefox-60.5.0/widget/gtk/nsWindow.cpp.1196777 firefox-60.5.0/widget/gtk/nsWindow.cpp
+--- firefox-60.5.0/widget/gtk/nsWindow.cpp.1196777	2019-01-22 11:41:58.630469400 +0100
++++ firefox-60.5.0/widget/gtk/nsWindow.cpp	2019-01-22 11:42:50.134227448 +0100
+@@ -152,7 +152,8 @@ const gint kEvents =
+ #if GTK_CHECK_VERSION(3, 4, 0)
+     GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK |
  #endif
-                      GDK_SCROLL_MASK |
-                      GDK_POINTER_MOTION_MASK |
--                     GDK_PROPERTY_CHANGE_MASK;
-+                     GDK_PROPERTY_CHANGE_MASK |
-+                     GDK_FOCUS_CHANGE_MASK;
+-    GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK;
++    GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK |
++    GDK_FOCUS_CHANGE_MASK;
  
  /* utility functions */
- static bool       is_mouse_in_window(GdkWindow* aWindow,
-                                      gdouble aMouseX, gdouble aMouseY);
- static nsWindow  *get_window_for_gtk_widget(GtkWidget *widget);
- static nsWindow  *get_window_for_gdk_window(GdkWindow *window);
- static GtkWidget *get_gtk_widget_for_gdk_window(GdkWindow *window);
- static GdkCursor *get_gtk_cursor(nsCursor aCursor);
+ static bool is_mouse_in_window(GdkWindow *aWindow, gdouble aMouseX,
diff --git a/SOURCES/mozilla-256180.patch b/SOURCES/mozilla-256180.patch
index 13a1c97..4b61b5f 100644
--- a/SOURCES/mozilla-256180.patch
+++ b/SOURCES/mozilla-256180.patch
@@ -1,5 +1,6 @@
---- a/layout/generic/nsIFrame.h.old	2016-07-11 13:41:39.688276559 +0200
-+++ b/layout/generic/nsIFrame.h	2016-07-11 13:42:12.791406976 +0200
+diff -up firefox-60.5.0/layout/generic/nsIFrame.h.256180 firefox-60.5.0/layout/generic/nsIFrame.h
+--- firefox-60.5.0/layout/generic/nsIFrame.h.256180	2019-01-22 11:44:10.849848268 +0100
++++ firefox-60.5.0/layout/generic/nsIFrame.h	2019-01-22 11:44:53.918645941 +0100
 @@ -13,7 +13,7 @@
  #error This header/class should only be used within Mozilla code. It should not be used by extensions.
  #endif
@@ -7,5 +8,5 @@
 -#define MAX_REFLOW_DEPTH 200
 +#define MAX_REFLOW_DEPTH 1000
  
- /* nsIFrame is in the process of being deCOMtaminated, i.e., this file is eventually
-    going to be eliminated, and all callers will use nsFrame instead.  At the moment
+ /* nsIFrame is in the process of being deCOMtaminated, i.e., this file is
+    eventually going to be eliminated, and all callers will use nsFrame instead.
diff --git a/SOURCES/rhbz-1173156.patch b/SOURCES/rhbz-1173156.patch
index 9855710..c35d901 100644
--- a/SOURCES/rhbz-1173156.patch
+++ b/SOURCES/rhbz-1173156.patch
@@ -1,12 +1,12 @@
-diff -up firefox-31.3.0/mozilla-esr31/extensions/auth/nsAuthSambaNTLM.cpp.old firefox-31.3.0/mozilla-esr31/extensions/auth/nsAuthSambaNTLM.cpp
---- firefox-31.3.0/mozilla-esr31/extensions/auth/nsAuthSambaNTLM.cpp.old	2014-11-25 12:23:22.000000000 +0100
-+++ firefox-31.3.0/mozilla-esr31/extensions/auth/nsAuthSambaNTLM.cpp	2014-12-23 15:26:36.606674625 +0100
-@@ -174,7 +174,7 @@ nsAuthSambaNTLM::SpawnNTLMAuthHelper()
-         return NS_ERROR_FAILURE;
+diff -up firefox-60.5.0/extensions/auth/nsAuthSambaNTLM.cpp.rhbz-1173156 firefox-60.5.0/extensions/auth/nsAuthSambaNTLM.cpp
+--- firefox-60.5.0/extensions/auth/nsAuthSambaNTLM.cpp.rhbz-1173156	2019-01-22 10:36:09.284069020 +0100
++++ firefox-60.5.0/extensions/auth/nsAuthSambaNTLM.cpp	2019-01-22 10:37:12.669757744 +0100
+@@ -161,7 +161,7 @@ nsresult nsAuthSambaNTLM::SpawnNTLMAuthH
+   const char* username = PR_GetEnv("USER");
+   if (!username) return NS_ERROR_FAILURE;
  
-     const char* const args[] = {
--        "ntlm_auth",
-+        "/usr/bin/ntlm_auth",
-         "--helper-protocol", "ntlmssp-client-1",
-         "--use-cached-creds",
-         "--username", username,
+-  const char* const args[] = {"ntlm_auth",
++  const char* const args[] = {"/usr/bin/ntlm_auth",
+                               "--helper-protocol",
+                               "ntlmssp-client-1",
+                               "--use-cached-creds",
diff --git a/SOURCES/rhbz-1354671.patch b/SOURCES/rhbz-1354671.patch
index 6ee89b7..7660f14 100644
--- a/SOURCES/rhbz-1354671.patch
+++ b/SOURCES/rhbz-1354671.patch
@@ -1,12 +1,12 @@
-diff -up firefox-53.0/layout/base/nsIPresShell.h.1354671 firefox-53.0/layout/base/nsIPresShell.h
---- firefox-53.0/layout/base/nsIPresShell.h.1354671	2017-04-27 13:07:43.808653320 +0200
-+++ firefox-53.0/layout/base/nsIPresShell.h	2017-04-27 13:09:40.404427641 +0200
-@@ -212,7 +212,7 @@ public:
+diff -up firefox-60.5.0/layout/base/nsIPresShell.h.1354671 firefox-60.5.0/layout/base/nsIPresShell.h
+--- firefox-60.5.0/layout/base/nsIPresShell.h.1354671	2019-01-22 16:08:40.796539950 +0100
++++ firefox-60.5.0/layout/base/nsIPresShell.h	2019-01-22 16:10:25.106069228 +0100
+@@ -204,7 +204,7 @@ class nsIPresShell : public nsStubDocume
     * to the same aSize value.  AllocateFrame is infallible and will abort
     * on out-of-memory.
     */
--  void* AllocateFrame(nsQueryFrame::FrameIID aID, size_t aSize)
-+  void* __attribute__((optimize("no-lifetime-dse"))) AllocateFrame(nsQueryFrame::FrameIID aID, size_t aSize)
-   {
+-  void* AllocateFrame(nsQueryFrame::FrameIID aID, size_t aSize) {
++  void* __attribute__((optimize("no-lifetime-dse"))) AllocateFrame(nsQueryFrame::FrameIID aID, size_t aSize) {
      void* result = mFrameArena.AllocateByFrameID(aID, aSize);
      RecordAlloc(result);
+     return result;
diff --git a/SOURCES/rhbz-1503632-nss.patch b/SOURCES/rhbz-1503632-nss.patch
index f9f5e4d..f7a26d3 100644
--- a/SOURCES/rhbz-1503632-nss.patch
+++ b/SOURCES/rhbz-1503632-nss.patch
@@ -1,12 +1,7 @@
-diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp
---- a/security/certverifier/NSSCertDBTrustDomain.cpp
-+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
-@@ -1057,22 +1057,20 @@ InitializeNSS(const nsACString& dir, boo
-   // "/usr/lib/nss/libnssckbi.so".
-   uint32_t flags = NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE;
-   if (readOnly) {
-     flags |= NSS_INIT_READONLY;
-   }
+diff -up firefox-60.5.0/security/certverifier/NSSCertDBTrustDomain.cpp.1503632-nss firefox-60.5.0/security/certverifier/NSSCertDBTrustDomain.cpp
+--- firefox-60.5.0/security/certverifier/NSSCertDBTrustDomain.cpp.1503632-nss	2019-01-22 11:38:49.484365928 +0100
++++ firefox-60.5.0/security/certverifier/NSSCertDBTrustDomain.cpp	2019-01-22 11:40:52.694779150 +0100
+@@ -1077,13 +1077,11 @@ SECStatus InitializeNSS(const nsACString
    if (!loadPKCS11Modules) {
      flags |= NSS_INIT_NOMODDB;
    }
@@ -16,13 +11,9 @@ diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverif
 -          ("InitializeNSS(%s, %d, %d)", dbTypeAndDirectory.get(), readOnly,
 +          ("InitializeNSS(%s, %d, %d)", PromiseFlatCString(dir).get(), readOnly,
             loadPKCS11Modules));
--  SECStatus srv = NSS_Initialize(dbTypeAndDirectory.get(), "", "",
-+  SECStatus srv = NSS_Initialize(PromiseFlatCString(dir).get(), "", "",
-                                  SECMOD_DB, flags);
+   SECStatus srv =
+-      NSS_Initialize(dbTypeAndDirectory.get(), "", "", SECMOD_DB, flags);
++      NSS_Initialize(PromiseFlatCString(dir).get(), "", "", SECMOD_DB, flags);
    if (srv != SECSuccess) {
      return srv;
    }
- 
-   if (!readOnly) {
-     UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
-     if (!slot) {
diff --git a/SOURCES/xulrunner-24.0-jemalloc-ppc.patch b/SOURCES/xulrunner-24.0-jemalloc-ppc.patch
index 75aed9a..c8fe421 100644
--- a/SOURCES/xulrunner-24.0-jemalloc-ppc.patch
+++ b/SOURCES/xulrunner-24.0-jemalloc-ppc.patch
@@ -1,12 +1,12 @@
-diff -up firefox-60.0/memory/build/mozjemalloc.cpp.ppc-jemalloc firefox-60.0/memory/build/mozjemalloc.cpp
---- firefox-60.0/memory/build/mozjemalloc.cpp.ppc-jemalloc	2018-06-06 14:39:28.454371053 +0200
-+++ firefox-60.0/memory/build/mozjemalloc.cpp	2018-06-06 14:39:40.242397928 +0200
+diff -up firefox-60.5.0/memory/build/mozjemalloc.cpp.jemalloc-ppc firefox-60.5.0/memory/build/mozjemalloc.cpp
+--- firefox-60.5.0/memory/build/mozjemalloc.cpp.jemalloc-ppc	2019-01-22 10:25:30.764207480 +0100
++++ firefox-60.5.0/memory/build/mozjemalloc.cpp	2019-01-22 10:28:48.352235343 +0100
 @@ -180,7 +180,7 @@ using namespace mozilla;
  // Debug builds are opted out too, for test coverage.
  #ifndef MOZ_DEBUG
- #if !defined(__ia64__) && !defined(__sparc__) && !defined(__mips__) &&         \
--  !defined(__aarch64__)
-+  !defined(__aarch64__) && !defined(__powerpc__)
+ #if !defined(__ia64__) && !defined(__sparc__) && !defined(__mips__) && \
+-    !defined(__aarch64__)
++    !defined(__aarch64__) && !defined(__powerpc__)
  #define MALLOC_STATIC_PAGESIZE 1
  #endif
  #endif
diff --git a/SPECS/firefox.spec b/SPECS/firefox.spec
index 7634bed..18f3345 100644
--- a/SPECS/firefox.spec
+++ b/SPECS/firefox.spec
@@ -26,7 +26,9 @@
 %define use_bundled_python 0
 %endif
 
+%if 0%{?rhel} < 8
 %global use_rustts        1
+%endif
 %global dts_version       7
 %global rst_version       7
 %global llvm_version      7
@@ -139,8 +141,8 @@
 
 Summary:        Mozilla Firefox Web browser
 Name:           firefox
-Version:        60.4.0
-Release:        1%{?pre_tag}%{?dist}
+Version:        60.5.0
+Release:        2%{?pre_tag}%{?dist}
 URL:            https://www.mozilla.org/firefox/
 License:        MPLv1.1 or GPLv2+ or LGPLv2+
 %if 0%{?rhel} == 7
@@ -152,10 +154,10 @@ ExclusiveArch:  i686 x86_64 ppc64 s390x
 
 Source0:        https://hg.mozilla.org/releases/mozilla-release/archive/firefox-%{version}%{?pre_version}.source.tar.xz
 %if %{build_langpacks}
-Source1:        firefox-langpacks-%{version}%{?pre_version}-20181205.tar.xz
+Source1:        firefox-langpacks-%{version}%{?pre_version}-20190125.tar.xz
 %endif
 Source10:       firefox-mozconfig
-Source12:       firefox-centos-default-prefs.js
+Source12:       firefox-redhat-default-prefs.js
 Source20:       firefox.desktop
 Source21:       firefox.sh.in
 Source23:       firefox.1
@@ -190,7 +192,7 @@ Patch37:        build-jit-atomic-always-lucky.patch
 Patch40:        build-aarch64-skia.patch
 Patch41:        build-debug-qcms.patch
 Patch43:        xulrunner-24.0-jemalloc-ppc.patch
-Patch44:        firefox-disable-dbus-remote.patch
+#Patch44:        firefox-disable-dbus-remote.patch
 Patch45:        build-disable-elfhack.patch
 
 # Fedora/RHEL specific patches
@@ -201,6 +203,7 @@ Patch225:        mozilla-1005640-accept-lang.patch
 #ARM run-time patch
 Patch226:        rhbz-1354671.patch
 Patch230:        rhbz-1503632-nss.patch
+Patch231:        firefox-pipewire.patch
 
 # Upstream patches
 Patch402:        mozilla-1196777.patch
@@ -208,8 +211,6 @@ Patch406:        mozilla-256180.patch
 Patch413:        mozilla-1353817.patch
 Patch415:        mozilla-1436242.patch
 
-Patch1000:       Bug-1238661---fix-mozillaSignalTrampoline-to-work-.patch
-
 # Debian patches
 
 %if %{?system_nss}
@@ -264,6 +265,14 @@ BuildRequires:  llvm-toolset-%{llvm_version}
 BuildRequires:  llvm-toolset-%{llvm_version}-llvm-devel
 %endif
 %endif
+
+%if 0%{?rhel} == 8
+BuildRequires:  cargo
+BuildRequires:  rust >= 1.24
+BuildRequires:  llvm >= %{llvm_version}
+BuildRequires:  llvm-devel >= %{llvm_version}
+BuildRequires:  clang >= %{llvm_version}
+%else
 %if 0%{?use_rustts}
 BuildRequires:  rust-toolset-%{rst_version}-cargo
 BuildRequires:  rust-toolset-%{rst_version}-rust >= 1.24
@@ -272,6 +281,8 @@ BuildRequires:  rust-toolset-%{rst_version}-rust >= 1.24
 BuildRequires:  llvm-toolset-%{llvm_version}
 BuildRequires:  llvm-toolset-%{llvm_version}-llvm-devel
 %endif
+%endif
+
 %if 0%{?use_bundled_python}
 #%if 0%{?rhel} == 6
 # Needed for Python in RHEL6
@@ -279,6 +290,10 @@ BuildRequires:  openssl-devel
 #%endif
 %endif
 
+%if 0%{?rhel} == 8
+BuildRequires:  pipewire-devel
+%endif
+
 %if 0%{?bundle_gtk3}
 BuildRequires:        automake
 BuildRequires:        autoconf
@@ -405,9 +420,6 @@ Requires:       gnome-icon-theme
 Requires:       gnome-shell
 Requires:       hicolor-icon-theme
 Requires:       mozilla-filesystem
-Requires:       python3-gobject-base
-Requires:       python3-requests
-
 
 %description -n firefox-gnome-shell-extension
 Browser extension for Firefox and native host messaging connector that provides 
@@ -433,9 +445,9 @@ https://extensions.gnome.org.
 %endif
 %patch43 -p1 -b .jemalloc-ppc
 # Disable DBus remote on RHEL6 as it does not build here.
-%if 0%{?rhel} == 6
-%patch44 -p1 -b .disable-dbus-remote
-%endif
+#%if 0%{?rhel} == 6
+#%patch44 -p1 -b .disable-dbus-remote
+#%endif
 %if 0%{?rhel} == 8
 %patch45 -p1 -b .disable-elfhack
 %endif
@@ -447,9 +459,12 @@ https://extensions.gnome.org.
 
 # Fedora patches
 %patch215 -p1 -b .addons
-%patch219 -p2 -b .rhbz-1173156
+%patch219 -p1 -b .rhbz-1173156
 %patch224 -p1 -b .1170092
 %patch225 -p1 -b .1005640-accept-lang
+%if 0%{?rhel} == 8
+%patch231 -p1 -b .pipewire
+%endif
 
 # This ensures no migration of certdb to sqlite on the RHEL6 and RHEL7.
 # This needs to stay for the future releases
@@ -473,10 +488,6 @@ https://extensions.gnome.org.
 %patch26 -p1 -b .icu
 %endif
 
-%ifarch %{arm}
-%patch1000 -p1 -b .mozilla-1238661
-%endif
-
 %{__rm} -f .mozconfig
 %{__cp} %{SOURCE10} .mozconfig
 %if %{official_branding}
@@ -816,6 +827,9 @@ MOZ_SMP_FLAGS=-j1
 export MOZ_MAKE_FLAGS="$MOZ_SMP_FLAGS"
 export MOZ_SERVICES_SYNC="1"
 export STRIP=/bin/true
+%if 0%{?rhel} == 8
+export LLVM_CONFIG=/usr/bin/llvm-config-64
+%endif
 ./mach build -v
 
 # create debuginfo for crash-stats.mozilla.com
@@ -914,7 +928,7 @@ desktop-file-install --dir %{buildroot}%{_datadir}/applications %{SOURCE20}
 %{__rm} -rf %{buildroot}%{_bindir}/firefox
 %{__cat} %{SOURCE21} > %{buildroot}%{_bindir}/firefox
 %if 0%{?bundle_gtk3}
-sed -i -e 's|%RHEL_ENV_VARS%|export XDG_DATA_DIRS="$MOZ_LIB_DIR/firefox/bundled/share:/usr/share:$XDG_DATA_DIRS"|' %{buildroot}%{_bindir}/firefox
+sed -i -e 's|%RHEL_ENV_VARS%|export XDG_DATA_DIRS="$MOZ_LIB_DIR/firefox/bundled/share:/usr/share:$XDG_DATA_DIRS"\nexport FONTCONFIG_FILE="$MOZ_LIB_DIR/firefox/bundled/etc/fonts/fonts.conf"|' %{buildroot}%{_bindir}/firefox
 %else
 sed -i -e 's|%RHEL_ENV_VARS%||' %{buildroot}%{_bindir}/firefox
 %endif
@@ -1205,8 +1219,17 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 #---------------------------------------------------------------------
 
 %changelog
-* Wed Dec 19 2018 Johnny Hughes <johnny@centos.org> - 60.4.0-1
-- Manual CentOS Debranding
+* Fri Jan 25 2019 Martin Stransky <stransky@redhat.com> - 60.5.0-2
+- Updated to 60.5.0 ESR build2
+
+* Tue Jan 22 2019 Martin Stransky <stransky@redhat.com> - 60.5.0-1
+- Updated to 60.5.0 ESR build1
+
+* Thu Jan 10 2019 Jan Horak <jhorak@redhat.com> - 60.4.0-3
+- Fixing fontconfig warnings (rhbz#1601475)
+
+* Wed Jan  9 2019 Jan Horak <jhorak@redhat.com> - 60.4.0-2
+- Added pipewire patch from Tomas Popela (rhbz#1664270)
 
 * Wed Dec  5 2018 Jan Horak <jhorak@redhat.com> - 60.4.0-1
 - Update to 60.4.0 ESR