Implement handling for MS PowerPoint Presentation Mode.

* Introduce a FullScreenWindowDetector to manage routines for updating the list of sources being application agnostic, inspired by FullScreenChromeWindowDetector.
* Introduce a FullScreenApplicationHandler to make a decision about changing window to share in application specific way, inspired by FullScreenChromeWindowDetector.
* Remove FullScreenChromeWindowDetector as redundant.
* Add FullScreenApplicationHandler for MS PowerPoint and Apple Keynote on MacOS.
* Add FullScreenApplicationHandler for MS PowerPoint on Windows.

Bug: webrtc:3852
Change-Id: I06507d929308e85b882b2f8210a025afef7f26a9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/156020
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Reviewed-by: Justin Uberti <juberti@webrtc.org>
Reviewed-by: Wez <wez@google.com>
Cr-Commit-Position: refs/heads/master@{#29993}
diff --git a/AUTHORS b/AUTHORS
index df32313..b11ca9a 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -101,6 +101,7 @@
 Opera Software ASA <*@opera.com>
 Optical Tone Ltd <*@opticaltone.com>
 Pengutronix e.K. <*@pengutronix.de>
+RingCentral, Inc. <*@ringcentral.com>
 Sinch AB <*@sinch.com>
 struktur AG <*@struktur.de>
 Telenor Digital AS <*@telenor.com>
diff --git a/modules/desktop_capture/BUILD.gn b/modules/desktop_capture/BUILD.gn
index 88a10a1..789aac4 100644
--- a/modules/desktop_capture/BUILD.gn
+++ b/modules/desktop_capture/BUILD.gn
@@ -300,6 +300,10 @@
     "fake_desktop_capturer.h",
     "fallback_desktop_capturer_wrapper.cc",
     "fallback_desktop_capturer_wrapper.h",
+    "full_screen_application_handler.cc",
+    "full_screen_application_handler.h",
+    "full_screen_window_detector.cc",
+    "full_screen_window_detector.h",
     "mouse_cursor.cc",
     "mouse_cursor.h",
     "mouse_cursor_monitor.h",
@@ -319,8 +323,8 @@
       "mac/desktop_configuration.h",
       "mac/desktop_configuration_monitor.cc",
       "mac/desktop_configuration_monitor.h",
-      "mac/full_screen_chrome_window_detector.cc",
-      "mac/full_screen_chrome_window_detector.h",
+      "mac/full_screen_mac_application_handler.cc",
+      "mac/full_screen_mac_application_handler.h",
       "mac/window_list_utils.cc",
       "mac/window_list_utils.h",
     ]
@@ -431,6 +435,8 @@
       "win/dxgi_texture_mapping.h",
       "win/dxgi_texture_staging.cc",
       "win/dxgi_texture_staging.h",
+      "win/full_screen_win_application_handler.cc",
+      "win/full_screen_win_application_handler.h",
       "win/scoped_gdi_object.h",
       "win/scoped_thread_desktop.cc",
       "win/scoped_thread_desktop.h",
@@ -470,6 +476,7 @@
     "../../system_wrappers:cpu_features_api",
     "../../system_wrappers:metrics",
     "//third_party/abseil-cpp/absl/memory",
