blob: 9e6eacce8525891bbb0e46e22682495cbcef4168 [file] [log] [blame]
* 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",
u8"PowerPoint スライド ショー",
u8"PowerPoint Slide Show",
u8"PowerPoint 幻灯片放映",
u8"Presentación de PowerPoint",
u8"Presentazione di PowerPoint",
u8"Prezentácia programu PowerPoint",
u8"Apresentação do PowerPoint",
u8"Prezentace v aplikaci PowerPoint",
u8"PowerPoint 슬라이드 쇼",
u8"PowerPoint Slayt Gösterisi",
u8"Pokaz slajdów programu PowerPoint",
u8"PowerPoint 投影片放映",
u8"Демонстрация PowerPoint",
u8"Diaporama PowerPoint",
u8"Peragaan Slide PowerPoint",
u8"การนำเสนอสไลด์ PowerPoint",
u8"Apresentação de slides do PowerPoint",
u8"הצגת שקופיות של PowerPoint",
u8"عرض شرائح في PowerPoint"};
class FullScreenMacApplicationHandler : public FullScreenApplicationHandler {
using TitlePredicate =
std::function<bool(const std::string&, const std::string&)>;
FullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId,
TitlePredicate title_predicate)
: FullScreenApplicationHandler(sourceId),
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_) {
std::copy_if(source_list.begin(), source_list.end(),
[&](const DesktopCapturer::Source& src) {
return != GetSourceId() &&
GetWindowOwnerPid( == 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 =
const auto it = std::find_if(
cache_sources_.begin(), cache_sources_.end(),
[&](const DesktopCapturer::Source& src) {
const std::string window_title = GetWindowTitle(;
if (window_title.empty())
return false;
if (title_predicate_ && !title_predicate_(title, window_title))
return false;
return IsWindowFullScreen(desktop_config,;
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);
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
CreateFullScreenMacApplicationHandler(DesktopCapturer::SourceId sourceId) {
std::unique_ptr<FullScreenApplicationHandler> result;
int pid = GetWindowOwnerPid(sourceId);
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