* 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}
175 lines
6.0 KiB
C++
175 lines
6.0 KiB
C++
/*
|
|
* 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
|