+    "//third_party/abseil-cpp/absl/strings",
   ]
 
   if (build_with_mozilla) {
diff --git a/modules/desktop_capture/cropping_window_capturer.h b/modules/desktop_capture/cropping_window_capturer.h
index f9ad36c..272a196 100644
--- a/modules/desktop_capture/cropping_window_capturer.h
+++ b/modules/desktop_capture/cropping_window_capturer.h
@@ -68,6 +68,7 @@
 
   WindowId selected_window() const { return selected_window_; }
   WindowId excluded_window() const { return excluded_window_; }
+  DesktopCapturer* window_capturer() const { return window_capturer_.get(); }
 
  private:
   DesktopCaptureOptions options_;
diff --git a/modules/desktop_capture/cropping_window_capturer_win.cc b/modules/desktop_capture/cropping_window_capturer_win.cc
index ce93ca3..e67f4f4 100644
--- a/modules/desktop_capture/cropping_window_capturer_win.cc
+++ b/modules/desktop_capture/cropping_window_capturer_win.cc
@@ -98,26 +98,53 @@
 
 class CroppingWindowCapturerWin : public CroppingWindowCapturer {
  public:
-  CroppingWindowCapturerWin(const DesktopCaptureOptions& options)
-      : CroppingWindowCapturer(options) {}
+  explicit CroppingWindowCapturerWin(const DesktopCaptureOptions& options)
+      : CroppingWindowCapturer(options),
+        full_screen_window_detector_(options.full_screen_window_detector()) {}
+
+  void CaptureFrame() override;
 
  private:
   bool ShouldUseScreenCapturer() override;
   DesktopRect GetWindowRectInVirtualScreen() override;
 
+  // Returns either selected by user sourceId or sourceId provided by
+  // FullScreenWindowDetector
+  WindowId GetWindowToCapture() const;
+
   // The region from GetWindowRgn in the desktop coordinate if the region is
   // rectangular, or the rect from GetWindowRect if the region is not set.
   DesktopRect window_region_rect_;
 
   WindowCaptureHelperWin window_capture_helper_;
+
+  rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector_;
 };
 
+void CroppingWindowCapturerWin::CaptureFrame() {
+  DesktopCapturer* win_capturer = window_capturer();
+  if (win_capturer) {
+    // Update the list of available sources and override source to capture if
+    // FullScreenWindowDetector returns not zero
+    if (full_screen_window_detector_) {
+      full_screen_window_detector_->UpdateWindowListIfNeeded(
+          selected_window(),
+          [win_capturer](DesktopCapturer::SourceList* sources) {
+            return win_capturer->GetSourceList(sources);
+          });
+    }
+    win_capturer->SelectSource(GetWindowToCapture());
+  }
+
+  CroppingWindowCapturer::CaptureFrame();
+}
+
 bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
   if (!rtc::IsWindows8OrLater() && window_capture_helper_.IsAeroEnabled()) {
     return false;
   }
 
-  const HWND selected = reinterpret_cast<HWND>(selected_window());
+  const HWND selected = reinterpret_cast<HWND>(GetWindowToCapture());
   // Check if the window is visible on current desktop.
   if (!window_capture_helper_.IsWindowVisibleOnCurrentDesktop(selected)) {
     return false;
@@ -207,7 +234,7 @@
   TRACE_EVENT0("webrtc",
                "CroppingWindowCapturerWin::GetWindowRectInVirtualScreen");
   DesktopRect window_rect;
-  HWND hwnd = reinterpret_cast<HWND>(selected_window());
+  HWND hwnd = reinterpret_cast<HWND>(GetWindowToCapture());
   if (!GetCroppedWindowRect(hwnd, /*avoid_cropping_border*/ false, &window_rect,
                             /*original_rect*/ nullptr)) {
     RTC_LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
@@ -222,6 +249,15 @@
   return window_rect;
 }
 
+WindowId CroppingWindowCapturerWin::GetWindowToCapture() const {
+  const auto selected_source = selected_window();
+  const auto full_screen_source =
+      full_screen_window_detector_
+          ? full_screen_window_detector_->FindFullScreenWindow(selected_source)
+          : 0;
+  return full_screen_source ? full_screen_source : selected_source;
+}
+
 }  // namespace
 
 // static
diff --git a/modules/desktop_capture/desktop_capture_options.cc b/modules/desktop_capture/desktop_capture_options.cc
index 8a33807..ee1e477 100644
--- a/modules/desktop_capture/desktop_capture_options.cc
+++ b/modules/desktop_capture/desktop_capture_options.cc
@@ -9,6 +9,11 @@
  */
 
 #include "modules/desktop_capture/desktop_capture_options.h"
+#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
+#include "modules/desktop_capture/mac/full_screen_mac_application_handler.h"
+#elif defined(WEBRTC_WIN)
+#include "modules/desktop_capture/win/full_screen_win_application_handler.h"
+#endif
 
 namespace webrtc {
 
@@ -32,8 +37,11 @@
 #endif
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
   result.set_configuration_monitor(new DesktopConfigurationMonitor());
-  result.set_full_screen_chrome_window_detector(
-      new FullScreenChromeWindowDetector());
+  result.set_full_screen_window_detector(
+      new FullScreenWindowDetector(CreateFullScreenMacApplicationHandler));
+#elif defined(WEBRTC_WIN)
+  result.set_full_screen_window_detector(
+      new FullScreenWindowDetector(CreateFullScreenWinApplicationHandler));
 #endif
   return result;
 }
diff --git a/modules/desktop_capture/desktop_capture_options.h b/modules/desktop_capture/desktop_capture_options.h
index 11e5f4c..d7dac1f 100644
--- a/modules/desktop_capture/desktop_capture_options.h
+++ b/modules/desktop_capture/desktop_capture_options.h
@@ -19,9 +19,10 @@
 
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
 #include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
-#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
 #endif
 
+#include "modules/desktop_capture/full_screen_window_detector.h"
+
 namespace webrtc {
 
 // An object that stores initialization parameters for screen and window
@@ -62,21 +63,18 @@
     configuration_monitor_ = m;
   }
 
-  // TODO(zijiehe): Instead of FullScreenChromeWindowDetector, provide a
-  // FullScreenWindowDetector for external consumers to detect the target
-  // fullscreen window.
-  FullScreenChromeWindowDetector* full_screen_chrome_window_detector() const {
-    return full_screen_window_detector_;
-  }
-  void set_full_screen_chrome_window_detector(
-      rtc::scoped_refptr<FullScreenChromeWindowDetector> detector) {
-    full_screen_window_detector_ = detector;
-  }
-
   bool allow_iosurface() const { return allow_iosurface_; }
   void set_allow_iosurface(bool allow) { allow_iosurface_ = allow; }
 #endif
 
+  FullScreenWindowDetector* full_screen_window_detector() const {
+    return full_screen_window_detector_;
+  }
+  void set_full_screen_window_detector(
+      rtc::scoped_refptr<FullScreenWindowDetector> detector) {
+    full_screen_window_detector_ = detector;
+  }
+
   // Flag indicating that the capturer should use screen change notifications.
   // Enables/disables use of XDAMAGE in the X11 capturer.
   bool use_update_notifications() const { return use_update_notifications_; }
@@ -142,11 +140,11 @@
 
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
   rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
-  rtc::scoped_refptr<FullScreenChromeWindowDetector>
-      full_screen_window_detector_;
   bool allow_iosurface_ = false;
 #endif
 
+  rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector_;
+
 #if defined(WEBRTC_WIN)
   bool allow_use_magnification_api_ = false;
   bool allow_directx_capturer_ = false;
diff --git a/modules/desktop_capture/full_screen_application_handler.cc b/modules/desktop_capture/full_screen_application_handler.cc
new file mode 100644
index 0000000..e097557
--- /dev/null
+++ b/modules/desktop_capture/full_screen_application_handler.cc
@@ -0,0 +1,30 @@
+/*
+ *  Copyright (c) 2019 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 "modules/desktop_capture/full_screen_application_handler.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+FullScreenApplicationHandler::FullScreenApplicationHandler(
+    DesktopCapturer::SourceId sourceId)
+    : source_id_(sourceId) {}
+
+DesktopCapturer::SourceId FullScreenApplicationHandler::FindFullScreenWindow(
+    const DesktopCapturer::SourceList&,
+    int64_t) const {
+  return 0;
+}
+
+DesktopCapturer::SourceId FullScreenApplicationHandler::GetSourceId() const {
+  return source_id_;
+}
+
+}  // namespace webrtc
diff --git a/modules/desktop_capture/full_screen_application_handler.h b/modules/desktop_capture/full_screen_application_handler.h
new file mode 100644
index 0000000..849cb2c
--- /dev/null
+++ b/modules/desktop_capture/full_screen_application_handler.h
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (c) 2019 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_FULL_SCREEN_APPLICATION_HANDLER_H_
+#define MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_
+
+#include <memory>
+#include "modules/desktop_capture/desktop_capturer.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// Base class for application specific handler to check criteria for switch to
+// full-screen mode and find if possible the full-screen window to share.
+// Supposed to be created and owned by platform specific
+// FullScreenWindowDetector.
+class FullScreenApplicationHandler {
+ public:
+  virtual ~FullScreenApplicationHandler() {}
+
+  explicit FullScreenApplicationHandler(DesktopCapturer::SourceId sourceId);
+
+  // Returns the full-screen window in place of the original window if all the
+  // criteria are met, or 0 if no such window found.
+  virtual DesktopCapturer::SourceId FindFullScreenWindow(
+      const DesktopCapturer::SourceList& window_list,
+      int64_t timestamp) const;
+
+  // Returns source id of original window associated with
+  // FullScreenApplicationHandler
+  DesktopCapturer::SourceId GetSourceId() const;
+
+ private:
+  const DesktopCapturer::SourceId source_id_;
+
+  RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenApplicationHandler);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_FULL_SCREEN_APPLICATION_HANDLER_H_
diff --git a/modules/desktop_capture/full_screen_window_detector.cc b/modules/desktop_capture/full_screen_window_detector.cc
new file mode 100644
index 0000000..d0bc9c7
--- /dev/null
+++ b/modules/desktop_capture/full_screen_window_detector.cc
@@ -0,0 +1,84 @@
+/*
+ *  Copyright (c) 2019 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 "modules/desktop_capture/full_screen_window_detector.h"
+#include "modules/desktop_capture/full_screen_application_handler.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+FullScreenWindowDetector::FullScreenWindowDetector(
+    ApplicationHandlerFactory application_handler_factory)
+    : application_handler_factory_(application_handler_factory),
+      last_update_time_ms_(0),
+      previous_source_id_(0),
+      no_handler_source_id_(0) {}
+
+DesktopCapturer::SourceId FullScreenWindowDetector::FindFullScreenWindow(
+    DesktopCapturer::SourceId original_source_id) {
+  if (app_handler_ == nullptr ||
+      app_handler_->GetSourceId() != original_source_id) {
+    return 0;
+  }
+  return app_handler_->FindFullScreenWindow(window_list_, last_update_time_ms_);
+}
+
+void FullScreenWindowDetector::UpdateWindowListIfNeeded(
+    DesktopCapturer::SourceId original_source_id,
+    rtc::FunctionView<bool(DesktopCapturer::SourceList*)> get_sources) {
+  const bool skip_update = previous_source_id_ != original_source_id;
+  previous_source_id_ = original_source_id;
+
+  // Here is an attempt to avoid redundant creating application handler in case
+  // when an instance of WindowCapturer is used to generate a thumbnail to show
+  // in picker by calling SelectSource and CaptureFrame for every available
+  // source.
+  if (skip_update) {
+    return;
+  }
+
+  CreateApplicationHandlerIfNeeded(original_source_id);
+  if (app_handler_ == nullptr) {
+    // There is no FullScreenApplicationHandler specific for
+    // current application
+    return;
+  }
+
+  constexpr int64_t kUpdateIntervalMs = 500;
+
+  if ((rtc::TimeMillis() - last_update_time_ms_) <= kUpdateIntervalMs) {
+    return;
+  }
+
+  DesktopCapturer::SourceList window_list;
+  if (get_sources(&window_list)) {
+    last_update_time_ms_ = rtc::TimeMillis();
+    window_list_.swap(window_list);
+  }
+}
+
+void FullScreenWindowDetector::CreateApplicationHandlerIfNeeded(
+    DesktopCapturer::SourceId source_id) {
+  if (no_handler_source_id_ == source_id) {
+    return;
+  }
+
+  if (app_handler_ == nullptr || app_handler_->GetSourceId() != source_id) {
+    app_handler_ = application_handler_factory_
+                       ? application_handler_factory_(source_id)
+                       : nullptr;
+  }
+
+  if (app_handler_ == nullptr) {
+    no_handler_source_id_ = source_id;
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/desktop_capture/full_screen_window_detector.h b/modules/desktop_capture/full_screen_window_detector.h
new file mode 100644
index 0000000..46fb607
--- /dev/null
+++ b/modules/desktop_capture/full_screen_window_detector.h
@@ -0,0 +1,80 @@
+/*
+ *  Copyright (c) 2014 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_FULL_SCREEN_WINDOW_DETECTOR_H_
+#define MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_
+
+#include <memory>
+#include "api/function_view.h"
+#include "api/ref_counted_base.h"
+#include "api/scoped_refptr.h"
+#include "modules/desktop_capture/desktop_capturer.h"
+#include "modules/desktop_capture/full_screen_application_handler.h"
+#include "rtc_base/constructor_magic.h"
+
+namespace webrtc {
+
+// This is a way to handle switch to full-screen mode for application in some
+// specific cases:
+// - Chrome on MacOS creates a new window in full-screen mode to
+//   show a tab full-screen and minimizes the old window.
+// - PowerPoint creates new windows in full-screen mode when user goes to
+//   presentation mode (Slide Show Window, Presentation Window).
+//
+// To continue capturing in these cases, we try to find the new full-screen
+// window using criteria provided by application specific
+// FullScreenApplicationHandler.
+
+class FullScreenWindowDetector : public rtc::RefCountedBase {
+ public:
+  using ApplicationHandlerFactory =
+      std::function<std::unique_ptr<FullScreenApplicationHandler>(
+          DesktopCapturer::SourceId sourceId)>;
+
+  FullScreenWindowDetector(
+      ApplicationHandlerFactory application_handler_factory);
+
+  // Returns the full-screen window in place of the original window if all the
+  // criteria provided by FullScreenApplicationHandler are met, or 0 if no such
+  // window found.
+  DesktopCapturer::SourceId FindFullScreenWindow(
+      DesktopCapturer::SourceId original_source_id);
+
+  // The caller should call this function periodically, implementation will
+  // update internal state no often than twice per second
+  void UpdateWindowListIfNeeded(
+      DesktopCapturer::SourceId original_source_id,
+      rtc::FunctionView<bool(DesktopCapturer::SourceList*)> get_sources);
+
+  static rtc::scoped_refptr<FullScreenWindowDetector>
+  CreateFullScreenWindowDetector();
+
+ protected:
+  std::unique_ptr<FullScreenApplicationHandler> app_handler_;
+
+ private:
+  void CreateApplicationHandlerIfNeeded(DesktopCapturer::SourceId source_id);
+
+  ApplicationHandlerFactory application_handler_factory_;
+
+  int64_t last_update_time_ms_;
+  DesktopCapturer::SourceId previous_source_id_;
+
+  // Save the source id when we fail to create an instance of
+  // CreateApplicationHandlerIfNeeded to avoid redundant attempt to do it again.
+  DesktopCapturer::SourceId no_handler_source_id_;
+
+  DesktopCapturer::SourceList window_list_;
+  RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenWindowDetector);
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_FULL_SCREEN_WINDOW_DETECTOR_H_
diff --git a/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc b/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc
deleted file mode 100644
index f2c8fd4..0000000
--- a/modules/desktop_capture/mac/full_screen_chrome_window_detector.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *  Copyright (c) 2014 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 "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
-
-#include <libproc.h>
-
-#include <string>
-
-#include "modules/desktop_capture/mac/window_list_utils.h"
-#include "rtc_base/logging.h"
-#include "rtc_base/time_utils.h"
-
-namespace webrtc {
-
-namespace {
-
-const int64_t kUpdateIntervalMs = 500;
-
-// Returns the window that is full-screen and has the same title and owner pid
-// as the input window.
-CGWindowID FindFullScreenWindowWithSamePidAndTitle(CGWindowID id) {
-  const int pid = GetWindowOwnerPid(id);
-  std::string title = GetWindowTitle(id);
-  if (title.empty())
-    return kCGNullWindowID;
-
-  // Only get on screen, non-desktop windows.
-  CFArrayRef window_array = CGWindowListCopyWindowInfo(
-      kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
-      kCGNullWindowID);
-  if (!window_array)
-    return kCGNullWindowID;
-
-  CGWindowID full_screen_window = kCGNullWindowID;
-
-  MacDesktopConfiguration desktop_config = MacDesktopConfiguration::GetCurrent(
-      MacDesktopConfiguration::TopLeftOrigin);
-
-  // Check windows to make sure they have an id, title, and use window layer
-  // other than 0.
-  CFIndex count = CFArrayGetCount(window_array);
-  for (CFIndex i = 0; i < count; ++i) {
-    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
-        CFArrayGetValueAtIndex(window_array, i));
-
-    CGWindowID window_id = GetWindowId(window);
-    if (window_id == kNullWindowId)
-      continue;
-
-    if (GetWindowOwnerPid(window) != pid)
-      continue;
-
-    std::string window_title = GetWindowTitle(window);
-    if (window_title != title)
-      continue;
-
-    if (IsWindowFullScreen(desktop_config, window)) {
-      full_screen_window = window_id;
-      break;
-    }
-  }
-
-  CFRelease(window_array);
-  return full_screen_window;
-}
-
-bool IsChromeWindow(CGWindowID id) {
-  int pid = GetWindowOwnerPid(id);
-  char buffer[PROC_PIDPATHINFO_MAXSIZE];
-  int path_length = proc_pidpath(pid, buffer, sizeof(buffer));
-  if (path_length <= 0)
-    return false;
-
-  const char* last_slash = strrchr(buffer, '/');
-  std::string name(last_slash ? last_slash + 1 : buffer);
-  return name.find("Google Chrome") == 0 || name == "Chromium";
-}
-
-}  // namespace
-
-FullScreenChromeWindowDetector::FullScreenChromeWindowDetector()
-    : last_update_time_ns_(0) {}
-
-FullScreenChromeWindowDetector::~FullScreenChromeWindowDetector() {}
-
-CGWindowID FullScreenChromeWindowDetector::FindFullScreenWindow(
-    CGWindowID original_window) {
-  if (!IsChromeWindow(original_window) || IsWindowOnScreen(original_window))
-    return kCGNullWindowID;
-
-  CGWindowID full_screen_window_id =
-      FindFullScreenWindowWithSamePidAndTitle(original_window);
-
-  if (full_screen_window_id == kCGNullWindowID)
-    return kCGNullWindowID;
-
-  for (const auto& window : previous_window_list_) {
-    if (static_cast<CGWindowID>(window.id) != full_screen_window_id)
-      continue;
-
-    RTC_LOG(LS_WARNING) << "The full-screen window exists in the list.";
-    return kCGNullWindowID;
-  }
-
-  return full_screen_window_id;
-}
-
-void FullScreenChromeWindowDetector::UpdateWindowListIfNeeded(
-    CGWindowID original_window) {
-  if (IsChromeWindow(original_window) &&
-      (rtc::TimeNanos() - last_update_time_ns_) / rtc::kNumNanosecsPerMillisec >
-          kUpdateIntervalMs) {
-    previous_window_list_.clear();
-    previous_window_list_.swap(current_window_list_);
-
-    // No need to update the window list when the window is minimized.
-    if (!IsWindowOnScreen(original_window)) {
-      previous_window_list_.clear();
-      return;
-    }
-
-    GetWindowList(&current_window_list_, false);
-    last_update_time_ns_ = rtc::TimeNanos();
-  }
-}
-
-}  // namespace webrtc
diff --git a/modules/desktop_capture/mac/full_screen_chrome_window_detector.h b/modules/desktop_capture/mac/full_screen_chrome_window_detector.h
deleted file mode 100644
index 2ee99ad..0000000
--- a/modules/desktop_capture/mac/full_screen_chrome_window_detector.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- *  Copyright (c) 2014 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_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
-#define MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
-
-#include <ApplicationServices/ApplicationServices.h>
-
-#include "api/ref_counted_base.h"
-#include "modules/desktop_capture/desktop_capturer.h"
-#include "rtc_base/constructor_magic.h"
-
-namespace webrtc {
-
-// This is a work around for the Chrome tab full-screen behavior: Chrome
-// creates a new window in full-screen mode to show a tab full-screen and
-// minimizes the old window. To continue capturing in this case, we try to
-// find the new full-screen window using these criteria:
-// 0. The original shared window is minimized.
-// 1. The original shared window's owner application name is "Google Chrome".
-// 2. The original window and the new window have the same title and owner
-// pid.
-// 3. The new window is full-screen.
-// 4. The new window didn't exist at least 500 millisecond ago.
-
-class FullScreenChromeWindowDetector : public rtc::RefCountedBase {
- public:
-  FullScreenChromeWindowDetector();
-
-  // Returns the full-screen window in place of the original window if all the
-  // criteria are met, or kCGNullWindowID if no such window found.
-  CGWindowID FindFullScreenWindow(CGWindowID original_window);
-
-  // The caller should call this function periodically, no less than twice per
-  // second.
-  void UpdateWindowListIfNeeded(CGWindowID original_window);
-
- protected:
-  ~FullScreenChromeWindowDetector() override;
-
- private:
-  // We cache the last two results of the window list, so
-  // |previous_window_list_| is taken at least 500ms before the next Capture()
-  // call. If we only save the last result, we may get false positive (i.e.
-  // full-screen window exists in the list) if Capture() is called too soon.
-  DesktopCapturer::SourceList current_window_list_;
-  DesktopCapturer::SourceList previous_window_list_;
-  int64_t last_update_time_ns_;
-
-  RTC_DISALLOW_COPY_AND_ASSIGN(FullScreenChromeWindowDetector);
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_CHROME_WINDOW_DETECTOR_H_
diff --git a/modules/desktop_capture/mac/full_screen_mac_application_handler.cc b/modules/desktop_capture/mac/full_screen_mac_application_handler.cc
new file mode 100644
index 0000000..9e6eacc
--- /dev/null
+++ b/modules/desktop_capture/mac/full_screen_mac_application_handler.cc
@@ -0,0 +1,174 @@
+/*
+ *  Copyright (c) 2019 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 "modules/desktop_capture/mac/full_screen_mac_application_handler.h"
+#include <libproc.h>
+#include <algorithm>
+#include <functional>
+#include <string>
+#include "absl/strings/match.h"
+#include "modules/desktop_capture/mac/window_list_utils.h"
+
+namespace webrtc {
+namespace {
+
+static constexpr const char* kPowerPointSlideShowTitles[] = {
+    u8"PowerPoint-Bildschirmpräsentation",
+    u8"Προβολή παρουσίασης PowerPoint",
+    u8"PowerPoint スライド ショー",
+    u8"PowerPoint Slide Show",
+    u8"PowerPoint 幻灯片放映",
+    u8"Presentación de PowerPoint",
+    u8"PowerPoint-slideshow",
+    u8"Presentazione di PowerPoint",
+    u8"Prezentácia programu PowerPoint",
+    u8"Apresentação do PowerPoint",
+    u8"PowerPoint-bildspel",
+    u8"Prezentace v aplikaci PowerPoint",
+    u8"PowerPoint 슬라이드 쇼",
+    u8"PowerPoint-lysbildefremvisning",
+    u8"PowerPoint-vetítés",
+    u8"PowerPoint Slayt Gösterisi",
+    u8"Pokaz slajdów programu PowerPoint",
+    u8"PowerPoint 投影片放映",
+    u8"Демонстрация PowerPoint",
+    u8"Diaporama PowerPoint",
+    u8"PowerPoint-diaesitys",
+    u8"Peragaan Slide PowerPoint",
+    u8"PowerPoint-diavoorstelling",
+    u8"การนำเสนอสไลด์ PowerPoint",
+    u8"Apresentação de slides do PowerPoint",
+    u8"הצגת שקופיות של PowerPoint",
+    u8"عرض شرائح في PowerPoint"};
+
+class FullScreenMacApplicationHandler : public FullScreenApplicationHandler {
+ public:
+  using TitlePredicate =
+      std::function<bool(const std::string&, const std::string&)>;
+
+  FullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId,
+                                  TitlePredicate title_predicate)
+      : FullScreenApplicationHandler(sourceId),
+        title_predicate_(title_predicate),
+        owner_pid_(GetWindowOwnerPid(sourceId)) {}
+
+  void InvalidateCacheIfNeeded(const DesktopCapturer::SourceList& source_list,
+                               int64_t timestamp) const {
+    // Copy only sources with the same pid
+    if (timestamp != cache_timestamp_) {
+      cache_sources_.clear();
+      std::copy_if(source_list.begin(), source_list.end(),
+                   std::back_inserter(cache_sources_),
+                   [&](const DesktopCapturer::Source& src) {
+                     return src.id != GetSourceId() &&
+                            GetWindowOwnerPid(src.id) == owner_pid_;
+                   });
+      cache_timestamp_ = timestamp;
+    }
+  }
+
+  WindowId FindFullScreenWindowWithSamePid(
+      const DesktopCapturer::SourceList& source_list,
+      int64_t timestamp) const {
+    InvalidateCacheIfNeeded(source_list, timestamp);
+    if (cache_sources_.empty())
+      return kCGNullWindowID;
+
+    const auto original_window = GetSourceId();
+    const std::string title = GetWindowTitle(original_window);
+
+    // We can ignore any windows with empty titles cause regardless type of
+    // application it's impossible to verify that full screen window and
+    // original window are related to the same document.
+    if (title.empty())
+      return kCGNullWindowID;
+
+    MacDesktopConfiguration desktop_config =
+        MacDesktopConfiguration::GetCurrent(
+            MacDesktopConfiguration::TopLeftOrigin);
+
+    const auto it = std::find_if(
+        cache_sources_.begin(), cache_sources_.end(),
+        [&](const DesktopCapturer::Source& src) {
+          const std::string window_title = GetWindowTitle(src.id);
+
+          if (window_title.empty())
+            return false;
+
+          if (title_predicate_ && !title_predicate_(title, window_title))
+            return false;
+
+          return IsWindowFullScreen(desktop_config, src.id);
+        });
+
+    return it != cache_sources_.end() ? it->id : 0;
+  }
+
+  DesktopCapturer::SourceId FindFullScreenWindow(
+      const DesktopCapturer::SourceList& source_list,
+      int64_t timestamp) const override {
+    return IsWindowOnScreen(GetSourceId())
+               ? 0
+               : FindFullScreenWindowWithSamePid(source_list, timestamp);
+  }
+
+ private:
+  const TitlePredicate title_predicate_;
+  const int owner_pid_;
+  mutable int64_t cache_timestamp_ = 0;
+  mutable DesktopCapturer::SourceList cache_sources_;
+};
+
+bool equal_title_predicate(const std::string& original_title,
+                           const std::string& title) {
+  return original_title == title;
+}
+
+bool slide_show_title_predicate(const std::string& original_title,
+                                const std::string& title) {
+  if (title.find(original_title) == std::string::npos)
+    return false;
+
+  for (const char* pp_slide_title : kPowerPointSlideShowTitles) {
+    if (absl::StartsWith(title, pp_slide_title))
+      return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+std::unique_ptr<FullScreenApplicationHandler>
+CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId) {
+  std::unique_ptr<FullScreenApplicationHandler> result;
+  int pid = GetWindowOwnerPid(sourceId);
+  char buffer[PROC_PIDPATHINFO_MAXSIZE];
+  int path_length = proc_pidpath(pid, buffer, sizeof(buffer));
+  if (path_length > 0) {
+    const char* last_slash = strrchr(buffer, '/');
+    const std::string name{last_slash ? last_slash + 1 : buffer};
+    FullScreenMacApplicationHandler::TitlePredicate predicate = nullptr;
+    if (name.find("Google Chrome") == 0 || name == "Chromium") {
+      predicate = equal_title_predicate;
+    } else if (name == "Microsoft PowerPoint") {
+      predicate = slide_show_title_predicate;
+    } else if (name == "Keynote") {
+      predicate = equal_title_predicate;
+    }
+
+    if (predicate) {
+      result.reset(new FullScreenMacApplicationHandler(sourceId, predicate));
+    }
+  }
+
+  return result;
+}
+
+}  // namespace webrtc
diff --git a/modules/desktop_capture/mac/full_screen_mac_application_handler.h b/modules/desktop_capture/mac/full_screen_mac_application_handler.h
new file mode 100644
index 0000000..f795a22
--- /dev/null
+++ b/modules/desktop_capture/mac/full_screen_mac_application_handler.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (c) 2019 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_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_
+#define MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_
+
+#include <memory>
+#include "modules/desktop_capture/full_screen_application_handler.h"
+
+namespace webrtc {
+
+std::unique_ptr<FullScreenApplicationHandler>
+CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId);
+
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_MAC_FULL_SCREEN_MAC_APPLICATION_HANDLER_H_
diff --git a/modules/desktop_capture/mac/window_list_utils.cc b/modules/desktop_capture/mac/window_list_utils.cc
index 3f0a9b0..67cf81c 100644
--- a/modules/desktop_capture/mac/window_list_utils.cc
+++ b/modules/desktop_capture/mac/window_list_utils.cc
@@ -15,8 +15,11 @@
 #include <algorithm>
 #include <cmath>
 #include <iterator>
+#include <limits>
 #include <list>
 #include <map>
+#include <memory>
+#include <utility>
 
 #include "rtc_base/checks.h"
 
@@ -78,7 +81,8 @@
 }  // namespace
 
 bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
-                   bool ignore_minimized) {
+                   bool ignore_minimized,
+                   bool only_zero_layer) {
   RTC_DCHECK(on_window);
 
   // Only get on screen, non-desktop windows.
@@ -122,7 +126,7 @@
     if (!CFNumberGetValue(window_layer, kCFNumberIntType, &layer)) {
       continue;
     }
-    if (layer != 0) {
+    if (only_zero_layer && layer != 0) {
       continue;
     }
 
@@ -151,7 +155,8 @@
 }
 
 bool GetWindowList(DesktopCapturer::SourceList* windows,
-                   bool ignore_minimized) {
+                   bool ignore_minimized,
+                   bool only_zero_layer) {
   // Use a std::list so that iterators are preversed upon insertion and
   // deletion.
   std::list<DesktopCapturer::Source> sources;
@@ -201,7 +206,7 @@
         }
         return true;
       },
-      ignore_minimized);
+      ignore_minimized, only_zero_layer);
 
   if (!ret)
     return false;
@@ -239,6 +244,15 @@
   return fullscreen;
 }
 
+bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
+                        CGWindowID id) {
+  bool fullscreen = false;
+  GetWindowRef(id, [&](CFDictionaryRef window) {
+    fullscreen = IsWindowFullScreen(desktop_config, window);
+  });
+  return fullscreen;
+}
+
 bool IsWindowOnScreen(CFDictionaryRef window) {
   CFBooleanRef on_screen = reinterpret_cast<CFBooleanRef>(
       CFDictionaryGetValue(window, kCGWindowIsOnscreen));
diff --git a/modules/desktop_capture/mac/window_list_utils.h b/modules/desktop_capture/mac/window_list_utils.h
index ff9ad14..f1c0601 100644
--- a/modules/desktop_capture/mac/window_list_utils.h
+++ b/modules/desktop_capture/mac/window_list_utils.h
@@ -13,6 +13,7 @@
 
 #include <ApplicationServices/ApplicationServices.h>
 
+#include <string>
 #include "api/function_view.h"
 #include "modules/desktop_capture/desktop_capture_types.h"
 #include "modules/desktop_capture/desktop_capturer.h"
@@ -24,18 +25,26 @@
 // Iterates all on-screen windows in decreasing z-order and sends them
 // one-by-one to |on_window| function. If |on_window| returns false, this
 // function returns immediately. GetWindowList() returns false if native APIs
-// failed. Menus, dock, minimized windows (if |ignore_minimized| is true) and
-// any windows which do not have a valid window id or title will be ignored.
+// failed. Menus, dock (if |only_zero_layer|), minimized windows (if
+// |ignore_minimized| is true) and any windows which do not have a valid window
+// id or title will be ignored.
 bool GetWindowList(rtc::FunctionView<bool(CFDictionaryRef)> on_window,
-                   bool ignore_minimized);
+                   bool ignore_minimized,
+                   bool only_zero_layer);
 
 // Another helper function to get the on-screen windows.
-bool GetWindowList(DesktopCapturer::SourceList* windows, bool ignore_minimized);
+bool GetWindowList(DesktopCapturer::SourceList* windows,
+                   bool ignore_minimized,
+                   bool only_zero_layer);
 
 // Returns true if the window is occupying a full screen.
 bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
                         CFDictionaryRef window);
 
+// Returns true if the window is occupying a full screen.
+bool IsWindowFullScreen(const MacDesktopConfiguration& desktop_config,
+                        CGWindowID id);
+
 // Returns true if the |window| is on screen. This function returns false if
 // native APIs fail.
 bool IsWindowOnScreen(CFDictionaryRef window);
diff --git a/modules/desktop_capture/mouse_cursor_monitor_mac.mm b/modules/desktop_capture/mouse_cursor_monitor_mac.mm
index afc4497..31ad428 100644
--- a/modules/desktop_capture/mouse_cursor_monitor_mac.mm
+++ b/modules/desktop_capture/mouse_cursor_monitor_mac.mm
@@ -24,7 +24,6 @@
 #include "modules/desktop_capture/desktop_frame.h"
 #include "modules/desktop_capture/mac/desktop_configuration.h"
 #include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
-#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
 #include "modules/desktop_capture/mac/window_list_utils.h"
 #include "modules/desktop_capture/mouse_cursor.h"
 
@@ -79,21 +78,16 @@
   Callback* callback_;
   Mode mode_;
   __strong NSImage* last_cursor_;
-  rtc::scoped_refptr<FullScreenChromeWindowDetector>
-      full_screen_chrome_window_detector_;
 };
 
-MouseCursorMonitorMac::MouseCursorMonitorMac(
-    const DesktopCaptureOptions& options,
-    CGWindowID window_id,
-    ScreenId screen_id)
+MouseCursorMonitorMac::MouseCursorMonitorMac(const DesktopCaptureOptions& options,
+                                             CGWindowID window_id,
+                                             ScreenId screen_id)
     : configuration_monitor_(options.configuration_monitor()),
       window_id_(window_id),
       screen_id_(screen_id),
       callback_(NULL),
-      mode_(SHAPE_AND_POSITION),
-      full_screen_chrome_window_detector_(
-          options.full_screen_chrome_window_detector()) {
+      mode_(SHAPE_AND_POSITION) {
   assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId);
 }
 
diff --git a/modules/desktop_capture/win/full_screen_win_application_handler.cc b/modules/desktop_capture/win/full_screen_win_application_handler.cc
new file mode 100644
index 0000000..0b7e3fc
--- /dev/null
+++ b/modules/desktop_capture/win/full_screen_win_application_handler.cc
@@ -0,0 +1,208 @@
+/*
+ *  Copyright (c) 2019 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 "modules/desktop_capture/win/full_screen_win_application_handler.h"
+#include <algorithm>
+#include <cwctype>
+#include <memory>
+#include <string>
+#include <vector>
+#include "rtc_base/arraysize.h"
+#include "rtc_base/logging.h"  // For RTC_LOG_GLE
+#include "rtc_base/string_utils.h"
+
+namespace webrtc {
+namespace {
+
+std::string WindowText(HWND window) {
+  size_t len = ::GetWindowTextLength(window);
+  if (len == 0)
+    return std::string();
+
+  std::vector<wchar_t> buffer(len + 1, 0);
+  size_t copied = ::GetWindowTextW(window, buffer.data(), buffer.size());
+  if (copied == 0)
+    return std::string();
+  return rtc::ToUtf8(buffer.data(), copied);
+}
+
+DWORD WindowProcessId(HWND window) {
+  DWORD dwProcessId = 0;
+  ::GetWindowThreadProcessId(window, &dwProcessId);
+  return dwProcessId;
+}
+
+std::wstring FileNameFromPath(const std::wstring& path) {
+  auto found = path.rfind(L"\\");
+  if (found == std::string::npos)
+    return path;
+  return path.substr(found + 1);
+}
+
+// Returns windows which belong to given process id
+// |sources| is a full list of available windows
+// |processId| is a process identifier (window owner)
+// |window_to_exclude| is a window to be exluded from result
+DesktopCapturer::SourceList GetProcessWindows(
+    const DesktopCapturer::SourceList& sources,
+    DWORD processId,
+    HWND window_to_exclude) {
+  DesktopCapturer::SourceList result;
+  std::copy_if(sources.begin(), sources.end(), std::back_inserter(result),
+               [&](DesktopCapturer::Source source) {
+                 const HWND source_hwnd = reinterpret_cast<HWND>(source.id);
+                 return window_to_exclude != source_hwnd &&
+                        WindowProcessId(source_hwnd) == processId;
+               });
+  return result;
+}
+
+class FullScreenPowerPointHandler : public FullScreenApplicationHandler {
+ public:
+  explicit FullScreenPowerPointHandler(DesktopCapturer::SourceId sourceId)
+      : FullScreenApplicationHandler(sourceId) {}
+
+  ~FullScreenPowerPointHandler() override {}
+
+  DesktopCapturer::SourceId FindFullScreenWindow(
+      const DesktopCapturer::SourceList& window_list,
+      int64_t timestamp) const override {
+    if (window_list.empty())
+      return 0;
+
+    HWND original_window = reinterpret_cast<HWND>(GetSourceId());
+    DWORD process_id = WindowProcessId(original_window);
+
+    DesktopCapturer::SourceList powerpoint_windows =
+        GetProcessWindows(window_list, process_id, original_window);
+
+    if (powerpoint_windows.empty())
+      return 0;
+
+    if (GetWindowType(original_window) != WindowType::kEditor)
+      return 0;
+
+    const auto original_document = GetDocumentFromEditorTitle(original_window);
+
+    for (const auto& source : powerpoint_windows) {
+      HWND window = reinterpret_cast<HWND>(source.id);
+
+      // Looking for slide show window for the same document
+      if (GetWindowType(window) != WindowType::kSlideShow ||
+          GetDocumentFromSlideShowTitle(window) != original_document) {
+        continue;
+      }
+
+      return source.id;
+    }
+
+    return 0;
+  }
+
+ private:
+  enum class WindowType { kEditor, kSlideShow, kOther };
+
+  WindowType GetWindowType(HWND window) const {
+    if (IsEditorWindow(window))
+      return WindowType::kEditor;
+    else if (IsSlideShowWindow(window))
+      return WindowType::kSlideShow;
+    else
+      return WindowType::kOther;
+  }
+
+  constexpr static char kDocumentTitleSeparator[] = " - ";
+
+  std::string GetDocumentFromEditorTitle(HWND window) const {
+    std::string title = WindowText(window);
+    auto position = title.find(kDocumentTitleSeparator);
+    return rtc::string_trim(title.substr(0, position));
+  }
+
+  std::string GetDocumentFromSlideShowTitle(HWND window) const {
+    std::string title = WindowText(window);
+    auto left_pos = title.find(kDocumentTitleSeparator);
+    auto right_pos = title.rfind(kDocumentTitleSeparator);
+    constexpr size_t kSeparatorLength = arraysize(kDocumentTitleSeparator) - 1;
+    if (left_pos == std::string::npos || right_pos == std::string::npos)
+      return title;
+
+    if (right_pos > left_pos + kSeparatorLength) {
+      auto result_len = right_pos - left_pos - kSeparatorLength;
+      auto document = title.substr(left_pos + kSeparatorLength, result_len);
+      return rtc::string_trim(document);
+    } else {
+      auto document =
+          title.substr(left_pos + kSeparatorLength, std::wstring::npos);
+      return rtc::string_trim(document);
+    }
+  }
+
+  bool IsEditorWindow(HWND window) const {
+    constexpr WCHAR kScreenClassName[] = L"PPTFrameClass";
+    constexpr size_t kScreenClassNameLength = arraysize(kScreenClassName) - 1;
+
+    // We need to verify that window class is equal to |kScreenClassName|.
+    // To do that we need a buffer large enough to include a null terminated
+    // string one code point bigger than |kScreenClassName|. It will help us to
+    // check that size of class name string returned by GetClassNameW is equal
+    // to |kScreenClassNameLength| not being limited by size of buffer (case
+    // when |kScreenClassName| is a prefix for class name string).
+    WCHAR buffer[arraysize(kScreenClassName) + 3];
+    const int length = ::GetClassNameW(window, buffer, arraysize(buffer));
+    if (length != kScreenClassNameLength)
+      return false;
+    return wcsncmp(buffer, kScreenClassName, kScreenClassNameLength) == 0;
+  }
+
+  bool IsSlideShowWindow(HWND window) const {
+    const LONG style = ::GetWindowLong(window, GWL_STYLE);
+    const bool min_box = WS_MINIMIZEBOX & style;
+    const bool max_box = WS_MAXIMIZEBOX & style;
+    return !min_box && !max_box;
+  }
+};
+
+std::wstring GetPathByWindowId(HWND window_id) {
+  DWORD process_id = WindowProcessId(window_id);
+  HANDLE process =
+      ::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id);
+  if (process == NULL)
+    return L"";
+  DWORD path_len = MAX_PATH;
+  WCHAR path[MAX_PATH];
+  std::wstring result;
+  if (::QueryFullProcessImageNameW(process, 0, path, &path_len))
+    result = std::wstring(path, path_len);
+  else
+    RTC_LOG_GLE(LS_ERROR) << "QueryFullProcessImageName failed.";
+
+  ::CloseHandle(process);
+  return result;
+}
+
+}  // namespace
+
+std::unique_ptr<FullScreenApplicationHandler>
+CreateFullScreenWinApplicationHandler(DesktopCapturer::SourceId source_id) {
+  std::unique_ptr<FullScreenApplicationHandler> result;
+  std::wstring exe_path = GetPathByWindowId(reinterpret_cast<HWND>(source_id));
+  std::wstring file_name = FileNameFromPath(exe_path);
+  std::transform(file_name.begin(), file_name.end(), file_name.begin(),
+                 std::towupper);
+
+  if (file_name == L"POWERPNT.EXE") {
+    result = std::make_unique<FullScreenPowerPointHandler>(source_id);
+  }
+
+  return result;
+}
+
+}  // namespace webrtc
diff --git a/modules/desktop_capture/win/full_screen_win_application_handler.h b/modules/desktop_capture/win/full_screen_win_application_handler.h
new file mode 100644
index 0000000..c97cbe2
--- /dev/null
+++ b/modules/desktop_capture/win/full_screen_win_application_handler.h
@@ -0,0 +1,24 @@
+/*
+ *  Copyright (c) 2019 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_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_
+#define MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_
+
+#include <memory>
+#include "modules/desktop_capture/full_screen_application_handler.h"
+
+namespace webrtc {
+
+std::unique_ptr<FullScreenApplicationHandler>
+CreateFullScreenWinApplicationHandler(DesktopCapturer::SourceId sourceId);
+
+}  // namespace webrtc
+
+#endif  // MODULES_DESKTOP_CAPTURE_WIN_FULL_SCREEN_WIN_APPLICATION_HANDLER_H_
diff --git a/modules/desktop_capture/window_capturer_mac.mm b/modules/desktop_capture/window_capturer_mac.mm
index 828122b..96f89eb 100644
--- a/modules/desktop_capture/window_capturer_mac.mm
+++ b/modules/desktop_capture/window_capturer_mac.mm
@@ -22,7 +22,6 @@
 #include "modules/desktop_capture/mac/desktop_configuration.h"
 #include "modules/desktop_capture/mac/desktop_configuration_monitor.h"
 #include "modules/desktop_capture/mac/desktop_frame_cgimage.h"
-#include "modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
 #include "modules/desktop_capture/mac/window_list_utils.h"
 #include "modules/desktop_capture/window_finder_mac.h"
 #include "rtc_base/constructor_magic.h"
@@ -48,10 +47,9 @@
 
 class WindowCapturerMac : public DesktopCapturer {
  public:
-  explicit WindowCapturerMac(rtc::scoped_refptr<FullScreenChromeWindowDetector>
-                                 full_screen_chrome_window_detector,
-                             rtc::scoped_refptr<DesktopConfigurationMonitor>
-                                 configuration_monitor);
+  explicit WindowCapturerMac(
+      rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector,
+      rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor);
   ~WindowCapturerMac() override;
 
   // DesktopCapturer interface.
@@ -68,8 +66,7 @@
   // The window being captured.
   CGWindowID window_id_ = 0;
 
-  const rtc::scoped_refptr<FullScreenChromeWindowDetector>
-      full_screen_chrome_window_detector_;
+  rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector_;
 
   const rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
 
@@ -79,18 +76,16 @@
 };
 
 WindowCapturerMac::WindowCapturerMac(
-    rtc::scoped_refptr<FullScreenChromeWindowDetector>
-        full_screen_chrome_window_detector,
+    rtc::scoped_refptr<FullScreenWindowDetector> full_screen_window_detector,
     rtc::scoped_refptr<DesktopConfigurationMonitor> configuration_monitor)
-    : full_screen_chrome_window_detector_(
-          std::move(full_screen_chrome_window_detector)),
+    : full_screen_window_detector_(std::move(full_screen_window_detector)),
       configuration_monitor_(std::move(configuration_monitor)),
       window_finder_(configuration_monitor_) {}
 
 WindowCapturerMac::~WindowCapturerMac() {}
 
 bool WindowCapturerMac::GetSourceList(SourceList* sources) {
-  return webrtc::GetWindowList(sources, true);
+  return webrtc::GetWindowList(sources, true, true);
 }
 
 bool WindowCapturerMac::SelectSource(SourceId id) {
@@ -163,12 +158,15 @@
   }
 
   CGWindowID on_screen_window = window_id_;
-  if (full_screen_chrome_window_detector_) {
-    CGWindowID full_screen_window =
-        full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_);
+  if (full_screen_window_detector_) {
+    full_screen_window_detector_->UpdateWindowListIfNeeded(
+        window_id_, [](DesktopCapturer::SourceList* sources) {
+          return webrtc::GetWindowList(sources, true, false);
+        });
 
-    if (full_screen_window != kCGNullWindowID)
-      on_screen_window = full_screen_window;
+    CGWindowID full_screen_window = full_screen_window_detector_->FindFullScreenWindow(window_id_);
+
+    if (full_screen_window != kCGNullWindowID) on_screen_window = full_screen_window;
   }
 
   std::unique_ptr<DesktopFrame> frame = DesktopFrameCGImage::CreateForWindow(on_screen_window);
@@ -186,9 +184,6 @@
   frame->set_dpi(DesktopVector(kStandardDPI * scale_factor, kStandardDPI * scale_factor));
 
   callback_->OnCaptureResult(Result::SUCCESS, std::move(frame));
-
-  if (full_screen_chrome_window_detector_)
-    full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_);
 }
 
 }  // namespace
@@ -196,9 +191,8 @@
 // static
 std::unique_ptr<DesktopCapturer> DesktopCapturer::CreateRawWindowCapturer(
     const DesktopCaptureOptions& options) {
-  return std::unique_ptr<DesktopCapturer>(
-      new WindowCapturerMac(options.full_screen_chrome_window_detector(),
-                            options.configuration_monitor()));
+  return std::unique_ptr<DesktopCapturer>(new WindowCapturerMac(
+      options.full_screen_window_detector(), options.configuration_monitor()));
 }
 
 }  // namespace webrtc
diff --git a/modules/desktop_capture/window_finder_mac.mm b/modules/desktop_capture/window_finder_mac.mm
index 64979c6..e1d0316 100644
--- a/modules/desktop_capture/window_finder_mac.mm
+++ b/modules/desktop_capture/window_finder_mac.mm
@@ -38,6 +38,7 @@
         }
         return true;
       },
+      true,
       true);
   return id;
 }